Wed Aug 18 22:33:42 2010

Asterisk developer's documentation


app_rpt.c

Go to the documentation of this file.
00001 #define  NEW_ASTERISK
00002 /* #define OLD_ASTERISK */
00003 /*
00004  * Asterisk -- An open source telephony toolkit.
00005  *
00006  * Copyright (C) 2002-2008, Jim Dixon, WB6NIL
00007  *
00008  * Jim Dixon, WB6NIL <jim@lambdatel.com>
00009  * Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
00010  *
00011  * See http://www.asterisk.org for more information about
00012  * the Asterisk project. Please do not directly contact
00013  * any of the maintainers of this project for assistance;
00014  * the project provides a web site, mailing lists and IRC
00015  * channels for your use.
00016  *
00017  * This program is free software, distributed under the terms of
00018  * the GNU General Public License Version 2. See the LICENSE file
00019  * at the top of the source tree.
00020  */
00021 /*! \file
00022  *
00023  * \brief Radio Repeater / Remote Base program 
00024  *  version 0.115 5/12/08 2055 EDT
00025  * 
00026  * \author Jim Dixon, WB6NIL <jim@lambdatel.com>
00027  *
00028  * \note Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
00029  * \note Steven Henke, W9SH, <w9sh@arrl.net> added a few features here and there.
00030  *
00031  * See http://www.zapatatelephony.org/app_rpt.html
00032  *
00033  *
00034  * Repeater / Remote Functions:
00035  * "Simple" Mode:  * - autopatch access, # - autopatch hangup
00036  * Normal mode:
00037  * See the function list in rpt.conf (autopatchup, autopatchdn)
00038  * autopatchup can optionally take comma delimited setting=value pairs:
00039  *  
00040  *
00041  * context=string    :  Override default context with "string"
00042  * dialtime=ms       :  Specify the max number of milliseconds between phone number digits (1000 milliseconds = 1 second)
00043  * farenddisconnect=1      :  Automatically disconnect when called party hangs up
00044  * noct=1         :  Don't send repeater courtesy tone during autopatch calls
00045  * quiet=1        :  Don't send dial tone, or connect messages. Do not send patch down message when called party hangs up
00046  *
00047  *
00048  * Example: 123=autopatchup,dialtime=20000,noct=1,farenddisconnect=1
00049  *
00050  *  To send an asterisk (*) while dialing or talking on phone,
00051  *  use the autopatch acess code.
00052  *
00053  *
00054  * status cmds:
00055  *
00056  *  1 - Force ID (global)
00057  *  2 - Give Time of Day (global)
00058  *  3 - Give software Version (global)
00059  *  11 - Force ID (local only)
00060  *  12 - Give Time of Day (local only)
00061  *
00062  * cop (control operator) cmds:
00063  *
00064  *  1 - System warm boot
00065  *  2 - System enable
00066  *  3 - System disable
00067  *  4 - Test Tone On/Off
00068  *  5 - Dump System Variables on Console (debug)
00069  *  6 - PTT (phone mode only)
00070  *  7 - Time out timer enable
00071  *  8 - Time out timer disable
00072  *  9 - Autopatch enable
00073  *  10 - Autopatch disable
00074  *  11 - Link enable
00075  *  12 - Link disable
00076  *  13 - Query System State
00077  *  14 - Change System State
00078  *  15 - Scheduler Enable
00079  *  16 - Scheduler Disable
00080  *  17 - User functions (time, id, etc) enable
00081  *  18 - User functions (time, id, etc) disable
00082  *  19 - Select alternate hang timer
00083  *  20 - Select standard hang timer 
00084  *  21 - Enable Parrot Mode
00085  *  22 - Disable Parrot Mode
00086  *  23 - Birdbath (Current Parrot Cleanup/Flush)
00087  *  24 - Flush all telemetry
00088  *  25 - Query last node un-keyed
00089  *  26 - Query all nodes keyed/unkeyed
00090  *  30 - Recall Memory Setting in Attached Xcvr
00091  *  31 - Channel Selector for Parallel Programmed Xcvr
00092  *  32 - Touchtone pad test: command + Digit string + # to playback all digits pressed
00093  *
00094  * ilink cmds:
00095  *
00096  *  1 - Disconnect specified link
00097  *  2 - Connect specified link -- monitor only
00098  *  3 - Connect specified link -- tranceive
00099  *  4 - Enter command mode on specified link
00100  *  5 - System status
00101  *  6 - Disconnect all links
00102  *  11 - Disconnect a previously permanently connected link
00103  *  12 - Permanently connect specified link -- monitor only
00104  *  13 - Permanently connect specified link -- tranceive
00105  *  15 - Full system status (all nodes)
00106  *  16 - Reconnect links disconnected with "disconnect all links"
00107  *  200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
00108  *
00109  * remote cmds:
00110  *
00111  *  1 - Recall Memory MM  (*000-*099) (Gets memory from rpt.conf)
00112  *  2 - Set VFO MMMMM*KKK*O   (Mhz digits, Khz digits, Offset)
00113  *  3 - Set Rx PL Tone HHH*D*
00114  *  4 - Set Tx PL Tone HHH*D* (Not currently implemented with DHE RBI-1)
00115  *  5 - Link Status (long)
00116  *  6 - Set operating mode M (FM, USB, LSB, AM, etc)
00117  *  100 - RX PL off (Default)
00118  *  101 - RX PL On
00119  *  102 - TX PL Off (Default)
00120  *  103 - TX PL On
00121  *  104 - Low Power
00122  *  105 - Med Power
00123  *  106 - Hi Power
00124  *  107 - Bump Down 20 Hz
00125  *  108 - Bump Down 100 Hz
00126  *  109 - Bump Down 500 Hz
00127  *  110 - Bump Up 20 Hz
00128  *  111 - Bump Up 100 Hz
00129  *  112 - Bump Up 500 Hz
00130  *  113 - Scan Down Slow
00131  *  114 - Scan Down Medium
00132  *  115 - Scan Down Fast
00133  *  116 - Scan Up Slow
00134  *  117 - Scan Up Medium
00135  *  118 - Scan Up Fast
00136  *  119 - Transmit allowing auto-tune
00137  *  140 - Link Status (brief)
00138  *  200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
00139  *
00140  * playback cmds:
00141  *  specify the name of the file to be played (for example, 25=rpt/foo)
00142  *
00143  *
00144  * 'duplex' modes:  (defaults to duplex=2)
00145  *
00146  * 0 - Only remote links key Tx and no main repeat audio.
00147  * 1 - Everything other then main Rx keys Tx, no main repeat audio.
00148  * 2 - Normal mode
00149  * 3 - Normal except no main repeat audio.
00150  * 4 - Normal except no main repeat audio during autopatch only
00151  *
00152 */
00153 
00154 /*** MODULEINFO
00155    <depend>dahdi</depend>
00156    <depend>tonezone</depend>
00157    <defaultenabled>no</defaultenabled>
00158  ***/
00159 
00160 /* Un-comment the following to include support for MDC-1200 digital tone
00161    signalling protocol (using KA6SQG's GPL'ed implementation) */
00162 /* #include "mdc_decode.c" */
00163 
00164 /* Un-comment the following to include support for notch filters in the
00165    rx audio stream (using Tony Fisher's mknotch (mkfilter) implementation) */
00166 /* #include "rpt_notch.c" */
00167 
00168 /* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
00169 
00170 #ifdef OLD_ASTERISK
00171 #define ast_free free
00172 #define ast_malloc malloc
00173 #define ast_strdup strdup
00174 #endif
00175 
00176 
00177 #define  MAXDTMF 32
00178 #define  MAXMACRO 2048
00179 #define  MAXLINKLIST 512
00180 #define  LINKLISTTIME 10000
00181 #define  LINKLISTSHORTTIME 200
00182 #define  LINKPOSTTIME 30000
00183 #define  LINKPOSTSHORTTIME 200
00184 #define  KEYPOSTTIME 30000
00185 #define  KEYPOSTSHORTTIME 200
00186 #define  MACROTIME 100
00187 #define  MACROPTIME 500
00188 #define  DTMF_TIMEOUT 3
00189 #define  KENWOOD_RETRIES 5
00190 #define  TOPKEYN 32
00191 #define  TOPKEYWAIT 3
00192 #define  TOPKEYMAXSTR 30
00193 
00194 #define  AUTHTELLTIME 7000
00195 #define  AUTHTXTIME 1000
00196 #define  AUTHLOGOUTTIME 25000
00197 
00198 #ifdef   __RPT_NOTCH
00199 #define  MAXFILTERS 10
00200 #endif
00201 
00202 #define  DISC_TIME 10000  /* report disc after 10 seconds of no connect */
00203 #define  MAX_RETRIES 5
00204 #define  MAX_RETRIES_PERM 1000000000
00205 
00206 #define  REDUNDANT_TX_TIME 2000
00207 
00208 #define  RETRY_TIMER_MS 5000
00209 
00210 #define  PATCH_DIALPLAN_TIMEOUT 1500
00211 
00212 #ifdef OLD_ASTERISK
00213 #define  START_DELAY 10
00214 #else
00215 #define  START_DELAY 2
00216 #endif
00217 
00218 #define  RPT_LOCKOUT_SECS 10
00219 
00220 #define MAXPEERSTR 31
00221 #define  MAXREMSTR 15
00222 
00223 #define  DELIMCHR ','
00224 #define  QUOTECHR 34
00225 
00226 #define  MONITOR_DISK_BLOCKS_PER_MINUTE 38
00227 
00228 #define  DEFAULT_MONITOR_MIN_DISK_BLOCKS 10000
00229 #define  DEFAULT_REMOTE_INACT_TIMEOUT (15 * 60)
00230 #define  DEFAULT_REMOTE_TIMEOUT (60 * 60)
00231 #define  DEFAULT_REMOTE_TIMEOUT_WARNING (3 * 60)
00232 #define  DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ 30
00233 
00234 #define  NODES "nodes"
00235 #define  EXTNODES "extnodes"
00236 #define MEMORY "memory"
00237 #define MACRO "macro"
00238 #define  FUNCTIONS "functions"
00239 #define TELEMETRY "telemetry"
00240 #define MORSE "morse"
00241 #define  TONEMACRO "tonemacro"
00242 #define  FUNCCHAR '*'
00243 #define  ENDCHAR '#'
00244 #define  EXTNODEFILE "/var/lib/asterisk/rpt_extnodes"
00245 #define  NODENAMES "rpt/nodenames"
00246 #define  PARROTFILE "/tmp/parrot_%s_%u"
00247 
00248 #define  PARROTTIME 1000
00249 
00250 #define  DEFAULT_IOBASE 0x378
00251 
00252 #define  DEFAULT_CIV_ADDR 0x58
00253 
00254 #define  MAXCONNECTTIME 5000
00255 
00256 #define MAXNODESTR 300
00257 
00258 #define MAXNODELEN 16
00259 
00260 #define MAXIDENTLEN 32
00261 
00262 #define MAXPATCHCONTEXT 100
00263 
00264 #define ACTIONSIZE 32
00265 
00266 #define TELEPARAMSIZE 256
00267 
00268 #define REM_SCANTIME 100
00269 
00270 #define  DTMF_LOCAL_TIME 250
00271 #define  DTMF_LOCAL_STARTTIME 500
00272 
00273 #define  IC706_PL_MEMORY_OFFSET 50
00274 
00275 #define  VOX_ON_DEBOUNCE_COUNT 3
00276 #define  VOX_OFF_DEBOUNCE_COUNT 20
00277 #define  VOX_MAX_THRESHOLD 10000.0
00278 #define  VOX_MIN_THRESHOLD 3000.0
00279 #define  VOX_TIMEOUT_MS 5000
00280 #define  VOX_RECOVER_MS 500
00281 #define  SIMPLEX_PATCH_DELAY 25
00282 #define  SIMPLEX_PHONE_DELAY 25
00283 
00284 #define  STATPOST_PROGRAM "/usr/bin/wget,-q,--output-document=/dev/null,--no-check-certificate"
00285 
00286 #define  ALLOW_LOCAL_CHANNELS
00287 
00288 enum {REM_OFF,REM_MONITOR,REM_TX};
00289 
00290 enum{ID,PROC,TERM,COMPLETE,UNKEY,REMDISC,REMALREADY,REMNOTFOUND,REMGO,
00291    CONNECTED,CONNFAIL,STATUS,TIMEOUT,ID1, STATS_TIME, PLAYBACK,
00292    STATS_VERSION, IDTALKOVER, ARB_ALPHA, TEST_TONE, REV_PATCH,
00293    TAILMSG, MACRO_NOTFOUND, MACRO_BUSY, LASTNODEKEY, FULLSTATUS,
00294    MEMNOTFOUND, INVFREQ, REMMODE, REMLOGIN, REMXXX, REMSHORTSTATUS,
00295    REMLONGSTATUS, LOGINREQ, SCAN, SCANSTAT, TUNE, SETREMOTE, TOPKEY,
00296    TIMEOUT_WARNING, ACT_TIMEOUT_WARNING, LINKUNKEY, UNAUTHTX, PARROT,
00297    STATS_TIME_LOCAL};
00298 
00299 
00300 enum {REM_SIMPLEX,REM_MINUS,REM_PLUS};
00301 
00302 enum {REM_LOWPWR,REM_MEDPWR,REM_HIPWR};
00303 
00304 enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_COMPLETEQUIET, DC_DOKEY};
00305 
00306 enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT, SOURCE_PHONE, SOURCE_DPHONE, SOURCE_ALT};
00307 
00308 enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM, DLY_COMP, DLY_LINKUNKEY, DLY_PARROT};
00309 
00310 enum {REM_MODE_FM,REM_MODE_USB,REM_MODE_LSB,REM_MODE_AM};
00311 
00312 enum {HF_SCAN_OFF,HF_SCAN_DOWN_SLOW,HF_SCAN_DOWN_QUICK,
00313       HF_SCAN_DOWN_FAST,HF_SCAN_UP_SLOW,HF_SCAN_UP_QUICK,HF_SCAN_UP_FAST};
00314 
00315 #include "asterisk.h"
00316 
00317 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 211569 $")
00318 
00319 #include <signal.h>
00320 #include <stdio.h>
00321 #include <stdint.h>
00322 #include <unistd.h>
00323 #include <string.h>
00324 #include <stdlib.h>
00325 #include <search.h>
00326 #include <sys/types.h>
00327 #include <sys/stat.h>
00328 #include <errno.h>
00329 #include <dirent.h>
00330 #include <ctype.h>
00331 #include <sys/stat.h>
00332 #include <sys/time.h>
00333 #include <sys/file.h>
00334 #include <sys/ioctl.h>
00335 #ifdef HAVE_SYS_IO_H
00336 #include <sys/io.h>
00337 #endif
00338 #include <sys/vfs.h>
00339 #include <math.h>
00340 #include <dahdi/user.h>
00341 #include <dahdi/tonezone.h>
00342 #include <netinet/in.h>
00343 #include <arpa/inet.h>
00344 
00345 #include "asterisk/utils.h"
00346 #include "asterisk/lock.h"
00347 #include "asterisk/file.h"
00348 #include "asterisk/logger.h"
00349 #include "asterisk/channel.h"
00350 #include "asterisk/callerid.h"
00351 #include "asterisk/pbx.h"
00352 #include "asterisk/module.h"
00353 #include "asterisk/translate.h"
00354 #include "asterisk/features.h"
00355 #include "asterisk/options.h"
00356 #include "asterisk/cli.h"
00357 #include "asterisk/config.h"
00358 #include "asterisk/say.h"
00359 #include "asterisk/localtime.h"
00360 #include "asterisk/cdr.h"
00361 #include "asterisk/options.h"
00362 #include "asterisk/manager.h"
00363 #include "asterisk/app.h"
00364 
00365 #include <termios.h>
00366 
00367 #ifdef   NEW_ASTERISK
00368 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
00369 #endif
00370 
00371 
00372 /* Start a tone-list going */
00373 int ast_playtones_start(struct ast_channel *chan, int vol, const char* tonelist, int interruptible);
00374 /*! Stop the tones from playing */
00375 void ast_playtones_stop(struct ast_channel *chan);
00376 
00377 static  char *tdesc = "Radio Repeater / Remote Base  version 0.115  5/12/2008";
00378 
00379 static char *app = "Rpt";
00380 
00381 static char *synopsis = "Radio Repeater/Remote Base Control System";
00382 
00383 static char *descrip = 
00384 "  Rpt(nodename[|options][|M][|*]):  \n"
00385 "    Radio Remote Link or Remote Base Link Endpoint Process.\n"
00386 "\n"
00387 "    Not specifying an option puts it in normal endpoint mode (where source\n"
00388 "    IP and nodename are verified).\n"
00389 "\n"
00390 "    Options are as follows:\n"
00391 "\n"
00392 "        X - Normal endpoint mode WITHOUT security check. Only specify\n"
00393 "            this if you have checked security already (like with an IAX2\n"
00394 "            user/password or something).\n"
00395 "\n"
00396 "        Rannounce-string[|timeout[|timeout-destination]] - Amateur Radio\n"
00397 "            Reverse Autopatch. Caller is put on hold, and announcement (as\n"
00398 "            specified by the 'announce-string') is played on radio system.\n"
00399 "            Users of radio system can access autopatch, dial specified\n"
00400 "            code, and pick up call. Announce-string is list of names of\n"
00401 "            recordings, or \"PARKED\" to substitute code for un-parking,\n"
00402 "            or \"NODE\" to substitute node number.\n"
00403 "\n"
00404 "        P - Phone Control mode. This allows a regular phone user to have\n"
00405 "            full control and audio access to the radio system. For the\n"
00406 "            user to have DTMF control, the 'phone_functions' parameter\n"
00407 "            must be specified for the node in 'rpt.conf'. An additional\n"
00408 "            function (cop,6) must be listed so that PTT control is available.\n"
00409 "\n"
00410 "        D - Dumb Phone Control mode. This allows a regular phone user to\n"
00411 "            have full control and audio access to the radio system. In this\n"
00412 "            mode, the PTT is activated for the entire length of the call.\n"
00413 "            For the user to have DTMF control (not generally recomended in\n"
00414 "            this mode), the 'dphone_functions' parameter must be specified\n"
00415 "            for the node in 'rpt.conf'. Otherwise no DTMF control will be\n"
00416 "            available to the phone user.\n"
00417 "\n"
00418 "        S - Simplex Dumb Phone Control mode. This allows a regular phone user\n"
00419 "            audio-only access to the radio system. In this mode, the\n"
00420 "            transmitter is toggled on and off when the phone user presses the\n"
00421 "            funcchar (*) key on the telephone set. In addition, the transmitter\n"
00422 "            will turn off if the endchar (#) key is pressed. When a user first\n"
00423 "            calls in, the transmitter will be off, and the user can listen for\n"
00424 "            radio traffic. When the user wants to transmit, they press the *\n" 
00425 "            key, start talking, then press the * key again or the # key to turn\n"
00426 "            the transmitter off.  No other functions can be executed by the\n"
00427 "            user on the phone when this mode is selected. Note: If your\n"
00428 "            radio system is full-duplex, we recommend using either P or D\n"
00429 "            modes as they provide more flexibility.\n"
00430 "\n"
00431 "        q - Query Status. Sets channel variables and returns + 101 in plan.\n"
00432 "\n"
00433 "        M - Memory Channel Steer as MXX where XX is the memory channel number.\n"
00434 "\n"
00435 "        * - Alt Macro to execute (e.g. *7 for status)\n"
00436 "\n";
00437 ;
00438 
00439 static int debug = 0;  /* Set this >0 for extra debug output */
00440 static int nrpts = 0;
00441 
00442 static char remdtmfstr[] = "0123456789*#ABCD";
00443 
00444 enum {TOP_TOP,TOP_WON,WON_BEFREAD,BEFREAD_AFTERREAD};
00445 
00446 int max_chan_stat [] = {22000,1000,22000,100,22000,2000,22000};
00447 
00448 #define NRPTSTAT 7
00449 
00450 struct rpt_chan_stat
00451 {
00452    struct timeval last;
00453    long long total;
00454    unsigned long count;
00455    unsigned long largest;
00456    struct timeval largest_time;
00457 };
00458 
00459 char *discstr = "!!DISCONNECT!!";
00460 char *newkeystr = "!NEWKEY!";
00461 static char *remote_rig_ft897="ft897";
00462 static char *remote_rig_rbi="rbi";
00463 static char *remote_rig_kenwood="kenwood";
00464 static char *remote_rig_tm271="tm271";
00465 static char *remote_rig_ic706="ic706";
00466 static char *remote_rig_rtx150="rtx150";
00467 static char *remote_rig_rtx450="rtx450";
00468 static char *remote_rig_ppp16="ppp16";       // parallel port programmable 16 channels
00469 
00470 #define ISRIG_RTX(x) ((!strcmp(x,remote_rig_rtx150)) || (!strcmp(x,remote_rig_rtx450)))
00471 #define  IS_XPMR(x) (!strncasecmp(x->rxchanname,"rad",3))
00472 
00473 #ifdef   OLD_ASTERISK
00474 STANDARD_LOCAL_USER;
00475 LOCAL_USER_DECL;
00476 #endif
00477 
00478 #define  MSWAIT 200
00479 #define  HANGTIME 5000
00480 #define  TOTIME 180000
00481 #define  IDTIME 300000
00482 #define  MAXRPTS 20
00483 #define MAX_STAT_LINKS 32
00484 #define POLITEID 30000
00485 #define FUNCTDELAY 1500
00486 
00487 #define  MAXXLAT 20
00488 #define  MAXXLATTIME 3
00489 
00490 #define MAX_SYSSTATES 10
00491 
00492 struct vox {
00493    float speech_energy;
00494    float noise_energy;
00495    int   enacount;
00496    char  voxena;
00497    char  lastvox;
00498    int   offdebcnt;
00499    int   ondebcnt;
00500 } ;
00501 
00502 #define  mymax(x,y) ((x > y) ? x : y)
00503 #define  mymin(x,y) ((x < y) ? x : y)
00504 
00505 struct rpt_topkey
00506 {
00507 char  node[TOPKEYMAXSTR];
00508 int   timesince;
00509 int   keyed;
00510 } ;
00511 
00512 struct rpt_xlat
00513 {
00514 char  funccharseq[MAXXLAT];
00515 char  endcharseq[MAXXLAT];
00516 char  passchars[MAXXLAT];
00517 int   funcindex;
00518 int   endindex;
00519 time_t   lastone;
00520 } ;
00521 
00522 static time_t  starttime = 0;
00523 
00524 static  pthread_t rpt_master_thread;
00525 
00526 struct rpt;
00527 
00528 struct rpt_link
00529 {
00530    struct rpt_link *next;
00531    struct rpt_link *prev;
00532    char  mode;       /* 1 if in tx mode */
00533    char  isremote;
00534    char  phonemode;
00535    char  phonevox;      /* vox the phone */
00536    char  name[MAXNODESTR]; /* identifier (routing) string */
00537    char  lasttx;
00538    char  lasttx1;
00539    char  lastrx;
00540    char  lastrealrx;
00541    char  lastrx1;
00542    char  connected;
00543    char  hasconnected;
00544    char  perma;
00545    char  thisconnected;
00546    char  outbound;
00547    char  disced;
00548    char  killme;
00549    long  elaptime;
00550    long  disctime;
00551    long  retrytimer;
00552    long  retxtimer;
00553    long  rerxtimer;
00554    int   retries;
00555    int   max_retries;
00556    int   reconnects;
00557    long long connecttime;
00558    struct ast_channel *chan;  
00559    struct ast_channel *pchan; 
00560    char  linklist[MAXLINKLIST];
00561    time_t   linklistreceived;
00562    long  linklisttimer;
00563    int   dtmfed;
00564    int linkunkeytocttimer;
00565    struct timeval lastlinktv;
00566    struct   ast_frame *lastf1,*lastf2;
00567    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00568    struct vox vox;
00569    char wasvox;
00570    int voxtotimer;
00571    char voxtostate;
00572    char newkey;
00573 #ifdef OLD_ASTERISK
00574         AST_LIST_HEAD(, ast_frame) rxq;
00575 #else
00576    AST_LIST_HEAD_NOLOCK(, ast_frame) rxq;
00577 #endif
00578 } ;
00579 
00580 struct rpt_lstat
00581 {
00582    struct   rpt_lstat *next;
00583    struct   rpt_lstat *prev;
00584    char  peer[MAXPEERSTR];
00585    char  name[MAXNODESTR];
00586    char  mode;
00587    char  outbound;
00588    char  reconnects;
00589    char  thisconnected;
00590    long long   connecttime;
00591    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00592 } ;
00593 
00594 struct rpt_tele
00595 {
00596    struct rpt_tele *next;
00597    struct rpt_tele *prev;
00598    struct rpt *rpt;
00599    struct ast_channel *chan;
00600    int   mode;
00601    struct rpt_link mylink;
00602    char param[TELEPARAMSIZE];
00603    intptr_t submode;
00604    uintptr_t  parrot;
00605    pthread_t threadid;
00606 } ;
00607 
00608 struct function_table_tag
00609 {
00610    char action[ACTIONSIZE];
00611    int (*function)(struct rpt *myrpt, char *param, char *digitbuf, 
00612       int command_source, struct rpt_link *mylink);
00613 } ;
00614 
00615 /* Used to store the morse code patterns */
00616 
00617 struct morse_bits
00618 {       
00619    int len;
00620    int ddcomb;
00621 } ;
00622 
00623 struct telem_defaults
00624 {
00625    char name[20];
00626    char value[80];
00627 } ;
00628 
00629 
00630 struct sysstate
00631 {
00632    char txdisable;
00633    char totdisable;
00634    char linkfundisable;
00635    char autopatchdisable;
00636    char schedulerdisable;
00637    char userfundisable;
00638    char alternatetail;
00639 };
00640 
00641 /* rpt cmd support */
00642 #define CMD_DEPTH 1
00643 #define CMD_STATE_IDLE 0
00644 #define CMD_STATE_BUSY 1
00645 #define CMD_STATE_READY 2
00646 #define CMD_STATE_EXECUTING 3
00647 
00648 struct rpt_cmd_struct
00649 {
00650     int state;
00651     int functionNumber;
00652     char param[MAXDTMF];
00653     char digits[MAXDTMF];
00654     int command_source;
00655 };
00656 
00657 static struct rpt
00658 {
00659    ast_mutex_t lock;
00660    ast_mutex_t remlock;
00661    ast_mutex_t statpost_lock;
00662    struct ast_config *cfg;
00663    char reload;
00664    char xlink;                         // cross link state of a share repeater/remote radio
00665    unsigned int statpost_seqno;
00666 
00667    char *name;
00668    char *rxchanname;
00669    char *txchanname;
00670    char remote;
00671    char *remoterig;
00672    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00673    unsigned int scram;
00674 
00675    struct {
00676       char *ourcontext;
00677       char *ourcallerid;
00678       char *acctcode;
00679       char *ident;
00680       char *tonezone;
00681       char simple;
00682       char *functions;
00683       char *link_functions;
00684       char *phone_functions;
00685       char *dphone_functions;
00686       char *alt_functions;
00687       char *nodes;
00688       char *extnodes;
00689       char *extnodefile;
00690       int hangtime;
00691       int althangtime;
00692       int totime;
00693       int idtime;
00694       int tailmessagetime;
00695       int tailsquashedtime;
00696       int duplex;
00697       int politeid;
00698       char *tailmessages[500];
00699       int tailmessagemax;
00700       char  *memory;
00701       char  *macro;
00702       char  *tonemacro;
00703       char  *startupmacro;
00704       int iobase;
00705       char *ioport;
00706       char funcchar;
00707       char endchar;
00708       char nobusyout;
00709       char notelemtx;
00710       char propagate_dtmf;
00711       char propagate_phonedtmf;
00712       char linktolink;
00713       unsigned char civaddr;
00714       struct rpt_xlat inxlat;
00715       struct rpt_xlat outxlat;
00716       char *archivedir;
00717       int authlevel;
00718       char *csstanzaname;
00719       char *skedstanzaname;
00720       char *txlimitsstanzaname;
00721       long monminblocks;
00722       int remoteinacttimeout;
00723       int remotetimeout;
00724       int remotetimeoutwarning;
00725       int remotetimeoutwarningfreq;
00726       int sysstate_cur;
00727       struct sysstate s[MAX_SYSSTATES];
00728       char parrotmode;
00729       int parrottime;
00730       char *rptnode;
00731       char remote_mars;
00732       int voxtimeout_ms;
00733       int voxrecover_ms;
00734       int simplexpatchdelay;
00735       int simplexphonedelay;
00736       char *statpost_program;
00737       char *statpost_url;
00738    } p;
00739    struct rpt_link links;
00740    int unkeytocttimer;
00741    time_t lastkeyedtime;
00742    time_t lasttxkeyedtime;
00743    char keyed;
00744    char txkeyed;
00745    char exttx;
00746    char localtx;
00747    char remoterx;
00748    char remotetx;
00749    char remoteon;
00750    char remtxfreqok;
00751    char tounkeyed;
00752    char tonotify;
00753    char dtmfbuf[MAXDTMF];
00754    char macrobuf[MAXMACRO];
00755    char rem_dtmfbuf[MAXDTMF];
00756    char lastdtmfcommand[MAXDTMF];
00757    char cmdnode[50];
00758    char nowchan;                 // channel now
00759    char waschan;                 // channel selected initially or by command
00760    char bargechan;                  // barge in channel
00761    char macropatch;              // autopatch via tonemacro state
00762    char parrotstate;
00763    int  parrottimer;
00764    unsigned int parrotcnt;
00765    struct ast_channel *rxchannel,*txchannel, *monchannel, *parrotchannel;
00766    struct ast_channel *pchannel,*txpchannel, *dahdirxchannel, *dahditxchannel;
00767    struct ast_channel *voxchannel;
00768    struct ast_frame *lastf1,*lastf2;
00769    struct rpt_tele tele;
00770    struct timeval lasttv,curtv;
00771    pthread_t rpt_call_thread,rpt_thread;
00772    time_t dtmf_time,rem_dtmf_time,dtmf_time_rem;
00773    int calldigittimer;
00774    int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx,scantimer,tmsgtimer,skedtimer;
00775    int mustid,tailid;
00776    int tailevent;
00777    int telemrefcount;
00778    int dtmfidx,rem_dtmfidx;
00779    int dailytxtime,dailykerchunks,totalkerchunks,dailykeyups,totalkeyups,timeouts;
00780    int totalexecdcommands, dailyexecdcommands;
00781    long  retxtimer;
00782    long  rerxtimer;
00783    long long totaltxtime;
00784    char mydtmf;
00785    char exten[AST_MAX_EXTENSION];
00786    char freq[MAXREMSTR],rxpl[MAXREMSTR],txpl[MAXREMSTR];
00787    char offset;
00788    char powerlevel;
00789    char txplon;
00790    char rxplon;
00791    char remmode;
00792    char tunerequest;
00793    char hfscanmode;
00794    int hfscanstatus;
00795    char hfscanstop;
00796    char lastlinknode[MAXNODESTR];
00797    char savednodes[MAXNODESTR];
00798    int stopgen;
00799    char patchfarenddisconnect;
00800    char patchnoct;
00801    char patchquiet;
00802    char patchcontext[MAXPATCHCONTEXT];
00803    int patchdialtime;
00804    int macro_longest;
00805    int phone_longestfunc;
00806    int alt_longestfunc;
00807    int dphone_longestfunc;
00808    int link_longestfunc;
00809    int longestfunc;
00810    int longestnode;
00811    int threadrestarts;     
00812    int tailmessagen;
00813    time_t disgorgetime;
00814    time_t lastthreadrestarttime;
00815    long  macrotimer;
00816    char  lastnodewhichkeyedusup[MAXNODESTR];
00817    int   dtmf_local_timer;
00818    char  dtmf_local_str[100];
00819    struct ast_filestream *monstream,*parrotstream;
00820    char  loginuser[50];
00821    char  loginlevel[10];
00822    long  authtelltimer;
00823    long  authtimer;
00824    int iofd;
00825    time_t start_time,last_activity_time;
00826    char  lasttone[32];
00827    struct rpt_tele *active_telem;
00828    struct   rpt_topkey topkey[TOPKEYN];
00829    int topkeystate;
00830    time_t topkeytime;
00831    int topkeylong;
00832    struct vox vox;
00833    char wasvox;
00834    int voxtotimer;
00835    char voxtostate;
00836    int linkposttimer;         
00837    int keyposttimer;       
00838    char newkey;
00839    char inpadtest;
00840 #ifdef OLD_ASTERISK
00841    AST_LIST_HEAD(, ast_frame) txq;
00842 #else
00843    AST_LIST_HEAD_NOLOCK(, ast_frame) txq;
00844 #endif
00845    char txrealkeyed;
00846 #ifdef   __RPT_NOTCH
00847    struct rptfilter
00848    {
00849       char  desc[100];
00850       float x0;
00851       float x1;
00852       float x2;
00853       float y0;
00854       float y1;
00855       float y2;
00856       float gain;
00857       float const0;
00858       float const1;
00859       float const2;
00860    } filters[MAXFILTERS];
00861 #endif
00862 #ifdef   _MDC_DECODE_H_
00863    mdc_decoder_t *mdc;
00864    unsigned short lastunit;
00865 #endif
00866    struct rpt_cmd_struct cmdAction;
00867 } rpt_vars[MAXRPTS]; 
00868 
00869 struct nodelog {
00870 struct nodelog *next;
00871 struct nodelog *prev;
00872 time_t   timestamp;
00873 char archivedir[MAXNODESTR];
00874 char str[MAXNODESTR * 2];
00875 } nodelog;
00876 
00877 static int service_scan(struct rpt *myrpt);
00878 static int set_mode_ft897(struct rpt *myrpt, char newmode);
00879 static int set_mode_ic706(struct rpt *myrpt, char newmode);
00880 static int simple_command_ft897(struct rpt *myrpt, char command);
00881 static int setrem(struct rpt *myrpt);
00882 static int setrtx_check(struct rpt *myrpt);
00883 static int channel_revert(struct rpt *myrpt);
00884 static int channel_steer(struct rpt *myrpt, char *data);
00885 
00886 AST_MUTEX_DEFINE_STATIC(nodeloglock);
00887 
00888 AST_MUTEX_DEFINE_STATIC(nodelookuplock);
00889 
00890 #ifdef   APP_RPT_LOCK_DEBUG
00891 
00892 #warning COMPILING WITH LOCK-DEBUGGING ENABLED!!
00893 
00894 #define  MAXLOCKTHREAD 100
00895 
00896 #define rpt_mutex_lock(x) _rpt_mutex_lock(x,myrpt,__LINE__)
00897 #define rpt_mutex_unlock(x) _rpt_mutex_unlock(x,myrpt,__LINE__)
00898 
00899 struct lockthread
00900 {
00901    pthread_t id;
00902    int lockcount;
00903    int lastlock;
00904    int lastunlock;
00905 } lockthreads[MAXLOCKTHREAD];
00906 
00907 
00908 struct by_lightning
00909 {
00910    int line;
00911    struct timeval tv;
00912    struct rpt *rpt;
00913    struct lockthread lockthread;
00914 } lock_ring[32];
00915 
00916 int lock_ring_index = 0;
00917 
00918 AST_MUTEX_DEFINE_STATIC(locklock);
00919 
00920 static struct lockthread *get_lockthread(pthread_t id)
00921 {
00922 int   i;
00923 
00924    for(i = 0; i < MAXLOCKTHREAD; i++)
00925    {
00926       if (lockthreads[i].id == id) return(&lockthreads[i]);
00927    }
00928    return(NULL);
00929 }
00930 
00931 static struct lockthread *put_lockthread(pthread_t id)
00932 {
00933 int   i;
00934 
00935    for(i = 0; i < MAXLOCKTHREAD; i++)
00936    {
00937       if (lockthreads[i].id == id)
00938          return(&lockthreads[i]);
00939    }
00940    for(i = 0; i < MAXLOCKTHREAD; i++)
00941    {
00942       if (!lockthreads[i].id)
00943       {
00944          lockthreads[i].lockcount = 0;
00945          lockthreads[i].lastlock = 0;
00946          lockthreads[i].lastunlock = 0;
00947          lockthreads[i].id = id;
00948          return(&lockthreads[i]);
00949       }
00950    }
00951    return(NULL);
00952 }
00953 
00954 
00955 static void rpt_mutex_spew(void)
00956 {
00957    struct by_lightning lock_ring_copy[32];
00958    int lock_ring_index_copy;
00959    int i,j;
00960    long long diff;
00961    char a[100];
00962    struct timeval lasttv;
00963 
00964    ast_mutex_lock(&locklock);
00965    memcpy(&lock_ring_copy, &lock_ring, sizeof(lock_ring_copy));
00966    lock_ring_index_copy = lock_ring_index;
00967    ast_mutex_unlock(&locklock);
00968 
00969    lasttv.tv_sec = lasttv.tv_usec = 0;
00970    for(i = 0 ; i < 32 ; i++)
00971    {
00972       j = (i + lock_ring_index_copy) % 32;
00973       strftime(a,sizeof(a) - 1,"%m/%d/%Y %H:%M:%S",
00974          localtime(&lock_ring_copy[j].tv.tv_sec));
00975       diff = 0;
00976       if(lasttv.tv_sec)
00977       {
00978          diff = (lock_ring_copy[j].tv.tv_sec - lasttv.tv_sec)
00979             * 1000000;
00980          diff += (lock_ring_copy[j].tv.tv_usec - lasttv.tv_usec);
00981       }
00982       lasttv.tv_sec = lock_ring_copy[j].tv.tv_sec;
00983       lasttv.tv_usec = lock_ring_copy[j].tv.tv_usec;
00984       if (!lock_ring_copy[j].tv.tv_sec) continue;
00985       if (lock_ring_copy[j].line < 0)
00986       {
00987          ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] UNLOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
00988             i - 31,-lock_ring_copy[j].line,lock_ring_copy[j].rpt->name,(int) lock_ring_copy[j].lockthread.id,diff,a,(int)lock_ring_copy[j].tv.tv_usec);
00989       }
00990       else
00991       {
00992          ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] LOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
00993             i - 31,lock_ring_copy[j].line,lock_ring_copy[j].rpt->name,(int) lock_ring_copy[j].lockthread.id,diff,a,(int)lock_ring_copy[j].tv.tv_usec);
00994       }
00995    }
00996 }
00997 
00998 
00999 static void _rpt_mutex_lock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
01000 {
01001 struct lockthread *t;
01002 pthread_t id;
01003 
01004    id = pthread_self();
01005    ast_mutex_lock(&locklock);
01006    t = put_lockthread(id);
01007    if (!t)
01008    {
01009       ast_mutex_unlock(&locklock);
01010       return;
01011    }
01012    if (t->lockcount)
01013    {
01014       int lastline = t->lastlock;
01015       ast_mutex_unlock(&locklock);
01016       ast_log(LOG_NOTICE,"rpt_mutex_lock: Double lock request line %d node %s pid %x, last lock was line %d\n",line,myrpt->name,(int) t->id,lastline);
01017       rpt_mutex_spew();
01018       return;
01019    }
01020    t->lastlock = line;
01021    t->lockcount = 1;
01022    gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
01023    lock_ring[lock_ring_index].rpt = myrpt;
01024    memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
01025    lock_ring[lock_ring_index++].line = line;
01026    if(lock_ring_index == 32)
01027       lock_ring_index = 0;
01028    ast_mutex_unlock(&locklock);
01029    ast_mutex_lock(lockp);
01030 }
01031 
01032 
01033 static void _rpt_mutex_unlock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
01034 {
01035 struct lockthread *t;
01036 pthread_t id;
01037 
01038    id = pthread_self();
01039    ast_mutex_lock(&locklock);
01040    t = put_lockthread(id);
01041    if (!t)
01042    {
01043       ast_mutex_unlock(&locklock);
01044       return;
01045    }
01046    if (!t->lockcount)
01047    {
01048       int lastline = t->lastunlock;
01049       ast_mutex_unlock(&locklock);
01050       ast_log(LOG_NOTICE,"rpt_mutex_lock: Double un-lock request line %d node %s pid %x, last un-lock was line %d\n",line,myrpt->name,(int) t->id,lastline);
01051       rpt_mutex_spew();
01052       return;
01053    }
01054    t->lastunlock = line;
01055    t->lockcount = 0;
01056    gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
01057    lock_ring[lock_ring_index].rpt = myrpt;
01058    memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
01059    lock_ring[lock_ring_index++].line = -line;
01060    if(lock_ring_index == 32)
01061       lock_ring_index = 0;
01062    ast_mutex_unlock(&locklock);
01063    ast_mutex_unlock(lockp);
01064 }
01065 
01066 #else  /* APP_RPT_LOCK_DEBUG */
01067 
01068 #define rpt_mutex_lock(x) ast_mutex_lock(x)
01069 #define rpt_mutex_unlock(x) ast_mutex_unlock(x)
01070 
01071 #endif  /* APP_RPT_LOCK_DEBUG */
01072 
01073 /*
01074 * Return 1 if rig is multimode capable
01075 */
01076 
01077 static int multimode_capable(struct rpt *myrpt)
01078 {
01079    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
01080       return 1;
01081    if(!strcmp(myrpt->remoterig, remote_rig_ic706))
01082       return 1;
01083    return 0;
01084 }  
01085 
01086 static void voxinit_rpt(struct rpt *myrpt,char enable)
01087 {
01088 
01089    myrpt->vox.speech_energy = 0.0;
01090    myrpt->vox.noise_energy = 0.0;
01091    myrpt->vox.enacount = 0;
01092    myrpt->vox.voxena = 0;
01093    if (!enable) myrpt->vox.voxena = -1;
01094    myrpt->vox.lastvox = 0;
01095    myrpt->vox.ondebcnt = VOX_ON_DEBOUNCE_COUNT;
01096    myrpt->vox.offdebcnt = VOX_OFF_DEBOUNCE_COUNT;
01097    myrpt->wasvox = 0;
01098    myrpt->voxtotimer = 0;
01099    myrpt->voxtostate = 0;
01100 }
01101 
01102 static void voxinit_link(struct rpt_link *mylink,char enable)
01103 {
01104 
01105    mylink->vox.speech_energy = 0.0;
01106    mylink->vox.noise_energy = 0.0;
01107    mylink->vox.enacount = 0;
01108    mylink->vox.voxena = 0;
01109    if (!enable) mylink->vox.voxena = -1;
01110    mylink->vox.lastvox = 0;
01111    mylink->vox.ondebcnt = VOX_ON_DEBOUNCE_COUNT;
01112    mylink->vox.offdebcnt = VOX_OFF_DEBOUNCE_COUNT;
01113    mylink->wasvox = 0;
01114    mylink->voxtotimer = 0;
01115    mylink->voxtostate = 0;
01116 }
01117 
01118 static int dovox(struct vox *v,short *buf,int bs)
01119 {
01120 
01121    int i;
01122    float esquare = 0.0;
01123    float energy = 0.0;
01124    float threshold = 0.0;
01125    
01126    if (v->voxena < 0) return(v->lastvox);
01127    for(i = 0; i < bs; i++)
01128    {
01129       esquare += (float) buf[i] * (float) buf[i];
01130    }
01131    energy = sqrt(esquare);
01132 
01133    if (energy >= v->speech_energy)
01134       v->speech_energy += (energy - v->speech_energy) / 4;
01135    else
01136       v->speech_energy += (energy - v->speech_energy) / 64;
01137 
01138    if (energy >= v->noise_energy)
01139       v->noise_energy += (energy - v->noise_energy) / 64;
01140    else
01141       v->noise_energy += (energy - v->noise_energy) / 4;
01142    
01143    if (v->voxena) threshold = v->speech_energy / 8;
01144    else
01145    {
01146       threshold = mymax(v->speech_energy / 16,v->noise_energy * 2);
01147       threshold = mymin(threshold,VOX_MAX_THRESHOLD);
01148    }
01149    threshold = mymax(threshold,VOX_MIN_THRESHOLD);
01150    if (energy > threshold)
01151    {
01152       if (v->voxena) v->noise_energy *= 0.75;
01153       v->voxena = 1;
01154    } else   v->voxena = 0;
01155    if (v->lastvox != v->voxena)
01156    {
01157       if (v->enacount++ >= ((v->lastvox) ? v->offdebcnt : v->ondebcnt))
01158       {
01159          v->lastvox = v->voxena;
01160          v->enacount = 0;
01161       }
01162    } else v->enacount = 0;
01163    return(v->lastvox);
01164 }
01165 
01166 
01167 
01168 
01169 /*
01170 * CLI extensions
01171 */
01172 
01173 /* Debug mode */
01174 static int rpt_do_debug(int fd, int argc, char *argv[]);
01175 static int rpt_do_dump(int fd, int argc, char *argv[]);
01176 static int rpt_do_stats(int fd, int argc, char *argv[]);
01177 static int rpt_do_lstats(int fd, int argc, char *argv[]);
01178 static int rpt_do_nodes(int fd, int argc, char *argv[]);
01179 static int rpt_do_local_nodes(int fd, int argc, char *argv[]);
01180 static int rpt_do_reload(int fd, int argc, char *argv[]);
01181 static int rpt_do_restart(int fd, int argc, char *argv[]);
01182 static int rpt_do_fun(int fd, int argc, char *argv[]);
01183 static int rpt_do_fun1(int fd, int argc, char *argv[]);
01184 static int rpt_do_cmd(int fd, int argc, char *argv[]);
01185 
01186 static char debug_usage[] =
01187 "Usage: rpt debug level {0-7}\n"
01188 "       Enables debug messages in app_rpt\n";
01189 
01190 static char dump_usage[] =
01191 "Usage: rpt dump <nodename>\n"
01192 "       Dumps struct debug info to log\n";
01193 
01194 static char dump_stats[] =
01195 "Usage: rpt stats <nodename>\n"
01196 "       Dumps node statistics to console\n";
01197 
01198 static char dump_lstats[] =
01199 "Usage: rpt lstats <nodename>\n"
01200 "       Dumps link statistics to console\n";
01201 
01202 static char dump_nodes[] =
01203 "Usage: rpt nodes <nodename>\n"
01204 "       Dumps a list of directly and indirectly connected nodes to the console\n";
01205 
01206 static char usage_local_nodes[] =
01207 "Usage: rpt localnodes\n"
01208 "       Dumps a list of the locally configured node numbers to the console.\n";
01209 
01210 static char reload_usage[] =
01211 "Usage: rpt reload\n"
01212 "       Reloads app_rpt running config parameters\n";
01213 
01214 static char restart_usage[] =
01215 "Usage: rpt restart\n"
01216 "       Restarts app_rpt\n";
01217 
01218 static char fun_usage[] =
01219 "Usage: rpt fun <nodename> <command>\n"
01220 "       Send a DTMF function to a node\n";
01221 
01222 static char cmd_usage[] =
01223 "Usage: rpt cmd <nodename> <cmd-name> <cmd-index> <cmd-args.\n"
01224 "       Send a command to a node.\n        i.e. rpt cmd 2000 ilink 3 2001\n";
01225 
01226 #ifndef  NEW_ASTERISK
01227 
01228 static struct ast_cli_entry  cli_debug =
01229         { { "rpt", "debug", "level" }, rpt_do_debug, 
01230       "Enable app_rpt debugging", debug_usage };
01231 
01232 static struct ast_cli_entry  cli_dump =
01233         { { "rpt", "dump" }, rpt_do_dump,
01234       "Dump app_rpt structs for debugging", dump_usage };
01235 
01236 static struct ast_cli_entry  cli_stats =
01237         { { "rpt", "stats" }, rpt_do_stats,
01238       "Dump node statistics", dump_stats };
01239 
01240 static struct ast_cli_entry  cli_nodes =
01241         { { "rpt", "nodes" }, rpt_do_nodes,
01242       "Dump node list", dump_nodes };
01243 
01244 static struct ast_cli_entry  cli_local_nodes =
01245         { { "rpt", "localnodes" }, rpt_do_local_nodes,
01246       "Dump list of local node numbers", usage_local_nodes };
01247 
01248 static struct ast_cli_entry  cli_lstats =
01249         { { "rpt", "lstats" }, rpt_do_lstats,
01250       "Dump link statistics", dump_lstats };
01251 
01252 static struct ast_cli_entry  cli_reload =
01253         { { "rpt", "reload" }, rpt_do_reload,
01254       "Reload app_rpt config", reload_usage };
01255 
01256 static struct ast_cli_entry  cli_restart =
01257         { { "rpt", "restart" }, rpt_do_restart,
01258       "Restart app_rpt", restart_usage };
01259 
01260 static struct ast_cli_entry  cli_fun =
01261         { { "rpt", "fun" }, rpt_do_fun,
01262       "Execute a DTMF function", fun_usage };
01263 
01264 static struct ast_cli_entry  cli_fun1 =
01265         { { "rpt", "fun1" }, rpt_do_fun1,
01266       "Execute a DTMF function", fun_usage };
01267 
01268 static struct ast_cli_entry  cli_cmd =
01269         { { "rpt", "cmd" }, rpt_do_cmd,
01270       "Execute a DTMF function", cmd_usage };
01271 
01272 #endif
01273 
01274 /*
01275 * Telemetry defaults
01276 */
01277 
01278 
01279 static struct telem_defaults tele_defs[] = {
01280    {"ct1","|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
01281    {"ct2","|t(660,880,150,3072)"},
01282    {"ct3","|t(440,0,150,3072)"},
01283    {"ct4","|t(550,0,150,3072)"},
01284    {"ct5","|t(660,0,150,3072)"},
01285    {"ct6","|t(880,0,150,3072)"},
01286    {"ct7","|t(660,440,150,3072)"},
01287    {"ct8","|t(700,1100,150,3072)"},
01288    {"remotemon","|t(1600,0,75,2048)"},
01289    {"remotetx","|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
01290    {"cmdmode","|t(900,904,200,2048)"},
01291    {"functcomplete","|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
01292 } ;
01293 
01294 /*
01295 * Forward decl's - these suppress compiler warnings when funcs coded further down the file than thier invokation
01296 */
01297 
01298 static int setrbi(struct rpt *myrpt);
01299 static int set_ft897(struct rpt *myrpt);
01300 static int set_ic706(struct rpt *myrpt);
01301 static int setkenwood(struct rpt *myrpt);
01302 static int set_tm271(struct rpt *myrpt);
01303 static int setrbi_check(struct rpt *myrpt);
01304 
01305 
01306 
01307 /*
01308 * Define function protos for function table here
01309 */
01310 
01311 static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01312 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01313 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01314 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01315 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01316 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01317 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01318 static int function_playback(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01319 /*
01320 * Function table
01321 */
01322 
01323 static struct function_table_tag function_table[] = {
01324    {"cop", function_cop},
01325    {"autopatchup", function_autopatchup},
01326    {"autopatchdn", function_autopatchdn},
01327    {"ilink", function_ilink},
01328    {"status", function_status},
01329    {"remote", function_remote},
01330    {"macro", function_macro},
01331    {"playback", function_playback}
01332 } ;
01333 
01334 static long diskavail(struct rpt *myrpt)
01335 {
01336 struct   statfs statfsbuf;
01337 
01338    if (!myrpt->p.archivedir) return(0);
01339    if (statfs(myrpt->p.archivedir,&statfsbuf) == -1)
01340    {
01341       ast_log(LOG_WARNING,"Cannot get filesystem size for %s node %s\n",
01342          myrpt->p.archivedir,myrpt->name);
01343       return(-1);
01344    }
01345    return(statfsbuf.f_bavail);
01346 }
01347 
01348 static void flush_telem(struct rpt *myrpt)
01349 {
01350    struct rpt_tele *telem;
01351    if(debug > 2)
01352       ast_log(LOG_NOTICE, "flush_telem()!!");
01353    rpt_mutex_lock(&myrpt->lock);
01354    telem = myrpt->tele.next;
01355    while(telem != &myrpt->tele)
01356    {
01357       if (telem->mode != SETREMOTE) ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
01358       telem = telem->next;
01359    }
01360    rpt_mutex_unlock(&myrpt->lock);
01361 }
01362 /*
01363    return via error priority
01364 */
01365 static int priority_jump(struct rpt *myrpt, struct ast_channel *chan)
01366 {
01367    int res=0;
01368 
01369    // if (ast_test_flag(&flags,OPT_JUMP) && ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101) == 0){
01370    if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101) == 0){
01371       res = 0;
01372    } else {
01373       res = -1;
01374    }
01375    return res;
01376 }
01377 /*
01378 */
01379 static int linkcount(struct rpt *myrpt)
01380 {
01381    struct   rpt_link *l;
01382    char *reverse_patch_state;
01383    int numoflinks;
01384 
01385    reverse_patch_state = "DOWN";
01386    numoflinks = 0;
01387    l = myrpt->links.next;
01388    while(l && (l != &myrpt->links)){
01389       if(numoflinks >= MAX_STAT_LINKS){
01390          ast_log(LOG_WARNING,
01391          "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
01392          break;
01393       }
01394       //if (l->name[0] == '0'){ /* Skip '0' nodes */
01395       // reverse_patch_state = "UP";
01396       // l = l->next;
01397       // continue;
01398       //}
01399       numoflinks++;
01400     
01401       l = l->next;
01402    }
01403    ast_log(LOG_NOTICE, "numoflinks=%i\n",numoflinks);
01404    return numoflinks;
01405 }
01406 /*
01407  * Retrieve a memory channel
01408  * Return 0 if sucessful,
01409  * -1 if channel not found,
01410  *  1 if parse error
01411  */
01412 static int retreive_memory(struct rpt *myrpt, char *memory)
01413 {
01414    char tmp[30], *s, *s1, *val;
01415 
01416    if (debug)ast_log(LOG_NOTICE, "memory=%s block=%s\n",memory,myrpt->p.memory);
01417 
01418    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.memory, memory);
01419    if (!val){
01420       return -1;
01421    }        
01422    strncpy(tmp,val,sizeof(tmp) - 1);
01423    tmp[sizeof(tmp)-1] = 0;
01424 
01425    s = strchr(tmp,',');
01426    if (!s)
01427       return 1; 
01428    *s++ = 0;
01429    s1 = strchr(s,',');
01430    if (!s1)
01431       return 1;
01432    *s1++ = 0;
01433    strncpy(myrpt->freq, tmp, sizeof(myrpt->freq) - 1);
01434    strncpy(myrpt->rxpl, s, sizeof(myrpt->rxpl) - 1);
01435    strncpy(myrpt->txpl, s, sizeof(myrpt->rxpl) - 1);
01436    myrpt->remmode = REM_MODE_FM;
01437    myrpt->offset = REM_SIMPLEX;
01438    myrpt->powerlevel = REM_MEDPWR;
01439    myrpt->txplon = myrpt->rxplon = 0;
01440    while(*s1){
01441       switch(*s1++){
01442          case 'A':
01443          case 'a':
01444             strcpy(myrpt->rxpl, "100.0");
01445             strcpy(myrpt->txpl, "100.0");
01446             myrpt->remmode = REM_MODE_AM; 
01447             break;
01448          case 'B':
01449          case 'b':
01450             strcpy(myrpt->rxpl, "100.0");
01451             strcpy(myrpt->txpl, "100.0");
01452             myrpt->remmode = REM_MODE_LSB;
01453             break;
01454          case 'F':
01455             myrpt->remmode = REM_MODE_FM;
01456             break;
01457          case 'L':
01458          case 'l':
01459             myrpt->powerlevel = REM_LOWPWR;
01460             break;               
01461          case 'H':
01462          case 'h':
01463             myrpt->powerlevel = REM_HIPWR;
01464             break;
01465                
01466          case 'M':
01467          case 'm':
01468             myrpt->powerlevel = REM_MEDPWR;
01469             break;
01470                   
01471          case '-':
01472             myrpt->offset = REM_MINUS;
01473             break;
01474                   
01475          case '+':
01476             myrpt->offset = REM_PLUS;
01477             break;
01478                   
01479          case 'S':
01480          case 's':
01481             myrpt->offset = REM_SIMPLEX;
01482             break;
01483                   
01484          case 'T':
01485          case 't':
01486             myrpt->txplon = 1;
01487             break;
01488                   
01489          case 'R':
01490          case 'r':
01491             myrpt->rxplon = 1;
01492             break;
01493 
01494          case 'U':
01495          case 'u':
01496             strcpy(myrpt->rxpl, "100.0");
01497             strcpy(myrpt->txpl, "100.0");
01498             myrpt->remmode = REM_MODE_USB;
01499             break;
01500          default:
01501             return 1;
01502       }
01503    }
01504    return 0;
01505 }
01506 /*
01507 
01508 */
01509 static void birdbath(struct rpt *myrpt)
01510 {
01511    struct rpt_tele *telem;
01512    if(debug > 2)
01513       ast_log(LOG_NOTICE, "birdbath!!");
01514    rpt_mutex_lock(&myrpt->lock);
01515    telem = myrpt->tele.next;
01516    while(telem != &myrpt->tele)
01517    {
01518       if (telem->mode == PARROT) ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
01519       telem = telem->next;
01520    }
01521    rpt_mutex_unlock(&myrpt->lock);
01522 }
01523 
01524 static void do_dtmf_phone(struct rpt *myrpt, struct rpt_link *mylink, char c)
01525 {
01526 struct        rpt_link *l;
01527 
01528        l = myrpt->links.next;
01529        /* go thru all the links */
01530        while(l != &myrpt->links)
01531        {
01532                if (!l->phonemode)
01533                {
01534                        l = l->next;
01535                        continue;
01536                }
01537                /* dont send to self */
01538                if (mylink && (l == mylink))
01539                {
01540                        l = l->next;
01541                        continue;
01542                }
01543 #ifdef   NEW_ASTERISK
01544                if (l->chan) ast_senddigit(l->chan,c,0);
01545 #else
01546                if (l->chan) ast_senddigit(l->chan,c);
01547 #endif
01548                l = l->next;
01549        }
01550        return;
01551 }
01552 
01553 /* node logging function */
01554 static void donodelog(struct rpt *myrpt,char *str)
01555 {
01556 struct nodelog *nodep;
01557 char  datestr[100];
01558 
01559    if (!myrpt->p.archivedir) return;
01560    nodep = (struct nodelog *)ast_malloc(sizeof(struct nodelog));
01561    if (nodep == NULL)
01562    {
01563       ast_log(LOG_ERROR,"Cannot get memory for node log");
01564       return;
01565    }
01566    time(&nodep->timestamp);
01567    strncpy(nodep->archivedir,myrpt->p.archivedir,
01568       sizeof(nodep->archivedir) - 1);
01569    strftime(datestr,sizeof(datestr) - 1,"%Y%m%d%H%M%S",
01570       localtime(&nodep->timestamp));
01571    snprintf(nodep->str,sizeof(nodep->str) - 1,"%s %s,%s\n",
01572       myrpt->name,datestr,str);
01573    ast_mutex_lock(&nodeloglock);
01574    insque((struct qelem *) nodep, (struct qelem *) nodelog.prev);
01575    ast_mutex_unlock(&nodeloglock);
01576 }
01577 
01578 /* must be called locked */
01579 static void do_dtmf_local(struct rpt *myrpt, char c)
01580 {
01581 int   i;
01582 char  digit;
01583 static const char* dtmf_tones[] = {
01584    "!941+1336/200,!0/200", /* 0 */
01585    "!697+1209/200,!0/200", /* 1 */
01586    "!697+1336/200,!0/200", /* 2 */
01587    "!697+1477/200,!0/200", /* 3 */
01588    "!770+1209/200,!0/200", /* 4 */
01589    "!770+1336/200,!0/200", /* 5 */
01590    "!770+1477/200,!0/200", /* 6 */
01591    "!852+1209/200,!0/200", /* 7 */
01592    "!852+1336/200,!0/200", /* 8 */
01593    "!852+1477/200,!0/200", /* 9 */
01594    "!697+1633/200,!0/200", /* A */
01595    "!770+1633/200,!0/200", /* B */
01596    "!852+1633/200,!0/200", /* C */
01597    "!941+1633/200,!0/200", /* D */
01598    "!941+1209/200,!0/200", /* * */
01599    "!941+1477/200,!0/200" };  /* # */
01600 
01601 
01602    if (c)
01603    {
01604       snprintf(myrpt->dtmf_local_str + strlen(myrpt->dtmf_local_str),sizeof(myrpt->dtmf_local_str) - 1,"%c",c);
01605       if (!myrpt->dtmf_local_timer) 
01606           myrpt->dtmf_local_timer = DTMF_LOCAL_STARTTIME;
01607    }
01608    /* if at timeout */
01609    if (myrpt->dtmf_local_timer == 1)
01610    {
01611       if(debug > 6)
01612          ast_log(LOG_NOTICE,"time out dtmf_local_timer=%i\n",myrpt->dtmf_local_timer);
01613 
01614       /* if anything in the string */
01615       if (myrpt->dtmf_local_str[0])
01616       {
01617          digit = myrpt->dtmf_local_str[0];
01618          myrpt->dtmf_local_str[0] = 0;
01619          for(i = 1; myrpt->dtmf_local_str[i]; i++)
01620          {
01621             myrpt->dtmf_local_str[i - 1] =
01622                myrpt->dtmf_local_str[i];
01623          }
01624          myrpt->dtmf_local_str[i - 1] = 0;
01625          myrpt->dtmf_local_timer = DTMF_LOCAL_TIME;
01626          rpt_mutex_unlock(&myrpt->lock);
01627          if (digit >= '0' && digit <='9')
01628             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'0'], 0);
01629          else if (digit >= 'A' && digit <= 'D')
01630             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'A'+10], 0);
01631          else if (digit == '*')
01632             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[14], 0);
01633          else if (digit == '#')
01634             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[15], 0);
01635          else {
01636             /* not handled */
01637             ast_log(LOG_DEBUG, "Unable to generate DTMF tone '%c' for '%s'\n", digit, myrpt->txchannel->name);
01638          }
01639          rpt_mutex_lock(&myrpt->lock);
01640       }
01641       else
01642       {
01643          myrpt->dtmf_local_timer = 0;
01644       }
01645    }
01646 }
01647 
01648 static int setdtr(int fd, int enable)
01649 {
01650 struct termios mode;
01651 
01652    if (fd < 0) return -1;
01653    if (tcgetattr(fd, &mode)) {
01654       ast_log(LOG_WARNING, "Unable to get serial parameters for dtr: %s\n", strerror(errno));
01655       return -1;
01656    }
01657    if (enable)
01658    {
01659       cfsetspeed(&mode, B9600);
01660    }
01661    else
01662    {
01663       cfsetspeed(&mode, B0);
01664       usleep(100000);
01665    }
01666    if (tcsetattr(fd, TCSADRAIN, &mode)) {
01667       ast_log(LOG_WARNING, "Unable to set serial parameters for dtr: %s\n", strerror(errno));
01668       return -1;
01669    }
01670    if (enable) usleep(100000);
01671    return 0;
01672 }
01673 
01674 static int openserial(struct rpt *myrpt,char *fname)
01675 {
01676    struct termios mode;
01677    int fd;
01678 
01679    fd = open(fname,O_RDWR);
01680    if (fd == -1)
01681    {
01682       ast_log(LOG_WARNING,"Cannot open serial port %s\n",fname);
01683       return -1;
01684    }
01685    memset(&mode, 0, sizeof(mode));
01686    if (tcgetattr(fd, &mode)) {
01687       ast_log(LOG_WARNING, "Unable to get serial parameters on %s: %s\n", fname, strerror(errno));
01688       return -1;
01689    }
01690 #ifndef  SOLARIS
01691    cfmakeraw(&mode);
01692 #else
01693         mode.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
01694                         |INLCR|IGNCR|ICRNL|IXON);
01695         mode.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
01696         mode.c_cflag &= ~(CSIZE|PARENB|CRTSCTS);
01697         mode.c_cflag |= CS8;
01698    mode.c_cc[VTIME] = 3;
01699    mode.c_cc[VMIN] = 1; 
01700 #endif
01701 
01702    cfsetispeed(&mode, B9600);
01703    cfsetospeed(&mode, B9600);
01704    if (tcsetattr(fd, TCSANOW, &mode)) 
01705       ast_log(LOG_WARNING, "Unable to set serial parameters on %s: %s\n", fname, strerror(errno));
01706    if(!strcmp(myrpt->remoterig, remote_rig_kenwood)) setdtr(fd,0); 
01707    usleep(100000);
01708    if (debug)ast_log(LOG_NOTICE,"Opened serial port %s\n",fname);
01709    return(fd); 
01710 }
01711 
01712 static void mdc1200_notify(struct rpt *myrpt,char *fromnode, unsigned int unit)
01713 {
01714    if (!fromnode)
01715    {
01716       ast_verbose("Got MDC-1200 ID %04X from local system (%s)\n",
01717          unit,myrpt->name);
01718    }
01719    else
01720    {
01721       ast_verbose("Got MDC-1200 ID %04X from node %s (%s)\n",
01722          unit,fromnode,myrpt->name);
01723    }
01724 }
01725 
01726 #ifdef   _MDC_DECODE_H_
01727 
01728 static void mdc1200_send(struct rpt *myrpt, unsigned int unit)
01729 {
01730 struct rpt_link *l;
01731 struct   ast_frame wf;
01732 char  str[200];
01733 
01734 
01735    sprintf(str,"I %s %04X",myrpt->name,unit);
01736 
01737    wf.frametype = AST_FRAME_TEXT;
01738    wf.subclass = 0;
01739    wf.offset = 0;
01740    wf.mallocd = 0;
01741    wf.datalen = strlen(str) + 1;
01742    wf.samples = 0;
01743 
01744 
01745    l = myrpt->links.next;
01746    /* otherwise, send it to all of em */
01747    while(l != &myrpt->links)
01748    {
01749       if (l->name[0] == '0') 
01750       {
01751          l = l->next;
01752          continue;
01753       }
01754       wf.data = str;
01755       if (l->chan) ast_write(l->chan,&wf); 
01756       l = l->next;
01757    }
01758    return;
01759 }
01760 
01761 #endif
01762 
01763 static char func_xlat(struct rpt *myrpt,char c,struct rpt_xlat *xlat)
01764 {
01765 time_t   now;
01766 int   gotone;
01767 
01768    time(&now);
01769    gotone = 0;
01770    /* if too much time, reset the skate machine */
01771    if ((now - xlat->lastone) > MAXXLATTIME)
01772    {
01773       xlat->funcindex = xlat->endindex = 0;
01774    }
01775    if (xlat->funccharseq[0] && (c == xlat->funccharseq[xlat->funcindex++]))
01776    {
01777       time(&xlat->lastone);
01778       gotone = 1;
01779       if (!xlat->funccharseq[xlat->funcindex])
01780       {
01781          xlat->funcindex = xlat->endindex = 0;
01782          return(myrpt->p.funcchar);
01783       }
01784    } else xlat->funcindex = 0;
01785    if (xlat->endcharseq[0] && (c == xlat->endcharseq[xlat->endindex++]))
01786    {
01787       time(&xlat->lastone);
01788       gotone = 1;
01789       if (!xlat->endcharseq[xlat->endindex])
01790       {
01791          xlat->funcindex = xlat->endindex = 0;
01792          return(myrpt->p.endchar);
01793       }
01794    } else xlat->endindex = 0;
01795    /* if in middle of decode seq, send nothing back */
01796    if (gotone) return(0);
01797    /* if no pass chars specified, return em all */
01798    if (!xlat->passchars[0]) return(c);
01799    /* if a "pass char", pass it */
01800    if (strchr(xlat->passchars,c)) return(c);
01801    return(0);
01802 }
01803 
01804 /*
01805  * Return a pointer to the first non-whitespace character
01806  */
01807 
01808 static char *eatwhite(char *s)
01809 {
01810    while((*s == ' ') || (*s == 0x09)){ /* get rid of any leading white space */
01811       if(!*s)
01812          break;
01813       s++;
01814    }
01815    return s;
01816 }
01817 
01818 /*
01819 * Break up a delimited string into a table of substrings
01820 *
01821 * str - delimited string ( will be modified )
01822 * strp- list of pointers to substrings (this is built by this function), NULL will be placed at end of list
01823 * limit- maximum number of substrings to process
01824 */
01825    
01826 
01827 
01828 static int finddelim(char *str, char *strp[], int limit)
01829 {
01830 int     i,l,inquo;
01831 
01832         inquo = 0;
01833         i = 0;
01834         strp[i++] = str;
01835         if (!*str)
01836            {
01837                 strp[0] = 0;
01838                 return(0);
01839            }
01840         for(l = 0; *str && (l < limit) ; str++)
01841            {
01842                 if (*str == QUOTECHR)
01843                    {
01844                         if (inquo)
01845                            {
01846                                 *str = 0;
01847                                 inquo = 0;
01848                            }
01849                         else
01850                            {
01851                                 strp[i - 1] = str + 1;
01852                                 inquo = 1;
01853                            }
01854       }
01855                 if ((*str == DELIMCHR) && (!inquo))
01856                 {
01857                         *str = 0;
01858          l++;
01859                         strp[i++] = str + 1;
01860                 }
01861            }
01862         strp[i] = 0;
01863         return(i);
01864 
01865 }
01866 /*
01867    send asterisk frame text message on the current tx channel
01868 */
01869 static int send_usb_txt(struct rpt *myrpt, char *txt) 
01870 {
01871    struct ast_frame wf;
01872  
01873    if (debug)ast_log(LOG_NOTICE, "send_usb_txt %s\n",txt);
01874    wf.frametype = AST_FRAME_TEXT;
01875    wf.subclass = 0;
01876    wf.offset = 0;
01877    wf.mallocd = 0;
01878    wf.datalen = strlen(txt) + 1;
01879    wf.data.ptr = txt;
01880    wf.samples = 0;
01881    ast_write(myrpt->txchannel,&wf); 
01882    return 0;
01883 }
01884 /* must be called locked */
01885 static void __mklinklist(struct rpt *myrpt, struct rpt_link *mylink, char *buf)
01886 {
01887 struct rpt_link *l;
01888 char mode;
01889 int   i,spos;
01890 
01891    buf[0] = 0; /* clear output buffer */
01892    if (myrpt->remote) return;
01893    /* go thru all links */
01894    for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
01895    {
01896       /* if is not a real link, ignore it */
01897       if (l->name[0] == '0') continue;
01898       /* dont count our stuff */
01899       if (l == mylink) continue;
01900       if (mylink && (!strcmp(l->name,mylink->name))) continue;
01901       /* figure out mode to report */
01902       mode = 'T'; /* use Tranceive by default */
01903       if (!l->mode) mode = 'R'; /* indicate RX for our mode */
01904       if (!l->thisconnected)  mode = 'C'; /* indicate connecting */
01905       spos = strlen(buf); /* current buf size (b4 we add our stuff) */
01906       if (spos)
01907       {
01908          strcat(buf,",");
01909          spos++;
01910       }
01911       /* add nodes into buffer */
01912       if (l->linklist[0])
01913       {
01914          snprintf(buf + spos,MAXLINKLIST - spos,
01915             "%c%s,%s",mode,l->name,l->linklist);
01916       }
01917       else /* if no nodes, add this node into buffer */
01918       {
01919          snprintf(buf + spos,MAXLINKLIST - spos,
01920             "%c%s",mode,l->name);
01921       }
01922       /* if we are in tranceive mode, let all modes stand */
01923       if (mode == 'T') continue;
01924       /* downgrade everyone on this node if appropriate */
01925       for(i = spos; buf[i]; i++)
01926       {
01927          if (buf[i] == 'T') buf[i] = mode;
01928          if ((buf[i] == 'R') && (mode == 'C')) buf[i] = mode;
01929       }
01930    }
01931    return;
01932 }
01933 
01934 /* must be called locked */
01935 static void __kickshort(struct rpt *myrpt)
01936 {
01937 struct rpt_link *l;
01938 
01939    for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
01940    {
01941       /* if is not a real link, ignore it */
01942       if (l->name[0] == '0') continue;
01943       l->linklisttimer = LINKLISTSHORTTIME;
01944    }
01945    myrpt->linkposttimer = LINKPOSTSHORTTIME;
01946    return;
01947 }
01948 
01949 static void statpost(struct rpt *myrpt,char *pairs)
01950 {
01951 char *str,*astr;
01952 char *astrs[100];
01953 int   n,pid;
01954 time_t   now;
01955 unsigned int seq;
01956 
01957    if (!myrpt->p.statpost_url) return;
01958    str = ast_malloc(strlen(pairs) + strlen(myrpt->p.statpost_url) + 200);
01959    astr = ast_strdup(myrpt->p.statpost_program);
01960    if ((!str) || (!astr)) return;
01961    n = finddelim(astr,astrs,100);
01962    if (n < 1) return;
01963    ast_mutex_lock(&myrpt->statpost_lock);
01964    seq = ++myrpt->statpost_seqno;
01965    ast_mutex_unlock(&myrpt->statpost_lock);
01966    astrs[n++] = str;
01967    astrs[n] = NULL;
01968    time(&now);
01969    sprintf(str,"%s?node=%s&time=%u&seqno=%u",myrpt->p.statpost_url,
01970       myrpt->name,(unsigned int) now,seq);
01971    if (pairs) sprintf(str + strlen(str),"&%s",pairs);
01972    if (!(pid = ast_safe_fork(0)))
01973    {
01974       execv(astrs[0],astrs);
01975       ast_log(LOG_ERROR, "exec of %s failed.\n", astrs[0]);
01976       perror("asterisk");
01977       exit(0);
01978    }
01979    ast_free(astr);
01980    ast_free(str);
01981    return;
01982 }
01983 
01984 static char *node_lookup(struct rpt *myrpt,char *digitbuf)
01985 {
01986 
01987 char *val;
01988 int longestnode,j;
01989 struct stat mystat;
01990 static time_t last = 0;
01991 static struct ast_config *ourcfg = NULL;
01992 struct ast_variable *vp;
01993 
01994    /* try to look it up locally first */
01995    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
01996    if (val) return(val);
01997    ast_mutex_lock(&nodelookuplock);
01998    /* if file does not exist */
01999    if (stat(myrpt->p.extnodefile,&mystat) == -1)
02000    {
02001       if (ourcfg) ast_config_destroy(ourcfg);
02002       ourcfg = NULL;
02003       ast_mutex_unlock(&nodelookuplock);
02004       return(NULL);
02005    }
02006    /* if we need to reload */
02007    if (mystat.st_mtime > last)
02008    {
02009       if (ourcfg) ast_config_destroy(ourcfg);
02010 #ifdef   NEW_ASTERISK
02011       ourcfg = ast_config_load(myrpt->p.extnodefile,config_flags);
02012 #else
02013       ourcfg = ast_config_load(myrpt->p.extnodefile);
02014 #endif
02015       /* if file not there, just bail */
02016       if (!ourcfg)
02017       {
02018          ast_mutex_unlock(&nodelookuplock);
02019          return(NULL);
02020       }
02021       /* reset "last" time */
02022       last = mystat.st_mtime;
02023 
02024       /* determine longest node length again */    
02025       longestnode = 0;
02026       vp = ast_variable_browse(myrpt->cfg, myrpt->p.nodes);
02027       while(vp){
02028          j = strlen(vp->name);
02029          if (j > longestnode)
02030             longestnode = j;
02031          vp = vp->next;
02032       }
02033 
02034       vp = ast_variable_browse(ourcfg, myrpt->p.extnodes);
02035       while(vp){
02036          j = strlen(vp->name);
02037          if (j > longestnode)
02038             longestnode = j;
02039          vp = vp->next;
02040       }
02041 
02042       myrpt->longestnode = longestnode;
02043    }
02044    val = NULL;
02045    if (ourcfg)
02046       val = (char *) ast_variable_retrieve(ourcfg, myrpt->p.extnodes, digitbuf);
02047    ast_mutex_unlock(&nodelookuplock);
02048    return(val);
02049 }
02050 
02051 /*
02052 * Match a keyword in a list, and return index of string plus 1 if there was a match,* else return 0.
02053 * If param is passed in non-null, then it will be set to the first character past the match
02054 */
02055 
02056 static int matchkeyword(char *string, char **param, char *keywords[])
02057 {
02058 int   i,ls;
02059    for( i = 0 ; keywords[i] ; i++){
02060       ls = strlen(keywords[i]);
02061       if(!ls){
02062          *param = NULL;
02063          return 0;
02064       }
02065       if(!strncmp(string, keywords[i], ls)){
02066          if(param)
02067             *param = string + ls;
02068          return i + 1; 
02069       }
02070    }
02071    *param = NULL;
02072    return 0;
02073 }
02074 
02075 /*
02076 * Skip characters in string which are in charlist, and return a pointer to the
02077 * first non-matching character
02078 */
02079 
02080 static char *skipchars(char *string, char *charlist)
02081 {
02082 int i;   
02083    while(*string){
02084       for(i = 0; charlist[i] ; i++){
02085          if(*string == charlist[i]){
02086             string++;
02087             break;
02088          }
02089       }
02090       if(!charlist[i])
02091          return string;
02092    }
02093    return string;
02094 }  
02095                
02096 
02097 
02098 static int myatoi(char *str)
02099 {
02100 int   ret;
02101 
02102    if (str == NULL) return -1;
02103    /* leave this %i alone, non-base-10 input is useful here */
02104    if (sscanf(str, "%30i", &ret) != 1)
02105       return -1;
02106    return ret;
02107 }
02108 
02109 static int mycompar(const void *a, const void *b)
02110 {
02111 char  **x = (char **) a;
02112 char  **y = (char **) b;
02113 int   xoff,yoff;
02114 
02115    if ((**x < '0') || (**x > '9')) xoff = 1; else xoff = 0;
02116    if ((**y < '0') || (**y > '9')) yoff = 1; else yoff = 0;
02117    return(strcmp((*x) + xoff,(*y) + yoff));
02118 }
02119 
02120 static int topcompar(const void *a, const void *b)
02121 {
02122 struct rpt_topkey *x = (struct rpt_topkey *) a;
02123 struct rpt_topkey *y = (struct rpt_topkey *) b;
02124 
02125    return(x->timesince - y->timesince);
02126 }
02127 
02128 #ifdef   __RPT_NOTCH
02129 
02130 /* rpt filter routine */
02131 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
02132 {
02133 int   i,j;
02134 struct   rptfilter *f;
02135 
02136    for(i = 0; i < len; i++)
02137    {
02138       for(j = 0; j < MAXFILTERS; j++)
02139       {
02140          f = &myrpt->filters[j];
02141          if (!*f->desc) continue;
02142          f->x0 = f->x1; f->x1 = f->x2;
02143               f->x2 = ((float)buf[i]) / f->gain;
02144               f->y0 = f->y1; f->y1 = f->y2;
02145               f->y2 =   (f->x0 + f->x2) +   f->const0 * f->x1
02146                            + (f->const1 * f->y0) + (f->const2 * f->y1);
02147          buf[i] = (short)f->y2;
02148       }
02149    }
02150 }
02151 
02152 #endif
02153 
02154 
02155 /*
02156  Get the time for the machine's time zone
02157  Note: Asterisk requires a copy of localtime
02158  in the /etc directory for this to work properly.
02159  If /etc/localtime is not present, you will get
02160  GMT time! This is especially important on systems
02161  running embedded linux distributions as they don't usually
02162  have support for locales. 
02163 
02164  If OLD_ASTERISK is defined, then the older localtime_r
02165  function will be used. The /etc/localtime file is not
02166  required in this case. This provides backward compatibility
02167  with Asterisk 1.2 systems.
02168 
02169 */
02170 
02171 #ifdef   NEW_ASTERISK
02172 static void rpt_localtime( time_t * t, struct ast_tm *lt)
02173 {
02174    struct timeval when;
02175 
02176    when.tv_sec = *t;
02177    when.tv_usec = 0;
02178    ast_localtime(&when, lt, NULL);
02179 }
02180 
02181 #else
02182 static void rpt_localtime( time_t * t, struct tm *lt)
02183 {
02184 #ifdef OLD_ASTERISK
02185    localtime_r(t, lt);
02186 #else
02187    ast_localtime(t, lt, NULL);
02188 #endif
02189 }
02190 #endif
02191 
02192 
02193 /* Retrieve an int from a config file */
02194                                                                                 
02195 static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl)
02196 {
02197         char *var;
02198         int ret;
02199    char include_zero = 0;
02200 
02201    if(min < 0){ /* If min is negative, this means include 0 as a valid entry */
02202       min = -min;
02203       include_zero = 1;
02204    }           
02205                                                                      
02206         var = (char *) ast_variable_retrieve(myrpt->cfg, category, name);
02207         if(var){
02208                 ret = myatoi(var);
02209       if(include_zero && !ret)
02210          return 0;
02211                 if(ret < min)
02212                         ret = min;
02213                 if(ret > max)
02214                         ret = max;
02215         }
02216         else
02217                 ret = defl;
02218         return ret;
02219 }
02220 
02221 
02222 static void load_rpt_vars(int n,int init)
02223 {
02224 char *this,*val;
02225 int   i,j,longestnode;
02226 struct ast_variable *vp;
02227 struct ast_config *cfg;
02228 char *strs[100];
02229 char s1[256];
02230 static char *cs_keywords[] = {"rptena","rptdis","apena","apdis","lnkena","lnkdis","totena","totdis","skena","skdis",
02231             "ufena","ufdis","atena","atdis",NULL};
02232 
02233    if (option_verbose > 2)
02234       ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n",
02235          (init) ? "Loading initial" : "Re-Loading",rpt_vars[n].name);
02236    ast_mutex_lock(&rpt_vars[n].lock);
02237    if (rpt_vars[n].cfg) ast_config_destroy(rpt_vars[n].cfg);
02238 #ifdef   NEW_ASTERISK
02239    cfg = ast_config_load("rpt.conf",config_flags);
02240 #else
02241    cfg = ast_config_load("rpt.conf");
02242 #endif
02243    if (!cfg) {
02244       ast_mutex_unlock(&rpt_vars[n].lock);
02245       ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
02246       pthread_exit(NULL);
02247    }
02248    rpt_vars[n].cfg = cfg; 
02249    this = rpt_vars[n].name;
02250    memset(&rpt_vars[n].p,0,sizeof(rpt_vars[n].p));
02251    if (init)
02252    {
02253       char *cp;
02254       int savearea = (char *)&rpt_vars[n].p - (char *)&rpt_vars[n];
02255 
02256       cp = (char *) &rpt_vars[n].p;
02257       memset(cp + sizeof(rpt_vars[n].p),0,
02258          sizeof(rpt_vars[n]) - (sizeof(rpt_vars[n].p) + savearea));
02259       rpt_vars[n].tele.next = &rpt_vars[n].tele;
02260       rpt_vars[n].tele.prev = &rpt_vars[n].tele;
02261       rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
02262       rpt_vars[n].tailmessagen = 0;
02263    }
02264 #ifdef   __RPT_NOTCH
02265    /* zot out filters stuff */
02266    memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
02267 #endif
02268    val = (char *) ast_variable_retrieve(cfg,this,"context");
02269    if (val) rpt_vars[n].p.ourcontext = val;
02270    else rpt_vars[n].p.ourcontext = this;
02271    val = (char *) ast_variable_retrieve(cfg,this,"callerid");
02272    if (val) rpt_vars[n].p.ourcallerid = val;
02273    val = (char *) ast_variable_retrieve(cfg,this,"accountcode");
02274    if (val) rpt_vars[n].p.acctcode = val;
02275    val = (char *) ast_variable_retrieve(cfg,this,"idrecording");
02276    if (val) rpt_vars[n].p.ident = val;
02277    val = (char *) ast_variable_retrieve(cfg,this,"hangtime");
02278    if (val) rpt_vars[n].p.hangtime = atoi(val);
02279       else rpt_vars[n].p.hangtime = HANGTIME;
02280    val = (char *) ast_variable_retrieve(cfg,this,"althangtime");
02281    if (val) rpt_vars[n].p.althangtime = atoi(val);
02282       else rpt_vars[n].p.althangtime = HANGTIME;
02283    val = (char *) ast_variable_retrieve(cfg,this,"totime");
02284    if (val) rpt_vars[n].p.totime = atoi(val);
02285       else rpt_vars[n].p.totime = TOTIME;
02286    val = (char *) ast_variable_retrieve(cfg,this,"voxtimeout");
02287    if (val) rpt_vars[n].p.voxtimeout_ms = atoi(val);
02288       else rpt_vars[n].p.voxtimeout_ms = VOX_TIMEOUT_MS;
02289    val = (char *) ast_variable_retrieve(cfg,this,"voxrecover");
02290    if (val) rpt_vars[n].p.voxrecover_ms = atoi(val);
02291       else rpt_vars[n].p.voxrecover_ms = VOX_RECOVER_MS;
02292    val = (char *) ast_variable_retrieve(cfg,this,"simplexpatchdelay");
02293    if (val) rpt_vars[n].p.simplexpatchdelay = atoi(val);
02294       else rpt_vars[n].p.simplexpatchdelay = SIMPLEX_PATCH_DELAY;
02295    val = (char *) ast_variable_retrieve(cfg,this,"simplexphonedelay");
02296    if (val) rpt_vars[n].p.simplexphonedelay = atoi(val);
02297       else rpt_vars[n].p.simplexphonedelay = SIMPLEX_PHONE_DELAY;
02298    val = (char *) ast_variable_retrieve(cfg,this,"statpost_program");
02299    if (val) rpt_vars[n].p.statpost_program = val;
02300       else rpt_vars[n].p.statpost_program = STATPOST_PROGRAM;
02301    rpt_vars[n].p.statpost_url = 
02302       (char *) ast_variable_retrieve(cfg,this,"statpost_url");
02303    rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0);    
02304    rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0);     
02305    rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2);
02306    rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", -60000, 2400000, IDTIME);   /* Enforce a min max including zero */
02307    rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
02308    val = (char *) ast_variable_retrieve(cfg,this,"tonezone");
02309    if (val) rpt_vars[n].p.tonezone = val;
02310    rpt_vars[n].p.tailmessages[0] = 0;
02311    rpt_vars[n].p.tailmessagemax = 0;
02312    val = (char *) ast_variable_retrieve(cfg,this,"tailmessagelist");
02313    if (val) rpt_vars[n].p.tailmessagemax = finddelim(val, rpt_vars[n].p.tailmessages, 500);
02314    val = (char *) ast_variable_retrieve(cfg,this,"memory");
02315    if (!val) val = MEMORY;
02316    rpt_vars[n].p.memory = val;
02317    val = (char *) ast_variable_retrieve(cfg,this,"macro");
02318    if (!val) val = MACRO;
02319    rpt_vars[n].p.macro = val;
02320    val = (char *) ast_variable_retrieve(cfg,this,"tonemacro");
02321    if (!val) val = TONEMACRO;
02322    rpt_vars[n].p.tonemacro = val;
02323    val = (char *) ast_variable_retrieve(cfg,this,"startup_macro");
02324    if (val) rpt_vars[n].p.startupmacro = val;
02325    val = (char *) ast_variable_retrieve(cfg,this,"iobase");
02326    /* do not use atoi() here, we need to be able to have
02327       the input specified in hex or decimal so we use
02328       sscanf with a %i */
02329    if ((!val) || (sscanf(val, "%30i", &rpt_vars[n].p.iobase) != 1))
02330       rpt_vars[n].p.iobase = DEFAULT_IOBASE;
02331    val = (char *) ast_variable_retrieve(cfg,this,"ioport");
02332    rpt_vars[n].p.ioport = val;
02333    val = (char *) ast_variable_retrieve(cfg,this,"functions");
02334    if (!val)
02335       {
02336          val = FUNCTIONS;
02337          rpt_vars[n].p.simple = 1;
02338       } 
02339    rpt_vars[n].p.functions = val;
02340    val =  (char *) ast_variable_retrieve(cfg,this,"link_functions");
02341    if (val) rpt_vars[n].p.link_functions = val;
02342    else 
02343       rpt_vars[n].p.link_functions = rpt_vars[n].p.functions;
02344    val = (char *) ast_variable_retrieve(cfg,this,"phone_functions");
02345    if (val) rpt_vars[n].p.phone_functions = val;
02346    val = (char *) ast_variable_retrieve(cfg,this,"dphone_functions");
02347    if (val) rpt_vars[n].p.dphone_functions = val;
02348    val = (char *) ast_variable_retrieve(cfg,this,"alt_functions");
02349    if (val) rpt_vars[n].p.alt_functions = val;
02350    val = (char *) ast_variable_retrieve(cfg,this,"funcchar");
02351    if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else 
02352       rpt_vars[n].p.funcchar = *val;      
02353    val = (char *) ast_variable_retrieve(cfg,this,"endchar");
02354    if (!val) rpt_vars[n].p.endchar = ENDCHAR; else 
02355       rpt_vars[n].p.endchar = *val;    
02356    val = (char *) ast_variable_retrieve(cfg,this,"nobusyout");
02357    if (val) rpt_vars[n].p.nobusyout = ast_true(val);
02358    val = (char *) ast_variable_retrieve(cfg,this,"notelemtx");
02359    if (val) rpt_vars[n].p.notelemtx = ast_true(val);
02360    val = (char *) ast_variable_retrieve(cfg,this,"propagate_dtmf");
02361    if (val) rpt_vars[n].p.propagate_dtmf = ast_true(val);
02362    val = (char *) ast_variable_retrieve(cfg,this,"propagate_phonedtmf");
02363    if (val) rpt_vars[n].p.propagate_phonedtmf = ast_true(val);
02364    val = (char *) ast_variable_retrieve(cfg,this,"linktolink");
02365    if (val) rpt_vars[n].p.linktolink = ast_true(val);
02366    val = (char *) ast_variable_retrieve(cfg,this,"nodes");
02367    if (!val) val = NODES;
02368    rpt_vars[n].p.nodes = val;
02369    val = (char *) ast_variable_retrieve(cfg,this,"extnodes");
02370    if (!val) val = EXTNODES;
02371    rpt_vars[n].p.extnodes = val;
02372    val = (char *) ast_variable_retrieve(cfg,this,"extnodefile");
02373    if (!val) val = EXTNODEFILE;
02374    rpt_vars[n].p.extnodefile = val;
02375    val = (char *) ast_variable_retrieve(cfg,this,"archivedir");
02376    if (val) rpt_vars[n].p.archivedir = val;
02377    val = (char *) ast_variable_retrieve(cfg,this,"authlevel");
02378    if (val) rpt_vars[n].p.authlevel = atoi(val); 
02379    else rpt_vars[n].p.authlevel = 0;
02380    val = (char *) ast_variable_retrieve(cfg,this,"parrot");
02381    if (val) rpt_vars[n].p.parrotmode = ast_true(val) * 2;
02382    else rpt_vars[n].p.parrotmode = 0;
02383    val = (char *) ast_variable_retrieve(cfg,this,"parrottime");
02384    if (val) rpt_vars[n].p.parrottime = atoi(val); 
02385    else rpt_vars[n].p.parrottime = PARROTTIME;
02386    val = (char *) ast_variable_retrieve(cfg,this,"rptnode");
02387    rpt_vars[n].p.rptnode = val;
02388    val = (char *) ast_variable_retrieve(cfg,this,"mars");
02389    if (val) rpt_vars[n].p.remote_mars = atoi(val); 
02390    else rpt_vars[n].p.remote_mars = 0;
02391    val = (char *) ast_variable_retrieve(cfg,this,"monminblocks");
02392    if (val) rpt_vars[n].p.monminblocks = atol(val); 
02393    else rpt_vars[n].p.monminblocks = DEFAULT_MONITOR_MIN_DISK_BLOCKS;
02394    val = (char *) ast_variable_retrieve(cfg,this,"remote_inact_timeout");
02395    if (val) rpt_vars[n].p.remoteinacttimeout = atoi(val); 
02396    else rpt_vars[n].p.remoteinacttimeout = DEFAULT_REMOTE_INACT_TIMEOUT;
02397    val = (char *) ast_variable_retrieve(cfg,this,"civaddr");
02398    if (val) rpt_vars[n].p.civaddr = atoi(val); 
02399    else rpt_vars[n].p.civaddr = DEFAULT_CIV_ADDR;
02400    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout");
02401    if (val) rpt_vars[n].p.remotetimeout = atoi(val); 
02402    else rpt_vars[n].p.remotetimeout = DEFAULT_REMOTE_TIMEOUT;
02403    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning");
02404    if (val) rpt_vars[n].p.remotetimeoutwarning = atoi(val); 
02405    else rpt_vars[n].p.remotetimeoutwarning = DEFAULT_REMOTE_TIMEOUT_WARNING;
02406    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning_freq");
02407    if (val) rpt_vars[n].p.remotetimeoutwarningfreq = atoi(val); 
02408    else rpt_vars[n].p.remotetimeoutwarningfreq = DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ;
02409 #ifdef   __RPT_NOTCH
02410    val = (char *) ast_variable_retrieve(cfg,this,"rxnotch");
02411    if (val) {
02412       i = finddelim(val,strs,MAXFILTERS * 2);
02413       i &= ~1; /* force an even number, rounded down */
02414       if (i >= 2) for(j = 0; j < i; j += 2)
02415       {
02416          rpt_mknotch(atof(strs[j]),atof(strs[j + 1]),
02417            &rpt_vars[n].filters[j >> 1].gain,
02418              &rpt_vars[n].filters[j >> 1].const0,
02419             &rpt_vars[n].filters[j >> 1].const1,
02420                 &rpt_vars[n].filters[j >> 1].const2);
02421          sprintf(rpt_vars[n].filters[j >> 1].desc,"%s Hz, BW = %s",
02422             strs[j],strs[j + 1]);
02423       }
02424 
02425    }
02426 #endif
02427    val = (char *) ast_variable_retrieve(cfg,this,"inxlat");
02428    if (val) {
02429       memset(&rpt_vars[n].p.inxlat,0,sizeof(struct rpt_xlat));
02430       i = finddelim(val,strs,3);
02431       if (i) strncpy(rpt_vars[n].p.inxlat.funccharseq,strs[0],MAXXLAT - 1);
02432       if (i > 1) strncpy(rpt_vars[n].p.inxlat.endcharseq,strs[1],MAXXLAT - 1);
02433       if (i > 2) strncpy(rpt_vars[n].p.inxlat.passchars,strs[2],MAXXLAT - 1);
02434    }
02435    val = (char *) ast_variable_retrieve(cfg,this,"outxlat");
02436    if (val) {
02437       memset(&rpt_vars[n].p.outxlat,0,sizeof(struct rpt_xlat));
02438       i = finddelim(val,strs,3);
02439       if (i) strncpy(rpt_vars[n].p.outxlat.funccharseq,strs[0],MAXXLAT - 1);
02440       if (i > 1) strncpy(rpt_vars[n].p.outxlat.endcharseq,strs[1],MAXXLAT - 1);
02441       if (i > 2) strncpy(rpt_vars[n].p.outxlat.passchars,strs[2],MAXXLAT - 1);
02442    }
02443    /* retreive the stanza name for the control states if there is one */
02444    val = (char *) ast_variable_retrieve(cfg,this,"controlstates");
02445    rpt_vars[n].p.csstanzaname = val;
02446       
02447    /* retreive the stanza name for the scheduler if there is one */
02448    val = (char *) ast_variable_retrieve(cfg,this,"scheduler");
02449    rpt_vars[n].p.skedstanzaname = val;
02450 
02451    /* retreive the stanza name for the txlimits */
02452    val = (char *) ast_variable_retrieve(cfg,this,"txlimits");
02453    rpt_vars[n].p.txlimitsstanzaname = val;
02454 
02455    longestnode = 0;
02456 
02457    vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
02458       
02459    while(vp){
02460       j = strlen(vp->name);
02461       if (j > longestnode)
02462          longestnode = j;
02463       vp = vp->next;
02464    }
02465 
02466    rpt_vars[n].longestnode = longestnode;
02467       
02468    /*
02469    * For this repeater, Determine the length of the longest function 
02470    */
02471    rpt_vars[n].longestfunc = 0;
02472    vp = ast_variable_browse(cfg, rpt_vars[n].p.functions);
02473    while(vp){
02474       j = strlen(vp->name);
02475       if (j > rpt_vars[n].longestfunc)
02476          rpt_vars[n].longestfunc = j;
02477       vp = vp->next;
02478    }
02479    /*
02480    * For this repeater, Determine the length of the longest function 
02481    */
02482    rpt_vars[n].link_longestfunc = 0;
02483    vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions);
02484    while(vp){
02485       j = strlen(vp->name);
02486       if (j > rpt_vars[n].link_longestfunc)
02487          rpt_vars[n].link_longestfunc = j;
02488       vp = vp->next;
02489    }
02490    rpt_vars[n].phone_longestfunc = 0;
02491    if (rpt_vars[n].p.phone_functions)
02492    {
02493       vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions);
02494       while(vp){
02495          j = strlen(vp->name);
02496          if (j > rpt_vars[n].phone_longestfunc)
02497             rpt_vars[n].phone_longestfunc = j;
02498          vp = vp->next;
02499       }
02500    }
02501    rpt_vars[n].dphone_longestfunc = 0;
02502    if (rpt_vars[n].p.dphone_functions)
02503    {
02504       vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions);
02505       while(vp){
02506          j = strlen(vp->name);
02507          if (j > rpt_vars[n].dphone_longestfunc)
02508             rpt_vars[n].dphone_longestfunc = j;
02509          vp = vp->next;
02510       }
02511    }
02512    rpt_vars[n].alt_longestfunc = 0;
02513    if (rpt_vars[n].p.alt_functions)
02514    {
02515       vp = ast_variable_browse(cfg, rpt_vars[n].p.alt_functions);
02516       while(vp){
02517          j = strlen(vp->name);
02518          if (j > rpt_vars[n].alt_longestfunc)
02519             rpt_vars[n].alt_longestfunc = j;
02520          vp = vp->next;
02521       }
02522    }
02523    rpt_vars[n].macro_longest = 1;
02524    vp = ast_variable_browse(cfg, rpt_vars[n].p.macro);
02525    while(vp){
02526       j = strlen(vp->name);
02527       if (j > rpt_vars[n].macro_longest)
02528          rpt_vars[n].macro_longest = j;
02529       vp = vp->next;
02530    }
02531    
02532    /* Browse for control states */
02533    if(rpt_vars[n].p.csstanzaname)
02534       vp = ast_variable_browse(cfg, rpt_vars[n].p.csstanzaname);
02535    else
02536       vp = NULL;
02537    for( i = 0 ; vp && (i < MAX_SYSSTATES) ; i++){ /* Iterate over the number of control state lines in the stanza */
02538       int k,nukw,statenum;
02539       statenum=atoi(vp->name);
02540       strncpy(s1, vp->value, 255);
02541       s1[255] = 0;
02542       nukw  = finddelim(s1,strs,32);
02543       
02544       for (k = 0 ; k < nukw ; k++){ /* for each user specified keyword */  
02545          for(j = 0 ; cs_keywords[j] != NULL ; j++){ /* try to match to one in our internal table */
02546             if(!strcmp(strs[k],cs_keywords[j])){
02547                switch(j){
02548                   case 0: /* rptena */
02549                      rpt_vars[n].p.s[statenum].txdisable = 0;
02550                      break;
02551                   case 1: /* rptdis */
02552                      rpt_vars[n].p.s[statenum].txdisable = 1;
02553                      break;
02554          
02555                   case 2: /* apena */
02556                      rpt_vars[n].p.s[statenum].autopatchdisable = 0;
02557                      break;
02558 
02559                   case 3: /* apdis */
02560                      rpt_vars[n].p.s[statenum].autopatchdisable = 1;
02561                      break;
02562 
02563                   case 4: /* lnkena */
02564                      rpt_vars[n].p.s[statenum].linkfundisable = 0;
02565                      break;
02566    
02567                   case 5: /* lnkdis */
02568                      rpt_vars[n].p.s[statenum].linkfundisable = 1;
02569                      break;
02570 
02571                   case 6: /* totena */
02572                      rpt_vars[n].p.s[statenum].totdisable = 0;
02573                      break;
02574                
02575                   case 7: /* totdis */
02576                      rpt_vars[n].p.s[statenum].totdisable = 1;
02577                      break;
02578 
02579                   case 8: /* skena */
02580                      rpt_vars[n].p.s[statenum].schedulerdisable = 0;
02581                      break;
02582 
02583                   case 9: /* skdis */
02584                      rpt_vars[n].p.s[statenum].schedulerdisable = 1;
02585                      break;
02586 
02587                   case 10: /* ufena */
02588                      rpt_vars[n].p.s[statenum].userfundisable = 0;
02589                      break;
02590 
02591                   case 11: /* ufdis */
02592                      rpt_vars[n].p.s[statenum].userfundisable = 1;
02593                      break;
02594 
02595                   case 12: /* atena */
02596                      rpt_vars[n].p.s[statenum].alternatetail = 1;
02597                      break;
02598 
02599                   case 13: /* atdis */
02600                      rpt_vars[n].p.s[statenum].alternatetail = 0;
02601                      break;
02602          
02603                   default:
02604                      ast_log(LOG_WARNING,
02605                         "Unhandled control state keyword %s", cs_keywords[i]);
02606                      break;
02607                }
02608             }
02609          }
02610       }
02611       vp = vp->next;
02612    }
02613    ast_mutex_unlock(&rpt_vars[n].lock);
02614 }
02615 
02616 /*
02617 * Enable or disable debug output at a given level at the console
02618 */
02619                                                                                                                                  
02620 static int rpt_do_debug(int fd, int argc, char *argv[])
02621 {
02622    int newlevel;
02623 
02624         if (argc != 4)
02625                 return RESULT_SHOWUSAGE;
02626         newlevel = myatoi(argv[3]);
02627         if((newlevel < 0) || (newlevel > 7))
02628                 return RESULT_SHOWUSAGE;
02629         if(newlevel)
02630                 ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
02631         else
02632                 ast_cli(fd, "app_rpt Debugging disabled\n");
02633 
02634         debug = newlevel;                                                                                                                          
02635         return RESULT_SUCCESS;
02636 }
02637 
02638 /*
02639 * Dump rpt struct debugging onto console
02640 */
02641                                                                                                                                  
02642 static int rpt_do_dump(int fd, int argc, char *argv[])
02643 {
02644    int i;
02645 
02646         if (argc != 3)
02647                 return RESULT_SHOWUSAGE;
02648 
02649    for(i = 0; i < nrpts; i++)
02650    {
02651       if (!strcmp(argv[2],rpt_vars[i].name))
02652       {
02653          rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
02654               ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
02655               return RESULT_SUCCESS;
02656       }
02657    }
02658    return RESULT_FAILURE;
02659 }
02660 
02661 /*
02662 * Dump statistics onto console
02663 */
02664 
02665 static int rpt_do_stats(int fd, int argc, char *argv[])
02666 {
02667    int i,j,numoflinks;
02668    int dailytxtime, dailykerchunks;
02669    time_t now;
02670    int totalkerchunks, dailykeyups, totalkeyups, timeouts;
02671    int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
02672    int uptime;
02673    long long totaltxtime;
02674    struct   rpt_link *l;
02675    char *listoflinks[MAX_STAT_LINKS];  
02676    char *lastdtmfcommand,*parrot_ena;
02677    char *tot_state, *ider_state, *patch_state;
02678    char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
02679    char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
02680    struct rpt *myrpt;
02681 
02682    static char *not_applicable = "N/A";
02683 
02684    if(argc != 3)
02685       return RESULT_SHOWUSAGE;
02686 
02687    tot_state = ider_state = 
02688    patch_state = reverse_patch_state = 
02689    input_signal = not_applicable;
02690    called_number = lastdtmfcommand = NULL;
02691 
02692    time(&now);
02693    for(i = 0; i < nrpts; i++)
02694    {
02695       if (!strcmp(argv[2],rpt_vars[i].name)){
02696          /* Make a copy of all stat variables while locked */
02697          myrpt = &rpt_vars[i];
02698          rpt_mutex_lock(&myrpt->lock); /* LOCK */
02699          uptime = (int)(now - starttime);
02700          dailytxtime = myrpt->dailytxtime;
02701          totaltxtime = myrpt->totaltxtime;
02702          dailykeyups = myrpt->dailykeyups;
02703          totalkeyups = myrpt->totalkeyups;
02704          dailykerchunks = myrpt->dailykerchunks;
02705          totalkerchunks = myrpt->totalkerchunks;
02706          dailyexecdcommands = myrpt->dailyexecdcommands;
02707          totalexecdcommands = myrpt->totalexecdcommands;
02708          timeouts = myrpt->timeouts;
02709 
02710          /* Traverse the list of connected nodes */
02711          reverse_patch_state = "DOWN";
02712          numoflinks = 0;
02713          l = myrpt->links.next;
02714          while(l && (l != &myrpt->links)){
02715             if(numoflinks >= MAX_STAT_LINKS){
02716                ast_log(LOG_NOTICE,
02717                "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
02718                break;
02719             }
02720             if (l->name[0] == '0'){ /* Skip '0' nodes */
02721                reverse_patch_state = "UP";
02722                l = l->next;
02723                continue;
02724             }
02725             listoflinks[numoflinks] = ast_strdup(l->name);
02726             if(listoflinks[numoflinks] == NULL){
02727                break;
02728             }
02729             else{
02730                numoflinks++;
02731             }
02732             l = l->next;
02733          }
02734 
02735          if(myrpt->keyed)
02736             input_signal = "YES";
02737          else
02738             input_signal = "NO";
02739 
02740          if(myrpt->p.parrotmode)
02741             parrot_ena = "ENABLED";
02742          else
02743             parrot_ena = "DISABLED";
02744 
02745          if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
02746             sys_ena = "DISABLED";
02747          else
02748             sys_ena = "ENABLED";
02749 
02750          if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
02751             tot_ena = "DISABLED";
02752          else
02753             tot_ena = "ENABLED";
02754 
02755          if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
02756             link_ena = "DISABLED";
02757          else
02758             link_ena = "ENABLED";
02759 
02760          if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
02761             patch_ena = "DISABLED";
02762          else
02763             patch_ena = "ENABLED";
02764 
02765          if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
02766             sch_ena = "DISABLED";
02767          else
02768             sch_ena = "ENABLED";
02769 
02770          if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
02771             user_funs = "DISABLED";
02772          else
02773             user_funs = "ENABLED";
02774 
02775          if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
02776             tail_type = "ALTERNATE";
02777          else
02778             tail_type = "STANDARD";
02779 
02780          if(!myrpt->totimer)
02781             tot_state = "TIMED OUT!";
02782          else if(myrpt->totimer != myrpt->p.totime)
02783             tot_state = "ARMED";
02784          else
02785             tot_state = "RESET";
02786 
02787          if(myrpt->tailid)
02788             ider_state = "QUEUED IN TAIL";
02789          else if(myrpt->mustid)
02790             ider_state = "QUEUED FOR CLEANUP";
02791          else
02792             ider_state = "CLEAN";
02793 
02794          switch(myrpt->callmode){
02795             case 1:
02796                patch_state = "DIALING";
02797                break;
02798             case 2:
02799                patch_state = "CONNECTING";
02800                break;
02801             case 3:
02802                patch_state = "UP";
02803                break;
02804 
02805             case 4:
02806                patch_state = "CALL FAILED";
02807                break;
02808 
02809             default:
02810                patch_state = "DOWN";
02811          }
02812 
02813          if(strlen(myrpt->exten)){
02814             called_number = ast_strdup(myrpt->exten);
02815          }
02816 
02817          if(strlen(myrpt->lastdtmfcommand)){
02818             lastdtmfcommand = ast_strdup(myrpt->lastdtmfcommand);
02819          }
02820          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02821 
02822          ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
02823          ast_cli(fd, "Selected system state............................: %d\n", myrpt->p.sysstate_cur);
02824          ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
02825          ast_cli(fd, "System...........................................: %s\n", sys_ena);
02826          ast_cli(fd, "Parrot Mode......................................: %s\n", parrot_ena);
02827          ast_cli(fd, "Scheduler........................................: %s\n", sch_ena);
02828          ast_cli(fd, "Tail Time........................................: %s\n", tail_type);
02829          ast_cli(fd, "Time out timer...................................: %s\n", tot_ena);
02830          ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
02831          ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
02832          ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
02833          ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
02834          ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
02835          ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
02836          ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
02837          ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
02838          ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
02839          ast_cli(fd, "Last DTMF command executed.......................: %s\n", 
02840          (lastdtmfcommand && strlen(lastdtmfcommand)) ? lastdtmfcommand : not_applicable);
02841          hours = dailytxtime/3600000;
02842          dailytxtime %= 3600000;
02843          minutes = dailytxtime/60000;
02844          dailytxtime %= 60000;
02845          seconds = dailytxtime/1000;
02846          dailytxtime %= 1000;
02847 
02848          ast_cli(fd, "TX time today....................................: %02d:%02d:%02d.%d\n",
02849             hours, minutes, seconds, dailytxtime);
02850 
02851          hours = (int) totaltxtime/3600000;
02852          totaltxtime %= 3600000;
02853          minutes = (int) totaltxtime/60000;
02854          totaltxtime %= 60000;
02855          seconds = (int)  totaltxtime/1000;
02856          totaltxtime %= 1000;
02857 
02858          ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
02859              hours, minutes, seconds, (int) totaltxtime);
02860 
02861                         hours = uptime/3600;
02862                         uptime %= 3600;
02863                         minutes = uptime/60;
02864                         uptime %= 60;
02865 
02866                         ast_cli(fd, "Uptime...........................................: %02d:%02d:%02d\n",
02867                                 hours, minutes, uptime);
02868 
02869          ast_cli(fd, "Nodes currently connected to us..................: ");
02870                         if(!numoflinks){
02871                          ast_cli(fd,"<NONE>");
02872                         }
02873          else{
02874             for(j = 0 ;j < numoflinks; j++){
02875                ast_cli(fd, "%s", listoflinks[j]);
02876                if(j % 4 == 3){
02877                   ast_cli(fd, "\n");
02878                   ast_cli(fd, "                                                 : ");
02879                }  
02880                else{
02881                   if((numoflinks - 1) - j  > 0)
02882                      ast_cli(fd, ", ");
02883                }
02884             }
02885          }
02886          ast_cli(fd,"\n");
02887 
02888          ast_cli(fd, "Autopatch........................................: %s\n", patch_ena);
02889          ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
02890          ast_cli(fd, "Autopatch called number..........................: %s\n",
02891          (called_number && strlen(called_number)) ? called_number : not_applicable);
02892          ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n", reverse_patch_state);
02893          ast_cli(fd, "User linking commands............................: %s\n", link_ena);
02894          ast_cli(fd, "User functions...................................: %s\n\n", user_funs);
02895 
02896          for(j = 0; j < numoflinks; j++){ /* ast_free() all link names */
02897             ast_free(listoflinks[j]);
02898          }
02899          if(called_number){
02900             ast_free(called_number);
02901          }
02902          if(lastdtmfcommand){
02903             ast_free(lastdtmfcommand);
02904          }
02905               return RESULT_SUCCESS;
02906       }
02907    }
02908    return RESULT_FAILURE;
02909 }
02910 
02911 /*
02912 * Link stats function
02913 */
02914 
02915 static int rpt_do_lstats(int fd, int argc, char *argv[])
02916 {
02917    int i,j;
02918    char *connstate;
02919    struct rpt *myrpt;
02920    struct rpt_link *l;
02921    struct rpt_lstat *s,*t;
02922    struct rpt_lstat s_head;
02923    if(argc != 3)
02924       return RESULT_SHOWUSAGE;
02925 
02926    s = NULL;
02927    s_head.next = &s_head;
02928    s_head.prev = &s_head;
02929 
02930    for(i = 0; i < nrpts; i++)
02931    {
02932       if (!strcmp(argv[2],rpt_vars[i].name)){
02933          /* Make a copy of all stat variables while locked */
02934          myrpt = &rpt_vars[i];
02935          rpt_mutex_lock(&myrpt->lock); /* LOCK */
02936          /* Traverse the list of connected nodes */
02937          j = 0;
02938          l = myrpt->links.next;
02939          while(l && (l != &myrpt->links)){
02940             if (l->name[0] == '0'){ /* Skip '0' nodes */
02941                l = l->next;
02942                continue;
02943             }
02944             if((s = (struct rpt_lstat *) ast_malloc(sizeof(struct rpt_lstat))) == NULL){
02945                ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
02946                rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02947                return RESULT_FAILURE;
02948             }
02949             memset(s, 0, sizeof(struct rpt_lstat));
02950             strncpy(s->name, l->name, MAXREMSTR - 1);
02951             if (l->chan) pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
02952             else strcpy(s->peer,"(none)");
02953             s->mode = l->mode;
02954             s->outbound = l->outbound;
02955             s->reconnects = l->reconnects;
02956             s->connecttime = l->connecttime;
02957             s->thisconnected = l->thisconnected;
02958             memcpy(s->chan_stat,l->chan_stat,NRPTSTAT * sizeof(struct rpt_chan_stat));
02959             insque((struct qelem *) s, (struct qelem *) s_head.next);
02960             memset(l->chan_stat,0,NRPTSTAT * sizeof(struct rpt_chan_stat));
02961             l = l->next;
02962          }
02963          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02964          ast_cli(fd, "NODE      PEER                RECONNECTS  DIRECTION  CONNECT TIME        CONNECT STATE\n");
02965          ast_cli(fd, "----      ----                ----------  ---------  ------------        -------------\n");
02966 
02967          for(s = s_head.next; s != &s_head; s = s->next){
02968             int hours, minutes, seconds;
02969             long long connecttime = s->connecttime;
02970             char conntime[21];
02971             hours = (int) connecttime/3600000;
02972             connecttime %= 3600000;
02973             minutes = (int) connecttime/60000;
02974             connecttime %= 60000;
02975             seconds = (int)  connecttime/1000;
02976             connecttime %= 1000;
02977             snprintf(conntime, 20, "%02d:%02d:%02d.%d",
02978                hours, minutes, seconds, (int) connecttime);
02979             conntime[20] = 0;
02980             if(s->thisconnected)
02981                connstate  = "ESTABLISHED";
02982             else
02983                connstate = "CONNECTING";
02984             ast_cli(fd, "%-10s%-20s%-12d%-11s%-20s%-20s\n",
02985                s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime, connstate);
02986          }  
02987          /* destroy our local link queue */
02988          s = s_head.next;
02989          while(s != &s_head){
02990             t = s;
02991             s = s->next;
02992             remque((struct qelem *)t);
02993             ast_free(t);
02994          }        
02995          return RESULT_SUCCESS;
02996       }
02997    }
02998    return RESULT_FAILURE;
02999 }
03000 
03001 /*
03002 * List all nodes connected, directly or indirectly
03003 */
03004 
03005 static int rpt_do_nodes(int fd, int argc, char *argv[])
03006 {
03007    int i,j;
03008    char ns;
03009    char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
03010    struct rpt *myrpt;
03011    if(argc != 3)
03012       return RESULT_SHOWUSAGE;
03013 
03014    for(i = 0; i < nrpts; i++)
03015    {
03016       if (!strcmp(argv[2],rpt_vars[i].name)){
03017          /* Make a copy of all stat variables while locked */
03018          myrpt = &rpt_vars[i];
03019          rpt_mutex_lock(&myrpt->lock); /* LOCK */
03020          __mklinklist(myrpt,NULL,lbuf);
03021          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
03022          /* parse em */
03023          ns = finddelim(lbuf,strs,MAXLINKLIST);
03024          /* sort em */
03025          if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
03026          ast_cli(fd,"\n");
03027          ast_cli(fd, "************************* CONNECTED NODES *************************\n\n");
03028          for(j = 0 ;; j++){
03029             if(!strs[j]){
03030                if(!j){
03031                   ast_cli(fd,"<NONE>");
03032                }
03033                break;
03034             }
03035             ast_cli(fd, "%s", strs[j]);
03036             if(j % 8 == 7){
03037                ast_cli(fd, "\n");
03038             }
03039             else{
03040                if(strs[j + 1])
03041                   ast_cli(fd, ", ");
03042             }
03043          }
03044          ast_cli(fd,"\n\n");
03045          return RESULT_SUCCESS;
03046       }
03047    }
03048    return RESULT_FAILURE;
03049 }
03050 
03051 /*
03052 * List all locally configured nodes
03053 */
03054 
03055 static int rpt_do_local_nodes(int fd, int argc, char *argv[])
03056 {
03057 
03058     int i;
03059     ast_cli(fd, "\nNode\n----\n");
03060     for (i=0; i< nrpts; i++)
03061     {
03062         ast_cli(fd, "%s\n", rpt_vars[i].name);        
03063     } /* for i */
03064     ast_cli(fd,"\n");
03065     return RESULT_SUCCESS;
03066 } 
03067 
03068 
03069 /*
03070 * reload vars 
03071 */
03072 
03073 static int rpt_do_reload(int fd, int argc, char *argv[])
03074 {
03075 int   n;
03076 
03077         if (argc > 2) return RESULT_SHOWUSAGE;
03078 
03079    for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
03080 
03081    return RESULT_FAILURE;
03082 }
03083 
03084 /*
03085 * restart app_rpt
03086 */
03087                                                                                                                                  
03088 static int rpt_do_restart(int fd, int argc, char *argv[])
03089 {
03090 int   i;
03091 
03092         if (argc > 2) return RESULT_SHOWUSAGE;
03093    for(i = 0; i < nrpts; i++)
03094    {
03095       if (rpt_vars[i].rxchannel) ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
03096    }
03097    return RESULT_FAILURE;
03098 }
03099 
03100 
03101 /*
03102 * send an app_rpt DTMF function from the CLI
03103 */
03104                                                                                                                                  
03105 static int rpt_do_fun(int fd, int argc, char *argv[])
03106 {
03107    int   i,busy=0;
03108 
03109         if (argc != 4) return RESULT_SHOWUSAGE;
03110 
03111    for(i = 0; i < nrpts; i++){
03112       if(!strcmp(argv[2], rpt_vars[i].name)){
03113          struct rpt *myrpt = &rpt_vars[i];
03114          rpt_mutex_lock(&myrpt->lock);
03115          if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(argv[3])){
03116             rpt_mutex_unlock(&myrpt->lock);
03117             busy=1;
03118          }
03119          if(!busy){
03120             myrpt->macrotimer = MACROTIME;
03121             strncat(myrpt->macrobuf,argv[3],MAXMACRO - 1);
03122          }
03123          rpt_mutex_unlock(&myrpt->lock);
03124       }
03125    }
03126    if(busy){
03127       ast_cli(fd, "Function decoder busy");
03128    }
03129    return RESULT_FAILURE;
03130 }
03131 /*
03132    the convention is that macros in the data from the rpt() application
03133    are all at the end of the data, separated by the | and start with a *
03134    when put into the macro buffer, the characters have their high bit
03135    set so the macro processor knows they came from the application data
03136    and to use the alt-functions table.
03137    sph:
03138 */
03139 static int rpt_push_alt_macro(struct rpt *myrpt, char *sptr)
03140 {
03141    int   busy=0;
03142 
03143    rpt_mutex_lock(&myrpt->lock);
03144    if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(sptr)){
03145       rpt_mutex_unlock(&myrpt->lock);
03146       busy=1;
03147    }
03148    if(!busy){
03149       int x;
03150       if (debug)ast_log(LOG_NOTICE, "rpt_push_alt_macro %s\n",sptr);
03151       myrpt->macrotimer = MACROTIME;
03152       for(x = 0; *(sptr + x); x++)
03153           myrpt->macrobuf[x] = *(sptr + x) | 0x80;
03154       *(sptr + x) = 0;
03155    }
03156    rpt_mutex_unlock(&myrpt->lock);
03157 
03158    if(busy)ast_log(LOG_WARNING, "Function decoder busy on app_rpt command macro.\n");
03159 
03160    return busy;
03161 }
03162 /*
03163    allows us to test rpt() application data commands
03164 */
03165 static int rpt_do_fun1(int fd, int argc, char *argv[])
03166 {
03167    int   i;
03168 
03169     if (argc != 4) return RESULT_SHOWUSAGE;
03170 
03171    for(i = 0; i < nrpts; i++){
03172       if(!strcmp(argv[2], rpt_vars[i].name)){
03173          struct rpt *myrpt = &rpt_vars[i];
03174          rpt_push_alt_macro(myrpt,argv[3]);
03175       }
03176    }
03177    return RESULT_FAILURE;
03178 }
03179 /*
03180 * send an app_rpt **command** from the CLI
03181 */
03182 
03183 static int rpt_do_cmd(int fd, int argc, char *argv[])
03184 {
03185    int i, l;
03186    int busy=0;
03187    int maxActions = sizeof(function_table)/sizeof(struct function_table_tag);
03188 
03189    int thisRpt = -1;
03190    int thisAction = -1;
03191    struct rpt *myrpt = NULL;
03192    if (argc != 6) return RESULT_SHOWUSAGE;
03193    
03194    for(i = 0; i < nrpts; i++)
03195    {
03196       if(!strcmp(argv[2], rpt_vars[i].name))
03197       {
03198          thisRpt = i;
03199          myrpt = &rpt_vars[i];
03200          break;
03201       } /* if !strcmp... */
03202    } /* for i */
03203 
03204    if (thisRpt < 0)
03205    {
03206       ast_cli(fd, "Unknown node number %s.\n", argv[2]);
03207       return RESULT_FAILURE;
03208    } /* if thisRpt < 0 */
03209    
03210    /* Look up the action */
03211    l = strlen(argv[3]);
03212    for(i = 0 ; i < maxActions; i++)
03213    {
03214       if(!strncasecmp(argv[3], function_table[i].action, l))
03215       {
03216          thisAction = i;
03217          break;
03218       } /* if !strncasecmp... */
03219    } /* for i */
03220    
03221    if (thisAction < 0)
03222    {
03223       ast_cli(fd, "Unknown action name %s.\n", argv[3]);
03224       return RESULT_FAILURE;
03225    } /* if thisAction < 0 */
03226 
03227    /* at this point, it looks like all the arguments make sense... */
03228 
03229    rpt_mutex_lock(&myrpt->lock);
03230 
03231    if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE)
03232    {
03233       rpt_vars[thisRpt].cmdAction.state = CMD_STATE_BUSY;
03234       rpt_vars[thisRpt].cmdAction.functionNumber = thisAction;
03235       strncpy(rpt_vars[thisRpt].cmdAction.param, argv[4], MAXDTMF);
03236       strncpy(rpt_vars[thisRpt].cmdAction.digits, argv[5], MAXDTMF);
03237       rpt_vars[thisRpt].cmdAction.command_source = SOURCE_RPT;
03238       rpt_vars[thisRpt].cmdAction.state = CMD_STATE_READY;
03239    } /* if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE */
03240    else
03241    {
03242       busy = 1;
03243    } /* if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE */
03244    rpt_mutex_unlock(&myrpt->lock);
03245 
03246    return (busy ? RESULT_FAILURE : RESULT_SUCCESS);
03247 } /* rpt_do_cmd() */
03248 
03249 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
03250 {
03251    int res;
03252 
03253         if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
03254                 return res;
03255                                                                                                                                             
03256         while(chan->generatordata) {
03257       if (ast_safe_sleep(chan,1)) return -1;
03258    }
03259 
03260         return 0;
03261 }
03262 
03263 static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
03264 {
03265    return play_tone_pair(chan, freq, 0, duration, amplitude);
03266 }
03267 
03268 static int play_silence(struct ast_channel *chan, int duration)
03269 {
03270    return play_tone_pair(chan, 0, 0, duration, 0);
03271 }
03272 
03273 #ifdef   NEW_ASTERISK
03274 
03275 static char *res2cli(int r)
03276 
03277 {
03278    switch (r)
03279    {
03280        case RESULT_SUCCESS:
03281       return(CLI_SUCCESS);
03282        case RESULT_SHOWUSAGE:
03283       return(CLI_SHOWUSAGE);
03284        default:
03285       return(CLI_FAILURE);
03286    }
03287 }
03288 
03289 static char *handle_cli_debug(struct ast_cli_entry *e,
03290    int cmd, struct ast_cli_args *a)
03291 {
03292         switch (cmd) {
03293         case CLI_INIT:
03294                 e->command = "rpt debug level";
03295                 e->usage = debug_usage;
03296                 return NULL;
03297         case CLI_GENERATE:
03298                 return NULL;
03299    }
03300    return res2cli(rpt_do_debug(a->fd,a->argc,a->argv));
03301 }
03302 
03303 static char *handle_cli_dump(struct ast_cli_entry *e,
03304    int cmd, struct ast_cli_args *a)
03305 {
03306         switch (cmd) {
03307         case CLI_INIT:
03308                 e->command = "rpt dump level";
03309                 e->usage = dump_usage;
03310                 return NULL;
03311         case CLI_GENERATE:
03312                 return NULL;
03313    }
03314    return res2cli(rpt_do_dump(a->fd,a->argc,a->argv));
03315 }
03316 
03317 
03318 static char *handle_cli_stats(struct ast_cli_entry *e,
03319    int cmd, struct ast_cli_args *a)
03320 {
03321         switch (cmd) {
03322         case CLI_INIT:
03323                 e->command = "rpt stats";
03324                 e->usage = dump_stats;
03325                 return NULL;
03326         case CLI_GENERATE:
03327                 return NULL;
03328    }
03329    return res2cli(rpt_do_stats(a->fd,a->argc,a->argv));
03330 }
03331 
03332 static char *handle_cli_nodes(struct ast_cli_entry *e,
03333    int cmd, struct ast_cli_args *a)
03334 {
03335         switch (cmd) {
03336         case CLI_INIT:
03337                 e->command = "rpt nodes";
03338                 e->usage = dump_nodes;
03339                 return NULL;
03340         case CLI_GENERATE:
03341                 return NULL;
03342    }
03343    return res2cli(rpt_do_nodes(a->fd,a->argc,a->argv));
03344 }
03345 
03346 static char *handle_cli_local_nodes(struct ast_cli_entry *e,
03347    int cmd, struct ast_cli_args *a)
03348 {
03349         switch (cmd) {
03350         case CLI_INIT:
03351                 e->command = "rpt localnodes";
03352                 e->usage = usage_local_nodes;
03353                 return NULL;
03354         case CLI_GENERATE:
03355                 return NULL;
03356    }
03357    return res2cli(rpt_do_local_nodes(a->fd,a->argc,a->argv));
03358 }
03359 
03360 static char *handle_cli_lstats(struct ast_cli_entry *e,
03361    int cmd, struct ast_cli_args *a)
03362 {
03363         switch (cmd) {
03364         case CLI_INIT:
03365                 e->command = "rpt lstats";
03366                 e->usage = dump_lstats;
03367                 return NULL;
03368         case CLI_GENERATE:
03369                 return NULL;
03370    }
03371    return res2cli(rpt_do_lstats(a->fd,a->argc,a->argv));
03372 }
03373 
03374 static char *handle_cli_reload(struct ast_cli_entry *e,
03375    int cmd, struct ast_cli_args *a)
03376 {
03377         switch (cmd) {
03378         case CLI_INIT:
03379                 e->command = "rpt reload";
03380                 e->usage = reload_usage;
03381                 return NULL;
03382         case CLI_GENERATE:
03383                 return NULL;
03384    }
03385    return res2cli(rpt_do_reload(a->fd,a->argc,a->argv));
03386 }
03387 
03388 static char *handle_cli_restart(struct ast_cli_entry *e,
03389    int cmd, struct ast_cli_args *a)
03390 {
03391         switch (cmd) {
03392         case CLI_INIT:
03393                 e->command = "rpt restart";
03394                 e->usage = restart_usage;
03395                 return NULL;
03396         case CLI_GENERATE:
03397                 return NULL;
03398    }
03399    return res2cli(rpt_do_restart(a->fd,a->argc,a->argv));
03400 }
03401 
03402 static char *handle_cli_fun(struct ast_cli_entry *e,
03403    int cmd, struct ast_cli_args *a)
03404 {
03405         switch (cmd) {
03406         case CLI_INIT:
03407                 e->command = "rpt fun";
03408                 e->usage = fun_usage;
03409                 return NULL;
03410         case CLI_GENERATE:
03411                 return NULL;
03412    }
03413    return res2cli(rpt_do_fun(a->fd,a->argc,a->argv));
03414 }
03415 
03416 static char *handle_cli_fun1(struct ast_cli_entry *e,
03417    int cmd, struct ast_cli_args *a)
03418 {
03419         switch (cmd) {
03420         case CLI_INIT:
03421                 e->command = "rpt fun1";
03422                 e->usage = fun_usage;
03423                 return NULL;
03424         case CLI_GENERATE:
03425                 return NULL;
03426    }
03427    return res2cli(rpt_do_fun1(a->fd,a->argc,a->argv));
03428 }
03429 
03430 static char *handle_cli_cmd(struct ast_cli_entry *e,
03431    int cmd, struct ast_cli_args *a)
03432 {
03433         switch (cmd) {
03434         case CLI_INIT:
03435                 e->command = "rpt cmd";
03436                 e->usage = cmd_usage;
03437                 return NULL;
03438         case CLI_GENERATE:
03439                 return NULL;
03440    }
03441    return res2cli(rpt_do_cmd(a->fd,a->argc,a->argv));
03442 }
03443 
03444 static struct ast_cli_entry rpt_cli[] = {
03445    AST_CLI_DEFINE(handle_cli_debug,"Enable app_rpt debugging"),
03446    AST_CLI_DEFINE(handle_cli_dump,"Dump app_rpt structs for debugging"),
03447    AST_CLI_DEFINE(handle_cli_stats,"Dump node statistics"),
03448    AST_CLI_DEFINE(handle_cli_nodes,"Dump node list"),
03449    AST_CLI_DEFINE(handle_cli_local_nodes, "Dump list of local node numbers"),
03450    AST_CLI_DEFINE(handle_cli_lstats,"Dump link statistics"),
03451    AST_CLI_DEFINE(handle_cli_reload,"Reload app_rpt config"),
03452    AST_CLI_DEFINE(handle_cli_restart,"Restart app_rpt"),
03453    AST_CLI_DEFINE(handle_cli_fun,"Execute a DTMF function"),
03454    AST_CLI_DEFINE(handle_cli_fun1,"Execute a DTMF function"),
03455    AST_CLI_DEFINE(handle_cli_cmd,"Execute a DTMF function")
03456 };
03457 
03458 #endif
03459 
03460 static int send_morse(struct ast_channel *chan, char *string, int speed, int freq, int amplitude)
03461 {
03462 
03463 static struct morse_bits mbits[] = {
03464       {0, 0}, /* SPACE */
03465       {0, 0}, 
03466       {6, 18},/* " */
03467       {0, 0},
03468       {7, 72},/* $ */
03469       {0, 0},
03470       {0, 0},
03471       {6, 30},/* ' */
03472       {5, 13},/* ( */
03473       {6, 29},/* ) */
03474       {0, 0},
03475       {5, 10},/* + */
03476       {6, 51},/* , */
03477       {6, 33},/* - */
03478       {6, 42},/* . */
03479       {5, 9}, /* / */
03480       {5, 31},/* 0 */
03481       {5, 30},/* 1 */
03482       {5, 28},/* 2 */
03483       {5, 24},/* 3 */
03484       {5, 16},/* 4 */
03485       {5, 0}, /* 5 */
03486       {5, 1}, /* 6 */
03487       {5, 3}, /* 7 */
03488       {5, 7}, /* 8 */
03489       {5, 15},/* 9 */
03490       {6, 7}, /* : */
03491       {6, 21},/* ; */
03492       {0, 0},
03493       {5, 33},/* = */
03494       {0, 0},
03495       {6, 12},/* ? */
03496       {0, 0},
03497          {2, 2}, /* A */
03498       {4, 1}, /* B */
03499       {4, 5}, /* C */
03500       {3, 1}, /* D */
03501       {1, 0}, /* E */
03502       {4, 4}, /* F */
03503       {3, 3}, /* G */
03504       {4, 0}, /* H */
03505       {2, 0}, /* I */
03506       {4, 14},/* J */
03507       {3, 5}, /* K */
03508       {4, 2}, /* L */
03509       {2, 3}, /* M */
03510       {2, 1}, /* N */
03511       {3, 7}, /* O */
03512       {4, 6}, /* P */
03513       {4, 11},/* Q */
03514       {3, 2}, /* R */
03515       {3, 0}, /* S */
03516       {1, 1}, /* T */
03517       {3, 4}, /* U */
03518       {4, 8}, /* V */
03519       {3, 6}, /* W */
03520       {4, 9}, /* X */
03521       {4, 13},/* Y */
03522       {4, 3}  /* Z */
03523    };
03524 
03525 
03526    int dottime;
03527    int dashtime;
03528    int intralettertime;
03529    int interlettertime;
03530    int interwordtime;
03531    int len, ddcomb;
03532    int res;
03533    int c;
03534    int i;
03535    int flags;
03536          
03537    res = 0;
03538    
03539    /* Approximate the dot time from the speed arg. */
03540    
03541    dottime = 900/speed;
03542    
03543    /* Establish timing releationships */
03544    
03545    dashtime = 3 * dottime;
03546    intralettertime = dottime;
03547    interlettertime = dottime * 4 ;
03548    interwordtime = dottime * 7;
03549    
03550    for(;(*string) && (!res); string++){
03551    
03552       c = *string;
03553       
03554       /* Convert lower case to upper case */
03555       
03556       if((c >= 'a') && (c <= 'z'))
03557          c -= 0x20;
03558       
03559       /* Can't deal with any char code greater than Z, skip it */
03560       
03561       if(c  > 'Z')
03562          continue;
03563       
03564       /* If space char, wait the inter word time */
03565                
03566       if(c == ' '){
03567          if(!res)
03568             res = play_silence(chan, interwordtime);
03569          continue;
03570       }
03571       
03572       /* Subtract out control char offset to match our table */
03573       
03574       c -= 0x20;
03575       
03576       /* Get the character data */
03577       
03578       len = mbits[c].len;
03579       ddcomb = mbits[c].ddcomb;
03580       
03581       /* Send the character */
03582       
03583       for(; len ; len--){
03584          if(!res)
03585             res = play_tone(chan, freq, (ddcomb & 1) ? dashtime : dottime, amplitude);
03586          if(!res)
03587             res = play_silence(chan, intralettertime);
03588          ddcomb >>= 1;
03589       }
03590       
03591       /* Wait the interletter time */
03592       
03593       if(!res)
03594          res = play_silence(chan, interlettertime - intralettertime);
03595    }
03596    
03597    /* Wait for all the frames to be sent */
03598    
03599    if (!res) 
03600       res = ast_waitstream(chan, "");
03601    ast_stopstream(chan);
03602    
03603    /*
03604    * Wait for the DAHDI driver to physically write the tone blocks to the hardware
03605    */
03606 
03607    for(i = 0; i < 20 ; i++){
03608       flags =  DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT; 
03609       res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
03610       if(flags & DAHDI_IOMUX_WRITEEMPTY)
03611          break;
03612       if( ast_safe_sleep(chan, 50)){
03613          res = -1;
03614          break;
03615       }
03616    }
03617 
03618    
03619    return res;
03620 }
03621 
03622 static int send_tone_telemetry(struct ast_channel *chan, char *tonestring)
03623 {
03624    char *p,*stringp;
03625    char *tonesubset;
03626    int f1,f2;
03627    int duration;
03628    int amplitude;
03629    int res;
03630    int i;
03631    int flags;
03632    
03633    res = 0;
03634 
03635    if(!tonestring)
03636       return res;
03637    
03638    p = stringp = ast_strdup(tonestring);
03639 
03640    for(;tonestring;){
03641       tonesubset = strsep(&stringp,")");
03642       if(!tonesubset)
03643          break;
03644       if(sscanf(tonesubset,"(%30d,%30d,%30d,%30d", &f1, &f2, &duration, &amplitude) != 4)
03645          break;
03646       res = play_tone_pair(chan, f1, f2, duration, amplitude);
03647       if(res)
03648          break;
03649    }
03650    if(p)
03651       ast_free(p);
03652    if(!res)
03653       res = play_tone_pair(chan, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
03654    
03655    if (!res) 
03656       res = ast_waitstream(chan, "");
03657 
03658    ast_stopstream(chan);
03659 
03660    /*
03661    * Wait for the DAHDI driver to physically write the tone blocks to the hardware
03662    */
03663 
03664    for(i = 0; i < 20 ; i++){
03665       flags =  DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT; 
03666       res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
03667       if(flags & DAHDI_IOMUX_WRITEEMPTY)
03668          break;
03669       if( ast_safe_sleep(chan, 50)){
03670          res = -1;
03671          break;
03672       }
03673    }
03674       
03675    return res;
03676       
03677 }
03678 
03679 static int sayfile(struct ast_channel *mychannel,char *fname)
03680 {
03681 int   res;
03682 
03683    res = ast_streamfile(mychannel, fname, mychannel->language);
03684    if (!res) 
03685       res = ast_waitstream(mychannel, "");
03686    else
03687        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03688    ast_stopstream(mychannel);
03689    return res;
03690 }
03691 
03692 static int saycharstr(struct ast_channel *mychannel,char *str)
03693 {
03694 int   res;
03695 
03696    res = ast_say_character_str(mychannel,str,NULL,mychannel->language);
03697    if (!res) 
03698       res = ast_waitstream(mychannel, "");
03699    else
03700        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03701    ast_stopstream(mychannel);
03702    return res;
03703 }
03704 
03705 static int saynum(struct ast_channel *mychannel, int num)
03706 {
03707    int res;
03708    res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
03709    if(!res)
03710       res = ast_waitstream(mychannel, "");
03711    else
03712       ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03713    ast_stopstream(mychannel);
03714    return res;
03715 }
03716 
03717 /* say a node and nodename. Try to look in dir referred to by nodenames in
03718 config, and see if there's a custom node file to play, and if so, play it */
03719 
03720 static int saynode(struct rpt *myrpt, struct ast_channel *mychannel, char *name)
03721 {
03722 int   res;
03723 char  *val,fname[300];
03724 
03725    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "nodenames");
03726    if (!val) val = NODENAMES;
03727    snprintf(fname,sizeof(fname) - 1,"%s/%s",val,name);
03728    if (ast_fileexists(fname,NULL,mychannel->language) > 0)
03729       return(sayfile(mychannel,fname));
03730    res = sayfile(mychannel,"rpt/node");
03731    if (!res) 
03732       res = ast_say_character_str(mychannel,name,NULL,mychannel->language);
03733    return res;
03734 }
03735 
03736 static int telem_any(struct rpt *myrpt,struct ast_channel *chan, char *entry)
03737 {
03738    int res;
03739    char c;
03740    
03741    static int morsespeed;
03742    static int morsefreq;
03743    static int morseampl;
03744    static int morseidfreq = 0;
03745    static int morseidampl;
03746    static char mcat[] = MORSE;
03747    
03748    res = 0;
03749    
03750    if(!morseidfreq){ /* Get the morse parameters if not already loaded */
03751       morsespeed = retrieve_astcfgint(myrpt, mcat, "speed", 5, 20, 20);
03752          morsefreq = retrieve_astcfgint(myrpt, mcat, "frequency", 300, 3000, 800);
03753          morseampl = retrieve_astcfgint(myrpt, mcat, "amplitude", 200, 8192, 4096);
03754       morseidampl = retrieve_astcfgint(myrpt, mcat, "idamplitude", 200, 8192, 2048);
03755       morseidfreq = retrieve_astcfgint(myrpt, mcat, "idfrequency", 300, 3000, 330); 
03756    }
03757    
03758    /* Is it a file, or a tone sequence? */
03759          
03760    if(entry[0] == '|'){
03761       c = entry[1];
03762       if((c >= 'a')&&(c <= 'z'))
03763          c -= 0x20;
03764    
03765       switch(c){
03766          case 'I': /* Morse ID */
03767             res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
03768             break;
03769          
03770          case 'M': /* Morse Message */
03771             res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
03772             break;
03773          
03774          case 'T': /* Tone sequence */
03775             res = send_tone_telemetry(chan, entry + 2);
03776             break;
03777          default:
03778             res = -1;
03779       }
03780    }
03781    else
03782       res = sayfile(chan, entry); /* File */
03783    return res;
03784 }
03785 
03786 /*
03787 * This function looks up a telemetry name in the config file, and does a telemetry response as configured.
03788 *
03789 * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
03790 */
03791 
03792 static int telem_lookup(struct rpt *myrpt,struct ast_channel *chan, char *node, char *name)
03793 {
03794    
03795    int res;
03796    int i;
03797    char *entry;
03798    char *telemetry;
03799    char *telemetry_save;
03800 
03801    res = 0;
03802    telemetry_save = NULL;
03803    entry = NULL;
03804    
03805    /* Retrieve the section name for telemetry from the node section */
03806    telemetry = (char *) ast_variable_retrieve(myrpt->cfg, node, TELEMETRY);
03807    if(telemetry ){
03808       telemetry_save = ast_strdup(telemetry);
03809       if(!telemetry_save){
03810          ast_log(LOG_WARNING,"ast_strdup() failed in telem_lookup()\n");
03811          return res;
03812       }
03813       entry = (char *) ast_variable_retrieve(myrpt->cfg, telemetry_save, name);
03814    }
03815    
03816    /* Try to look up the telemetry name */   
03817 
03818    if(!entry){
03819       /* Telemetry name wasn't found in the config file, use the default */
03820       for(i = 0; i < sizeof(tele_defs)/sizeof(struct telem_defaults) ; i++){
03821          if(!strcasecmp(tele_defs[i].name, name))
03822             entry = tele_defs[i].value;
03823       }
03824    }
03825    if(entry){  
03826       if(strlen(entry))
03827          if (chan) telem_any(myrpt,chan, entry);
03828    }
03829    else{
03830       res = -1;
03831    }
03832    if(telemetry_save)
03833       ast_free(telemetry_save);
03834    return res;
03835 }
03836 
03837 /*
03838 * Retrieve a wait interval
03839 */
03840 
03841 static int get_wait_interval(struct rpt *myrpt, int type)
03842 {
03843         int interval;
03844         char *wait_times;
03845         char *wait_times_save;
03846                                                                                                                   
03847         wait_times_save = NULL;
03848         wait_times = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
03849                                                                                                                   
03850         if(wait_times){
03851                 wait_times_save = ast_strdup(wait_times);
03852                 if(!wait_times_save)
03853          return 0;
03854                 
03855         }
03856                                                                                                                   
03857         switch(type){
03858                 case DLY_TELEM:
03859                         if(wait_times)
03860                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "telemwait", 500, 5000, 1000);
03861                         else
03862                                 interval = 1000;
03863                         break;
03864                                                                                                                   
03865                 case DLY_ID:
03866                         if(wait_times)
03867                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "idwait",250,5000,500);
03868                         else
03869                                 interval = 500;
03870                         break;
03871                                                                                                                   
03872                 case DLY_UNKEY:
03873                         if(wait_times)
03874                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "unkeywait",50,5000,1000);
03875                         else
03876                                 interval = 1000;
03877                         break;
03878                                                                                                                   
03879                 case DLY_LINKUNKEY:
03880                         if(wait_times)
03881                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "linkunkeywait",500,5000,1000);
03882                         else
03883                                 interval = 1000;
03884                         break;
03885                                                                                                                   
03886                 case DLY_CALLTERM:
03887                         if(wait_times)
03888                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "calltermwait",500,5000,1500);
03889                         else
03890                                 interval = 1500;
03891                         break;
03892                                                                                                                   
03893                 case DLY_COMP:
03894                         if(wait_times)
03895                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "compwait",500,5000,200);
03896                         else
03897                                 interval = 200;
03898                         break;
03899                                                                                                                   
03900                 case DLY_PARROT:
03901                         if(wait_times)
03902                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "parrotwait",500,5000,200);
03903                         else
03904                                 interval = 200;
03905                         break;
03906                                                                                                                   
03907                 default:
03908          interval = 0;
03909          break;
03910         }
03911    if(wait_times_save)
03912             ast_free(wait_times_save);
03913    return interval;
03914 }                                                                                                                  
03915 
03916 
03917 /*
03918 * Wait a configurable interval of time 
03919 */
03920 static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
03921 {
03922    int interval;
03923    interval = get_wait_interval(myrpt, type);
03924    if(debug)
03925       ast_log(LOG_NOTICE,"Delay interval = %d\n", interval);
03926    if(interval)
03927       ast_safe_sleep(chan,interval);
03928    if(debug)
03929       ast_log(LOG_NOTICE,"Delay complete\n");
03930    return;
03931 }
03932 
03933 static int split_freq(char *mhz, char *decimals, char *freq);
03934 
03935 static void *rpt_tele_thread(void *this)
03936 {
03937 struct dahdi_confinfo ci;  /* conference info */
03938 int   res = 0,haslink,hastx,hasremote,imdone = 0, unkeys_queued, x;
03939 struct   rpt_tele *mytele = (struct rpt_tele *)this;
03940 struct  rpt_tele *tlist;
03941 struct   rpt *myrpt;
03942 struct   rpt_link *l,*l1,linkbase;
03943 struct   ast_channel *mychannel;
03944 int vmajor, vminor, m;
03945 char *p,*ct,*ct_copy,*ident, *nodename,*cp;
03946 time_t t;
03947 #ifdef   NEW_ASTERISK
03948 struct ast_tm localtm;
03949 #else
03950 struct tm localtm;
03951 #endif
03952 char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
03953 int   i,ns,rbimode;
03954 char mhz[MAXREMSTR];
03955 char decimals[MAXREMSTR];
03956 char  mystr[200];
03957 struct dahdi_params par;
03958 
03959 
03960    /* get a pointer to myrpt */
03961    myrpt = mytele->rpt;
03962 
03963    /* Snag copies of a few key myrpt variables */
03964    rpt_mutex_lock(&myrpt->lock);
03965    nodename = ast_strdup(myrpt->name);
03966    if(!nodename)
03967    {
03968        fprintf(stderr,"rpt:Sorry unable strdup nodename\n");
03969        rpt_mutex_lock(&myrpt->lock);
03970        remque((struct qelem *)mytele);
03971        ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
03972        rpt_mutex_unlock(&myrpt->lock);
03973        ast_free(mytele);
03974        pthread_exit(NULL);
03975    }
03976 
03977    if (myrpt->p.ident){
03978       ident = ast_strdup(myrpt->p.ident);
03979          if(!ident)
03980       {
03981                  fprintf(stderr,"rpt:Sorry unable strdup ident\n");
03982          rpt_mutex_lock(&myrpt->lock);
03983                   remque((struct qelem *)mytele);
03984                   ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",
03985          __LINE__, mytele->mode); /*@@@@@@@@@@@*/
03986                   rpt_mutex_unlock(&myrpt->lock);
03987          ast_free(nodename);
03988                   ast_free(mytele);
03989                   pthread_exit(NULL);
03990          }
03991    }
03992    else
03993    {
03994       ident = "";
03995    }
03996    rpt_mutex_unlock(&myrpt->lock);
03997       
03998 
03999 
04000    /* allocate a pseudo-channel thru asterisk */
04001    mychannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
04002    if (!mychannel)
04003    {
04004       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
04005       rpt_mutex_lock(&myrpt->lock);
04006       remque((struct qelem *)mytele);
04007       ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04008       rpt_mutex_unlock(&myrpt->lock);
04009       ast_free(nodename);
04010       ast_free(ident);
04011       ast_free(mytele);    
04012       pthread_exit(NULL);
04013    }
04014 #ifdef   AST_CDR_FLAG_POST_DISABLED
04015    if (mychannel->cdr) 
04016       ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
04017 #endif
04018    rpt_mutex_lock(&myrpt->lock);
04019    mytele->chan = mychannel;
04020    rpt_mutex_unlock(&myrpt->lock);
04021 
04022    while((mytele->mode != SETREMOTE) && (mytele->mode != UNKEY) &&
04023       (mytele->mode != LINKUNKEY))
04024    {  
04025                 rpt_mutex_lock(&myrpt->lock);
04026       if (!myrpt->active_telem)
04027       {
04028          myrpt->active_telem = mytele;
04029                    rpt_mutex_unlock(&myrpt->lock);
04030          break;
04031       }
04032                 rpt_mutex_unlock(&myrpt->lock);
04033       usleep(100000);
04034    }
04035 
04036    /* make a conference for the tx */
04037    ci.chan = 0;
04038    /* If the telemetry is only intended for a local audience, */
04039    /* only connect the ID audio to the local tx conference so */
04040    /* linked systems can't hear it */
04041    ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) || 
04042       (mytele->mode == TAILMSG) || (mytele->mode == LINKUNKEY) || (mytele->mode == TIMEOUT) || 
04043       (mytele->mode == PARROT) || (mytele->mode == STATS_TIME_LOCAL)) ? 
04044          myrpt->txconf : myrpt->conf);
04045    ci.confmode = DAHDI_CONF_CONFANN;
04046    /* first put the channel on the conference in announce mode */
04047    if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04048    {
04049       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04050       rpt_mutex_lock(&myrpt->lock);
04051       myrpt->active_telem = NULL;
04052       remque((struct qelem *)mytele);
04053       rpt_mutex_unlock(&myrpt->lock);
04054       ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04055       ast_free(nodename);
04056       ast_free(ident);
04057       ast_free(mytele);    
04058       ast_hangup(mychannel);
04059       pthread_exit(NULL);
04060    }
04061    ast_stopstream(mychannel);
04062    switch(mytele->mode)
04063    {
04064        case ID:
04065        case ID1:
04066       /* wait a bit */
04067       wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM,mychannel);
04068       res = telem_any(myrpt,mychannel, ident); 
04069       imdone=1;   
04070       break;
04071       
04072        case TAILMSG:
04073       res = ast_streamfile(mychannel, myrpt->p.tailmessages[myrpt->tailmessagen], mychannel->language); 
04074       break;
04075       
04076        case IDTALKOVER:
04077          p = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "idtalkover");
04078          if(p)
04079          res = telem_any(myrpt,mychannel, p); 
04080       imdone=1;   
04081          break;
04082             
04083        case PROC:
04084       /* wait a little bit longer */
04085       wait_interval(myrpt, DLY_TELEM, mychannel);
04086       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchup");
04087       if(res < 0){ /* Then default message */
04088          res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
04089       }
04090       break;
04091        case TERM:
04092       /* wait a little bit longer */
04093       wait_interval(myrpt, DLY_CALLTERM, mychannel);
04094       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchdown");
04095       if(res < 0){ /* Then default message */
04096          res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
04097       }
04098       break;
04099        case COMPLETE:
04100       /* wait a little bit */
04101       wait_interval(myrpt, DLY_TELEM, mychannel);
04102       res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04103       break;
04104        case MACRO_NOTFOUND:
04105       /* wait a little bit */
04106       wait_interval(myrpt, DLY_TELEM, mychannel);
04107       res = ast_streamfile(mychannel, "rpt/macro_notfound", mychannel->language);
04108       break;
04109        case MACRO_BUSY:
04110       /* wait a little bit */
04111       wait_interval(myrpt, DLY_TELEM, mychannel);
04112       res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
04113       break;
04114        case UNKEY:
04115       if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
04116          imdone = 1;
04117          break;
04118       }
04119          
04120       /*
04121       * Reset the Unkey to CT timer
04122       */
04123 
04124       x = get_wait_interval(myrpt, DLY_UNKEY);
04125       rpt_mutex_lock(&myrpt->lock);
04126       myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
04127       rpt_mutex_unlock(&myrpt->lock);
04128 
04129       /*
04130       * If there's one already queued, don't do another
04131       */
04132 
04133       tlist = myrpt->tele.next;
04134       unkeys_queued = 0;
04135                 if (tlist != &myrpt->tele)
04136                 {
04137                         rpt_mutex_lock(&myrpt->lock);
04138                         while(tlist != &myrpt->tele){
04139                                 if (tlist->mode == UNKEY) unkeys_queued++;
04140                                 tlist = tlist->next;
04141                         }
04142                         rpt_mutex_unlock(&myrpt->lock);
04143       }
04144       if( unkeys_queued > 1){
04145          imdone = 1;
04146          break;
04147       }
04148 
04149       /* Wait for the telemetry timer to expire */
04150       /* Periodically check the timer since it can be re-initialized above */
04151       while(myrpt->unkeytocttimer)
04152       {
04153          int ctint;
04154          if(myrpt->unkeytocttimer > 100)
04155             ctint = 100;
04156          else
04157             ctint = myrpt->unkeytocttimer;
04158          ast_safe_sleep(mychannel, ctint);
04159          rpt_mutex_lock(&myrpt->lock);
04160          if(myrpt->unkeytocttimer < ctint)
04161             myrpt->unkeytocttimer = 0;
04162          else
04163             myrpt->unkeytocttimer -= ctint;
04164          rpt_mutex_unlock(&myrpt->lock);
04165       }
04166    
04167       /*
04168       * Now, the carrier on the rptr rx should be gone. 
04169       * If it re-appeared, then forget about sending the CT
04170       */
04171       if(myrpt->keyed){
04172          imdone = 1;
04173          break;
04174       }
04175       
04176       rpt_mutex_lock(&myrpt->lock); /* Update the kerchunk counters */
04177       myrpt->dailykerchunks++;
04178       myrpt->totalkerchunks++;
04179       rpt_mutex_unlock(&myrpt->lock);
04180    
04181       haslink = 0;
04182       hastx = 0;
04183       hasremote = 0;    
04184       l = myrpt->links.next;
04185       if (l != &myrpt->links)
04186       {
04187          rpt_mutex_lock(&myrpt->lock);
04188          while(l != &myrpt->links)
04189          {
04190             if (l->name[0] == '0')
04191             {
04192                l = l->next;
04193                continue;
04194             }
04195             haslink = 1;
04196             if (l->mode) {
04197                hastx++;
04198                if (l->isremote) hasremote++;
04199             }
04200             l = l->next;
04201          }
04202          rpt_mutex_unlock(&myrpt->lock);
04203       }
04204       if (haslink)
04205       {
04206 
04207          res = telem_lookup(myrpt,mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
04208          if(res)
04209             ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
04210          
04211       
04212          /* if in remote cmd mode, indicate it */
04213          if (myrpt->cmdnode[0])
04214          {
04215             ast_safe_sleep(mychannel,200);
04216             res = telem_lookup(myrpt,mychannel, myrpt->name, "cmdmode");
04217             if(res)
04218                ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
04219             ast_stopstream(mychannel);
04220          }
04221       }
04222       else if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */
04223          ct_copy = ast_strdup(ct);
04224          if(ct_copy)
04225          {
04226             res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
04227             ast_free(ct_copy);
04228          }
04229          else
04230             res = -1;
04231          if(res)
04232             ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
04233       }  
04234       if (hasremote && (!myrpt->cmdnode[0]))
04235       {
04236          /* set for all to hear */
04237          ci.chan = 0;
04238          ci.confno = myrpt->conf;
04239          ci.confmode = DAHDI_CONF_CONFANN;
04240          /* first put the channel on the conference in announce mode */
04241          if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04242          {
04243             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04244             rpt_mutex_lock(&myrpt->lock);
04245             myrpt->active_telem = NULL;
04246             remque((struct qelem *)mytele);
04247             rpt_mutex_unlock(&myrpt->lock);
04248             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04249             ast_free(nodename);
04250             ast_free(ident);
04251             ast_free(mytele);    
04252             ast_hangup(mychannel);
04253             pthread_exit(NULL);
04254          }
04255          if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
04256             ast_safe_sleep(mychannel,200);
04257             ct_copy = ast_strdup(ct);
04258             if(ct_copy)
04259             {
04260                res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
04261                ast_free(ct_copy);
04262             }
04263             else
04264                res = -1;
04265       
04266             if(res)
04267                ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
04268          }  
04269       }
04270 #if   defined(_MDC_DECODE_H_) && defined(MDC_SAY_WHEN_DOING_CT)
04271       if (myrpt->lastunit)
04272       {
04273          char mystr[10];
04274 
04275          ast_safe_sleep(mychannel,200);
04276          /* set for all to hear */
04277          ci.chan = 0;
04278          ci.confno = myrpt->txconf;
04279          ci.confmode = DAHDI_CONF_CONFANN;
04280          /* first put the channel on the conference in announce mode */
04281          if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04282          {
04283             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04284             rpt_mutex_lock(&myrpt->lock);
04285             myrpt->active_telem = NULL;
04286             remque((struct qelem *)mytele);
04287             rpt_mutex_unlock(&myrpt->lock);
04288             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04289             ast_free(nodename);
04290             ast_free(ident);
04291             ast_free(mytele);    
04292             ast_hangup(mychannel);
04293             pthread_exit(NULL);
04294          }
04295          sprintf(mystr,"%04x",myrpt->lastunit);
04296          myrpt->lastunit = 0;
04297          ast_say_character_str(mychannel,mystr,NULL,mychannel->language);
04298          break;
04299       }
04300 #endif
04301       imdone = 1;
04302       break;
04303        case LINKUNKEY:
04304       if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
04305          imdone = 1;
04306          break;
04307       }
04308          
04309       /*
04310       * Reset the Unkey to CT timer
04311       */
04312 
04313       x = get_wait_interval(myrpt, DLY_LINKUNKEY);
04314       mytele->mylink.linkunkeytocttimer = x; /* Must be protected as it is changed below */
04315 
04316       /*
04317       * If there's one already queued, don't do another
04318       */
04319 
04320       tlist = myrpt->tele.next;
04321       unkeys_queued = 0;
04322                 if (tlist != &myrpt->tele)
04323                 {
04324                         rpt_mutex_lock(&myrpt->lock);
04325                         while(tlist != &myrpt->tele){
04326                                 if (tlist->mode == LINKUNKEY) unkeys_queued++;
04327                                 tlist = tlist->next;
04328                         }
04329                         rpt_mutex_unlock(&myrpt->lock);
04330       }
04331       if( unkeys_queued > 1){
04332          imdone = 1;
04333          break;
04334       }
04335 
04336       /* Wait for the telemetry timer to expire */
04337       /* Periodically check the timer since it can be re-initialized above */
04338       while(mytele->mylink.linkunkeytocttimer)
04339       {
04340          int ctint;
04341          if(mytele->mylink.linkunkeytocttimer > 100)
04342             ctint = 100;
04343          else
04344             ctint = mytele->mylink.linkunkeytocttimer;
04345          ast_safe_sleep(mychannel, ctint);
04346          rpt_mutex_lock(&myrpt->lock);
04347          if(mytele->mylink.linkunkeytocttimer < ctint)
04348             mytele->mylink.linkunkeytocttimer = 0;
04349          else
04350             mytele->mylink.linkunkeytocttimer -= ctint;
04351          rpt_mutex_unlock(&myrpt->lock);
04352       }
04353    
04354       if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "linkunkeyct"))){ /* Unlinked Courtesy Tone */
04355          ct_copy = ast_strdup(ct);
04356          if(ct_copy){
04357             res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
04358             ast_free(ct_copy);
04359          }
04360          else
04361             res = -1;
04362          if(res)
04363             ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
04364       }  
04365       imdone = 1;
04366       break;
04367        case REMDISC:
04368       /* wait a little bit */
04369       wait_interval(myrpt, DLY_TELEM, mychannel);
04370       l = myrpt->links.next;
04371       haslink = 0;
04372       /* dont report if a link for this one still on system */
04373       if (l != &myrpt->links)
04374       {
04375          rpt_mutex_lock(&myrpt->lock);
04376          while(l != &myrpt->links)
04377          {
04378             if (l->name[0] == '0')
04379             {
04380                l = l->next;
04381                continue;
04382             }
04383             if (!strcmp(l->name,mytele->mylink.name))
04384             {
04385                haslink = 1;
04386                break;
04387             }
04388             l = l->next;
04389          }
04390          rpt_mutex_unlock(&myrpt->lock);
04391       }
04392       if (haslink)
04393       {
04394          imdone = 1;
04395          break;
04396       }
04397       res = saynode(myrpt,mychannel,mytele->mylink.name);
04398       if (!res) 
04399           res = ast_streamfile(mychannel, ((mytele->mylink.hasconnected) ? 
04400          "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
04401       break;
04402        case REMALREADY:
04403       /* wait a little bit */
04404       wait_interval(myrpt, DLY_TELEM, mychannel);
04405       res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
04406       break;
04407        case REMNOTFOUND:
04408       /* wait a little bit */
04409       wait_interval(myrpt, DLY_TELEM, mychannel);
04410       res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
04411       break;
04412        case REMGO:
04413       /* wait a little bit */
04414       wait_interval(myrpt, DLY_TELEM, mychannel);
04415       res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
04416       break;
04417        case CONNECTED:
04418       /* wait a little bit */
04419       wait_interval(myrpt, DLY_TELEM,  mychannel);
04420       res = saynode(myrpt,mychannel,mytele->mylink.name);
04421       if (!res)
04422           res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
04423       if (!res) 
04424          res = ast_waitstream(mychannel, "");
04425       else
04426           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04427       ast_stopstream(mychannel);
04428       res = ast_streamfile(mychannel, "digits/2", mychannel->language);
04429       if (!res) 
04430          res = ast_waitstream(mychannel, "");
04431       else
04432           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04433       ast_stopstream(mychannel);
04434       res = saynode(myrpt,mychannel,myrpt->name);
04435       imdone = 1;
04436       break;
04437        case CONNFAIL:
04438       res = saynode(myrpt,mychannel,mytele->mylink.name);
04439       if (!res) 
04440           res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
04441       break;
04442        case MEMNOTFOUND:
04443       /* wait a little bit */
04444       wait_interval(myrpt, DLY_TELEM, mychannel);
04445       res = ast_streamfile(mychannel, "rpt/memory_notfound", mychannel->language);
04446       break;
04447        case PLAYBACK:
04448       /* wait a little bit */
04449       wait_interval(myrpt, DLY_TELEM, mychannel);
04450       res = ast_streamfile(mychannel, mytele->param, mychannel->language);
04451       break;
04452        case TOPKEY:
04453       /* wait a little bit */
04454       wait_interval(myrpt, DLY_TELEM, mychannel);
04455       for(i = 0; i < TOPKEYN; i++)
04456       {
04457          if (!myrpt->topkey[i].node[0]) continue;
04458          if ((!myrpt->topkeylong) && (myrpt->topkey[i].keyed)) continue;
04459          res = saynode(myrpt, mychannel,  myrpt->topkey[i].node);
04460          if (!res) res = sayfile(mychannel,(myrpt->topkey[i].keyed) ?
04461             "rpt/keyedfor" : "rpt/unkeyedfor");
04462          if (!res) res = saynum(mychannel,
04463             myrpt->topkey[i].timesince);
04464          if (!res) res = sayfile(mychannel,"rpt/seconds");
04465          if (!myrpt->topkeylong) break;
04466       }
04467       imdone = 1;
04468       break;
04469        case SETREMOTE:
04470       ast_mutex_lock(&myrpt->remlock);
04471       res = 0;
04472       if(!strcmp(myrpt->remoterig, remote_rig_ft897))
04473       {
04474          res = set_ft897(myrpt);
04475       }
04476       else if(!strcmp(myrpt->remoterig, remote_rig_tm271))
04477       {
04478          res = set_tm271(myrpt);
04479       }
04480       else if(!strcmp(myrpt->remoterig, remote_rig_ic706))
04481       {
04482          res = set_ic706(myrpt);
04483       }
04484 #ifdef HAVE_IOPERM
04485       else if(!strcmp(myrpt->remoterig, remote_rig_rbi)||!strcmp(myrpt->remoterig, remote_rig_ppp16))
04486       {
04487          if (ioperm(myrpt->p.iobase,1,1) == -1)
04488          {
04489             rpt_mutex_unlock(&myrpt->lock);
04490             ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
04491             res = -1;
04492          }
04493          else res = setrbi(myrpt);
04494       }
04495 #endif
04496       else if(!strcmp(myrpt->remoterig, remote_rig_kenwood))
04497       {
04498          if (myrpt->iofd >= 0) setdtr(myrpt->iofd,1);
04499          res = setkenwood(myrpt);
04500          if (myrpt->iofd >= 0) setdtr(myrpt->iofd,0);
04501          if (ast_safe_sleep(mychannel,200) == -1)
04502          {
04503             ast_mutex_unlock(&myrpt->remlock);
04504             res = -1;
04505             break;
04506          }
04507          if (myrpt->iofd < 0)
04508          {
04509             i = DAHDI_FLUSH_EVENT;
04510             if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_FLUSH,&i) == -1)
04511             {
04512                ast_mutex_unlock(&myrpt->remlock);
04513                ast_log(LOG_ERROR,"Cant flush events");
04514                res = -1;
04515                break;
04516             }
04517             if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_GET_PARAMS,&par) == -1)
04518             {
04519                ast_mutex_unlock(&myrpt->remlock);
04520                ast_log(LOG_ERROR,"Cant get params");
04521                res = -1;
04522                break;
04523             }
04524             myrpt->remoterx = 
04525                (par.rxisoffhook || (myrpt->tele.next != &myrpt->tele));
04526          }
04527       }
04528 
04529       ast_mutex_unlock(&myrpt->remlock);
04530       if (!res)
04531       {
04532          imdone = 1;
04533          break;
04534       }
04535       /* fall thru to invalid freq */
04536        case INVFREQ:
04537       /* wait a little bit */
04538       wait_interval(myrpt, DLY_TELEM, mychannel);
04539       res = ast_streamfile(mychannel, "rpt/invalid-freq", mychannel->language);
04540       break;
04541        case REMMODE:
04542       cp = 0;
04543       wait_interval(myrpt, DLY_TELEM, mychannel);
04544       switch(myrpt->remmode)
04545       {
04546           case REM_MODE_FM:
04547          saycharstr(mychannel,"FM");
04548          break;
04549           case REM_MODE_USB:
04550          saycharstr(mychannel,"USB");
04551          break;
04552           case REM_MODE_LSB:
04553          saycharstr(mychannel,"LSB");
04554          break;
04555           case REM_MODE_AM:
04556          saycharstr(mychannel,"AM");
04557          break;
04558       }
04559       wait_interval(myrpt, DLY_COMP, mychannel);
04560       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04561       break;
04562        case LOGINREQ:
04563       wait_interval(myrpt, DLY_TELEM, mychannel);
04564       sayfile(mychannel,"rpt/login");
04565       saycharstr(mychannel,myrpt->name);
04566       break;
04567        case REMLOGIN:
04568       wait_interval(myrpt, DLY_TELEM, mychannel);
04569       saycharstr(mychannel,myrpt->loginuser);
04570       saynode(myrpt,mychannel,myrpt->name);
04571       wait_interval(myrpt, DLY_COMP, mychannel);
04572       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04573       break;
04574        case REMXXX:
04575       wait_interval(myrpt, DLY_TELEM, mychannel);
04576       res = 0;
04577       switch(mytele->submode)
04578       {
04579           case 100: /* RX PL Off */
04580          sayfile(mychannel, "rpt/rxpl");
04581          sayfile(mychannel, "rpt/off");
04582          break;
04583           case 101: /* RX PL On */
04584          sayfile(mychannel, "rpt/rxpl");
04585          sayfile(mychannel, "rpt/on");
04586          break;
04587           case 102: /* TX PL Off */
04588          sayfile(mychannel, "rpt/txpl");
04589          sayfile(mychannel, "rpt/off");
04590          break;
04591           case 103: /* TX PL On */
04592          sayfile(mychannel, "rpt/txpl");
04593          sayfile(mychannel, "rpt/on");
04594          break;
04595           case 104: /* Low Power */
04596          sayfile(mychannel, "rpt/lopwr");
04597          break;
04598           case 105: /* Medium Power */
04599          sayfile(mychannel, "rpt/medpwr");
04600          break;
04601           case 106: /* Hi Power */
04602          sayfile(mychannel, "rpt/hipwr");
04603          break;
04604           case 113: /* Scan down slow */
04605          sayfile(mychannel,"rpt/down");
04606          sayfile(mychannel, "rpt/slow");
04607          break;
04608           case 114: /* Scan down quick */
04609          sayfile(mychannel,"rpt/down");
04610          sayfile(mychannel, "rpt/quick");
04611          break;
04612           case 115: /* Scan down fast */
04613          sayfile(mychannel,"rpt/down");
04614          sayfile(mychannel, "rpt/fast");
04615          break;
04616           case 116: /* Scan up slow */
04617          sayfile(mychannel,"rpt/up");
04618          sayfile(mychannel, "rpt/slow");
04619          break;
04620           case 117: /* Scan up quick */
04621          sayfile(mychannel,"rpt/up");
04622          sayfile(mychannel, "rpt/quick");
04623          break;
04624           case 118: /* Scan up fast */
04625          sayfile(mychannel,"rpt/up");
04626          sayfile(mychannel, "rpt/fast");
04627          break;
04628           default:
04629          res = -1;
04630       }
04631       wait_interval(myrpt, DLY_COMP, mychannel);
04632       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04633       break;
04634        case SCAN:
04635       ast_mutex_lock(&myrpt->remlock);
04636       if (myrpt->hfscanstop)
04637       {
04638          myrpt->hfscanstatus = 0;
04639          myrpt->hfscanmode = 0;
04640          myrpt->hfscanstop = 0;
04641          mytele->mode = SCANSTAT;
04642          ast_mutex_unlock(&myrpt->remlock);
04643          if (ast_safe_sleep(mychannel,1000) == -1) break;
04644          sayfile(mychannel, "rpt/stop"); 
04645          imdone = 1;
04646          break;
04647       }
04648       if (myrpt->hfscanstatus > -2) service_scan(myrpt);
04649       i = myrpt->hfscanstatus;
04650       myrpt->hfscanstatus = 0;
04651       if (i) mytele->mode = SCANSTAT;
04652       ast_mutex_unlock(&myrpt->remlock);
04653       if (i < 0) sayfile(mychannel, "rpt/stop"); 
04654       else if (i > 0) saynum(mychannel,i);
04655       imdone = 1;
04656       break;
04657        case TUNE:
04658       ast_mutex_lock(&myrpt->remlock);
04659       if (!strcmp(myrpt->remoterig,remote_rig_ic706))
04660       {
04661          set_mode_ic706(myrpt, REM_MODE_AM);
04662          if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
04663          ast_safe_sleep(mychannel,500);
04664          set_mode_ic706(myrpt, myrpt->remmode);
04665          myrpt->tunerequest = 0;
04666          ast_mutex_unlock(&myrpt->remlock);
04667          imdone = 1;
04668          break;
04669       }
04670       set_mode_ft897(myrpt, REM_MODE_AM);
04671       simple_command_ft897(myrpt, 8);
04672       if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
04673       simple_command_ft897(myrpt, 0x88);
04674       ast_safe_sleep(mychannel,500);
04675       set_mode_ft897(myrpt, myrpt->remmode);
04676       myrpt->tunerequest = 0;
04677       ast_mutex_unlock(&myrpt->remlock);
04678       imdone = 1;
04679       break;
04680        case REMSHORTSTATUS:
04681        case REMLONGSTATUS: 
04682       wait_interval(myrpt, DLY_TELEM, mychannel);
04683       res = saynode(myrpt,mychannel,myrpt->name);
04684       if(!res)
04685          res = sayfile(mychannel,"rpt/frequency");
04686       if(!res)
04687          res = split_freq(mhz, decimals, myrpt->freq);
04688       if (!multimode_capable(myrpt)) decimals[3] = 0;
04689       if(!res){
04690          m = atoi(mhz);
04691          if(m < 100)
04692             res = saynum(mychannel, m);
04693          else
04694             res = saycharstr(mychannel, mhz);
04695       }
04696       if(!res)
04697          res = sayfile(mychannel, "letters/dot");
04698       if(!res)
04699          res = saycharstr(mychannel, decimals);
04700    
04701       if(res)  break;
04702       if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
04703          switch(myrpt->offset){
04704    
04705             case REM_MINUS:
04706                res = sayfile(mychannel,"rpt/minus");
04707                break;
04708             
04709             case REM_SIMPLEX:
04710                res = sayfile(mychannel,"rpt/simplex");
04711                break;
04712                
04713             case REM_PLUS:
04714                res = sayfile(mychannel,"rpt/plus");
04715                break;
04716                
04717             default:
04718                break;
04719          }
04720       }
04721       else{ /* Must be USB, LSB, or AM */
04722          switch(myrpt->remmode){
04723 
04724             case REM_MODE_USB:
04725                res = saycharstr(mychannel, "USB");
04726                break;
04727 
04728             case REM_MODE_LSB:
04729                res = saycharstr(mychannel, "LSB");
04730                break;
04731 
04732             case REM_MODE_AM:
04733                res = saycharstr(mychannel, "AM");
04734                break;
04735 
04736 
04737             default:
04738                break;
04739          }
04740       }
04741 
04742       if (res == -1) break;
04743 
04744       if(mytele->mode == REMSHORTSTATUS){ /* Short status? */
04745          wait_interval(myrpt, DLY_COMP, mychannel);
04746          if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04747          break;
04748       }
04749 
04750       if (strcmp(myrpt->remoterig,remote_rig_ic706))
04751       {
04752          switch(myrpt->powerlevel){
04753 
04754             case REM_LOWPWR:
04755                res = sayfile(mychannel,"rpt/lopwr") ;
04756                break;
04757             case REM_MEDPWR:
04758                res = sayfile(mychannel,"rpt/medpwr");
04759                break;
04760             case REM_HIPWR:
04761                res = sayfile(mychannel,"rpt/hipwr"); 
04762                break;
04763             }
04764       }
04765 
04766       rbimode = ((!strncmp(myrpt->remoterig,remote_rig_rbi,3))
04767         || (!strncmp(myrpt->remoterig,remote_rig_ic706,3)));
04768       if (res || (sayfile(mychannel,"rpt/rxpl") == -1)) break;
04769       if (rbimode && (sayfile(mychannel,"rpt/txpl") == -1)) break;
04770       if ((sayfile(mychannel,"rpt/frequency") == -1) ||
04771          (saycharstr(mychannel,myrpt->rxpl) == -1)) break;
04772       if ((!rbimode) && ((sayfile(mychannel,"rpt/txpl") == -1) ||
04773          (sayfile(mychannel,"rpt/frequency") == -1) ||
04774          (saycharstr(mychannel,myrpt->txpl) == -1))) break;
04775       if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
04776          if ((sayfile(mychannel,"rpt/rxpl") == -1) ||
04777             (sayfile(mychannel,((myrpt->rxplon) ? "rpt/on" : "rpt/off")) == -1) ||
04778             (sayfile(mychannel,"rpt/txpl") == -1) ||
04779             (sayfile(mychannel,((myrpt->txplon) ? "rpt/on" : "rpt/off")) == -1))
04780             {
04781                break;
04782             }
04783       }
04784       wait_interval(myrpt, DLY_COMP, mychannel);
04785       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
04786       break;
04787        case STATUS:
04788       /* wait a little bit */
04789       wait_interval(myrpt, DLY_TELEM, mychannel);
04790       hastx = 0;
04791       linkbase.next = &linkbase;
04792       linkbase.prev = &linkbase;
04793       rpt_mutex_lock(&myrpt->lock);
04794       /* make our own list of links */
04795       l = myrpt->links.next;
04796       while(l != &myrpt->links)
04797       {
04798          if (l->name[0] == '0')
04799          {
04800             l = l->next;
04801             continue;
04802          }
04803          l1 = ast_malloc(sizeof(struct rpt_link));
04804          if (!l1)
04805          {
04806             ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
04807             remque((struct qelem *)mytele);
04808             myrpt->active_telem = NULL;
04809             rpt_mutex_unlock(&myrpt->lock);
04810             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
04811             ast_free(nodename);
04812             ast_free(ident);
04813             ast_free(mytele);    
04814             ast_hangup(mychannel);
04815             pthread_exit(NULL);
04816          }
04817          memcpy(l1,l,sizeof(struct rpt_link));
04818          l1->next = l1->prev = NULL;
04819          insque((struct qelem *)l1,(struct qelem *)linkbase.next);
04820          l = l->next;
04821       }
04822       rpt_mutex_unlock(&myrpt->lock);
04823       res = saynode(myrpt,mychannel,myrpt->name);
04824       if (myrpt->callmode)
04825       {
04826          hastx = 1;
04827          res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
04828          if (!res) 
04829             res = ast_waitstream(mychannel, "");
04830          else
04831              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04832          ast_stopstream(mychannel);
04833       }
04834       l = linkbase.next;
04835       while(l != &linkbase)
04836       {
04837          char *s;
04838 
04839          hastx = 1;
04840          res = saynode(myrpt,mychannel,l->name);
04841          s = "rpt/tranceive";
04842          if (!l->mode) s = "rpt/monitor";
04843          if (!l->thisconnected) s = "rpt/connecting";
04844          res = ast_streamfile(mychannel, s, mychannel->language);
04845          if (!res) 
04846             res = ast_waitstream(mychannel, "");
04847          else
04848             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04849          ast_stopstream(mychannel);
04850          l = l->next;
04851       }        
04852       if (!hastx)
04853       {
04854          res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
04855          if (!res) 
04856             res = ast_waitstream(mychannel, "");
04857          else
04858              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04859          ast_stopstream(mychannel);
04860       }
04861       /* destroy our local link queue */
04862       l = linkbase.next;
04863       while(l != &linkbase)
04864       {
04865          l1 = l;
04866          l = l->next;
04867          remque((struct qelem *)l1);
04868          ast_free(l1);
04869       }        
04870       imdone = 1;
04871       break;
04872        case FULLSTATUS:
04873       rpt_mutex_lock(&myrpt->lock);
04874       /* get all the nodes */
04875       __mklinklist(myrpt,NULL,lbuf);
04876       rpt_mutex_unlock(&myrpt->lock);
04877       /* parse em */
04878       ns = finddelim(lbuf,strs,MAXLINKLIST);
04879       /* sort em */
04880       if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
04881       /* wait a little bit */
04882       wait_interval(myrpt, DLY_TELEM, mychannel);
04883       hastx = 0;
04884       res = saynode(myrpt,mychannel,myrpt->name);
04885       if (myrpt->callmode)
04886       {
04887          hastx = 1;
04888          res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
04889          if (!res) 
04890             res = ast_waitstream(mychannel, "");
04891          else
04892              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04893          ast_stopstream(mychannel);
04894       }
04895       /* go thru all the nodes in list */
04896       for(i = 0; i < ns; i++)
04897       {
04898          char *s,mode = 'T';
04899 
04900          /* if a mode spec at first, handle it */
04901          if ((*strs[i] < '0') || (*strs[i] > '9'))
04902          {
04903             mode = *strs[i];
04904             strs[i]++;
04905          }
04906 
04907          hastx = 1;
04908          res = saynode(myrpt,mychannel,strs[i]);
04909          s = "rpt/tranceive";
04910          if (mode == 'R') s = "rpt/monitor";
04911          if (mode == 'C') s = "rpt/connecting";
04912          res = ast_streamfile(mychannel, s, mychannel->language);
04913          if (!res) 
04914             res = ast_waitstream(mychannel, "");
04915          else
04916             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04917          ast_stopstream(mychannel);
04918       }        
04919       if (!hastx)
04920       {
04921          res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
04922          if (!res) 
04923             res = ast_waitstream(mychannel, "");
04924          else
04925              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04926          ast_stopstream(mychannel);
04927       }
04928       imdone = 1;
04929       break;
04930 
04931        case LASTNODEKEY: /* Identify last node which keyed us up */
04932       rpt_mutex_lock(&myrpt->lock);
04933       if(myrpt->lastnodewhichkeyedusup){
04934          p = ast_strdup(myrpt->lastnodewhichkeyedusup); /* Make a local copy of the node name */
04935          if(!p){
04936             ast_log(LOG_WARNING, "ast_strdup failed in telemetery LASTNODEKEY");
04937             imdone = 1;
04938             break;
04939          }
04940       }
04941       else
04942          p = NULL;
04943       rpt_mutex_unlock(&myrpt->lock);
04944       if(!p){
04945          imdone = 1; /* no node previously keyed us up, or the node which did has been disconnected */
04946          break;
04947       }
04948       wait_interval(myrpt, DLY_TELEM, mychannel);
04949       res = saynode(myrpt,mychannel,p);
04950       ast_free(p);
04951       imdone = 1;
04952       break;      
04953 
04954        case UNAUTHTX: /* Say unauthorized transmit frequency */
04955       wait_interval(myrpt, DLY_TELEM, mychannel);
04956       res = ast_streamfile(mychannel, "rpt/unauthtx", mychannel->language);
04957       if (!res) 
04958          res = ast_waitstream(mychannel, "");
04959       else
04960           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04961       ast_stopstream(mychannel);
04962       imdone = 1;
04963       break;
04964 
04965        case PARROT: /* Repeat stuff */
04966 
04967       sprintf(mystr,PARROTFILE,myrpt->name,(unsigned int)mytele->parrot);
04968       if (ast_fileexists(mystr,NULL,mychannel->language) <= 0)
04969       {
04970          imdone = 1;
04971          myrpt->parrotstate = 0;
04972          break;
04973       }
04974       wait_interval(myrpt, DLY_PARROT, mychannel);
04975       sprintf(mystr,PARROTFILE,myrpt->name,(unsigned int)mytele->parrot);
04976       res = ast_streamfile(mychannel, mystr, mychannel->language);
04977       if (!res) 
04978          res = ast_waitstream(mychannel, "");
04979       else
04980           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04981       ast_stopstream(mychannel);
04982       sprintf(mystr,PARROTFILE,myrpt->name,(unsigned int)mytele->parrot);
04983       strcat(mystr,".wav");
04984       unlink(mystr);       
04985       imdone = 1;
04986       myrpt->parrotstate = 0;
04987       break;
04988 
04989        case TIMEOUT:
04990       res = saynode(myrpt,mychannel,myrpt->name);
04991       if (!res)
04992          res = ast_streamfile(mychannel, "rpt/timeout", mychannel->language);
04993       break;
04994       
04995        case TIMEOUT_WARNING:
04996       time(&t);
04997       res = saynode(myrpt,mychannel,myrpt->name);
04998       if (!res)
04999          res = ast_streamfile(mychannel, "rpt/timeout-warning", mychannel->language);
05000       if (!res) 
05001          res = ast_waitstream(mychannel, "");
05002       else
05003           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
05004       ast_stopstream(mychannel);
05005       if(!res) /* Say number of seconds */
05006          ast_say_number(mychannel, myrpt->p.remotetimeout - 
05007              (t - myrpt->last_activity_time), 
05008             "", mychannel->language, (char *) NULL);
05009       if (!res) 
05010          res = ast_waitstream(mychannel, "");
05011       ast_stopstream(mychannel); 
05012       res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
05013       break;
05014 
05015        case ACT_TIMEOUT_WARNING:
05016       time(&t);
05017       res = saynode(myrpt,mychannel,myrpt->name);
05018       if (!res)
05019           res = ast_streamfile(mychannel, "rpt/act-timeout-warning", mychannel->language);
05020       if (!res) 
05021          res = ast_waitstream(mychannel, "");
05022       else
05023           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
05024       ast_stopstream(mychannel);
05025       if(!res) /* Say number of seconds */
05026          ast_say_number(mychannel, myrpt->p.remoteinacttimeout - 
05027              (t - myrpt->last_activity_time), 
05028             "", mychannel->language, (char *) NULL);
05029       if (!res) 
05030          res = ast_waitstream(mychannel, "");
05031       ast_stopstream(mychannel); 
05032       res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
05033       break;
05034       
05035        case STATS_TIME:
05036             case STATS_TIME_LOCAL:
05037          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05038       t = time(NULL);
05039       rpt_localtime(&t, &localtm);
05040       /* Say the phase of the day is before the time */
05041       if((localtm.tm_hour >= 0) && (localtm.tm_hour < 12))
05042          p = "rpt/goodmorning";
05043       else if((localtm.tm_hour >= 12) && (localtm.tm_hour < 18))
05044          p = "rpt/goodafternoon";
05045       else
05046          p = "rpt/goodevening";
05047       if (sayfile(mychannel,p) == -1)
05048       {
05049          imdone = 1;
05050          break;
05051       }
05052       /* Say the time is ... */     
05053       if (sayfile(mychannel,"rpt/thetimeis") == -1)
05054       {
05055          imdone = 1;
05056          break;
05057       }
05058       /* Say the time */            
05059          res = ast_say_time(mychannel, t, "", mychannel->language);
05060       if (!res) 
05061          res = ast_waitstream(mychannel, "");
05062       ast_stopstream(mychannel);    
05063       imdone = 1;
05064          break;
05065        case STATS_VERSION:
05066       p = strstr(tdesc, "version"); 
05067       if(!p)
05068          break;   
05069       if(sscanf(p, "version %30d.%30d", &vmajor, &vminor) != 2)
05070          break;
05071          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05072       /* Say "version" */
05073       if (sayfile(mychannel,"rpt/version") == -1)
05074       {
05075          imdone = 1;
05076          break;
05077       }
05078       if(!res) /* Say "X" */
05079          ast_say_number(mychannel, vmajor, "", mychannel->language, (char *) NULL);
05080       if (!res) 
05081          res = ast_waitstream(mychannel, "");
05082       ast_stopstream(mychannel); 
05083       if (saycharstr(mychannel,".") == -1)
05084       {
05085          imdone = 1;
05086          break;
05087       }
05088       if(!res) /* Say "Y" */
05089          ast_say_number(mychannel, vminor, "", mychannel->language, (char *) NULL);
05090       if (!res){
05091          res = ast_waitstream(mychannel, "");
05092          ast_stopstream(mychannel);
05093       }  
05094       else
05095           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
05096       imdone = 1;
05097          break;
05098        case ARB_ALPHA:
05099          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05100          if(mytele->param)
05101             saycharstr(mychannel, mytele->param);
05102          imdone = 1;
05103       break;
05104        case REV_PATCH:
05105          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
05106          if(mytele->param) {
05107 
05108          /* Parts of this section taken from app_parkandannounce */
05109          char *tpl_working, *tpl_current;
05110          char *tmp[100], *myparm;
05111          int looptemp=0,idx=0, dres = 0;
05112    
05113 
05114          tpl_working = ast_strdup(mytele->param);
05115          myparm = strsep(&tpl_working,",");
05116          tpl_current=strsep(&tpl_working, ":");
05117 
05118          while(tpl_current && looptemp < sizeof(tmp)) {
05119             tmp[looptemp]=tpl_current;
05120             looptemp++;
05121             tpl_current=strsep(&tpl_working,":");
05122          }
05123 
05124          for(idx=0; idx<looptemp; idx++) {
05125             if(!strcmp(tmp[idx], "PARKED")) {
05126                ast_say_digits(mychannel, atoi(myparm), "", mychannel->language);
05127             } else if(!strcmp(tmp[idx], "NODE")) {
05128                ast_say_digits(mychannel, atoi(myrpt->name), "", mychannel->language);
05129             } else {
05130                dres = ast_streamfile(mychannel, tmp[idx], mychannel->language);
05131                if(!dres) {
05132                   dres = ast_waitstream(mychannel, "");
05133                } else {
05134                   ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[idx], mychannel->name);
05135                   dres = 0;
05136                }
05137             }
05138          }
05139          ast_free(tpl_working);
05140       }
05141          imdone = 1;
05142       break;
05143        case TEST_TONE:
05144       imdone = 1;
05145       if (myrpt->stopgen) break;
05146       myrpt->stopgen = -1;
05147            if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0))) 
05148       {
05149          myrpt->stopgen = 0;
05150          break;
05151       }
05152            while(mychannel->generatordata && (myrpt->stopgen <= 0)) {
05153          if (ast_safe_sleep(mychannel,1)) break;
05154             imdone = 1;
05155          }
05156       myrpt->stopgen = 0;
05157       break;
05158        default:
05159          break;
05160    }
05161    if (!imdone)
05162    {
05163       if (!res) 
05164          res = ast_waitstream(mychannel, "");
05165       else {
05166          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
05167          res = 0;
05168       }
05169    }
05170    ast_stopstream(mychannel);
05171    rpt_mutex_lock(&myrpt->lock);
05172    if (mytele->mode == TAILMSG)
05173    {
05174       if (!res)
05175       {
05176          myrpt->tailmessagen++;
05177          if(myrpt->tailmessagen >= myrpt->p.tailmessagemax) myrpt->tailmessagen = 0;
05178       }
05179       else
05180       {
05181          myrpt->tmsgtimer = myrpt->p.tailsquashedtime;
05182       }
05183    }
05184    remque((struct qelem *)mytele);
05185    myrpt->active_telem = NULL;
05186    rpt_mutex_unlock(&myrpt->lock);
05187    ast_free(nodename);
05188    ast_free(ident);
05189    ast_free(mytele);    
05190    ast_hangup(mychannel);
05191 #ifdef  APP_RPT_LOCK_DEBUG
05192    {
05193       struct lockthread *t;
05194 
05195       sleep(5);
05196       ast_mutex_lock(&locklock);
05197       t = get_lockthread(pthread_self());
05198       if (t) memset(t,0,sizeof(struct lockthread));
05199       ast_mutex_unlock(&locklock);
05200    }        
05201 #endif
05202    pthread_exit(NULL);
05203 }
05204 
05205 static void rpt_telemetry(struct rpt *myrpt,int mode, void *data)
05206 {
05207 struct rpt_tele *tele;
05208 struct rpt_link *mylink = NULL;
05209 int res;
05210 pthread_attr_t attr;
05211 char *v1, *v2;
05212 
05213    if(debug > 6)
05214       ast_log(LOG_NOTICE,"mode=%i  data=%s\n",mode, (char *)data);
05215 
05216    switch(mode)
05217    {
05218        case UNKEY:
05219       /* if any of the following are defined, go ahead and do it,
05220          otherwise, dont bother */
05221       v1 = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, 
05222          "unlinkedct");
05223       v2 = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, 
05224          "remotect");
05225       if (telem_lookup(myrpt,NULL, myrpt->name, "remotemon") &&
05226         telem_lookup(myrpt,NULL, myrpt->name, "remotetx") &&
05227         telem_lookup(myrpt,NULL, myrpt->name, "cmdmode") &&
05228         (!(v1 && telem_lookup(myrpt,NULL, myrpt->name, v1))) && 
05229         (!(v2 && telem_lookup(myrpt,NULL, myrpt->name, v2)))) return;
05230       break;
05231        case LINKUNKEY:
05232       if (!ast_variable_retrieve(myrpt->cfg, myrpt->name, "linkunkeyct"))
05233          return;
05234       break;
05235        default:
05236       break;
05237    }
05238    tele = ast_malloc(sizeof(struct rpt_tele));
05239    if (!tele)
05240    {
05241       ast_log(LOG_WARNING, "Unable to allocate memory\n");
05242       pthread_exit(NULL);
05243       return;
05244    }
05245    /* zero it out */
05246    memset((char *)tele,0,sizeof(struct rpt_tele));
05247    tele->rpt = myrpt;
05248    tele->mode = mode;
05249    if (mode == PARROT) tele->parrot = (uintptr_t) data;
05250    else mylink = (struct rpt_link *) data;
05251    rpt_mutex_lock(&myrpt->lock);
05252    if((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED) ||
05253        (mode == LINKUNKEY)){
05254       memset(&tele->mylink,0,sizeof(struct rpt_link));
05255       if (mylink){
05256          memcpy(&tele->mylink,mylink,sizeof(struct rpt_link));
05257       }
05258    }
05259    else if ((mode == ARB_ALPHA) || (mode == REV_PATCH) || (mode == PLAYBACK)) {
05260       strncpy(tele->param, (char *) data, TELEPARAMSIZE - 1);
05261       tele->param[TELEPARAMSIZE - 1] = 0;
05262    }
05263    if (mode == REMXXX) tele->submode = (intptr_t) data;
05264    insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next);
05265    rpt_mutex_unlock(&myrpt->lock);
05266         pthread_attr_init(&attr);
05267         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05268    res = ast_pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
05269    if(res < 0){
05270       rpt_mutex_lock(&myrpt->lock);
05271       remque((struct qlem *) tele); /* We don't like stuck transmitters, remove it from the queue */
05272       rpt_mutex_unlock(&myrpt->lock);  
05273       ast_log(LOG_WARNING, "Could not create telemetry thread: %s",strerror(res));
05274    }
05275    return;
05276 }
05277 
05278 static void *rpt_call(void *this)
05279 {
05280 struct dahdi_confinfo ci;  /* conference info */
05281 struct   rpt *myrpt = (struct rpt *)this;
05282 int   res;
05283 int stopped,congstarted,dialtimer,lastcidx,aborted;
05284 struct ast_channel *mychannel,*genchannel;
05285 
05286    myrpt->mydtmf = 0;
05287    /* allocate a pseudo-channel thru asterisk */
05288    mychannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
05289    if (!mychannel)
05290    {
05291       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
05292       pthread_exit(NULL);
05293    }
05294 #ifdef   AST_CDR_FLAG_POST_DISABLED
05295    if (mychannel->cdr)
05296       ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
05297 #endif
05298    ci.chan = 0;
05299    ci.confno = myrpt->conf; /* use the pseudo conference */
05300 #if   0
05301    ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
05302       | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER; 
05303 #endif
05304    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
05305    /* first put the channel on the conference */
05306    if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05307    {
05308       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05309       ast_hangup(mychannel);
05310       myrpt->callmode = 0;
05311       pthread_exit(NULL);
05312    }
05313    /* allocate a pseudo-channel thru asterisk */
05314    genchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
05315    if (!genchannel)
05316    {
05317       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
05318       ast_hangup(mychannel);
05319       pthread_exit(NULL);
05320    }
05321 #ifdef   AST_CDR_FLAG_POST_DISABLED
05322    if (genchannel->cdr)
05323       ast_set_flag(genchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
05324 #endif
05325    ci.chan = 0;
05326    ci.confno = myrpt->conf;
05327    ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
05328       | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER; 
05329    /* first put the channel on the conference */
05330    if (ioctl(genchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05331    {
05332       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05333       ast_hangup(mychannel);
05334       ast_hangup(genchannel);
05335       myrpt->callmode = 0;
05336       pthread_exit(NULL);
05337    }
05338    if (myrpt->p.tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->p.tonezone) == -1))
05339    {
05340       ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
05341       ast_hangup(mychannel);
05342       ast_hangup(genchannel);
05343       myrpt->callmode = 0;
05344       pthread_exit(NULL);
05345    }
05346    if (myrpt->p.tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->p.tonezone) == -1))
05347    {
05348       ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
05349       ast_hangup(mychannel);
05350       ast_hangup(genchannel);
05351       myrpt->callmode = 0;
05352       pthread_exit(NULL);
05353    }
05354    /* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
05355    if ((!myrpt->patchquiet) && (tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_DIALTONE) < 0))
05356    {
05357       ast_log(LOG_WARNING, "Cannot start dialtone\n");
05358       ast_hangup(mychannel);
05359       ast_hangup(genchannel);
05360       myrpt->callmode = 0;
05361       pthread_exit(NULL);
05362    }
05363    stopped = 0;
05364    congstarted = 0;
05365    dialtimer = 0;
05366    lastcidx = 0;
05367    myrpt->calldigittimer = 0;
05368    aborted = 0;
05369 
05370    while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
05371    {
05372       if((myrpt->patchdialtime)&&(myrpt->callmode == 1)&&(myrpt->cidx != lastcidx)){
05373          dialtimer = 0;
05374          lastcidx = myrpt->cidx;
05375       }     
05376 
05377       if((myrpt->patchdialtime)&&(dialtimer >= myrpt->patchdialtime)){ 
05378           if(debug)
05379             ast_log(LOG_NOTICE, "dialtimer %i > patchdialtime %i\n", dialtimer,myrpt->patchdialtime);
05380          rpt_mutex_lock(&myrpt->lock);
05381          aborted = 1;
05382          myrpt->callmode = 0;
05383          rpt_mutex_unlock(&myrpt->lock);
05384          break;
05385       }
05386    
05387       if ((!myrpt->patchquiet) && (!stopped) && (myrpt->callmode == 1) && (myrpt->cidx > 0))
05388       {
05389          stopped = 1;
05390          /* stop dial tone */
05391          tone_zone_play_tone(genchannel->fds[0],-1);
05392       }
05393       if (myrpt->callmode == 1)
05394       {
05395          if(myrpt->calldigittimer > PATCH_DIALPLAN_TIMEOUT)
05396          {
05397             myrpt->callmode = 2;
05398             break;
05399          }
05400          /* bump timer if active */
05401          if (myrpt->calldigittimer) 
05402             myrpt->calldigittimer += MSWAIT;
05403       }
05404       if (myrpt->callmode == 4)
05405       {
05406          if(!congstarted){
05407             congstarted = 1;
05408             /* start congestion tone */
05409             tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_CONGESTION);
05410          }
05411       }
05412       res = ast_safe_sleep(mychannel, MSWAIT);
05413       if (res < 0)
05414       {
05415           if(debug)
05416             ast_log(LOG_NOTICE, "ast_safe_sleep=%i\n", res);
05417          ast_hangup(mychannel);
05418          ast_hangup(genchannel);
05419          rpt_mutex_lock(&myrpt->lock);
05420          myrpt->callmode = 0;
05421          rpt_mutex_unlock(&myrpt->lock);
05422          pthread_exit(NULL);
05423       }
05424       dialtimer += MSWAIT;
05425    }
05426    /* stop any tone generation */
05427    tone_zone_play_tone(genchannel->fds[0],-1);
05428    /* end if done */
05429    if (!myrpt->callmode)
05430    {
05431       if(debug)
05432          ast_log(LOG_NOTICE, "callmode==0\n");
05433       ast_hangup(mychannel);
05434       ast_hangup(genchannel);
05435       rpt_mutex_lock(&myrpt->lock);
05436       myrpt->callmode = 0;
05437       myrpt->macropatch=0;
05438       channel_revert(myrpt);
05439       rpt_mutex_unlock(&myrpt->lock);
05440       if((!myrpt->patchquiet) && aborted)
05441          rpt_telemetry(myrpt, TERM, NULL);
05442       pthread_exit(NULL);        
05443    }
05444 
05445    if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid){
05446       char *name, *loc, *instr;
05447       instr = ast_strdup(myrpt->p.ourcallerid);
05448       if(instr){
05449          ast_callerid_parse(instr, &name, &loc);
05450          if(loc){
05451             if(mychannel->cid.cid_num)
05452                ast_free(mychannel->cid.cid_num);
05453             mychannel->cid.cid_num = ast_strdup(loc);
05454          }
05455          if(name){
05456             if(mychannel->cid.cid_name)
05457                ast_free(mychannel->cid.cid_name);
05458             mychannel->cid.cid_name = ast_strdup(name);
05459          }
05460          ast_free(instr);
05461       }
05462    }
05463 
05464    ast_copy_string(mychannel->exten, myrpt->exten, sizeof(mychannel->exten) - 1);
05465    ast_copy_string(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context) - 1);
05466    
05467    if (myrpt->p.acctcode)
05468       ast_cdr_setaccount(mychannel,myrpt->p.acctcode);
05469    mychannel->priority = 1;
05470    ast_channel_undefer_dtmf(mychannel);
05471    if (ast_pbx_start(mychannel) < 0)
05472    {
05473       ast_log(LOG_WARNING, "Unable to start PBX!!\n");
05474       ast_hangup(mychannel);
05475       ast_hangup(genchannel);
05476       rpt_mutex_lock(&myrpt->lock);
05477       myrpt->callmode = 0;
05478       rpt_mutex_unlock(&myrpt->lock);
05479       pthread_exit(NULL);
05480    }
05481    usleep(10000);
05482    rpt_mutex_lock(&myrpt->lock);
05483    myrpt->callmode = 3;
05484    /* set appropriate conference for the pseudo */
05485    ci.chan = 0;
05486    ci.confno = myrpt->conf;
05487    ci.confmode = (myrpt->p.duplex == 2) ? DAHDI_CONF_CONFANNMON :
05488       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
05489    /* first put the channel on the conference in announce mode */
05490    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05491    {
05492       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05493       ast_hangup(mychannel);
05494       ast_hangup(genchannel);
05495       myrpt->callmode = 0;
05496       pthread_exit(NULL);
05497    }
05498    /* get its channel number */
05499    if (ioctl(mychannel->fds[0],DAHDI_CHANNO,&res) == -1)
05500    {
05501       ast_log(LOG_WARNING, "Unable to get autopatch channel number\n");
05502       ast_hangup(mychannel);
05503       myrpt->callmode = 0;
05504       pthread_exit(NULL);
05505    }
05506    ci.chan = 0;
05507    ci.confno = res;
05508    ci.confmode = DAHDI_CONF_MONITOR;
05509    /* put vox channel monitoring on the channel  */
05510    if (ioctl(myrpt->voxchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05511    {
05512       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05513       ast_hangup(mychannel);
05514       myrpt->callmode = 0;
05515       pthread_exit(NULL);
05516    }
05517    while(myrpt->callmode)
05518    {
05519       if ((!mychannel->pbx) && (myrpt->callmode != 4))
05520       {
05521           /* If patch is setup for far end disconnect */
05522          if(myrpt->patchfarenddisconnect || (myrpt->p.duplex < 2)){ 
05523             if(debug)ast_log(LOG_NOTICE,"callmode=%i, patchfarenddisconnect=%i, duplex=%i\n",\
05524                   myrpt->callmode,myrpt->patchfarenddisconnect,myrpt->p.duplex);
05525             myrpt->callmode = 0;
05526             myrpt->macropatch=0;
05527             if(!myrpt->patchquiet){
05528                rpt_mutex_unlock(&myrpt->lock);
05529                rpt_telemetry(myrpt, TERM, NULL);
05530                rpt_mutex_lock(&myrpt->lock);
05531             }
05532          }
05533          else{ /* Send congestion until patch is downed by command */
05534             myrpt->callmode = 4;
05535             rpt_mutex_unlock(&myrpt->lock);
05536             /* start congestion tone */
05537             tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_CONGESTION);
05538             rpt_mutex_lock(&myrpt->lock);
05539          }
05540       }
05541       if (myrpt->mydtmf)
05542       {
05543          struct ast_frame wf = {AST_FRAME_DTMF, } ;
05544          wf.subclass = myrpt->mydtmf;
05545          rpt_mutex_unlock(&myrpt->lock);
05546          ast_queue_frame(mychannel,&wf);
05547 #ifdef   NEW_ASTERISK
05548          ast_senddigit(genchannel,myrpt->mydtmf,0);
05549 #else
05550          ast_senddigit(genchannel,myrpt->mydtmf);
05551 #endif
05552          rpt_mutex_lock(&myrpt->lock);
05553          myrpt->mydtmf = 0;
05554       }
05555       rpt_mutex_unlock(&myrpt->lock);
05556       usleep(MSWAIT * 1000);
05557       rpt_mutex_lock(&myrpt->lock);
05558    }
05559    if(debug)
05560       ast_log(LOG_NOTICE, "exit channel loop\n");
05561    rpt_mutex_unlock(&myrpt->lock);
05562    tone_zone_play_tone(genchannel->fds[0],-1);
05563    if (mychannel->pbx) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV);
05564    ast_hangup(genchannel);
05565    rpt_mutex_lock(&myrpt->lock);
05566    myrpt->callmode = 0;
05567    myrpt->macropatch=0;
05568    channel_revert(myrpt);
05569    rpt_mutex_unlock(&myrpt->lock);
05570    /* set appropriate conference for the pseudo */
05571    ci.chan = 0;
05572    ci.confno = myrpt->conf;
05573    ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
05574       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
05575    /* first put the channel on the conference in announce mode */
05576    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
05577    {
05578       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05579    }
05580    pthread_exit(NULL);
05581 }
05582 
05583 static void send_link_dtmf(struct rpt *myrpt,char c)
05584 {
05585 char  str[300];
05586 struct   ast_frame wf;
05587 struct   rpt_link *l;
05588 
05589    snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c);
05590    wf.frametype = AST_FRAME_TEXT;
05591    wf.subclass = 0;
05592    wf.offset = 0;
05593    wf.mallocd = 0;
05594    wf.datalen = strlen(str) + 1;
05595    wf.samples = 0;
05596    l = myrpt->links.next;
05597    /* first, see if our dude is there */
05598    while(l != &myrpt->links)
05599    {
05600       if (l->name[0] == '0') 
05601       {
05602          l = l->next;
05603          continue;
05604       }
05605       /* if we found it, write it and were done */
05606       if (!strcmp(l->name,myrpt->cmdnode))
05607       {
05608          wf.data.ptr = str;
05609          if (l->chan) ast_write(l->chan,&wf);
05610          return;
05611       }
05612       l = l->next;
05613    }
05614    l = myrpt->links.next;
05615    /* if not, give it to everyone */
05616    while(l != &myrpt->links)
05617    {
05618       wf.data.ptr = str;
05619       if (l->chan) ast_write(l->chan,&wf);
05620       l = l->next;
05621    }
05622    return;
05623 }
05624 
05625 static void send_link_keyquery(struct rpt *myrpt)
05626 {
05627 char  str[300];
05628 struct   ast_frame wf;
05629 struct   rpt_link *l;
05630 
05631    rpt_mutex_lock(&myrpt->lock);
05632    memset(myrpt->topkey,0,sizeof(myrpt->topkey));
05633    myrpt->topkeystate = 1;
05634    time(&myrpt->topkeytime);
05635    rpt_mutex_unlock(&myrpt->lock);
05636    snprintf(str, sizeof(str), "K? * %s 0 0", myrpt->name);
05637    wf.frametype = AST_FRAME_TEXT;
05638    wf.subclass = 0;
05639    wf.offset = 0;
05640    wf.mallocd = 0;
05641    wf.datalen = strlen(str) + 1;
05642    wf.samples = 0;
05643    l = myrpt->links.next;
05644    /* give it to everyone */
05645    while(l != &myrpt->links)
05646    {
05647       wf.data.ptr = str;
05648       if (l->chan) ast_write(l->chan,&wf);
05649       l = l->next;
05650    }
05651    return;
05652 }
05653 
05654 /* send newkey request */
05655 
05656 static void send_newkey(struct ast_channel *chan)
05657 {
05658 
05659    /* ast_safe_sleep(chan,10); */
05660    ast_sendtext(chan,newkeystr);
05661    return;
05662 }
05663 
05664 
05665 /* 
05666  * Connect a link 
05667  *
05668  * Return values:
05669  * -2: Attempt to connect to self 
05670  * -1: No such node
05671  *  0: Success
05672  *  1: No match yet
05673  *  2: Already connected to this node
05674  */
05675 
05676 static int connect_link(struct rpt *myrpt, char* node, int mode, int perma)
05677 {
05678    char *val, *s, *s1, *s2, *tele;
05679    char lstr[MAXLINKLIST],*strs[MAXLINKLIST];
05680    char tmp[300], deststr[300] = "",modechange = 0;
05681    char sx[320],*sy;
05682    struct rpt_link *l;
05683    int reconnects = 0;
05684    int i,n;
05685    struct dahdi_confinfo ci;  /* conference info */
05686 
05687    val = node_lookup(myrpt,node);
05688    if (!val){
05689       if(strlen(node) >= myrpt->longestnode)
05690          return -1; /* No such node */
05691       return 1; /* No match yet */
05692    }
05693 
05694    if(!strcmp(myrpt->name,node)) /* Do not allow connections to self */
05695       return -2;
05696       
05697    if(debug > 3){
05698       ast_log(LOG_NOTICE,"Connect attempt to node %s\n", node);
05699       ast_log(LOG_NOTICE,"Mode: %s\n",(mode)?"Transceive":"Monitor");
05700       ast_log(LOG_NOTICE,"Connection type: %s\n",(perma)?"Permalink":"Normal");
05701    }
05702 
05703    strncpy(tmp,val,sizeof(tmp) - 1);
05704    s = tmp;
05705    s1 = strsep(&s,",");
05706    if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
05707    {
05708       sy = strchr(s1,'/');    
05709       *sy = 0;
05710       sprintf(sx,"%s:4569/%s",s1,sy + 1);
05711       s1 = sx;
05712    }
05713    s2 = strsep(&s,",");
05714    rpt_mutex_lock(&myrpt->lock);
05715    l = myrpt->links.next;
05716    /* try to find this one in queue */
05717    while(l != &myrpt->links){
05718       if (l->name[0] == '0') 
05719       {
05720          l = l->next;
05721          continue;
05722       }
05723    /* if found matching string */
05724       if (!strcmp(l->name, node))
05725          break;
05726       l = l->next;
05727    }
05728    /* if found */
05729    if (l != &myrpt->links){ 
05730    /* if already in this mode, just ignore */
05731       if ((l->mode) || (!l->chan)) {
05732          rpt_mutex_unlock(&myrpt->lock);
05733          return 2; /* Already linked */
05734       }
05735       reconnects = l->reconnects;
05736       rpt_mutex_unlock(&myrpt->lock);
05737       if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
05738       l->retries = l->max_retries + 1;
05739       l->disced = 2;
05740       modechange = 1;
05741    } else
05742    {
05743       __mklinklist(myrpt,NULL,lstr);
05744       rpt_mutex_unlock(&myrpt->lock);
05745       n = finddelim(lstr,strs,MAXLINKLIST);
05746       for(i = 0; i < n; i++)
05747       {
05748          if ((*strs[i] < '0') || 
05749              (*strs[i] > '9')) strs[i]++;
05750          if (!strcmp(strs[i],node))
05751          {
05752             return 2; /* Already linked */
05753          }
05754       }
05755    }
05756    strncpy(myrpt->lastlinknode,node,MAXNODESTR - 1);
05757    /* establish call */
05758    l = ast_malloc(sizeof(struct rpt_link));
05759    if (!l)
05760    {
05761       ast_log(LOG_WARNING, "Unable to malloc\n");
05762       return -1;
05763    }
05764    /* zero the silly thing */
05765    memset((char *)l,0,sizeof(struct rpt_link));
05766    l->mode = mode;
05767    l->outbound = 1;
05768    l->thisconnected = 0;
05769    voxinit_link(l,1);
05770    strncpy(l->name, node, MAXNODESTR - 1);
05771    l->isremote = (s && ast_true(s));
05772    if (modechange) l->connected = 1;
05773    l->hasconnected = l->perma = perma;
05774 #ifdef ALLOW_LOCAL_CHANNELS
05775    if ((strncasecmp(s1,"iax2/", 5) == 0) || (strncasecmp(s1, "local/", 6) == 0))
05776          strncpy(deststr, s1, sizeof(deststr));
05777    else
05778            snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
05779 #else
05780    snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
05781 #endif
05782    tele = strchr(deststr, '/');
05783    if (!tele){
05784       ast_log(LOG_WARNING,"link3:Dial number (%s) must be in format tech/number\n",deststr);
05785       ast_free(l);
05786       return -1;
05787    }
05788    *tele++ = 0;
05789    l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
05790    if (l->chan){
05791       ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
05792       ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
05793 #ifdef   AST_CDR_FLAG_POST_DISABLED
05794       if (l->chan->cdr)
05795          ast_set_flag(l->chan->cdr,AST_CDR_FLAG_POST_DISABLED);
05796 #endif
05797 #ifndef  NEW_ASTERISK
05798       l->chan->whentohangup = 0;
05799 #endif
05800       l->chan->appl = "Apprpt";
05801       l->chan->data = "(Remote Rx)";
05802       if (debug > 3)
05803          ast_log(LOG_NOTICE, "rpt (remote) initiating call to %s/%s on %s\n",
05804       deststr, tele, l->chan->name);
05805       if(l->chan->cid.cid_num)
05806          ast_free(l->chan->cid.cid_num);
05807       l->chan->cid.cid_num = ast_strdup(myrpt->name);
05808       ast_call(l->chan,tele,999);
05809    }
05810    else {
05811       if(debug > 3) 
05812          ast_log(LOG_NOTICE, "Unable to place call to %s/%s on %s\n",
05813       deststr,tele,l->chan->name);
05814       if (myrpt->p.archivedir)
05815       {
05816          char str[100];
05817          sprintf(str,"LINKFAIL,%s",l->name);
05818          donodelog(myrpt,str);
05819       }
05820       ast_free(l);
05821       return -1;
05822    }
05823    /* allocate a pseudo-channel thru asterisk */
05824    l->pchan = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
05825    if (!l->pchan){
05826       ast_log(LOG_WARNING,"rpt connect: Sorry unable to obtain pseudo channel\n");
05827       ast_hangup(l->chan);
05828       ast_free(l);
05829       return -1;
05830    }
05831    ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
05832    ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
05833 #ifdef   AST_CDR_FLAG_POST_DISABLED
05834    if (l->pchan->cdr)
05835       ast_set_flag(l->pchan->cdr,AST_CDR_FLAG_POST_DISABLED);
05836 #endif
05837    /* make a conference for the tx */
05838    ci.chan = 0;
05839    ci.confno = myrpt->conf;
05840    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
05841    /* first put the channel on the conference in proper mode */
05842    if (ioctl(l->pchan->fds[0], DAHDI_SETCONF, &ci) == -1)
05843    {
05844       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05845       ast_hangup(l->chan);
05846       ast_hangup(l->pchan);
05847       ast_free(l);
05848       return -1;
05849    }
05850    rpt_mutex_lock(&myrpt->lock);
05851    l->reconnects = reconnects;
05852    /* insert at end of queue */
05853    l->max_retries = MAX_RETRIES;
05854    if (perma)
05855       l->max_retries = MAX_RETRIES_PERM;
05856    if (l->isremote) l->retries = l->max_retries + 1;
05857    insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
05858    __kickshort(myrpt);
05859    rpt_mutex_unlock(&myrpt->lock);
05860    if (!l->phonemode) send_newkey(l->chan);
05861    return 0;
05862 }
05863 
05864 
05865 
05866 /*
05867 * Internet linking function 
05868 */
05869 
05870 static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink)
05871 {
05872 
05873    char *val, *s, *s1, *s2;
05874    char tmp[300];
05875    char digitbuf[MAXNODESTR],*strs[MAXLINKLIST];
05876    char mode,perma;
05877    char sx[320],*sy;
05878    struct rpt_link *l;
05879    int i,r;
05880 
05881    if(!param)
05882       return DC_ERROR;
05883       
05884          
05885    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable )
05886       return DC_ERROR;
05887 
05888    strncpy(digitbuf,digits,MAXNODESTR - 1);
05889 
05890    if(debug > 6)
05891       printf("@@@@ ilink param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
05892       
05893    switch(myatoi(param)){
05894       case 11: /* Perm Link off */
05895       case 1: /* Link off */
05896          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
05897             strcpy(digitbuf,myrpt->lastlinknode);
05898          val = node_lookup(myrpt,digitbuf);
05899          if (!val){
05900             if(strlen(digitbuf) >= myrpt->longestnode)
05901                return DC_ERROR;
05902             break;
05903          }
05904          strncpy(tmp,val,sizeof(tmp) - 1);
05905          s = tmp;
05906          s1 = strsep(&s,",");
05907          if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
05908          {
05909             sy = strchr(s1,'/');    
05910             *sy = 0;
05911             sprintf(sx,"%s:4569/%s",s1,sy + 1);
05912             s1 = sx;
05913          }
05914          s2 = strsep(&s,",");
05915          rpt_mutex_lock(&myrpt->lock);
05916          l = myrpt->links.next;
05917          /* try to find this one in queue */
05918          while(l != &myrpt->links){
05919             if (l->name[0] == '0') 
05920             {
05921                l = l->next;
05922                continue;
05923             }
05924             /* if found matching string */
05925             if (!strcmp(l->name, digitbuf))
05926                break;
05927             l = l->next;
05928          }
05929          if (l != &myrpt->links){ /* if found */
05930             struct   ast_frame wf;
05931 
05932             /* must use perm command on perm link */
05933             if ((myatoi(param) < 10) && 
05934                 (l->max_retries > MAX_RETRIES))
05935             {
05936                rpt_mutex_unlock(&myrpt->lock);
05937                return DC_COMPLETE;
05938             }
05939             strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
05940             l->retries = l->max_retries + 1;
05941             l->disced = 1;
05942             rpt_mutex_unlock(&myrpt->lock);
05943             wf.frametype = AST_FRAME_TEXT;
05944             wf.subclass = 0;
05945             wf.offset = 0;
05946             wf.mallocd = 0;
05947             wf.datalen = strlen(discstr) + 1;
05948             wf.samples = 0;
05949             wf.data.ptr = discstr;
05950             if (l->chan)
05951             {
05952                ast_write(l->chan,&wf);
05953                if (ast_safe_sleep(l->chan,250) == -1) return DC_ERROR;
05954                ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
05955             }
05956             rpt_telemetry(myrpt, COMPLETE, NULL);
05957             return DC_COMPLETE;
05958          }
05959          rpt_mutex_unlock(&myrpt->lock);  
05960          return DC_COMPLETE;
05961       case 2: /* Link Monitor */
05962       case 3: /* Link transceive */
05963       case 12: /* Link Monitor permanent */
05964       case 13: /* Link transceive permanent */
05965          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
05966             strcpy(digitbuf,myrpt->lastlinknode);
05967          /* Attempt connection  */
05968          perma = (atoi(param) > 10) ? 1 : 0;
05969          mode = (atoi(param) & 1) ? 1 : 0;
05970          r = connect_link(myrpt, digitbuf, mode, perma);
05971          switch(r){
05972             case -2: /* Attempt to connect to self */
05973                return DC_COMPLETE; /* Silent error */
05974 
05975             case 0:
05976                rpt_telemetry(myrpt, COMPLETE, NULL);
05977                return DC_COMPLETE;
05978 
05979             case 1:
05980                break;
05981             
05982             case 2:
05983                rpt_telemetry(myrpt, REMALREADY, NULL);
05984                return DC_COMPLETE;
05985             
05986             default:
05987                rpt_telemetry(myrpt, CONNFAIL, NULL);
05988                return DC_COMPLETE;
05989          }
05990          break;
05991 
05992       case 4: /* Enter Command Mode */
05993       
05994          /* if doesnt allow link cmd, or no links active, return */
05995          if (((command_source != SOURCE_RPT) && 
05996             (command_source != SOURCE_PHONE) &&
05997             (command_source != SOURCE_ALT) &&
05998             (command_source != SOURCE_DPHONE)) ||
05999              (myrpt->links.next == &myrpt->links))
06000             return DC_COMPLETE;
06001          
06002          /* if already in cmd mode, or selected self, fughetabahtit */
06003          if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name, digitbuf))){
06004          
06005             rpt_telemetry(myrpt, REMALREADY, NULL);
06006             return DC_COMPLETE;
06007          }
06008          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
06009             strcpy(digitbuf,myrpt->lastlinknode);
06010          /* node must at least exist in list */
06011          val = node_lookup(myrpt,digitbuf);
06012          if (!val){
06013             if(strlen(digitbuf) >= myrpt->longestnode)
06014                return DC_ERROR;
06015             break;
06016          
06017          }
06018          rpt_mutex_lock(&myrpt->lock);
06019          strcpy(myrpt->lastlinknode,digitbuf);
06020          strncpy(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode) - 1);
06021          rpt_mutex_unlock(&myrpt->lock);
06022          rpt_telemetry(myrpt, REMGO, NULL);  
06023          return DC_COMPLETE;
06024          
06025       case 5: /* Status */
06026          rpt_telemetry(myrpt, STATUS, NULL);
06027          return DC_COMPLETE;
06028 
06029       case 15: /* Full Status */
06030          rpt_telemetry(myrpt, FULLSTATUS, NULL);
06031          return DC_COMPLETE;
06032          
06033          
06034       case 6: /* All Links Off, including permalinks */
06035                        rpt_mutex_lock(&myrpt->lock);
06036          myrpt->savednodes[0] = 0;
06037                         l = myrpt->links.next;
06038                         /* loop through all links */
06039                         while(l != &myrpt->links){
06040             struct   ast_frame wf;
06041                                 if (l->name[0] == '0') /* Skip any IAXRPT monitoring */
06042                                 {
06043                                         l = l->next;
06044                                         continue;
06045                                 }
06046             /* Make a string of disconnected nodes for possible restoration */
06047             sprintf(tmp,"%c%c%s",(l->mode) ? 'X' : 'M',(l->perma) ? 'P':'T',l->name);
06048             if(strlen(tmp) + strlen(myrpt->savednodes) + 1 < MAXNODESTR){ 
06049                if(myrpt->savednodes[0])
06050                   strcat(myrpt->savednodes, ",");
06051                strcat(myrpt->savednodes, tmp);
06052             }
06053                               l->retries = l->max_retries + 1;
06054                                 l->disced = 2; /* Silently disconnect */
06055                                 rpt_mutex_unlock(&myrpt->lock);
06056             /* ast_log(LOG_NOTICE,"dumping link %s\n",l->name); */
06057                                 
06058                                 wf.frametype = AST_FRAME_TEXT;
06059                                 wf.subclass = 0;
06060                                 wf.offset = 0;
06061                                 wf.mallocd = 0;
06062                                 wf.datalen = strlen(discstr) + 1;
06063                                 wf.samples = 0;
06064                                 wf.data.ptr = discstr;
06065                                 if (l->chan)
06066                                 {
06067                                         ast_write(l->chan,&wf);
06068                                         ast_safe_sleep(l->chan,250); /* It's dead already, why check the return value? */
06069                                         ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
06070                                 }
06071             rpt_mutex_lock(&myrpt->lock);
06072                                 l = l->next;
06073                         }
06074          rpt_mutex_unlock(&myrpt->lock);
06075          if(debug > 3)
06076             ast_log(LOG_NOTICE,"Nodes disconnected: %s\n",myrpt->savednodes);
06077                         rpt_telemetry(myrpt, COMPLETE, NULL);
06078          return DC_COMPLETE;
06079 
06080       case 7: /* Identify last node which keyed us up */
06081          rpt_telemetry(myrpt, LASTNODEKEY, NULL);
06082          break;
06083 
06084 
06085 #ifdef   _MDC_DECODE_H_
06086       case 8:
06087          myrpt->lastunit = 0xd00d; 
06088          mdc1200_notify(myrpt,NULL,myrpt->lastunit);
06089          mdc1200_send(myrpt,myrpt->lastunit);
06090          break;
06091 #endif
06092 
06093       case 16: /* Restore links disconnected with "disconnect all links" command */
06094          strcpy(tmp, myrpt->savednodes); /* Make a copy */
06095          finddelim(tmp, strs, MAXLINKLIST); /* convert into substrings */
06096          for(i = 0; tmp[0] && strs[i] != NULL && i < MAXLINKLIST; i++){
06097             s1 = strs[i];
06098             mode = (s1[0] == 'X') ? 1 : 0;
06099             perma = (s1[1] == 'P') ? 1 : 0;
06100             connect_link(myrpt, s1 + 2, mode, perma); /* Try to reconnect */
06101          }
06102                         rpt_telemetry(myrpt, COMPLETE, NULL);
06103          break;
06104    
06105       case 200:
06106       case 201:
06107       case 202:
06108       case 203:
06109       case 204:
06110       case 205:
06111       case 206:
06112       case 207:
06113       case 208:
06114       case 209:
06115       case 210:
06116       case 211:
06117       case 212:
06118       case 213:
06119       case 214:
06120       case 215:
06121          if (((myrpt->p.propagate_dtmf) && 
06122               (command_source == SOURCE_LNK)) ||
06123              ((myrpt->p.propagate_phonedtmf) &&
06124             ((command_source == SOURCE_PHONE) ||
06125               (command_source == SOURCE_ALT) ||
06126                 (command_source == SOURCE_DPHONE))))
06127                do_dtmf_local(myrpt,
06128                   remdtmfstr[myatoi(param) - 200]);
06129       default:
06130          return DC_ERROR;
06131          
06132    }
06133    
06134    return DC_INDETERMINATE;
06135 }  
06136 
06137 /*
06138 * Autopatch up
06139 */
06140 
06141 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06142 {
06143    pthread_attr_t attr;
06144    int i, idx, paramlength;
06145    char *lparam;
06146    char *value = NULL;
06147    char *paramlist[20];
06148 
06149    static char *keywords[] = {
06150    "context",
06151    "dialtime",
06152    "farenddisconnect",
06153    "noct",
06154    "quiet",
06155    NULL
06156    };
06157       
06158    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
06159       return DC_ERROR;
06160       
06161    if(debug)
06162       printf("@@@@ Autopatch up\n");
06163 
06164    if(!myrpt->callmode){
06165       /* Set defaults */
06166       myrpt->patchnoct = 0;
06167       myrpt->patchdialtime = 0;
06168       myrpt->patchfarenddisconnect = 0;
06169       myrpt->patchquiet = 0;
06170       strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
06171 
06172       if(param){
06173          /* Process parameter list */
06174          lparam = ast_strdup(param);
06175          if(!lparam){
06176             ast_log(LOG_ERROR,"App_rpt out of memory on line %d\n",__LINE__);
06177             return DC_ERROR;  
06178          }
06179          paramlength = finddelim(lparam, paramlist, 20);          
06180          for(i = 0; i < paramlength; i++){
06181             idx = matchkeyword(paramlist[i], &value, keywords);
06182             if(value)
06183                value = skipchars(value, "= ");
06184             switch(idx){
06185 
06186                case 1: /* context */
06187                   strncpy(myrpt->patchcontext, value, MAXPATCHCONTEXT - 1) ;
06188                   break;
06189                   
06190                case 2: /* dialtime */
06191                   myrpt->patchdialtime = atoi(value);
06192                   break;
06193 
06194                case 3: /* farenddisconnect */
06195                   myrpt->patchfarenddisconnect = atoi(value);
06196                   break;
06197 
06198                case 4:  /* noct */
06199                   myrpt->patchnoct = atoi(value);
06200                   break;
06201 
06202                case 5: /* quiet */
06203                   myrpt->patchquiet = atoi(value);
06204                   break;
06205                            
06206                default:
06207                   break;
06208             }
06209          }
06210       ast_free(lparam);
06211       }
06212    }
06213                
06214    rpt_mutex_lock(&myrpt->lock);
06215 
06216    /* if on call, force * into current audio stream */
06217    
06218    if ((myrpt->callmode == 2) || (myrpt->callmode == 3)){
06219       myrpt->mydtmf = myrpt->p.endchar;
06220    }
06221    if (myrpt->callmode){
06222       rpt_mutex_unlock(&myrpt->lock);
06223       return DC_COMPLETE;
06224    }
06225    myrpt->callmode = 1;
06226    myrpt->cidx = 0;
06227    myrpt->exten[myrpt->cidx] = 0;
06228    rpt_mutex_unlock(&myrpt->lock);
06229    pthread_attr_init(&attr);
06230    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
06231    ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *) myrpt);
06232    return DC_COMPLETE;
06233 }
06234 
06235 /*
06236 * Autopatch down
06237 */
06238 
06239 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06240 {
06241    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
06242       return DC_ERROR;
06243    
06244    if(debug)
06245       printf("@@@@ Autopatch down\n");
06246       
06247    rpt_mutex_lock(&myrpt->lock);
06248    
06249    myrpt->macropatch=0;
06250 
06251    if (!myrpt->callmode){
06252       rpt_mutex_unlock(&myrpt->lock);
06253       return DC_COMPLETE;
06254    }
06255    
06256    myrpt->callmode = 0;
06257    channel_revert(myrpt);
06258    rpt_mutex_unlock(&myrpt->lock);
06259    rpt_telemetry(myrpt, TERM, NULL);
06260    return DC_COMPLETE;
06261 }
06262 
06263 /*
06264 * Status
06265 */
06266 
06267 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06268 {
06269 
06270    if (!param)
06271       return DC_ERROR;
06272 
06273    if ((myrpt->p.s[myrpt->p.sysstate_cur].txdisable) || (myrpt->p.s[myrpt->p.sysstate_cur].userfundisable))
06274       return DC_ERROR;
06275 
06276    if(debug)
06277       printf("@@@@ status param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
06278    
06279    switch(myatoi(param)){
06280       case 1: /* System ID */
06281          rpt_telemetry(myrpt, ID1, NULL);
06282          return DC_COMPLETE;
06283       case 2: /* System Time */
06284          rpt_telemetry(myrpt, STATS_TIME, NULL);
06285          return DC_COMPLETE;
06286       case 3: /* app_rpt.c version */
06287          rpt_telemetry(myrpt, STATS_VERSION, NULL);
06288          return DC_COMPLETE;
06289       case 11: /* System ID (local only)*/
06290           rpt_telemetry(myrpt, ID , NULL);
06291             return DC_COMPLETE;
06292         case 12: /* System Time (local only)*/
06293             rpt_telemetry(myrpt, STATS_TIME_LOCAL, NULL);
06294             return DC_COMPLETE;
06295       default:
06296          return DC_ERROR;
06297    }
06298    return DC_INDETERMINATE;
06299 }
06300 /*
06301 *  Macro-oni (without Salami)
06302 */
06303 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06304 {
06305 char  *val;
06306 int   i;
06307    if (myrpt->remote)
06308       return DC_ERROR;
06309 
06310    if(debug) 
06311       printf("@@@@ macro-oni param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
06312    
06313    if(strlen(digitbuf) < 1) /* needs 1 digit */
06314       return DC_INDETERMINATE;
06315          
06316    for(i = 0 ; i < digitbuf[i] ; i++) {
06317       if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
06318          return DC_ERROR;
06319    }
06320    
06321    if (*digitbuf == '0') val = myrpt->p.startupmacro;
06322    else val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, digitbuf);
06323    /* param was 1 for local buf */
06324    if (!val){
06325                 if (strlen(digitbuf) < myrpt->macro_longest)
06326                         return DC_INDETERMINATE;
06327       rpt_telemetry(myrpt, MACRO_NOTFOUND, NULL);
06328       return DC_COMPLETE;
06329    }        
06330    rpt_mutex_lock(&myrpt->lock);
06331    if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val))
06332    {
06333       rpt_mutex_unlock(&myrpt->lock);
06334       rpt_telemetry(myrpt, MACRO_BUSY, NULL);
06335       return DC_ERROR;
06336    }
06337    myrpt->macrotimer = MACROTIME;
06338    strncat(myrpt->macrobuf,val,MAXMACRO - 1);
06339    rpt_mutex_unlock(&myrpt->lock);
06340    return DC_COMPLETE;  
06341 }
06342 
06343 /*
06344 *  Playback a recording
06345 */
06346 
06347 static int function_playback(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06348 {
06349 
06350    if (myrpt->remote)
06351       return DC_ERROR;
06352 
06353    if(debug) 
06354       printf("@@@@ playback param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
06355    
06356    if (ast_fileexists(param,NULL,myrpt->rxchannel->language) <= 0)
06357       return DC_ERROR;
06358 
06359    rpt_telemetry(myrpt,PLAYBACK,param);
06360    return DC_COMPLETE;
06361 }
06362 
06363 /*
06364 * COP - Control operator
06365 */
06366 
06367 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
06368 {
06369    char string[16];
06370    int res;
06371 
06372    int i, r;
06373 
06374    if(!param)
06375       return DC_ERROR;
06376    
06377    switch(myatoi(param)){
06378       case 1: /* System reset */
06379          res = system("killall -9 asterisk");
06380          return DC_COMPLETE;
06381 
06382       case 2:
06383          myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 0;
06384          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "RPTENA");
06385          return DC_COMPLETE;
06386          
06387       case 3:
06388          myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 1;
06389          return DC_COMPLETE;
06390          
06391       case 4: /* test tone on */
06392          if (myrpt->stopgen < 0) 
06393          {
06394             myrpt->stopgen = 1;
06395          }
06396          else 
06397          {
06398             myrpt->stopgen = 0;
06399             rpt_telemetry(myrpt, TEST_TONE, NULL);
06400          }
06401          return DC_COMPLETE;
06402 
06403       case 5: /* Disgorge variables to log for debug purposes */
06404          myrpt->disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
06405          return DC_COMPLETE;
06406 
06407       case 6: /* Simulate COR being activated (phone only) */
06408          if (command_source != SOURCE_PHONE) return DC_INDETERMINATE;
06409          return DC_DOKEY;  
06410 
06411 
06412       case 7: /* Time out timer enable */
06413          myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 0;
06414          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTENA");
06415          return DC_COMPLETE;
06416          
06417       case 8: /* Time out timer disable */
06418          myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 1;
06419          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTDIS");
06420          return DC_COMPLETE;
06421 
06422                 case 9: /* Autopatch enable */
06423                         myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 0;
06424                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APENA");
06425                         return DC_COMPLETE;
06426 
06427                 case 10: /* Autopatch disable */
06428                         myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 1;
06429                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APDIS");
06430                         return DC_COMPLETE;
06431 
06432                 case 11: /* Link Enable */
06433                         myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 0;
06434                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKENA");
06435                         return DC_COMPLETE;
06436 
06437                 case 12: /* Link Disable */
06438                         myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 1;
06439                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKDIS");
06440                         return DC_COMPLETE;
06441 
06442       case 13: /* Query System State */
06443          string[0] = string[1] = 'S';
06444          string[2] = myrpt->p.sysstate_cur + '0';
06445          string[3] = '\0';
06446          rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
06447          return DC_COMPLETE;
06448 
06449       case 14: /* Change System State */
06450          if(strlen(digitbuf) == 0)
06451             break;
06452          if((digitbuf[0] < '0') || (digitbuf[0] > '9'))
06453             return DC_ERROR;
06454          myrpt->p.sysstate_cur = digitbuf[0] - '0';
06455                         string[0] = string[1] = 'S';
06456                         string[2] = myrpt->p.sysstate_cur + '0';
06457                         string[3] = '\0';
06458                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
06459                         return DC_COMPLETE;
06460 
06461                 case 15: /* Scheduler Enable */
06462                         myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 0;
06463                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKENA");
06464                         return DC_COMPLETE;
06465 
06466                 case 16: /* Scheduler Disable */
06467                         myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 1;
06468                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKDIS");
06469                         return DC_COMPLETE;
06470 
06471                 case 17: /* User functions Enable */
06472                         myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 0;
06473                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFENA");
06474                         return DC_COMPLETE;
06475 
06476                 case 18: /* User Functions Disable */
06477                         myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 1;
06478                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFDIS");
06479                         return DC_COMPLETE;
06480 
06481                 case 19: /* Alternate Tail Enable */
06482                         myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 1;
06483                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATENA");
06484                         return DC_COMPLETE;
06485 
06486                 case 20: /* Alternate Tail Disable */
06487                         myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 0;
06488                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATDIS");
06489                         return DC_COMPLETE;
06490 
06491                 case 21: /* Parrot Mode Disable */
06492          birdbath(myrpt);
06493          if (myrpt->p.parrotmode < 2)
06494          {
06495             myrpt->p.parrotmode = 0;
06496             rpt_telemetry(myrpt,COMPLETE,NULL);
06497             return DC_COMPLETE;
06498          }
06499          break;
06500 
06501                 case 22: /* Parrot Mode Enable */
06502          birdbath(myrpt);
06503          if (myrpt->p.parrotmode < 2)
06504          {
06505             myrpt->p.parrotmode = 1;
06506             rpt_telemetry(myrpt,COMPLETE,NULL);
06507             return DC_COMPLETE;
06508          }
06509          break;
06510       case 23: /* flush parrot in progress */
06511          birdbath(myrpt);
06512          rpt_telemetry(myrpt,COMPLETE,NULL);
06513          return DC_COMPLETE;
06514       case 24: /* flush all telemetry */
06515          flush_telem(myrpt);
06516          rpt_telemetry(myrpt,COMPLETE,NULL);
06517          return DC_COMPLETE;
06518       case 25: /* request keying info (brief) */
06519          send_link_keyquery(myrpt);
06520          myrpt->topkeylong = 0;
06521          rpt_telemetry(myrpt,COMPLETE,NULL);
06522          return DC_COMPLETE;
06523       case 26: /* request keying info (full) */
06524          send_link_keyquery(myrpt);
06525          myrpt->topkeylong = 1;
06526          rpt_telemetry(myrpt,COMPLETE,NULL);
06527          return DC_COMPLETE;
06528 
06529       case 30: /* recall memory location on programmable radio */
06530 
06531          if(strlen(digitbuf) < 2) /* needs 2 digits */
06532             break;
06533          
06534          for(i = 0 ; i < 2 ; i++){
06535             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
06536                return DC_ERROR;
06537          }
06538        
06539          r = retreive_memory(myrpt, digitbuf);
06540          if (r < 0){
06541             rpt_telemetry(myrpt,MEMNOTFOUND,NULL);
06542             return DC_COMPLETE;
06543          }
06544          if (r > 0){
06545             return DC_ERROR;
06546          }
06547          if (setrem(myrpt) == -1) return DC_ERROR;
06548          return DC_COMPLETE;  
06549 
06550       case 31: 
06551           /* set channel. note that it's going to change channel 
06552              then confirm on the new channel! */
06553          if(strlen(digitbuf) < 2) /* needs 2 digits */
06554             break;
06555          
06556          for(i = 0 ; i < 2 ; i++){
06557             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
06558                return DC_ERROR;
06559          }
06560          channel_steer(myrpt,digitbuf);
06561          return DC_COMPLETE;  
06562 
06563       case 32: /* Touch Tone Pad Test */
06564          i = strlen(digitbuf);
06565          if(!i){
06566             if(debug > 3)
06567             ast_log(LOG_NOTICE,"Padtest entered");
06568             myrpt->inpadtest = 1;
06569          }
06570          else{
06571             if(debug > 3)
06572                ast_log(LOG_NOTICE,"Padtest len= %d digits=%s",i,digitbuf);
06573             if(digitbuf[i-1] != myrpt->p.endchar)
06574                break;
06575             rpt_telemetry(myrpt, ARB_ALPHA, digitbuf);
06576             myrpt->inpadtest = 0;
06577             if(debug > 3)
06578                ast_log(LOG_NOTICE,"Padtest exited");
06579             return DC_COMPLETE;
06580          }
06581    }  
06582    return DC_INDETERMINATE;
06583 }
06584 /*
06585 * Collect digits one by one until something matches
06586 */
06587 static int collect_function_digits(struct rpt *myrpt, char *digits, 
06588    int command_source, struct rpt_link *mylink)
06589 {
06590    int i,rv;
06591    char *stringp,*action,*param,*functiondigits;
06592    char function_table_name[30] = "";
06593    char workstring[200];
06594    
06595    struct ast_variable *vp;
06596    
06597    if (debug > 6) ast_log(LOG_NOTICE,"digits=%s  source=%d\n",digits, command_source);
06598 
06599    //if(debug) 
06600    // printf("@@@@ Digits collected: %s, source: %d\n", digits, command_source);
06601    
06602    if (command_source == SOURCE_DPHONE) {
06603       if (!myrpt->p.dphone_functions) return DC_INDETERMINATE;
06604       strncpy(function_table_name, myrpt->p.dphone_functions, sizeof(function_table_name) - 1);
06605       }
06606    else if (command_source == SOURCE_ALT) {
06607       if (!myrpt->p.alt_functions) return DC_INDETERMINATE;
06608       strncpy(function_table_name, myrpt->p.alt_functions, sizeof(function_table_name) - 1);
06609       }
06610    else if (command_source == SOURCE_PHONE) {
06611       if (!myrpt->p.phone_functions) return DC_INDETERMINATE;
06612       strncpy(function_table_name, myrpt->p.phone_functions, sizeof(function_table_name) - 1);
06613       }
06614    else if (command_source == SOURCE_LNK)
06615       strncpy(function_table_name, myrpt->p.link_functions, sizeof(function_table_name) - 1);
06616    else
06617       strncpy(function_table_name, myrpt->p.functions, sizeof(function_table_name) - 1);
06618     /* find context for function table in rpt.conf file */
06619    vp = ast_variable_browse(myrpt->cfg, function_table_name);
06620    while(vp) {
06621       if(!strncasecmp(vp->name, digits, strlen(vp->name)))
06622          break;
06623       vp = vp->next;
06624    }  
06625    /* if function context not found */
06626    if(!vp) {
06627       int n;
06628 
06629       n = myrpt->longestfunc;
06630       if (command_source == SOURCE_LNK) n = myrpt->link_longestfunc;
06631       else 
06632       if (command_source == SOURCE_PHONE) n = myrpt->phone_longestfunc;
06633       else 
06634       if (command_source == SOURCE_ALT) n = myrpt->alt_longestfunc;
06635       else 
06636       if (command_source == SOURCE_DPHONE) n = myrpt->dphone_longestfunc;
06637       
06638       if(strlen(digits) >= n)
06639          return DC_ERROR;
06640       else
06641          return DC_INDETERMINATE;
06642    }  
06643    /* Found a match, retrieve value part and parse */
06644    strncpy(workstring, vp->value, sizeof(workstring) - 1 );
06645    stringp = workstring;
06646    action = strsep(&stringp, ",");
06647    param = stringp;
06648    if(debug)
06649       printf("@@@@ action: %s, param = %s\n",action, (param) ? param : "(null)");
06650    /* Look up the action */
06651    for(i = 0 ; i < (sizeof(function_table)/sizeof(struct function_table_tag)); i++){
06652       if(!strncasecmp(action, function_table[i].action, strlen(action)))
06653          break;
06654    }
06655    if(debug)
06656       printf("@@@@ table index i = %d\n",i);
06657    if(i == (sizeof(function_table)/sizeof(struct function_table_tag))){
06658       /* Error, action not in table */
06659       return DC_ERROR;
06660    }
06661    if(function_table[i].function == NULL){
06662       /* Error, function undefined */
06663       if(debug)
06664          printf("@@@@ NULL for action: %s\n",action);
06665       return DC_ERROR;
06666    }
06667    functiondigits = digits + strlen(vp->name);
06668    rv=(*function_table[i].function)(myrpt, param, functiondigits, command_source, mylink);
06669    if (debug > 6) ast_log(LOG_NOTICE,"rv=%i\n",rv);
06670    return(rv);
06671 }
06672 
06673 
06674 static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink,
06675    char *str)
06676 {
06677    /* XXX ATTENTION: if you change the size of these arrays you MUST
06678     * change the limits in corresponding sscanf() calls below. */
06679    char tmp[512], tmp1[512], cmd[300] = "", dest[300], src[300], c;
06680    int   i,seq, res, ts;
06681    struct rpt_link *l;
06682    struct   ast_frame wf;
06683 
06684    wf.frametype = AST_FRAME_TEXT;
06685    wf.subclass = 0;
06686    wf.offset = 0;
06687    wf.mallocd = 0;
06688    wf.datalen = strlen(str) + 1;
06689    wf.samples = 0;
06690    /* put string in our buffer */
06691    strncpy(tmp,str,sizeof(tmp) - 1);
06692 
06693         if (!strcmp(tmp,discstr))
06694         {
06695                 mylink->disced = 1;
06696       mylink->retries = mylink->max_retries + 1;
06697                 ast_softhangup(mylink->chan,AST_SOFTHANGUP_DEV);
06698                 return;
06699         }
06700         if (!strcmp(tmp,newkeystr))
06701         {
06702       mylink->newkey = 1;
06703                 return;
06704         }
06705    if (tmp[0] == 'L')
06706    {
06707       rpt_mutex_lock(&myrpt->lock);
06708       strcpy(mylink->linklist,tmp + 2);
06709       time(&mylink->linklistreceived);
06710       rpt_mutex_unlock(&myrpt->lock);
06711       if (debug > 6) ast_log(LOG_NOTICE,"@@@@ node %s received node list %s from node %s\n",
06712          myrpt->name,tmp,mylink->name);
06713       return;
06714    }
06715    if (tmp[0] == 'K')
06716    {
06717       if (sscanf(tmp,"%299s %299s %299s %30d %30d",cmd,dest,src,&seq,&ts) != 5)
06718       {
06719          ast_log(LOG_WARNING, "Unable to parse keying string %s\n",str);
06720          return;
06721       }
06722       if (dest[0] == '0')
06723       {
06724          strcpy(dest,myrpt->name);
06725       }     
06726       /* if not for me, redistribute to all links */
06727       if (strcmp(dest,myrpt->name))
06728       {
06729          l = myrpt->links.next;
06730          /* see if this is one in list */
06731          while(l != &myrpt->links)
06732          {
06733             if (l->name[0] == '0') 
06734             {
06735                l = l->next;
06736                continue;
06737             }
06738             /* dont send back from where it came */
06739             if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06740             {
06741                l = l->next;
06742                continue;
06743             }
06744             /* if it is, send it and we're done */
06745             if (!strcmp(l->name,dest))
06746             {
06747                /* send, but not to src */
06748                if (strcmp(l->name,src)) {
06749                   wf.data.ptr = str;
06750                   if (l->chan) ast_write(l->chan,&wf);
06751                }
06752                return;
06753             }
06754             l = l->next;
06755          }
06756       }
06757       /* if not for me, or is broadcast, redistribute to all links */
06758       if ((strcmp(dest,myrpt->name)) || (dest[0] == '*'))
06759       {
06760          l = myrpt->links.next;
06761          /* otherwise, send it to all of em */
06762          while(l != &myrpt->links)
06763          {
06764             if (l->name[0] == '0') 
06765             {
06766                l = l->next;
06767                continue;
06768             }
06769             /* dont send back from where it came */
06770             if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06771             {
06772                l = l->next;
06773                continue;
06774             }
06775             /* send, but not to src */
06776             if (strcmp(l->name,src)) {
06777                wf.data.ptr = str;
06778                if (l->chan) ast_write(l->chan,&wf); 
06779             }
06780             l = l->next;
06781          }
06782       }
06783       /* if not for me, end here */
06784       if (strcmp(dest,myrpt->name) && (dest[0] != '*')) return;
06785       if (cmd[1] == '?')
06786       {
06787          time_t now;
06788          int n = 0;
06789 
06790          time(&now);
06791          if (myrpt->lastkeyedtime)
06792          {
06793             n = (int)(now - myrpt->lastkeyedtime);
06794          }
06795          sprintf(tmp1,"K %s %s %d %d",src,myrpt->name,myrpt->keyed,n);
06796          wf.data.ptr = tmp1;
06797          wf.datalen = strlen(tmp1) + 1;
06798          if (mylink->chan) ast_write(mylink->chan,&wf); 
06799          return;
06800       }
06801       if (myrpt->topkeystate != 1) return;
06802       rpt_mutex_lock(&myrpt->lock);
06803       for(i = 0; i < TOPKEYN; i++)
06804       {
06805          if (!strcmp(myrpt->topkey[i].node,src)) break;
06806       }
06807       if (i >= TOPKEYN)
06808       {
06809          for(i = 0; i < TOPKEYN; i++)
06810          {
06811             if (!myrpt->topkey[i].node[0]) break;
06812          }
06813       }
06814       if (i < TOPKEYN)
06815       {
06816          strncpy(myrpt->topkey[i].node,src,TOPKEYMAXSTR - 1);
06817          myrpt->topkey[i].timesince = ts;
06818          myrpt->topkey[i].keyed = seq;
06819       }
06820       rpt_mutex_unlock(&myrpt->lock);
06821       return;
06822    }
06823    if (tmp[0] == 'I')
06824    {
06825       if (sscanf(tmp, "%299s %299s %30x", cmd, src, &seq) != 3)
06826       {
06827          ast_log(LOG_WARNING, "Unable to parse ident string %s\n",str);
06828          return;
06829       }
06830       mdc1200_notify(myrpt,src,seq);
06831       strcpy(dest,"*");
06832    }
06833    else
06834    {
06835       if (sscanf(tmp, "%299s %299s %299s %30d %1c", cmd, dest, src, &seq, &c) != 5)
06836       {
06837          ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
06838          return;
06839       }
06840       if (strcmp(cmd,"D"))
06841       {
06842          ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
06843          return;
06844       }
06845    }
06846    if (dest[0] == '0')
06847    {
06848       strcpy(dest,myrpt->name);
06849    }     
06850 
06851    /* if not for me, redistribute to all links */
06852    if (strcmp(dest,myrpt->name))
06853    {
06854       l = myrpt->links.next;
06855       /* see if this is one in list */
06856       while(l != &myrpt->links)
06857       {
06858          if (l->name[0] == '0') 
06859          {
06860             l = l->next;
06861             continue;
06862          }
06863          /* dont send back from where it came */
06864          if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06865          {
06866             l = l->next;
06867             continue;
06868          }
06869          /* if it is, send it and we're done */
06870          if (!strcmp(l->name,dest))
06871          {
06872             /* send, but not to src */
06873             if (strcmp(l->name,src)) {
06874                wf.data.ptr = str;
06875                if (l->chan) ast_write(l->chan,&wf);
06876             }
06877             return;
06878          }
06879          l = l->next;
06880       }
06881       l = myrpt->links.next;
06882       /* otherwise, send it to all of em */
06883       while(l != &myrpt->links)
06884       {
06885          if (l->name[0] == '0') 
06886          {
06887             l = l->next;
06888             continue;
06889          }
06890          /* dont send back from where it came */
06891          if ((l == mylink) || (!strcmp(l->name,mylink->name)))
06892          {
06893             l = l->next;
06894             continue;
06895          }
06896          /* send, but not to src */
06897          if (strcmp(l->name,src)) {
06898             wf.data.ptr = str;
06899             if (l->chan) ast_write(l->chan,&wf); 
06900          }
06901          l = l->next;
06902       }
06903       return;
06904    }
06905    if (myrpt->p.archivedir)
06906    {
06907       char dtmfstr[100];
06908 
06909       sprintf(dtmfstr,"DTMF,%s,%c",mylink->name,c);
06910       donodelog(myrpt,dtmfstr);
06911    }
06912    c = func_xlat(myrpt,c,&myrpt->p.outxlat);
06913    if (!c) return;
06914    rpt_mutex_lock(&myrpt->lock);
06915    if (c == myrpt->p.endchar) myrpt->stopgen = 1;
06916    if (myrpt->callmode == 1)
06917    {
06918       myrpt->exten[myrpt->cidx++] = c;
06919       myrpt->exten[myrpt->cidx] = 0;
06920       /* if this exists */
06921       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
06922       {
06923          /* if this really it, end now */
06924          if (!ast_matchmore_extension(myrpt->pchannel,myrpt->patchcontext,
06925             myrpt->exten,1,NULL)) 
06926          {
06927             myrpt->callmode = 2;
06928             if(!myrpt->patchquiet)
06929             {
06930                rpt_mutex_unlock(&myrpt->lock);
06931                rpt_telemetry(myrpt,PROC,NULL); 
06932                rpt_mutex_lock(&myrpt->lock);
06933             }
06934          }
06935          else /* othewise, reset timer */
06936          {
06937             myrpt->calldigittimer = 1;
06938          }
06939       }
06940       /* if can continue, do so */
06941       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
06942       {
06943          /* call has failed, inform user */
06944          myrpt->callmode = 4;
06945       }
06946    }
06947    if ((!myrpt->inpadtest) &&(c == myrpt->p.funcchar))
06948    {
06949       myrpt->rem_dtmfidx = 0;
06950       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
06951       time(&myrpt->rem_dtmf_time);
06952       rpt_mutex_unlock(&myrpt->lock);
06953       return;
06954    } 
06955    else if (myrpt->rem_dtmfidx < 0)
06956    {
06957       if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
06958       {
06959          myrpt->mydtmf = c;
06960       }
06961       if (myrpt->p.propagate_dtmf) do_dtmf_local(myrpt,c);
06962       if (myrpt->p.propagate_phonedtmf) do_dtmf_phone(myrpt,mylink,c);
06963       rpt_mutex_unlock(&myrpt->lock);
06964       return;
06965    }
06966    else if (((myrpt->inpadtest) || (c != myrpt->p.endchar)) && (myrpt->rem_dtmfidx >= 0))
06967    {
06968       time(&myrpt->rem_dtmf_time);
06969       if (myrpt->rem_dtmfidx < MAXDTMF)
06970       {
06971          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
06972          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
06973          
06974          rpt_mutex_unlock(&myrpt->lock);
06975          strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
06976          res = collect_function_digits(myrpt, cmd, SOURCE_LNK, mylink);
06977          rpt_mutex_lock(&myrpt->lock);
06978          
06979          switch(res){
06980 
06981             case DC_INDETERMINATE:
06982                break;
06983             
06984             case DC_REQ_FLUSH:
06985                myrpt->rem_dtmfidx = 0;
06986                myrpt->rem_dtmfbuf[0] = 0;
06987                break;
06988             
06989             
06990             case DC_COMPLETE:
06991             case DC_COMPLETEQUIET:
06992                myrpt->totalexecdcommands++;
06993                myrpt->dailyexecdcommands++;
06994                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
06995                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
06996                myrpt->rem_dtmfbuf[0] = 0;
06997                myrpt->rem_dtmfidx = -1;
06998                myrpt->rem_dtmf_time = 0;
06999                break;
07000             
07001             case DC_ERROR:
07002             default:
07003                myrpt->rem_dtmfbuf[0] = 0;
07004                myrpt->rem_dtmfidx = -1;
07005                myrpt->rem_dtmf_time = 0;
07006                break;
07007          }
07008       }
07009 
07010    }
07011    rpt_mutex_unlock(&myrpt->lock);
07012    return;
07013 }
07014 
07015 static void handle_link_phone_dtmf(struct rpt *myrpt, struct rpt_link *mylink,
07016    char c)
07017 {
07018 
07019 char  cmd[300];
07020 int   res;
07021 
07022    if (myrpt->p.archivedir)
07023    {
07024       char str[100];
07025 
07026       sprintf(str,"DTMF(P),%s,%c",mylink->name,c);
07027       donodelog(myrpt,str);
07028    }
07029    rpt_mutex_lock(&myrpt->lock);
07030 
07031    if (mylink->phonemode == 3) /*If in simplex dumb phone mode */
07032    {
07033       if(c == myrpt->p.endchar) /* If end char */
07034       {
07035          mylink->lastrealrx = 0; /* Keying state = off */
07036          rpt_mutex_unlock(&myrpt->lock);
07037          return;
07038       }
07039 
07040       if(c == myrpt->p.funcchar) /* If lead-in char */
07041       {
07042          mylink->lastrealrx = !mylink->lastrealrx; /* Toggle keying state */
07043          rpt_mutex_unlock(&myrpt->lock);
07044          return;
07045       }
07046    }
07047    else
07048    {
07049       if (c == myrpt->p.endchar)
07050       {
07051          if (mylink->lastrx)
07052          {
07053             mylink->lastrealrx = 0;
07054             rpt_mutex_unlock(&myrpt->lock);
07055             return;
07056          }
07057          myrpt->stopgen = 1;
07058          if (myrpt->cmdnode[0])
07059          {
07060             myrpt->cmdnode[0] = 0;
07061             myrpt->dtmfidx = -1;
07062             myrpt->dtmfbuf[0] = 0;
07063             rpt_mutex_unlock(&myrpt->lock);
07064             rpt_telemetry(myrpt,COMPLETE,NULL);
07065             return;
07066          }
07067       }
07068    }
07069    if (myrpt->cmdnode[0])
07070    {
07071       rpt_mutex_unlock(&myrpt->lock);
07072       send_link_dtmf(myrpt,c);
07073       return;
07074    }
07075    if (myrpt->callmode == 1)
07076    {
07077       myrpt->exten[myrpt->cidx++] = c;
07078       myrpt->exten[myrpt->cidx] = 0;
07079       /* if this exists */
07080       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
07081       {
07082          /* if this really it, end now */
07083          if (!ast_matchmore_extension(myrpt->pchannel,myrpt->patchcontext,
07084             myrpt->exten,1,NULL)) 
07085          {
07086             myrpt->callmode = 2;
07087             if(!myrpt->patchquiet)
07088             {
07089                rpt_mutex_unlock(&myrpt->lock);
07090                rpt_telemetry(myrpt,PROC,NULL); 
07091                rpt_mutex_lock(&myrpt->lock);
07092             }
07093          }
07094          else /* othewise, reset timer */
07095          {
07096             myrpt->calldigittimer = 1;
07097          }
07098       }
07099       /* if can continue, do so */
07100       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
07101       {
07102          /* call has failed, inform user */
07103          myrpt->callmode = 4;
07104       }
07105    }
07106    if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
07107    {
07108       myrpt->mydtmf = c;
07109    }
07110    if ((!myrpt->inpadtest) && (c == myrpt->p.funcchar))
07111    {
07112       myrpt->rem_dtmfidx = 0;
07113       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
07114       time(&myrpt->rem_dtmf_time);
07115       rpt_mutex_unlock(&myrpt->lock);
07116       return;
07117    } 
07118    else if (((myrpt->inpadtest) || (c != myrpt->p.endchar)) && (myrpt->rem_dtmfidx >= 0))
07119    {
07120       time(&myrpt->rem_dtmf_time);
07121       if (myrpt->rem_dtmfidx < MAXDTMF)
07122       {
07123          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
07124          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
07125          
07126          rpt_mutex_unlock(&myrpt->lock);
07127          strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
07128          switch(mylink->phonemode)
07129          {
07130              case 1:
07131             res = collect_function_digits(myrpt, cmd, 
07132                SOURCE_PHONE, mylink);
07133             break;
07134              case 2:
07135             res = collect_function_digits(myrpt, cmd, 
07136                SOURCE_DPHONE,mylink);
07137             break;
07138              case 4:
07139             res = collect_function_digits(myrpt, cmd, 
07140                SOURCE_ALT,mylink);
07141             break;
07142              default:
07143             res = collect_function_digits(myrpt, cmd, 
07144                SOURCE_LNK, mylink);
07145             break;
07146          }
07147 
07148          rpt_mutex_lock(&myrpt->lock);
07149          
07150          switch(res){
07151 
07152             case DC_INDETERMINATE:
07153                break;
07154             
07155             case DC_DOKEY:
07156                mylink->lastrealrx = 1;
07157                break;
07158             
07159             case DC_REQ_FLUSH:
07160                myrpt->rem_dtmfidx = 0;
07161                myrpt->rem_dtmfbuf[0] = 0;
07162                break;
07163             
07164             
07165             case DC_COMPLETE:
07166             case DC_COMPLETEQUIET:
07167                myrpt->totalexecdcommands++;
07168                myrpt->dailyexecdcommands++;
07169                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
07170                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
07171                myrpt->rem_dtmfbuf[0] = 0;
07172                myrpt->rem_dtmfidx = -1;
07173                myrpt->rem_dtmf_time = 0;
07174                break;
07175             
07176             case DC_ERROR:
07177             default:
07178                myrpt->rem_dtmfbuf[0] = 0;
07179                myrpt->rem_dtmfidx = -1;
07180                myrpt->rem_dtmf_time = 0;
07181                break;
07182          }
07183       }
07184 
07185    }
07186    rpt_mutex_unlock(&myrpt->lock);
07187    return;
07188 }
07189 
07190 /* Doug Hall RBI-1 serial data definitions:
07191  *
07192  * Byte 0: Expansion external outputs 
07193  * Byte 1: 
07194  * Bits 0-3 are BAND as follows:
07195  * Bits 4-5 are POWER bits as follows:
07196  *    00 - Low Power
07197  *    01 - Hi Power
07198  *    02 - Med Power
07199  * Bits 6-7 are always set
07200  * Byte 2:
07201  * Bits 0-3 MHZ in BCD format
07202  * Bits 4-5 are offset as follows:
07203  *    00 - minus
07204  *    01 - plus
07205  *    02 - simplex
07206  *    03 - minus minus (whatever that is)
07207  * Bit 6 is the 0/5 KHZ bit
07208  * Bit 7 is always set
07209  * Byte 3:
07210  * Bits 0-3 are 10 KHZ in BCD format
07211  * Bits 4-7 are 100 KHZ in BCD format
07212  * Byte 4: PL Tone code and encode/decode enable bits
07213  * Bits 0-5 are PL tone code (comspec binary codes)
07214  * Bit 6 is encode enable/disable
07215  * Bit 7 is decode enable/disable
07216  */
07217 
07218 /* take the frequency from the 10 mhz digits (and up) and convert it
07219    to a band number */
07220 
07221 static int rbi_mhztoband(char *str)
07222 {
07223 int   i;
07224 
07225    i = atoi(str) / 10; /* get the 10's of mhz */
07226    switch(i)
07227    {
07228        case 2:
07229       return 10;
07230        case 5:
07231       return 11;
07232        case 14:
07233       return 2;
07234        case 22:
07235       return 3;
07236        case 44:
07237       return 4;
07238        case 124:
07239       return 0;
07240        case 125:
07241       return 1;
07242        case 126:
07243       return 8;
07244        case 127:
07245       return 5;
07246        case 128:
07247       return 6;
07248        case 129:
07249       return 7;
07250        default:
07251       break;
07252    }
07253    return -1;
07254 }
07255 
07256 /* take a PL frequency and turn it into a code */
07257 static int rbi_pltocode(char *str)
07258 {
07259 int i;
07260 char *s;
07261 
07262    s = strchr(str,'.');
07263    i = 0;
07264    if (s) i = atoi(s + 1);
07265    i += atoi(str) * 10;
07266    switch(i)
07267    {
07268        case 670:
07269       return 0;
07270        case 719:
07271       return 1;
07272        case 744:
07273       return 2;
07274        case 770:
07275       return 3;
07276        case 797:
07277       return 4;
07278        case 825:
07279       return 5;
07280        case 854:
07281       return 6;
07282        case 885:
07283       return 7;
07284        case 915:
07285       return 8;
07286        case 948:
07287       return 9;
07288        case 974:
07289       return 10;
07290        case 1000:
07291       return 11;
07292        case 1035:
07293       return 12;
07294        case 1072:
07295       return 13;
07296        case 1109:
07297       return 14;
07298        case 1148:
07299       return 15;
07300        case 1188:
07301       return 16;
07302        case 1230:
07303       return 17;
07304        case 1273:
07305       return 18;
07306        case 1318:
07307       return 19;
07308        case 1365:
07309       return 20;
07310        case 1413:
07311       return 21;
07312        case 1462:
07313       return 22;
07314        case 1514:
07315       return 23;
07316        case 1567:
07317       return 24;
07318        case 1622:
07319       return 25;
07320        case 1679:
07321       return 26;
07322        case 1738:
07323       return 27;
07324        case 1799:
07325       return 28;
07326        case 1862:
07327       return 29;
07328        case 1928:
07329       return 30;
07330        case 2035:
07331       return 31;
07332        case 2107:
07333       return 32;
07334        case 2181:
07335       return 33;
07336        case 2257:
07337       return 34;
07338        case 2336:
07339       return 35;
07340        case 2418:
07341       return 36;
07342        case 2503:
07343       return 37;
07344    }
07345    return -1;
07346 }
07347 
07348 /*
07349 * Shift out a formatted serial bit stream
07350 */
07351 
07352 static void rbi_out_parallel(struct rpt *myrpt,unsigned char *data)
07353     {
07354 #ifdef __i386__
07355     int i,j;
07356     unsigned char od,d;
07357     static volatile long long delayvar;
07358 
07359     for(i = 0 ; i < 5 ; i++){
07360         od = *data++; 
07361         for(j = 0 ; j < 8 ; j++){
07362             d = od & 1;
07363             outb(d,myrpt->p.iobase);
07364        /* >= 15 us */
07365        for(delayvar = 1; delayvar < 15000; delayvar++); 
07366             od >>= 1;
07367             outb(d | 2,myrpt->p.iobase);
07368        /* >= 30 us */
07369        for(delayvar = 1; delayvar < 30000; delayvar++); 
07370             outb(d,myrpt->p.iobase);
07371        /* >= 10 us */
07372        for(delayvar = 1; delayvar < 10000; delayvar++); 
07373             }
07374         }
07375    /* >= 50 us */
07376         for(delayvar = 1; delayvar < 50000; delayvar++); 
07377 #endif
07378     }
07379 
07380 static void rbi_out(struct rpt *myrpt,unsigned char *data)
07381 {
07382 struct dahdi_radio_param r;
07383 
07384    memset(&r,0,sizeof(struct dahdi_radio_param));
07385    r.radpar = DAHDI_RADPAR_REMMODE;
07386    r.data = DAHDI_RADPAR_REM_RBI1;
07387    /* if setparam ioctl fails, its probably not a pciradio card */
07388    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&r) == -1)
07389    {
07390       rbi_out_parallel(myrpt,data);
07391       return;
07392    }
07393    r.radpar = DAHDI_RADPAR_REMCOMMAND;
07394    memcpy(&r.data,data,5);
07395    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&r) == -1)
07396    {
07397       ast_log(LOG_WARNING,"Cannot send RBI command for channel %s\n",myrpt->dahdirxchannel->name);
07398       return;
07399    }
07400 }
07401 
07402 static int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes, 
07403    unsigned char *rxbuf, int rxmaxbytes, int asciiflag)
07404 {
07405    int i,j,idx,oldmode,olddata;
07406    struct dahdi_radio_param prm;
07407    char c;
07408 
07409     if(debug) {
07410        ast_log(LOG_NOTICE, "ioport=%s  iofd=0x%x\n",myrpt->p.ioport,myrpt->iofd);
07411       printf("String output was:\n");
07412       for(i = 0; i < txbytes; i++)
07413          printf("%02X ", (unsigned char ) txbuf[i]);
07414       printf("\n");
07415    }
07416 
07417    if (myrpt->iofd >= 0)  /* if to do out a serial port */
07418    {
07419       if (write(myrpt->iofd,txbuf,txbytes) != txbytes)
07420       {
07421          return -1;
07422       }
07423       if ((!rxmaxbytes) || (rxbuf == NULL)) 
07424       {
07425          return(0);
07426       }
07427       memset(rxbuf,0,rxmaxbytes);
07428       for(i = 0; i < rxmaxbytes; i++)
07429       {
07430          j = read(myrpt->iofd,&c,1);
07431          if (j < 1) 
07432          {
07433             return(i);
07434          }
07435          rxbuf[i] = c;
07436          if (asciiflag & 1)
07437          {
07438             rxbuf[i + 1] = 0;
07439             if (c == '\r') break;
07440          }
07441       }              
07442       if(debug) {
07443          printf("String returned was:\n");
07444          for(j = 0; j < i; j++)
07445             printf("%02X ", (unsigned char ) rxbuf[j]);
07446          printf("\n");
07447       }
07448       return(i);
07449    }
07450 
07451    /* if not a DAHDI channel, cant use pciradio stuff */
07452    if (myrpt->rxchannel != myrpt->dahdirxchannel) return -1;   
07453 
07454    prm.radpar = DAHDI_RADPAR_UIOMODE;
07455    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_GETPARAM,&prm) == -1) return -1;
07456    oldmode = prm.data;
07457    prm.radpar = DAHDI_RADPAR_UIODATA;
07458    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_GETPARAM,&prm) == -1) return -1;
07459    olddata = prm.data;
07460         prm.radpar = DAHDI_RADPAR_REMMODE;
07461         if (asciiflag & 1)  prm.data = DAHDI_RADPAR_REM_SERIAL_ASCII;
07462         else prm.data = DAHDI_RADPAR_REM_SERIAL;
07463    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07464    if (asciiflag & 2)
07465    {
07466       i = DAHDI_ONHOOK;
07467       if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_HOOK,&i) == -1) return -1;
07468       usleep(100000);
07469    }
07470         prm.radpar = DAHDI_RADPAR_REMCOMMAND;
07471         prm.data = rxmaxbytes;
07472         memcpy(prm.buf,txbuf,txbytes);
07473         prm.index = txbytes;
07474    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07475         if (rxbuf)
07476         {
07477                 *rxbuf = 0;
07478                 memcpy(rxbuf,prm.buf,prm.index);
07479         }
07480    idx = prm.index;
07481         prm.radpar = DAHDI_RADPAR_REMMODE;
07482         prm.data = DAHDI_RADPAR_REM_NONE;
07483    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07484    if (asciiflag & 2)
07485    {
07486       i = DAHDI_OFFHOOK;
07487       if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_HOOK,&i) == -1) return -1;
07488    }
07489    prm.radpar = DAHDI_RADPAR_UIOMODE;
07490    prm.data = oldmode;
07491    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07492    prm.radpar = DAHDI_RADPAR_UIODATA;
07493    prm.data = olddata;
07494    if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
07495         return(idx);
07496 }
07497 
07498 static int civ_cmd(struct rpt *myrpt,unsigned char *cmd, int cmdlen)
07499 {
07500 unsigned char rxbuf[100];
07501 int   i,rv ;
07502 
07503    rv = serial_remote_io(myrpt,cmd,cmdlen,rxbuf,cmdlen + 6,0);
07504    if (rv == -1) return(-1);
07505    if (rv != (cmdlen + 6)) return(1);
07506    for(i = 0; i < 6; i++)
07507       if (rxbuf[i] != cmd[i]) return(1);
07508    if (rxbuf[cmdlen] != 0xfe) return(1);
07509    if (rxbuf[cmdlen + 1] != 0xfe) return(1);
07510    if (rxbuf[cmdlen + 4] != 0xfb) return(1);
07511    if (rxbuf[cmdlen + 5] != 0xfd) return(1);
07512    return(0);
07513 }
07514 
07515 static int sendkenwood(struct rpt *myrpt,char *txstr, char *rxstr)
07516 {
07517 int   i;
07518 
07519 ast_log(LOG_NOTICE,"Sent to kenwood: %s\n",txstr);
07520    if (debug) printf("Send to kenwood: %s\n",txstr);
07521    i = serial_remote_io(myrpt, (unsigned char *)txstr, strlen(txstr), 
07522       (unsigned char *)rxstr,RAD_SERIAL_BUFLEN - 1,3);
07523    if (i < 0) return -1;
07524    if ((i > 0) && (rxstr[i - 1] == '\r'))
07525       rxstr[i-- - 1] = 0;
07526    if (debug) printf("Got from kenwood: %s\n",rxstr);
07527 ast_log(LOG_NOTICE,"Got from kenwood: %s\n",rxstr);
07528    return(i);
07529 }
07530 
07531 /* take a PL frequency and turn it into a code */
07532 static int kenwood_pltocode(char *str)
07533 {
07534 int i;
07535 char *s;
07536 
07537    s = strchr(str,'.');
07538    i = 0;
07539    if (s) i = atoi(s + 1);
07540    i += atoi(str) * 10;
07541    switch(i)
07542    {
07543        case 670:
07544       return 1;
07545        case 719:
07546       return 3;
07547        case 744:
07548       return 4;
07549        case 770:
07550       return 5;
07551        case 797:
07552       return 6;
07553        case 825:
07554       return 7;
07555        case 854:
07556       return 8;
07557        case 885:
07558       return 9;
07559        case 915:
07560       return 10;
07561        case 948:
07562       return 11;
07563        case 974:
07564       return 12;
07565        case 1000:
07566       return 13;
07567        case 1035:
07568       return 14;
07569        case 1072:
07570       return 15;
07571        case 1109:
07572       return 16;
07573        case 1148:
07574       return 17;
07575        case 1188:
07576       return 18;
07577        case 1230:
07578       return 19;
07579        case 1273:
07580       return 20;
07581        case 1318:
07582       return 21;
07583        case 1365:
07584       return 22;
07585        case 1413:
07586       return 23;
07587        case 1462:
07588       return 24;
07589        case 1514:
07590       return 25;
07591        case 1567:
07592       return 26;
07593        case 1622:
07594       return 27;
07595        case 1679:
07596       return 28;
07597        case 1738:
07598       return 29;
07599        case 1799:
07600       return 30;
07601        case 1862:
07602       return 31;
07603        case 1928:
07604       return 32;
07605        case 2035:
07606       return 33;
07607        case 2107:
07608       return 34;
07609        case 2181:
07610       return 35;
07611        case 2257:
07612       return 36;
07613        case 2336:
07614       return 37;
07615        case 2418:
07616       return 38;
07617        case 2503:
07618       return 39;
07619    }
07620    return -1;
07621 }
07622 
07623 static int sendrxkenwood(struct rpt *myrpt, char *txstr, char *rxstr, 
07624    char *cmpstr)
07625 {
07626 int   i,j;
07627 
07628    for(i = 0;i < KENWOOD_RETRIES;i++)
07629    {
07630       j = sendkenwood(myrpt,txstr,rxstr);
07631       if (j < 0) return(j);
07632       if (j == 0) continue;
07633       if (!strncmp(rxstr,cmpstr,strlen(cmpstr))) return(0);
07634    }
07635    return(-1);
07636 }     
07637 
07638 static int setkenwood(struct rpt *myrpt)
07639 {
07640 char rxstr[RAD_SERIAL_BUFLEN],txstr[RAD_SERIAL_BUFLEN],freq[20];
07641 char mhz[MAXREMSTR],offset[20],band,decimals[MAXREMSTR],band1,band2;
07642 int myrxpl;
07643    
07644 int offsets[] = {0,2,1};
07645 int powers[] = {2,1,0};
07646 
07647    if (sendrxkenwood(myrpt,"VMC 0,0\r",rxstr,"VMC") < 0) return -1;
07648    split_freq(mhz, decimals, myrpt->freq);
07649    if (atoi(mhz) > 400)
07650    {
07651       band = '6';
07652       band1 = '1';
07653       band2 = '5';
07654       strcpy(offset,"005000000");
07655    }
07656    else
07657    {
07658       band = '2';
07659       band1 = '0';
07660       band2 = '2';
07661       strcpy(offset,"000600000");
07662    }
07663    strcpy(freq,"000000");
07664    strncpy(freq,decimals,strlen(decimals));
07665    myrxpl = myrpt->rxplon;
07666    if (IS_XPMR(myrpt)) myrxpl = 0;
07667    sprintf(txstr,"VW %c,%05d%s,0,%d,0,%d,%d,,%02d,,%02d,%s\r",
07668       band,atoi(mhz),freq,offsets[(int)myrpt->offset],
07669       (myrpt->txplon != 0),myrxpl,
07670       kenwood_pltocode(myrpt->txpl),kenwood_pltocode(myrpt->rxpl),
07671       offset);
07672    if (sendrxkenwood(myrpt,txstr,rxstr,"VW") < 0) return -1;
07673    sprintf(txstr,"RBN %c\r",band2);
07674    if (sendrxkenwood(myrpt,txstr,rxstr,"RBN") < 0) return -1;
07675    sprintf(txstr,"PC %c,%d\r",band1,powers[(int)myrpt->powerlevel]);
07676    if (sendrxkenwood(myrpt,txstr,rxstr,"PC") < 0) return -1;
07677    return 0;
07678 }
07679 
07680 static int set_tm271(struct rpt *myrpt)
07681 {
07682 char rxstr[RAD_SERIAL_BUFLEN],txstr[RAD_SERIAL_BUFLEN],freq[20];
07683 char mhz[MAXREMSTR],decimals[MAXREMSTR];
07684    
07685 int offsets[] = {0,2,1};
07686 int powers[] = {2,1,0};
07687 
07688    split_freq(mhz, decimals, myrpt->freq);
07689    strcpy(freq,"000000");
07690    strncpy(freq,decimals,strlen(decimals));
07691 
07692    sprintf(txstr,"VF %04d%s,4,%d,0,%d,0,0,%d,%d,000,00600000,0,0\r",
07693       atoi(mhz),freq,offsets[(int)myrpt->offset],
07694       (myrpt->txplon != 0),kenwood_pltocode(myrpt->txpl),
07695       kenwood_pltocode(myrpt->rxpl));
07696 
07697    if (sendrxkenwood(myrpt,txstr,rxstr,"VF") < 0) return -1;
07698    if (sendrxkenwood(myrpt,"VM 0\r",rxstr,"VM") < 0) return -1;
07699    sprintf(txstr,"PC %d\r",powers[(int)myrpt->powerlevel]);
07700    if (sendrxkenwood(myrpt,txstr,rxstr,"PC") < 0) return -1;
07701    return 0;
07702 }
07703 
07704 static int setrbi(struct rpt *myrpt)
07705 {
07706 char tmp[MAXREMSTR] = "",*s;
07707 unsigned char rbicmd[5];
07708 int   band,txoffset = 0,txpower = 0,rxpl;
07709 
07710    /* must be a remote system */
07711    if (!myrpt->remoterig) return(0);
07712    if (!myrpt->remoterig[0]) return(0);
07713    /* must have rbi hardware */
07714    if (strncmp(myrpt->remoterig,remote_rig_rbi,3)) return(0);
07715    if (setrbi_check(myrpt) == -1) return(-1);
07716    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
07717    s = strchr(tmp,'.');
07718    /* if no decimal, is invalid */
07719    
07720    if (s == NULL){
07721       if(debug)
07722          printf("@@@@ Frequency needs a decimal\n");
07723       return -1;
07724    }
07725    
07726    *s++ = 0;
07727    if (strlen(tmp) < 2){
07728       if(debug)
07729          printf("@@@@ Bad MHz digits: %s\n", tmp);
07730       return -1;
07731    }
07732     
07733    if (strlen(s) < 3){
07734       if(debug)
07735          printf("@@@@ Bad KHz digits: %s\n", s);
07736       return -1;
07737    }
07738 
07739    if ((s[2] != '0') && (s[2] != '5')){
07740       if(debug)
07741          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
07742       return -1;
07743    }
07744     
07745    band = rbi_mhztoband(tmp);
07746    if (band == -1){
07747       if(debug)
07748          printf("@@@@ Bad Band: %s\n", tmp);
07749       return -1;
07750    }
07751    
07752    rxpl = rbi_pltocode(myrpt->rxpl);
07753    
07754    if (rxpl == -1){
07755       if(debug)
07756          printf("@@@@ Bad TX PL: %s\n", myrpt->rxpl);
07757       return -1;
07758    }
07759 
07760    
07761    switch(myrpt->offset)
07762    {
07763        case REM_MINUS:
07764       txoffset = 0;
07765       break;
07766        case REM_PLUS:
07767       txoffset = 0x10;
07768       break;
07769        case REM_SIMPLEX:
07770       txoffset = 0x20;
07771       break;
07772    }
07773    switch(myrpt->powerlevel)
07774    {
07775        case REM_LOWPWR:
07776       txpower = 0;
07777       break;
07778        case REM_MEDPWR:
07779       txpower = 0x20;
07780       break;
07781        case REM_HIPWR:
07782       txpower = 0x10;
07783       break;
07784    }
07785    rbicmd[0] = 0;
07786    rbicmd[1] = band | txpower | 0xc0;
07787    rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80;
07788    if (s[2] == '5') rbicmd[2] |= 0x40;
07789    rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0');
07790    rbicmd[4] = rxpl;
07791    if (myrpt->txplon) rbicmd[4] |= 0x40;
07792    if (myrpt->rxplon) rbicmd[4] |= 0x80;
07793    rbi_out(myrpt,rbicmd);
07794    return 0;
07795 }
07796 
07797 static int setrtx(struct rpt *myrpt)
07798 {
07799 char tmp[MAXREMSTR] = "",*s,rigstr[200],pwr,res = 0;
07800 int   band,txoffset = 0,txpower = 0,rxpl,txpl;
07801 float ofac;
07802 double txfreq;
07803 
07804    /* must be a remote system */
07805    if (!myrpt->remoterig) return(0);
07806    if (!myrpt->remoterig[0]) return(0);
07807    /* must have rtx hardware */
07808    if (!ISRIG_RTX(myrpt->remoterig)) return(0);
07809    /* must be a usbradio interface type */
07810    if (!IS_XPMR(myrpt)) return(0);
07811    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
07812    s = strchr(tmp,'.');
07813    /* if no decimal, is invalid */
07814    
07815    if(debug)printf("setrtx() %s %s\n",myrpt->name,myrpt->remoterig);
07816 
07817    if (s == NULL){
07818       if(debug)
07819          printf("@@@@ Frequency needs a decimal\n");
07820       return -1;
07821    }
07822    *s++ = 0;
07823    if (strlen(tmp) < 2){
07824       if(debug)
07825          printf("@@@@ Bad MHz digits: %s\n", tmp);
07826       return -1;
07827    }
07828     
07829    if (strlen(s) < 3){
07830       if(debug)
07831          printf("@@@@ Bad KHz digits: %s\n", s);
07832       return -1;
07833    }
07834 
07835    if ((s[2] != '0') && (s[2] != '5')){
07836       if(debug)
07837          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
07838       return -1;
07839    }
07840     
07841    band = rbi_mhztoband(tmp);
07842    if (band == -1){
07843       if(debug)
07844          printf("@@@@ Bad Band: %s\n", tmp);
07845       return -1;
07846    }
07847    
07848    rxpl = rbi_pltocode(myrpt->rxpl);
07849    
07850    if (rxpl == -1){
07851       if(debug)
07852          printf("@@@@ Bad RX PL: %s\n", myrpt->rxpl);
07853       return -1;
07854    }
07855 
07856    txpl = rbi_pltocode(myrpt->txpl);
07857    
07858    if (txpl == -1){
07859       if(debug)
07860          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
07861       return -1;
07862    }
07863    
07864    switch(myrpt->offset)
07865    {
07866        case REM_MINUS:
07867       txoffset = 0;
07868       break;
07869        case REM_PLUS:
07870       txoffset = 0x10;
07871       break;
07872        case REM_SIMPLEX:
07873       txoffset = 0x20;
07874       break;
07875    }
07876    switch(myrpt->powerlevel)
07877    {
07878        case REM_LOWPWR:
07879       txpower = 0;
07880       break;
07881        case REM_MEDPWR:
07882       txpower = 0x20;
07883       break;
07884        case REM_HIPWR:
07885       txpower = 0x10;
07886       break;
07887    }
07888 
07889    res = setrtx_check(myrpt);
07890    if (res < 0) return res;
07891    ofac = 0.0;
07892    if (myrpt->offset == REM_MINUS) ofac = -1.0;
07893    if (myrpt->offset == REM_PLUS) ofac = 1.0;
07894 
07895    if (!strcmp(myrpt->remoterig,remote_rig_rtx450))
07896       txfreq = atof(myrpt->freq) +  (ofac * 5.0);
07897    else
07898       txfreq = atof(myrpt->freq) +  (ofac * 0.6);
07899 
07900    pwr = 'L';
07901    if (myrpt->powerlevel == REM_HIPWR) pwr = 'H';
07902    if (!res)
07903    {
07904       sprintf(rigstr,"SETFREQ %s %f %s %s %c",myrpt->freq,txfreq,
07905          (myrpt->rxplon) ? myrpt->rxpl : "0.0",
07906          (myrpt->txplon) ? myrpt->txpl : "0.0",pwr);
07907       send_usb_txt(myrpt,rigstr);
07908       rpt_telemetry(myrpt,COMPLETE,NULL);
07909       res = 0;
07910    }
07911    return 0;
07912 }
07913 #if 0
07914 /*
07915    sets current signaling code for xpmr routines
07916    under development for new radios.
07917 */
07918 static int setxpmr(struct rpt *myrpt)
07919 {
07920    char rigstr[200];
07921    int rxpl,txpl;
07922 
07923    /* must be a remote system */
07924    if (!myrpt->remoterig) return(0);
07925    if (!myrpt->remoterig[0]) return(0);
07926    /* must not have rtx hardware */
07927    if (ISRIG_RTX(myrpt->remoterig)) return(0);
07928    /* must be a usbradio interface type */
07929    if (!IS_XPMR(myrpt)) return(0);
07930    
07931    if(debug)printf("setxpmr() %s %s\n",myrpt->name,myrpt->remoterig );
07932 
07933    rxpl = rbi_pltocode(myrpt->rxpl);
07934    
07935    if (rxpl == -1){
07936       if(debug)
07937          printf("@@@@ Bad RX PL: %s\n", myrpt->rxpl);
07938       return -1;
07939    }
07940 
07941    txpl = rbi_pltocode(myrpt->txpl);
07942    if (txpl == -1){
07943       if(debug)
07944          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
07945       return -1;
07946    }
07947    sprintf(rigstr,"SETFREQ 0.0 0.0 %s %s L",
07948       (myrpt->rxplon) ? myrpt->rxpl : "0.0",
07949       (myrpt->txplon) ? myrpt->txpl : "0.0");
07950    send_usb_txt(myrpt,rigstr);
07951    return 0;
07952 }
07953 #endif
07954 
07955 static int setrbi_check(struct rpt *myrpt)
07956 {
07957 char tmp[MAXREMSTR] = "",*s;
07958 int   band,txpl;
07959 
07960    /* must be a remote system */
07961    if (!myrpt->remote) return(0);
07962    /* must have rbi hardware */
07963    if (strncmp(myrpt->remoterig,remote_rig_rbi,3)) return(0);
07964    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
07965    s = strchr(tmp,'.');
07966    /* if no decimal, is invalid */
07967    
07968    if (s == NULL){
07969       if(debug)
07970          printf("@@@@ Frequency needs a decimal\n");
07971       return -1;
07972    }
07973    
07974    *s++ = 0;
07975    if (strlen(tmp) < 2){
07976       if(debug)
07977          printf("@@@@ Bad MHz digits: %s\n", tmp);
07978       return -1;
07979    }
07980     
07981    if (strlen(s) < 3){
07982       if(debug)
07983          printf("@@@@ Bad KHz digits: %s\n", s);
07984       return -1;
07985    }
07986 
07987    if ((s[2] != '0') && (s[2] != '5')){
07988       if(debug)
07989          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
07990       return -1;
07991    }
07992     
07993    band = rbi_mhztoband(tmp);
07994    if (band == -1){
07995       if(debug)
07996          printf("@@@@ Bad Band: %s\n", tmp);
07997       return -1;
07998    }
07999    
08000    txpl = rbi_pltocode(myrpt->txpl);
08001    
08002    if (txpl == -1){
08003       if(debug)
08004          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
08005       return -1;
08006    }
08007    return 0;
08008 }
08009 
08010 static int setrtx_check(struct rpt *myrpt)
08011 {
08012 char tmp[MAXREMSTR] = "",*s;
08013 int   band,txpl,rxpl;
08014 
08015    /* must be a remote system */
08016    if (!myrpt->remote) return(0);
08017    /* must have rbi hardware */
08018    if (strncmp(myrpt->remoterig,remote_rig_rbi,3)) return(0);
08019    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
08020    s = strchr(tmp,'.');
08021    /* if no decimal, is invalid */
08022    
08023    if (s == NULL){
08024       if(debug)
08025          printf("@@@@ Frequency needs a decimal\n");
08026       return -1;
08027    }
08028    
08029    *s++ = 0;
08030    if (strlen(tmp) < 2){
08031       if(debug)
08032          printf("@@@@ Bad MHz digits: %s\n", tmp);
08033       return -1;
08034    }
08035     
08036    if (strlen(s) < 3){
08037       if(debug)
08038          printf("@@@@ Bad KHz digits: %s\n", s);
08039       return -1;
08040    }
08041 
08042    if ((s[2] != '0') && (s[2] != '5')){
08043       if(debug)
08044          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
08045       return -1;
08046    }
08047     
08048    band = rbi_mhztoband(tmp);
08049    if (band == -1){
08050       if(debug)
08051          printf("@@@@ Bad Band: %s\n", tmp);
08052       return -1;
08053    }
08054    
08055    txpl = rbi_pltocode(myrpt->txpl);
08056    
08057    if (txpl == -1){
08058       if(debug)
08059          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
08060       return -1;
08061    }
08062 
08063    rxpl = rbi_pltocode(myrpt->rxpl);
08064    
08065    if (rxpl == -1){
08066       if(debug)
08067          printf("@@@@ Bad RX PL: %s\n", myrpt->rxpl);
08068       return -1;
08069    }
08070    return 0;
08071 }
08072 
08073 static int check_freq_kenwood(int m, int d, int *defmode)
08074 {
08075    int dflmd = REM_MODE_FM;
08076 
08077    if (m == 144){ /* 2 meters */
08078       if(d < 10100)
08079          return -1;
08080    }
08081    else if((m >= 145) && (m < 148)){
08082       ;
08083    }
08084    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
08085       ;
08086    }
08087    else
08088       return -1;
08089    
08090    if(defmode)
08091       *defmode = dflmd; 
08092 
08093 
08094    return 0;
08095 }
08096 
08097 
08098 static int check_freq_tm271(int m, int d, int *defmode)
08099 {
08100    int dflmd = REM_MODE_FM;
08101 
08102    if (m == 144){ /* 2 meters */
08103       if(d < 10100)
08104          return -1;
08105    }
08106    else if((m >= 145) && (m < 148)){
08107       ;
08108    }
08109       return -1;
08110    
08111    if(defmode)
08112       *defmode = dflmd; 
08113 
08114 
08115    return 0;
08116 }
08117 
08118 
08119 /* Check for valid rbi frequency */
08120 /* Hard coded limits now, configurable later, maybe? */
08121 
08122 static int check_freq_rbi(int m, int d, int *defmode)
08123 {
08124    int dflmd = REM_MODE_FM;
08125 
08126    if(m == 50){ /* 6 meters */
08127       if(d < 10100)
08128          return -1;
08129    }
08130    else if((m >= 51) && ( m < 54)){
08131                 ;
08132    }
08133    else if(m == 144){ /* 2 meters */
08134       if(d < 10100)
08135          return -1;
08136    }
08137    else if((m >= 145) && (m < 148)){
08138       ;
08139    }
08140    else if((m >= 222) && (m < 225)){ /* 1.25 meters */
08141       ;
08142    }
08143    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
08144       ;
08145    }
08146    else if((m >= 1240) && (m < 1300)){ /* 23 centimeters */
08147       ;
08148    }
08149    else
08150       return -1;
08151    
08152    if(defmode)
08153       *defmode = dflmd; 
08154 
08155 
08156    return 0;
08157 }
08158 
08159 /* Check for valid rtx frequency */
08160 /* Hard coded limits now, configurable later, maybe? */
08161 
08162 static int check_freq_rtx(int m, int d, int *defmode, struct rpt *myrpt)
08163 {
08164    int dflmd = REM_MODE_FM;
08165 
08166    if (!strcmp(myrpt->remoterig,remote_rig_rtx150))
08167    {
08168 
08169       if(m == 144){ /* 2 meters */
08170          if(d < 10100)
08171             return -1;
08172       }
08173       else if((m >= 145) && (m < 148)){
08174          ;
08175       }
08176       else
08177          return -1;
08178    }
08179    else 
08180    {
08181       if((m >= 430) && (m < 450)){ /* 70 centimeters */
08182          ;
08183       }
08184       else
08185          return -1;
08186    }
08187    if(defmode)
08188       *defmode = dflmd; 
08189 
08190 
08191    return 0;
08192 }
08193 
08194 /*
08195  * Convert decimals of frequency to int
08196  */
08197 
08198 static int decimals2int(char *fraction)
08199 {
08200    int i;
08201    char len = strlen(fraction);
08202    int multiplier = 100000;
08203    int res = 0;
08204 
08205    if(!len)
08206       return 0;
08207    for( i = 0 ; i < len ; i++, multiplier /= 10)
08208       res += (fraction[i] - '0') * multiplier;
08209    return res;
08210 }
08211 
08212 
08213 /*
08214 * Split frequency into mhz and decimals
08215 */
08216  
08217 static int split_freq(char *mhz, char *decimals, char *freq)
08218 {
08219    char freq_copy[MAXREMSTR];
08220    char *decp;
08221 
08222    decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
08223    if(decp){
08224       *decp++ = 0;
08225       strncpy(mhz, freq_copy, MAXREMSTR);
08226       strcpy(decimals, "00000");
08227       strncpy(decimals, decp, strlen(decp));
08228       decimals[5] = 0;
08229       return 0;
08230    }
08231    else
08232       return -1;
08233 
08234 }
08235    
08236 /*
08237 * Split ctcss frequency into hertz and decimal
08238 */
08239  
08240 static int split_ctcss_freq(char *hertz, char *decimal, char *freq)
08241 {
08242    char freq_copy[MAXREMSTR];
08243    char *decp;
08244 
08245    decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
08246    if(decp){
08247       *decp++ = 0;
08248       strncpy(hertz, freq_copy, MAXREMSTR);
08249       strncpy(decimal, decp, strlen(decp));
08250       decimal[strlen(decp)] = '\0';
08251       return 0;
08252    }
08253    else
08254       return -1;
08255 }
08256 
08257 
08258 
08259 /*
08260 * FT-897 I/O handlers
08261 */
08262 
08263 /* Check to see that the frequency is valid */
08264 /* Hard coded limits now, configurable later, maybe? */
08265 
08266 
08267 static int check_freq_ft897(int m, int d, int *defmode)
08268 {
08269    int dflmd = REM_MODE_FM;
08270 
08271    if(m == 1){ /* 160 meters */
08272       dflmd =  REM_MODE_LSB; 
08273       if(d < 80000)
08274          return -1;
08275    }
08276    else if(m == 3){ /* 80 meters */
08277       dflmd = REM_MODE_LSB;
08278       if(d < 50000)
08279          return -1;
08280    }
08281    else if(m == 7){ /* 40 meters */
08282       dflmd = REM_MODE_LSB;
08283       if(d > 30000)
08284          return -1;
08285    }
08286    else if(m == 14){ /* 20 meters */
08287       dflmd = REM_MODE_USB;
08288       if(d > 35000)
08289          return -1;
08290    }
08291    else if(m == 18){ /* 17 meters */
08292       dflmd = REM_MODE_USB;
08293       if((d < 6800) || (d > 16800))
08294          return -1;
08295    }
08296    else if(m == 21){ /* 15 meters */
08297       dflmd = REM_MODE_USB;
08298       if((d < 20000) || (d > 45000))
08299          return -1;
08300    }
08301    else if(m == 24){ /* 12 meters */
08302       dflmd = REM_MODE_USB;
08303       if((d < 89000) || (d > 99000))
08304          return -1;
08305    }
08306    else if(m == 28){ /* 10 meters */
08307       dflmd = REM_MODE_USB;
08308    }
08309    else if(m == 29){ 
08310       if(d >= 51000)
08311          dflmd = REM_MODE_FM;
08312       else
08313          dflmd = REM_MODE_USB;
08314       if(d > 70000)
08315          return -1;
08316    }
08317    else if(m == 50){ /* 6 meters */
08318       if(d >= 30000)
08319          dflmd = REM_MODE_FM;
08320       else
08321          dflmd = REM_MODE_USB;
08322 
08323    }
08324    else if((m >= 51) && ( m < 54)){
08325       dflmd = REM_MODE_FM;
08326    }
08327    else if(m == 144){ /* 2 meters */
08328       if(d >= 30000)
08329          dflmd = REM_MODE_FM;
08330       else
08331          dflmd = REM_MODE_USB;
08332    }
08333    else if((m >= 145) && (m < 148)){
08334       dflmd = REM_MODE_FM;
08335    }
08336    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
08337       if(m  < 438)
08338          dflmd = REM_MODE_USB;
08339       else
08340          dflmd = REM_MODE_FM;
08341       ;
08342    }
08343    else
08344       return -1;
08345 
08346    if(defmode)
08347       *defmode = dflmd;
08348 
08349    return 0;
08350 }
08351 
08352 /*
08353 * Set a new frequency for the FT897
08354 */
08355 
08356 static int set_freq_ft897(struct rpt *myrpt, char *newfreq)
08357 {
08358    unsigned char cmdstr[5];
08359    int fd,m,d;
08360    char mhz[MAXREMSTR];
08361    char decimals[MAXREMSTR];
08362 
08363    fd = 0;
08364    if(debug) 
08365       printf("New frequency: %s\n",newfreq);
08366 
08367    if(split_freq(mhz, decimals, newfreq))
08368       return -1; 
08369 
08370    m = atoi(mhz);
08371    d = atoi(decimals);
08372 
08373    /* The FT-897 likes packed BCD frequencies */
08374 
08375    cmdstr[0] = ((m / 100) << 4) + ((m % 100)/10);        /* 100MHz 10Mhz */
08376    cmdstr[1] = ((m % 10) << 4) + (d / 10000);         /* 1MHz 100KHz */
08377    cmdstr[2] = (((d % 10000)/1000) << 4) + ((d % 1000)/ 100);  /* 10KHz 1KHz */
08378    cmdstr[3] = (((d % 100)/10) << 4) + (d % 10);         /* 100Hz 10Hz */
08379    cmdstr[4] = 0x01;                /* command */
08380 
08381    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08382 
08383 }
08384 
08385 /* ft-897 simple commands */
08386 
08387 static int simple_command_ft897(struct rpt *myrpt, char command)
08388 {
08389    unsigned char cmdstr[5];
08390    
08391    memset(cmdstr, 0, 5);
08392 
08393    cmdstr[4] = command; 
08394 
08395    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08396 
08397 }
08398 
08399 /* ft-897 offset */
08400 
08401 static int set_offset_ft897(struct rpt *myrpt, char offset)
08402 {
08403    unsigned char cmdstr[5];
08404    
08405    memset(cmdstr, 0, 5);
08406 
08407    switch(offset){
08408       case  REM_SIMPLEX:
08409          cmdstr[0] = 0x89;
08410          break;
08411 
08412       case  REM_MINUS:
08413          cmdstr[0] = 0x09;
08414          break;
08415       
08416       case  REM_PLUS:
08417          cmdstr[0] = 0x49;
08418          break;   
08419 
08420       default:
08421          return -1;
08422    }
08423 
08424    cmdstr[4] = 0x09; 
08425 
08426    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08427 }
08428 
08429 /* ft-897 mode */
08430 
08431 static int set_mode_ft897(struct rpt *myrpt, char newmode)
08432 {
08433    unsigned char cmdstr[5];
08434    
08435    memset(cmdstr, 0, 5);
08436    
08437    switch(newmode){
08438       case  REM_MODE_FM:
08439          cmdstr[0] = 0x08;
08440          break;
08441 
08442       case  REM_MODE_USB:
08443          cmdstr[0] = 0x01;
08444          break;
08445 
08446       case  REM_MODE_LSB:
08447          cmdstr[0] = 0x00;
08448          break;
08449 
08450       case  REM_MODE_AM:
08451          cmdstr[0] = 0x04;
08452          break;
08453       
08454       default:
08455          return -1;
08456    }
08457    cmdstr[4] = 0x07; 
08458 
08459    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08460 }
08461 
08462 /* Set tone encode and decode modes */
08463 
08464 static int set_ctcss_mode_ft897(struct rpt *myrpt, char txplon, char rxplon)
08465 {
08466    unsigned char cmdstr[5];
08467    
08468    memset(cmdstr, 0, 5);
08469    
08470    if(rxplon && txplon)
08471       cmdstr[0] = 0x2A; /* Encode and Decode */
08472    else if (!rxplon && txplon)
08473       cmdstr[0] = 0x4A; /* Encode only */
08474    else if (rxplon && !txplon)
08475       cmdstr[0] = 0x3A; /* Encode only */
08476    else
08477       cmdstr[0] = 0x8A; /* OFF */
08478 
08479    cmdstr[4] = 0x0A; 
08480 
08481    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08482 }
08483 
08484 
08485 /* Set transmit and receive ctcss tone frequencies */
08486 
08487 static int set_ctcss_freq_ft897(struct rpt *myrpt, char *txtone, char *rxtone)
08488 {
08489    unsigned char cmdstr[5];
08490    char hertz[MAXREMSTR],decimal[MAXREMSTR];
08491    int h,d; 
08492 
08493    memset(cmdstr, 0, 5);
08494 
08495    if(split_ctcss_freq(hertz, decimal, txtone))
08496       return -1; 
08497 
08498    h = atoi(hertz);
08499    d = atoi(decimal);
08500    
08501    cmdstr[0] = ((h / 100) << 4) + (h % 100)/ 10;
08502    cmdstr[1] = ((h % 10) << 4) + (d % 10);
08503    
08504    if(rxtone){
08505    
08506       if(split_ctcss_freq(hertz, decimal, rxtone))
08507          return -1; 
08508 
08509       h = atoi(hertz);
08510       d = atoi(decimal);
08511    
08512       cmdstr[2] = ((h / 100) << 4) + (h % 100)/ 10;
08513       cmdstr[3] = ((h % 10) << 4) + (d % 10);
08514    }
08515    cmdstr[4] = 0x0B; 
08516 
08517    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
08518 }  
08519 
08520 
08521 
08522 static int set_ft897(struct rpt *myrpt)
08523 {
08524    int res;
08525    
08526    if(debug)
08527       printf("@@@@ lock on\n");
08528 
08529    res = simple_command_ft897(myrpt, 0x00);  /* LOCK on */  
08530 
08531    if(debug)
08532       printf("@@@@ ptt off\n");
08533 
08534    if(!res)
08535       res = simple_command_ft897(myrpt, 0x88);     /* PTT off */
08536 
08537    if(debug)
08538       printf("Modulation mode\n");
08539 
08540    if(!res)
08541       res = set_mode_ft897(myrpt, myrpt->remmode);    /* Modulation mode */
08542 
08543    if(debug)
08544       printf("Split off\n");
08545 
08546    if(!res)
08547       simple_command_ft897(myrpt, 0x82);        /* Split off */
08548 
08549    if(debug)
08550       printf("Frequency\n");
08551 
08552    if(!res)
08553       res = set_freq_ft897(myrpt, myrpt->freq);    /* Frequency */
08554    if((myrpt->remmode == REM_MODE_FM)){
08555       if(debug)
08556          printf("Offset\n");
08557       if(!res)
08558          res = set_offset_ft897(myrpt, myrpt->offset);   /* Offset if FM */
08559       if((!res)&&(myrpt->rxplon || myrpt->txplon)){
08560          if(debug)
08561             printf("CTCSS tone freqs.\n");
08562          res = set_ctcss_freq_ft897(myrpt, myrpt->txpl, myrpt->rxpl); /* CTCSS freqs if CTCSS is enabled */
08563       }
08564       if(!res){
08565          if(debug)
08566             printf("CTCSS mode\n");
08567          res = set_ctcss_mode_ft897(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
08568       }
08569    }
08570    if((myrpt->remmode == REM_MODE_USB)||(myrpt->remmode == REM_MODE_LSB)){
08571       if(debug)
08572          printf("Clarifier off\n");
08573       simple_command_ft897(myrpt, 0x85);        /* Clarifier off if LSB or USB */
08574    }
08575    return res;
08576 }
08577 
08578 static int closerem_ft897(struct rpt *myrpt)
08579 {
08580    simple_command_ft897(myrpt, 0x88); /* PTT off */
08581    return 0;
08582 }  
08583 
08584 /*
08585 * Bump frequency up or down by a small amount 
08586 * Return 0 if the new frequnecy is valid, or -1 if invalid
08587 * Interval is in Hz, resolution is 10Hz 
08588 */
08589 
08590 static int multimode_bump_freq_ft897(struct rpt *myrpt, int interval)
08591 {
08592    int m,d;
08593    char mhz[MAXREMSTR], decimals[MAXREMSTR];
08594 
08595    if(debug)
08596       printf("Before bump: %s\n", myrpt->freq);
08597 
08598    if(split_freq(mhz, decimals, myrpt->freq))
08599       return -1;
08600    
08601    m = atoi(mhz);
08602    d = atoi(decimals);
08603 
08604    d += (interval / 10); /* 10Hz resolution */
08605    if(d < 0){
08606       m--;
08607       d += 100000;
08608    }
08609    else if(d >= 100000){
08610       m++;
08611       d -= 100000;
08612    }
08613 
08614    if(check_freq_ft897(m, d, NULL)){
08615       if(debug)
08616          printf("Bump freq invalid\n");
08617       return -1;
08618    }
08619 
08620    snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
08621 
08622    if(debug)
08623       printf("After bump: %s\n", myrpt->freq);
08624 
08625    return set_freq_ft897(myrpt, myrpt->freq);   
08626 }
08627 
08628 
08629 
08630 /*
08631 * IC-706 I/O handlers
08632 */
08633 
08634 /* Check to see that the frequency is valid */
08635 /* returns 0 if frequency is valid          */
08636 
08637 static int check_freq_ic706(int m, int d, int *defmode, char mars)
08638 {
08639    int dflmd = REM_MODE_FM;
08640    int rv=0;
08641 
08642    if(debug > 6)
08643       ast_log(LOG_NOTICE,"(%i,%i,%i,%i)\n",m,d,*defmode,mars);
08644 
08645    /* first test for standard amateur radio bands */
08646 
08647    if(m == 1){                /* 160 meters */
08648       dflmd =  REM_MODE_LSB; 
08649       if(d < 80000)rv=-1;
08650    }
08651    else if(m == 3){           /* 80 meters */
08652       dflmd = REM_MODE_LSB;
08653       if(d < 50000)rv=-1;
08654    }
08655    else if(m == 7){           /* 40 meters */
08656       dflmd = REM_MODE_LSB;
08657       if(d > 30000)rv=-1;
08658    }
08659    else if(m == 14){             /* 20 meters */
08660       dflmd = REM_MODE_USB;
08661       if(d > 35000)rv=-1;
08662    }
08663    else if(m == 18){                      /* 17 meters */
08664       dflmd = REM_MODE_USB;
08665       if((d < 6800) || (d > 16800))rv=-1;
08666    }
08667    else if(m == 21){ /* 15 meters */
08668       dflmd = REM_MODE_USB;
08669       if((d < 20000) || (d > 45000))rv=-1;
08670    }
08671    else if(m == 24){ /* 12 meters */
08672       dflmd = REM_MODE_USB;
08673       if((d < 89000) || (d > 99000))rv=-1;
08674    }
08675    else if(m == 28){                      /* 10 meters */
08676       dflmd = REM_MODE_USB;
08677    }
08678    else if(m == 29){ 
08679       if(d >= 51000)
08680          dflmd = REM_MODE_FM;
08681       else
08682          dflmd = REM_MODE_USB;
08683       if(d > 70000)rv=-1;
08684    }
08685    else if(m == 50){                      /* 6 meters */
08686       if(d >= 30000)
08687          dflmd = REM_MODE_FM;
08688       else
08689          dflmd = REM_MODE_USB;
08690    }
08691    else if((m >= 51) && ( m < 54)){
08692       dflmd = REM_MODE_FM;
08693    }
08694    else if(m == 144){ /* 2 meters */
08695       if(d >= 30000)
08696          dflmd = REM_MODE_FM;
08697       else
08698          dflmd = REM_MODE_USB;
08699    }
08700    else if((m >= 145) && (m < 148)){
08701       dflmd = REM_MODE_FM;
08702    }
08703    else if((m >= 430) && (m < 450)){         /* 70 centimeters */
08704       if(m  < 438)
08705          dflmd = REM_MODE_USB;
08706       else
08707          dflmd = REM_MODE_FM;
08708    }
08709 
08710    /* check expanded coverage */
08711    if(mars && rv<0){
08712       if((m >= 450) && (m < 470)){        /* LMR */
08713          dflmd = REM_MODE_FM;
08714          rv=0;
08715       }
08716       else if((m >= 148) && (m < 174)){      /* LMR */
08717          dflmd = REM_MODE_FM;
08718          rv=0;
08719       }
08720       else if((m >= 138) && (m < 144)){      /* VHF-AM AIRCRAFT */
08721          dflmd = REM_MODE_AM;
08722          rv=0;
08723       }
08724       else if((m >= 108) && (m < 138)){      /* VHF-AM AIRCRAFT */
08725          dflmd = REM_MODE_AM;
08726          rv=0;
08727       }
08728       else if( (m==0 && d>=55000) || (m==1 && d<=75000) ){  /* AM BCB*/
08729          dflmd = REM_MODE_AM;
08730          rv=0;
08731       }
08732       else if( (m == 1 && d>75000) || (m>1 && m<30) ){      /* HF SWL*/
08733          dflmd = REM_MODE_AM;
08734          rv=0;
08735       }
08736    }
08737 
08738    if(defmode)
08739       *defmode = dflmd;
08740 
08741    if(debug > 1)
08742       ast_log(LOG_NOTICE,"(%i,%i,%i,%i) returning %i\n",m,d,*defmode,mars,rv);
08743 
08744    return rv;
08745 }
08746 
08747 /* take a PL frequency and turn it into a code */
08748 static int ic706_pltocode(char *str)
08749 {
08750    int i;
08751    char *s;
08752    int rv=-1;
08753 
08754    s = strchr(str,'.');
08755    i = 0;
08756    if (s) i = atoi(s + 1);
08757    i += atoi(str) * 10;
08758    switch(i)
08759    {
08760        case 670:
08761          rv=0;
08762        case 693:
08763          rv=1;
08764        case 719:
08765          rv=2;
08766        case 744:
08767          rv=3;
08768        case 770:
08769          rv=4;
08770        case 797:
08771          rv=5;
08772        case 825:
08773          rv=6;
08774        case 854:
08775          rv=7;
08776        case 885:
08777          rv=8;
08778        case 915:
08779          rv=9;
08780        case 948:
08781          rv=10;
08782        case 974:
08783          rv=11;
08784        case 1000:
08785          rv=12;
08786        case 1035:
08787          rv=13;
08788        case 1072:
08789          rv=14;
08790        case 1109:
08791          rv=15;
08792        case 1148:
08793          rv=16;
08794        case 1188:
08795          rv=17;
08796        case 1230:
08797          rv=18;
08798        case 1273:
08799          rv=19;
08800        case 1318:
08801          rv=20;
08802        case 1365:
08803          rv=21;
08804        case 1413:
08805          rv=22;
08806        case 1462:
08807          rv=23;
08808        case 1514:
08809          rv=24;
08810        case 1567:
08811          rv=25;
08812        case 1598:
08813          rv=26;
08814        case 1622:
08815          rv=27;
08816        case 1655:
08817          rv=28;      
08818        case 1679:
08819          rv=29;
08820        case 1713:
08821          rv=30;
08822        case 1738:
08823          rv=31;
08824        case 1773:
08825          rv=32;
08826        case 1799:
08827          rv=33;
08828         case 1835:
08829          rv=34;
08830        case 1862:
08831          rv=35;
08832        case 1899:
08833          rv=36;
08834        case 1928:
08835          rv=37;
08836        case 1966:
08837          rv=38;
08838        case 1995:
08839          rv=39;
08840        case 2035:
08841          rv=40;
08842        case 2065:
08843          rv=41;
08844        case 2107:
08845          rv=42;
08846        case 2181:
08847          rv=43;
08848        case 2257:
08849          rv=44;
08850        case 2291:
08851          rv=45;
08852        case 2336:
08853          rv=46;
08854        case 2418:
08855          rv=47;
08856        case 2503:
08857          rv=48;
08858        case 2541:
08859          rv=49;
08860    }
08861    if(debug > 1)
08862       ast_log(LOG_NOTICE,"%i  rv=%i\n",i, rv);
08863 
08864    return rv;
08865 }
08866 
08867 /* ic-706 simple commands */
08868 
08869 static int simple_command_ic706(struct rpt *myrpt, char command, char subcommand)
08870 {
08871    unsigned char cmdstr[10];
08872    
08873    cmdstr[0] = cmdstr[1] = 0xfe;
08874    cmdstr[2] = myrpt->p.civaddr;
08875    cmdstr[3] = 0xe0;
08876    cmdstr[4] = command;
08877    cmdstr[5] = subcommand;
08878    cmdstr[6] = 0xfd;
08879 
08880    return(civ_cmd(myrpt,cmdstr,7));
08881 }
08882 
08883 /*
08884 * Set a new frequency for the ic706
08885 */
08886 
08887 static int set_freq_ic706(struct rpt *myrpt, char *newfreq)
08888 {
08889    unsigned char cmdstr[20];
08890    char mhz[MAXREMSTR], decimals[MAXREMSTR];
08891    int fd,m,d;
08892 
08893    fd = 0;
08894    if(debug) 
08895       ast_log(LOG_NOTICE,"newfreq:%s\n",newfreq);        
08896 
08897    if(split_freq(mhz, decimals, newfreq))
08898       return -1; 
08899 
08900    m = atoi(mhz);
08901    d = atoi(decimals);
08902 
08903    /* The ic-706 likes packed BCD frequencies */
08904 
08905    cmdstr[0] = cmdstr[1] = 0xfe;
08906    cmdstr[2] = myrpt->p.civaddr;
08907    cmdstr[3] = 0xe0;
08908    cmdstr[4] = 5;
08909    cmdstr[5] = ((d % 10) << 4);
08910    cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
08911    cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
08912    cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
08913    cmdstr[9] = (m / 100);
08914    cmdstr[10] = 0xfd;
08915 
08916    return(civ_cmd(myrpt,cmdstr,11));
08917 }
08918 
08919 /* ic-706 offset */
08920 
08921 static int set_offset_ic706(struct rpt *myrpt, char offset)
08922 {
08923    unsigned char c;
08924 
08925    if(debug > 6)
08926       ast_log(LOG_NOTICE,"offset=%i\n",offset);
08927 
08928    switch(offset){
08929       case  REM_SIMPLEX:
08930          c = 0x10;
08931          break;
08932 
08933       case  REM_MINUS:
08934          c = 0x11;
08935          break;
08936       
08937       case  REM_PLUS:
08938          c = 0x12;
08939          break;   
08940 
08941       default:
08942          return -1;
08943    }
08944 
08945    return simple_command_ic706(myrpt,0x0f,c);
08946 
08947 }
08948 
08949 /* ic-706 mode */
08950 
08951 static int set_mode_ic706(struct rpt *myrpt, char newmode)
08952 {
08953    unsigned char c;
08954    
08955    if(debug > 6)
08956       ast_log(LOG_NOTICE,"newmode=%i\n",newmode);
08957 
08958    switch(newmode){
08959       case  REM_MODE_FM:
08960          c = 5;
08961          break;
08962 
08963       case  REM_MODE_USB:
08964          c = 1;
08965          break;
08966 
08967       case  REM_MODE_LSB:
08968          c = 0;
08969          break;
08970 
08971       case  REM_MODE_AM:
08972          c = 2;
08973          break;
08974       
08975       default:
08976          return -1;
08977    }
08978    return simple_command_ic706(myrpt,6,c);
08979 }
08980 
08981 /* Set tone encode and decode modes */
08982 
08983 static int set_ctcss_mode_ic706(struct rpt *myrpt, char txplon, char rxplon)
08984 {
08985    unsigned char cmdstr[10];
08986    int rv;
08987 
08988    if(debug > 6)
08989       ast_log(LOG_NOTICE,"txplon=%i  rxplon=%i \n",txplon,rxplon);
08990 
08991    cmdstr[0] = cmdstr[1] = 0xfe;
08992    cmdstr[2] = myrpt->p.civaddr;
08993    cmdstr[3] = 0xe0;
08994    cmdstr[4] = 0x16;
08995    cmdstr[5] = 0x42;
08996    cmdstr[6] = (txplon != 0);
08997    cmdstr[7] = 0xfd;
08998 
08999    rv = civ_cmd(myrpt,cmdstr,8);
09000    if (rv) return(-1);
09001 
09002    cmdstr[0] = cmdstr[1] = 0xfe;
09003    cmdstr[2] = myrpt->p.civaddr;
09004    cmdstr[3] = 0xe0;
09005    cmdstr[4] = 0x16;
09006    cmdstr[5] = 0x43;
09007    cmdstr[6] = (rxplon != 0);
09008    cmdstr[7] = 0xfd;
09009 
09010    return(civ_cmd(myrpt,cmdstr,8));
09011 }
09012 
09013 #if 0
09014 /* Set transmit and receive ctcss tone frequencies */
09015 
09016 static int set_ctcss_freq_ic706(struct rpt *myrpt, char *txtone, char *rxtone)
09017 {
09018    unsigned char cmdstr[10];
09019    char hertz[MAXREMSTR],decimal[MAXREMSTR];
09020    int h,d,rv;
09021 
09022    memset(cmdstr, 0, 5);
09023 
09024    if(debug > 6)
09025       ast_log(LOG_NOTICE,"txtone=%s  rxtone=%s \n",txtone,rxtone);
09026 
09027    if(split_ctcss_freq(hertz, decimal, txtone))
09028       return -1; 
09029 
09030    h = atoi(hertz);
09031    d = atoi(decimal);
09032    
09033    cmdstr[0] = cmdstr[1] = 0xfe;
09034    cmdstr[2] = myrpt->p.civaddr;
09035    cmdstr[3] = 0xe0;
09036    cmdstr[4] = 0x1b;
09037    cmdstr[5] = 0;
09038    cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
09039    cmdstr[7] = ((h % 10) << 4) + (d % 10);
09040    cmdstr[8] = 0xfd;
09041 
09042    rv = civ_cmd(myrpt,cmdstr,9);
09043    if (rv) return(-1);
09044 
09045    if (!rxtone) return(0);
09046 
09047    if(split_ctcss_freq(hertz, decimal, rxtone))
09048       return -1; 
09049 
09050    h = atoi(hertz);
09051    d = atoi(decimal);
09052 
09053    cmdstr[0] = cmdstr[1] = 0xfe;
09054    cmdstr[2] = myrpt->p.civaddr;
09055    cmdstr[3] = 0xe0;
09056    cmdstr[4] = 0x1b;
09057    cmdstr[5] = 1;
09058    cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
09059    cmdstr[7] = ((h % 10) << 4) + (d % 10);
09060    cmdstr[8] = 0xfd;
09061    return(civ_cmd(myrpt,cmdstr,9));
09062 }  
09063 #endif
09064 
09065 static int vfo_ic706(struct rpt *myrpt)
09066 {
09067    unsigned char cmdstr[10];
09068    
09069    cmdstr[0] = cmdstr[1] = 0xfe;
09070    cmdstr[2] = myrpt->p.civaddr;
09071    cmdstr[3] = 0xe0;
09072    cmdstr[4] = 7;
09073    cmdstr[5] = 0xfd;
09074 
09075    return(civ_cmd(myrpt,cmdstr,6));
09076 }
09077 
09078 static int mem2vfo_ic706(struct rpt *myrpt)
09079 {
09080    unsigned char cmdstr[10];
09081    
09082    cmdstr[0] = cmdstr[1] = 0xfe;
09083    cmdstr[2] = myrpt->p.civaddr;
09084    cmdstr[3] = 0xe0;
09085    cmdstr[4] = 0x0a;
09086    cmdstr[5] = 0xfd;
09087 
09088    return(civ_cmd(myrpt,cmdstr,6));
09089 }
09090 
09091 static int select_mem_ic706(struct rpt *myrpt, int slot)
09092 {
09093    unsigned char cmdstr[10];
09094    
09095    cmdstr[0] = cmdstr[1] = 0xfe;
09096    cmdstr[2] = myrpt->p.civaddr;
09097    cmdstr[3] = 0xe0;
09098    cmdstr[4] = 8;
09099    cmdstr[5] = 0;
09100    cmdstr[6] = ((slot / 10) << 4) + (slot % 10);
09101    cmdstr[7] = 0xfd;
09102 
09103    return(civ_cmd(myrpt,cmdstr,8));
09104 }
09105 
09106 static int set_ic706(struct rpt *myrpt)
09107 {
09108    int res = 0,i;
09109    
09110    if(debug)ast_log(LOG_NOTICE, "Set to VFO A iobase=%i\n",myrpt->p.iobase);
09111 
09112    if (!res)
09113       res = simple_command_ic706(myrpt,7,0);
09114 
09115    if((myrpt->remmode == REM_MODE_FM))
09116    {
09117       i = ic706_pltocode(myrpt->rxpl);
09118       if (i == -1) return -1;
09119       if(debug)
09120          printf("Select memory number\n");
09121       if (!res)
09122          res = select_mem_ic706(myrpt,i + IC706_PL_MEMORY_OFFSET);
09123       if(debug)
09124          printf("Transfer memory to VFO\n");
09125       if (!res)
09126          res = mem2vfo_ic706(myrpt);
09127    }
09128       
09129    if(debug)
09130       printf("Set to VFO\n");
09131 
09132    if (!res)
09133       res = vfo_ic706(myrpt);
09134 
09135    if(debug)
09136       printf("Modulation mode\n");
09137 
09138    if (!res)
09139       res = set_mode_ic706(myrpt, myrpt->remmode);    /* Modulation mode */
09140 
09141    if(debug)
09142       printf("Split off\n");
09143 
09144    if(!res)
09145       simple_command_ic706(myrpt, 0x82,0);         /* Split off */
09146 
09147    if(debug)
09148       printf("Frequency\n");
09149 
09150    if(!res)
09151       res = set_freq_ic706(myrpt, myrpt->freq);    /* Frequency */
09152    if((myrpt->remmode == REM_MODE_FM)){
09153       if(debug)
09154          printf("Offset\n");
09155       if(!res)
09156          res = set_offset_ic706(myrpt, myrpt->offset);   /* Offset if FM */
09157       if(!res){
09158          if(debug)
09159             printf("CTCSS mode\n");
09160          res = set_ctcss_mode_ic706(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
09161       }
09162    }
09163    return res;
09164 }
09165 
09166 /*
09167 * Bump frequency up or down by a small amount 
09168 * Return 0 if the new frequnecy is valid, or -1 if invalid
09169 * Interval is in Hz, resolution is 10Hz 
09170 */
09171 
09172 static int multimode_bump_freq_ic706(struct rpt *myrpt, int interval)
09173 {
09174    int m,d;
09175    char mhz[MAXREMSTR], decimals[MAXREMSTR];
09176    unsigned char cmdstr[20];
09177 
09178    if(debug)
09179       printf("Before bump: %s\n", myrpt->freq);
09180 
09181    if(split_freq(mhz, decimals, myrpt->freq))
09182       return -1;
09183    
09184    m = atoi(mhz);
09185    d = atoi(decimals);
09186 
09187    d += (interval / 10); /* 10Hz resolution */
09188    if(d < 0){
09189       m--;
09190       d += 100000;
09191    }
09192    else if(d >= 100000){
09193       m++;
09194       d -= 100000;
09195    }
09196 
09197    if(check_freq_ic706(m, d, NULL,myrpt->p.remote_mars)){
09198       if(debug)
09199          printf("Bump freq invalid\n");
09200       return -1;
09201    }
09202 
09203    snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
09204 
09205    if(debug)
09206       printf("After bump: %s\n", myrpt->freq);
09207 
09208    /* The ic-706 likes packed BCD frequencies */
09209 
09210    cmdstr[0] = cmdstr[1] = 0xfe;
09211    cmdstr[2] = myrpt->p.civaddr;
09212    cmdstr[3] = 0xe0;
09213    cmdstr[4] = 0;
09214    cmdstr[5] = ((d % 10) << 4);
09215    cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
09216    cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
09217    cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
09218    cmdstr[9] = (m / 100);
09219    cmdstr[10] = 0xfd;
09220 
09221    return(serial_remote_io(myrpt,cmdstr,11,NULL,0,0));
09222 }
09223 
09224 
09225 
09226 /*
09227 * Dispatch to correct I/O handler 
09228 */
09229 static int setrem(struct rpt *myrpt)
09230 {
09231 char  str[300];
09232 char  *offsets[] = {"SIMPLEX","MINUS","PLUS"};
09233 char  *powerlevels[] = {"LOW","MEDIUM","HIGH"};
09234 char  *modes[] = {"FM","USB","LSB","AM"};
09235 int   res = -1;
09236 
09237 #if   0
09238 printf("FREQ,%s,%s,%s,%s,%s,%s,%d,%d\n",myrpt->freq,
09239    modes[(int)myrpt->remmode],
09240    myrpt->txpl,myrpt->rxpl,offsets[(int)myrpt->offset],
09241    powerlevels[(int)myrpt->powerlevel],myrpt->txplon,
09242    myrpt->rxplon);
09243 #endif
09244    if (myrpt->p.archivedir)
09245    {
09246       sprintf(str,"FREQ,%s,%s,%s,%s,%s,%s,%d,%d",myrpt->freq,
09247          modes[(int)myrpt->remmode],
09248          myrpt->txpl,myrpt->rxpl,offsets[(int)myrpt->offset],
09249          powerlevels[(int)myrpt->powerlevel],myrpt->txplon,
09250          myrpt->rxplon);
09251       donodelog(myrpt,str);
09252    }
09253    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09254    {
09255       rpt_telemetry(myrpt,SETREMOTE,NULL);
09256       res = 0;
09257    }
09258    if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09259    {
09260       rpt_telemetry(myrpt,SETREMOTE,NULL);
09261       res = 0;
09262    }
09263    if(!strcmp(myrpt->remoterig, remote_rig_tm271))
09264    {
09265       rpt_telemetry(myrpt,SETREMOTE,NULL);
09266       res = 0;
09267    }
09268    else if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09269    {
09270       res = setrbi_check(myrpt);
09271       if (!res)
09272       {
09273          rpt_telemetry(myrpt,SETREMOTE,NULL);
09274          res = 0;
09275       }
09276    }
09277    else if(ISRIG_RTX(myrpt->remoterig))
09278    {
09279       setrtx(myrpt);
09280       res = 0;
09281    }
09282    else if(!strcmp(myrpt->remoterig, remote_rig_kenwood)) {
09283       rpt_telemetry(myrpt,SETREMOTE,NULL);
09284       res = 0;
09285    }
09286    else
09287       res = 0;
09288 
09289    if (res < 0) ast_log(LOG_ERROR,"Unable to send remote command on node %s\n",myrpt->name);
09290 
09291    return res;
09292 }
09293 
09294 static int closerem(struct rpt *myrpt)
09295 {
09296    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09297       return closerem_ft897(myrpt);
09298    else
09299       return 0;
09300 }
09301 
09302 /*
09303 * Dispatch to correct RX frequency checker
09304 */
09305 
09306 static int check_freq(struct rpt *myrpt, int m, int d, int *defmode)
09307 {
09308    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09309       return check_freq_ft897(m, d, defmode);
09310    else if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09311       return check_freq_ic706(m, d, defmode,myrpt->p.remote_mars);
09312    else if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09313       return check_freq_rbi(m, d, defmode);
09314    else if(!strcmp(myrpt->remoterig, remote_rig_kenwood))
09315       return check_freq_kenwood(m, d, defmode);
09316    else if(!strcmp(myrpt->remoterig, remote_rig_tm271))
09317       return check_freq_tm271(m, d, defmode);
09318    else if(ISRIG_RTX(myrpt->remoterig))
09319       return check_freq_rtx(m, d, defmode, myrpt);
09320    else
09321       return -1;
09322 }
09323 
09324 /*
09325  * Check TX frequency before transmitting
09326    rv=1 if tx frequency in ok.
09327 */
09328 
09329 static char check_tx_freq(struct rpt *myrpt)
09330 {
09331    int i,rv=0;
09332    int radio_mhz, radio_decimals, ulimit_mhz, ulimit_decimals, llimit_mhz, llimit_decimals;
09333    char radio_mhz_char[MAXREMSTR];
09334    char radio_decimals_char[MAXREMSTR];
09335    char limit_mhz_char[MAXREMSTR];
09336    char limit_decimals_char[MAXREMSTR];
09337    char limits[256];
09338    char *limit_ranges[40];
09339    struct ast_variable *limitlist;
09340    
09341    if(debug > 3){
09342       ast_log(LOG_NOTICE, "myrpt->freq = %s\n", myrpt->freq);
09343    }
09344 
09345    /* Must have user logged in and tx_limits defined */
09346 
09347    if(!myrpt->p.txlimitsstanzaname || !myrpt->loginuser[0] || !myrpt->loginlevel[0]){
09348       if(debug > 3){
09349          ast_log(LOG_NOTICE, "No tx band table defined, or no user logged in. rv=1\n");
09350       }
09351       rv=1;
09352       return 1; /* Assume it's ok otherwise */
09353    }
09354 
09355    /* Retrieve the band table for the loginlevel */
09356    limitlist = ast_variable_browse(myrpt->cfg, myrpt->p.txlimitsstanzaname);
09357 
09358    if(!limitlist){
09359       ast_log(LOG_WARNING, "No entries in %s band table stanza. rv=0\n", myrpt->p.txlimitsstanzaname);
09360       rv=0;
09361       return 0;
09362    }
09363 
09364    split_freq(radio_mhz_char, radio_decimals_char, myrpt->freq);
09365    radio_mhz = atoi(radio_mhz_char);
09366    radio_decimals = decimals2int(radio_decimals_char);
09367 
09368    if(debug > 3){
09369       ast_log(LOG_NOTICE, "Login User = %s, login level = %s\n", myrpt->loginuser, myrpt->loginlevel);
09370    }
09371 
09372    /* Find our entry */
09373 
09374    for(;limitlist; limitlist=limitlist->next){
09375       if(!strcmp(limitlist->name, myrpt->loginlevel))
09376          break;
09377    }
09378 
09379    if(!limitlist){
09380       ast_log(LOG_WARNING, "Can't find %s entry in band table stanza %s. rv=0\n", myrpt->loginlevel, myrpt->p.txlimitsstanzaname);
09381       rv=0;
09382        return 0;
09383    }
09384    
09385    if(debug > 3){
09386       ast_log(LOG_NOTICE, "Auth: %s = %s\n", limitlist->name, limitlist->value);
09387    }
09388 
09389    /* Parse the limits */
09390 
09391    strncpy(limits, limitlist->value, 256);
09392    limits[255] = 0;
09393    finddelim(limits, limit_ranges, 40);
09394    for(i = 0; i < 40 && limit_ranges[i] ; i++){
09395       char range[40];
09396       char *r,*s;
09397       strncpy(range, limit_ranges[i], 40);
09398       range[39] = 0;
09399         if(debug > 3) 
09400          ast_log(LOG_NOTICE, "Check %s within %s\n", myrpt->freq, range);
09401    
09402       r = strchr(range, '-');
09403       if(!r){
09404          ast_log(LOG_WARNING, "Malformed range in %s tx band table entry. rv=0\n", limitlist->name);
09405          rv=0;
09406          break;
09407       }
09408       *r++ = 0;
09409       s = eatwhite(range);
09410       r = eatwhite(r);
09411       split_freq(limit_mhz_char, limit_decimals_char, s);
09412       llimit_mhz = atoi(limit_mhz_char);
09413       llimit_decimals = decimals2int(limit_decimals_char);
09414       split_freq(limit_mhz_char, limit_decimals_char, r);
09415       ulimit_mhz = atoi(limit_mhz_char);
09416       ulimit_decimals = decimals2int(limit_decimals_char);
09417          
09418       if((radio_mhz >= llimit_mhz) && (radio_mhz <= ulimit_mhz)){
09419          if(radio_mhz == llimit_mhz){ /* CASE 1: TX freq is in llimit mhz portion of band */
09420             if(radio_decimals >= llimit_decimals){ /* Cannot be below llimit decimals */
09421                if(llimit_mhz == ulimit_mhz){ /* If bandwidth < 1Mhz, check ulimit decimals */
09422                   if(radio_decimals <= ulimit_decimals){
09423                      rv=1;
09424                      break;
09425                   }
09426                   else{
09427                      if(debug > 3)
09428                         ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 1\n");
09429                      rv=0;
09430                      break;
09431                   }
09432                }
09433                else{
09434                   rv=1;
09435                   break;
09436                }
09437             }
09438             else{ /* Is below llimit decimals */
09439                if(debug > 3)
09440                   ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 2\n");
09441                rv=0;
09442                break;
09443             }
09444          }
09445          else if(radio_mhz == ulimit_mhz){ /* CASE 2: TX freq not in llimit mhz portion of band */
09446             if(radio_decimals <= ulimit_decimals){
09447                if(debug > 3)
09448                   ast_log(LOG_NOTICE, "radio_decimals <= ulimit_decimals\n");
09449                rv=1;
09450                break;
09451             }
09452             else{ /* Is above ulimit decimals */
09453                if(debug > 3)
09454                   ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 3\n");
09455                rv=0;
09456                break;
09457             }
09458          }
09459          else /* CASE 3: TX freq within a multi-Mhz band and ok */
09460             if(debug > 3)
09461                   ast_log(LOG_NOTICE, "Valid TX freq within a multi-Mhz band and ok.\n");
09462             rv=1;
09463             break;
09464       }
09465    }
09466    if(debug > 3)  
09467       ast_log(LOG_NOTICE, "rv=%i\n",rv);
09468 
09469    return rv;
09470 }
09471 
09472 
09473 /*
09474 * Dispatch to correct frequency bumping function
09475 */
09476 
09477 static int multimode_bump_freq(struct rpt *myrpt, int interval)
09478 {
09479    if(!strcmp(myrpt->remoterig, remote_rig_ft897))
09480       return multimode_bump_freq_ft897(myrpt, interval);
09481    else if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09482       return multimode_bump_freq_ic706(myrpt, interval);
09483    else
09484       return -1;
09485 }
09486 
09487 
09488 /*
09489 * Queue announcment that scan has been stopped 
09490 */
09491 
09492 static void stop_scan(struct rpt *myrpt)
09493 {
09494    myrpt->hfscanstop = 1;
09495    rpt_telemetry(myrpt,SCAN,0);
09496 }
09497 
09498 /*
09499 * This is called periodically when in scan mode
09500 */
09501 
09502 
09503 static int service_scan(struct rpt *myrpt)
09504 {
09505    int res, interval;
09506    char mhz[MAXREMSTR], decimals[MAXREMSTR], k10=0i, k100=0;
09507 
09508    switch(myrpt->hfscanmode){
09509 
09510       case HF_SCAN_DOWN_SLOW:
09511          interval = -10; /* 100Hz /sec */
09512          break;
09513 
09514       case HF_SCAN_DOWN_QUICK:
09515          interval = -50; /* 500Hz /sec */
09516          break;
09517 
09518       case HF_SCAN_DOWN_FAST:
09519          interval = -200; /* 2KHz /sec */
09520          break;
09521 
09522       case HF_SCAN_UP_SLOW:
09523          interval = 10; /* 100Hz /sec */
09524          break;
09525 
09526       case HF_SCAN_UP_QUICK:
09527          interval = 50; /* 500 Hz/sec */
09528          break;
09529 
09530       case HF_SCAN_UP_FAST:
09531          interval = 200; /* 2KHz /sec */
09532          break;
09533 
09534       default:
09535          myrpt->hfscanmode = 0; /* Huh? */
09536          return -1;
09537    }
09538 
09539    res = split_freq(mhz, decimals, myrpt->freq);
09540       
09541    if(!res){
09542       k100 =decimals[0];
09543       k10 = decimals[1];
09544       res = multimode_bump_freq(myrpt, interval);
09545    }
09546 
09547    if(!res)
09548       res = split_freq(mhz, decimals, myrpt->freq);
09549 
09550 
09551    if(res){
09552       myrpt->hfscanmode = 0;
09553       myrpt->hfscanstatus = -2;
09554       return -1;
09555    }
09556 
09557    /* Announce 10KHz boundaries */
09558    if(k10 != decimals[1]){
09559       int myhund = (interval < 0) ? k100 : decimals[0];
09560       int myten = (interval < 0) ? k10 : decimals[1];
09561       myrpt->hfscanstatus = (myten == '0') ? (myhund - '0') * 100 : (myten - '0') * 10;
09562    } else myrpt->hfscanstatus = 0;
09563    return res;
09564 
09565 }
09566 /*
09567    retrieve memory setting and set radio
09568 */
09569 static int get_mem_set(struct rpt *myrpt, char *digitbuf)
09570 {
09571    int res=0;
09572    if(debug)ast_log(LOG_NOTICE," digitbuf=%s\n", digitbuf);
09573    res = retreive_memory(myrpt, digitbuf);
09574    if(!res)res=setrem(myrpt); 
09575    if(debug)ast_log(LOG_NOTICE," freq=%s  res=%i\n", myrpt->freq, res);
09576    return res;
09577 }
09578 /*
09579    steer the radio selected channel to either one programmed into the radio
09580    or if the radio is VFO agile, to an rpt.conf memory location.
09581 */
09582 static int channel_steer(struct rpt *myrpt, char *data)
09583 {
09584    int res=0;
09585 
09586    if(debug)ast_log(LOG_NOTICE,"remoterig=%s, data=%s\n",myrpt->remoterig,data);
09587    if (!myrpt->remoterig) return(0);
09588    if(data<=0)
09589    {
09590       res=-1;
09591    }
09592    else
09593    {
09594       myrpt->nowchan=strtod(data,NULL);
09595       if(!strcmp(myrpt->remoterig, remote_rig_ppp16))
09596       {
09597          char string[16];
09598          sprintf(string,"SETCHAN %d ",myrpt->nowchan);
09599          send_usb_txt(myrpt,string);   
09600       }
09601       else
09602       {
09603          if(get_mem_set(myrpt, data))res=-1;
09604       }
09605    }
09606    if(debug)ast_log(LOG_NOTICE,"nowchan=%i  res=%i\n",myrpt->nowchan, res);
09607    return res;
09608 }
09609 /*
09610 */
09611 static int channel_revert(struct rpt *myrpt)
09612 {
09613    int res=0;
09614    if(debug)ast_log(LOG_NOTICE,"remoterig=%s, nowchan=%02d, waschan=%02d\n",myrpt->remoterig,myrpt->nowchan,myrpt->waschan);
09615    if (!myrpt->remoterig) return(0);
09616    if(myrpt->nowchan!=myrpt->waschan)
09617    {
09618       char data[8];
09619         if(debug)ast_log(LOG_NOTICE,"reverting.\n");
09620       sprintf(data,"%02d",myrpt->waschan);
09621       myrpt->nowchan=myrpt->waschan;
09622       channel_steer(myrpt,data);
09623       res=1;
09624    }
09625    return(res);
09626 }
09627 /*
09628 * Remote base function
09629 */
09630 
09631 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
09632 {
09633    char *s,*s1,*s2;
09634    int i,j,r,ht,k,l,ls2,m,d,offset,offsave, modesave, defmode=0;
09635    intptr_t p;
09636    char multimode = 0;
09637    char oc,*cp,*cp1,*cp2;
09638    char tmp[20], freq[20] = "", savestr[20] = "";
09639    char mhz[MAXREMSTR], decimals[MAXREMSTR];
09640 
09641     if(debug > 6) {
09642       ast_log(LOG_NOTICE,"%s param=%s digitbuf=%s source=%i\n",myrpt->name,param,digitbuf,command_source);
09643    }
09644 
09645    if((!param) || (command_source == SOURCE_RPT) || (command_source == SOURCE_LNK))
09646       return DC_ERROR;
09647       
09648    p = myatoi(param);
09649 
09650    if ((p != 99) && (p != 5) && (p != 140) && myrpt->p.authlevel && 
09651       (!myrpt->loginlevel[0])) return DC_ERROR;
09652    multimode = multimode_capable(myrpt);
09653 
09654    switch(p){
09655 
09656       case 1:  /* retrieve memory */
09657          if(strlen(digitbuf) < 2) /* needs 2 digits */
09658             break;
09659          
09660          for(i = 0 ; i < 2 ; i++){
09661             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09662                return DC_ERROR;
09663          }
09664          r=get_mem_set(myrpt, digitbuf);
09665          if (r < 0){
09666             rpt_telemetry(myrpt,MEMNOTFOUND,NULL);
09667             return DC_COMPLETE;
09668          }
09669          else if (r > 0){
09670             return DC_ERROR;
09671          }
09672          return DC_COMPLETE;  
09673          
09674       case 2:  /* set freq and offset */
09675       
09676          
09677             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for M+*K+*O or M+*H+* depending on mode */
09678             if(digitbuf[i] == '*'){
09679                j++;
09680                continue;
09681             }
09682             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09683                goto invalid_freq;
09684             else{
09685                if(j == 0)
09686                   l++; /* # of digits before first * */
09687                if(j == 1)
09688                   k++; /* # of digits after first * */
09689             }
09690          }
09691       
09692          i = strlen(digitbuf) - 1;
09693          if(multimode){
09694             if((j > 2) || (l > 3) || (k > 6))
09695                goto invalid_freq; /* &^@#! */
09696          }
09697          else{
09698             if((j > 2) || (l > 4) || (k > 3))
09699                goto invalid_freq; /* &^@#! */
09700          }
09701 
09702          /* Wait for M+*K+* */
09703 
09704          if(j < 2)
09705             break; /* Not yet */
09706 
09707          /* We have a frequency */
09708 
09709          strncpy(tmp, digitbuf ,sizeof(tmp) - 1);
09710          
09711          s = tmp;
09712          s1 = strsep(&s, "*"); /* Pick off MHz */
09713          s2 = strsep(&s,"*"); /* Pick off KHz and Hz */
09714          ls2 = strlen(s2); 
09715          
09716          switch(ls2){ /* Allow partial entry of khz and hz digits for laziness support */
09717             case 1:
09718                ht = 0;
09719                k = 100 * atoi(s2);
09720                break;
09721             
09722             case 2:
09723                ht = 0;
09724                k = 10 * atoi(s2);
09725                break;
09726                
09727             case 3:
09728                if(!multimode){
09729                   if((s2[2] != '0')&&(s2[2] != '5'))
09730                      goto invalid_freq;
09731                }
09732                ht = 0;
09733                k = atoi(s2);
09734                   break;
09735             case 4:
09736                k = atoi(s2)/10;
09737                ht = 10 * (atoi(s2+(ls2-1)));
09738                break;
09739 
09740             case 5:
09741                k = atoi(s2)/100;
09742                ht = (atoi(s2+(ls2-2)));
09743                break;
09744                
09745             default:
09746                goto invalid_freq;
09747          }
09748 
09749          /* Check frequency for validity and establish a default mode */
09750          
09751          snprintf(freq, sizeof(freq), "%s.%03d%02d",s1, k, ht);
09752 
09753          if(debug)
09754             ast_log(LOG_NOTICE, "New frequency: %s\n", freq);
09755    
09756          split_freq(mhz, decimals, freq);
09757          m = atoi(mhz);
09758          d = atoi(decimals);
09759 
09760          if(check_freq(myrpt, m, d, &defmode)) /* Check to see if frequency entered is legit */
09761                  goto invalid_freq;
09762 
09763 
09764          if((defmode == REM_MODE_FM) && (digitbuf[i] == '*')) /* If FM, user must enter and additional offset digit */
09765             break; /* Not yet */
09766 
09767 
09768          offset = REM_SIMPLEX; /* Assume simplex */
09769 
09770          if(defmode == REM_MODE_FM){
09771             oc = *s; /* Pick off offset */
09772          
09773             if (oc){
09774                switch(oc){
09775                   case '1':
09776                      offset = REM_MINUS;
09777                      break;
09778                   
09779                   case '2':
09780                      offset = REM_SIMPLEX;
09781                   break;
09782                   
09783                   case '3':
09784                      offset = REM_PLUS;
09785                      break;
09786                   
09787                   default:
09788                      goto invalid_freq;
09789                } 
09790             } 
09791          }  
09792          offsave = myrpt->offset;
09793          modesave = myrpt->remmode;
09794          strncpy(savestr, myrpt->freq, sizeof(savestr) - 1);
09795          strncpy(myrpt->freq, freq, sizeof(myrpt->freq) - 1);
09796          myrpt->offset = offset;
09797          myrpt->remmode = defmode;
09798 
09799          if (setrem(myrpt) == -1){
09800             myrpt->offset = offsave;
09801             myrpt->remmode = modesave;
09802             strncpy(myrpt->freq, savestr, sizeof(myrpt->freq) - 1);
09803             goto invalid_freq;
09804          }
09805 
09806          return DC_COMPLETE;
09807 
09808 invalid_freq:
09809          rpt_telemetry(myrpt,INVFREQ,NULL);
09810          return DC_ERROR; 
09811       
09812       case 3: /* set rx PL tone */
09813             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
09814             if(digitbuf[i] == '*'){
09815                j++;
09816                continue;
09817             }
09818             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09819                return DC_ERROR;
09820             else{
09821                if(j)
09822                   l++;
09823                else
09824                   k++;
09825             }
09826          }
09827          if((j > 1) || (k > 3) || (l > 1))
09828             return DC_ERROR; /* &$@^! */
09829          i = strlen(digitbuf) - 1;
09830          if((j != 1) || (k < 2)|| (l != 1))
09831             break; /* Not yet */
09832          if(debug)
09833             printf("PL digits entered %s\n", digitbuf);
09834             
09835          strncpy(tmp, digitbuf, sizeof(tmp) - 1);
09836          /* see if we have at least 1 */
09837          s = strchr(tmp,'*');
09838          if(s)
09839             *s = '.';
09840          strncpy(savestr, myrpt->rxpl, sizeof(savestr) - 1);
09841          strncpy(myrpt->rxpl, tmp, sizeof(myrpt->rxpl) - 1);
09842          if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09843          {
09844             strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
09845          }
09846          if (setrem(myrpt) == -1){
09847             strncpy(myrpt->rxpl, savestr, sizeof(myrpt->rxpl) - 1);
09848             return DC_ERROR;
09849          }
09850          return DC_COMPLETE;
09851       
09852       case 4: /* set tx PL tone */
09853          /* cant set tx tone on RBI (rx tone does both) */
09854          if(!strcmp(myrpt->remoterig, remote_rig_rbi))
09855             return DC_ERROR;
09856          /*  eventually for the ic706 instead of just throwing the exception
09857             we can check if we are in encode only mode and allow the tx
09858             ctcss code to be changed. but at least the warning message is
09859             issued for now.
09860          */
09861          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
09862          {
09863             if(debug)
09864                ast_log(LOG_WARNING,"Setting IC706 Tx CTCSS Code Not Supported. Set Rx Code for both.\n");
09865             return DC_ERROR;
09866          }
09867          for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
09868             if(digitbuf[i] == '*'){
09869                j++;
09870                continue;
09871             }
09872             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
09873                return DC_ERROR;
09874             else{
09875                if(j)
09876                   l++;
09877                else
09878                   k++;
09879             }
09880          }
09881          if((j > 1) || (k > 3) || (l > 1))
09882             return DC_ERROR; /* &$@^! */
09883          i = strlen(digitbuf) - 1;
09884          if((j != 1) || (k < 2)|| (l != 1))
09885             break; /* Not yet */
09886          if(debug)
09887             printf("PL digits entered %s\n", digitbuf);
09888             
09889          strncpy(tmp, digitbuf, sizeof(tmp) - 1);
09890          /* see if we have at least 1 */
09891          s = strchr(tmp,'*');
09892          if(s)
09893             *s = '.';
09894          strncpy(savestr, myrpt->txpl, sizeof(savestr) - 1);
09895          strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
09896          
09897          if (setrem(myrpt) == -1){
09898             strncpy(myrpt->txpl, savestr, sizeof(myrpt->txpl) - 1);
09899             return DC_ERROR;
09900          }
09901          return DC_COMPLETE;
09902       
09903 
09904       case 6: /* MODE (FM,USB,LSB,AM) */
09905          if(strlen(digitbuf) < 1)
09906             break;
09907 
09908          if(!multimode)
09909             return DC_ERROR; /* Multimode radios only */
09910 
09911          switch(*digitbuf){
09912             case '1':
09913                split_freq(mhz, decimals, myrpt->freq); 
09914                m=atoi(mhz);
09915                if(m < 29) /* No FM allowed below 29MHz! */
09916                   return DC_ERROR;
09917                myrpt->remmode = REM_MODE_FM;
09918                
09919                rpt_telemetry(myrpt,REMMODE,NULL);
09920                break;
09921 
09922             case '2':
09923                myrpt->remmode = REM_MODE_USB;
09924                rpt_telemetry(myrpt,REMMODE,NULL);
09925                break;   
09926 
09927             case '3':
09928                myrpt->remmode = REM_MODE_LSB;
09929                rpt_telemetry(myrpt,REMMODE,NULL);
09930                break;
09931             
09932             case '4':
09933                myrpt->remmode = REM_MODE_AM;
09934                rpt_telemetry(myrpt,REMMODE,NULL);
09935                break;
09936       
09937             default:
09938                return DC_ERROR;
09939          }
09940 
09941          if(setrem(myrpt))
09942             return DC_ERROR;
09943          return DC_COMPLETEQUIET;
09944       case 99:
09945          /* cant log in when logged in */
09946          if (myrpt->loginlevel[0]) 
09947             return DC_ERROR;
09948          *myrpt->loginuser = 0;
09949          myrpt->loginlevel[0] = 0;
09950          cp = ast_strdup(param);
09951          cp1 = strchr(cp,',');
09952          ast_mutex_lock(&myrpt->lock);
09953          if (cp1) 
09954          {
09955             *cp1 = 0;
09956             cp2 = strchr(cp1 + 1,',');
09957             if (cp2) 
09958             {
09959                *cp2 = 0;
09960                strncpy(myrpt->loginlevel,cp2 + 1,
09961                   sizeof(myrpt->loginlevel) - 1);
09962             }
09963             strncpy(myrpt->loginuser,cp1 + 1,sizeof(myrpt->loginuser));
09964             ast_mutex_unlock(&myrpt->lock);
09965             if (myrpt->p.archivedir)
09966             {
09967                char str[100];
09968 
09969                sprintf(str,"LOGIN,%s,%s",
09970                    myrpt->loginuser,myrpt->loginlevel);
09971                donodelog(myrpt,str);
09972             }
09973             if (debug) 
09974                printf("loginuser %s level %s\n",myrpt->loginuser,myrpt->loginlevel);
09975             rpt_telemetry(myrpt,REMLOGIN,NULL);
09976          }
09977          ast_free(cp);
09978          return DC_COMPLETEQUIET;
09979       case 100: /* RX PL Off */
09980          myrpt->rxplon = 0;
09981          setrem(myrpt);
09982          rpt_telemetry(myrpt,REMXXX,(void *)p);
09983          return DC_COMPLETEQUIET;
09984       case 101: /* RX PL On */
09985          myrpt->rxplon = 1;
09986          setrem(myrpt);
09987          rpt_telemetry(myrpt,REMXXX,(void *)p);
09988          return DC_COMPLETEQUIET;
09989       case 102: /* TX PL Off */
09990          myrpt->txplon = 0;
09991          setrem(myrpt);
09992          rpt_telemetry(myrpt,REMXXX,(void *)p);
09993          return DC_COMPLETEQUIET;
09994       case 103: /* TX PL On */
09995          myrpt->txplon = 1;
09996          setrem(myrpt);
09997          rpt_telemetry(myrpt,REMXXX,(void *)p);
09998          return DC_COMPLETEQUIET;
09999       case 104: /* Low Power */
10000          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
10001             return DC_ERROR;
10002          myrpt->powerlevel = REM_LOWPWR;
10003          setrem(myrpt);
10004          rpt_telemetry(myrpt,REMXXX,(void *)p);
10005          return DC_COMPLETEQUIET;
10006       case 105: /* Medium Power */
10007          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
10008             return DC_ERROR;
10009          if (ISRIG_RTX(myrpt->remoterig)) return DC_ERROR;
10010          myrpt->powerlevel = REM_MEDPWR;
10011          setrem(myrpt);
10012          rpt_telemetry(myrpt,REMXXX,(void *)p);
10013          return DC_COMPLETEQUIET;
10014       case 106: /* Hi Power */
10015          if(!strcmp(myrpt->remoterig, remote_rig_ic706))
10016             return DC_ERROR;
10017          myrpt->powerlevel = REM_HIPWR;
10018          setrem(myrpt);
10019          rpt_telemetry(myrpt,REMXXX,(void *)p);
10020          return DC_COMPLETEQUIET;
10021       case 107: /* Bump down 20Hz */
10022          multimode_bump_freq(myrpt, -20);
10023          return DC_COMPLETE;
10024       case 108: /* Bump down 100Hz */
10025          multimode_bump_freq(myrpt, -100);
10026          return DC_COMPLETE;
10027       case 109: /* Bump down 500Hz */
10028          multimode_bump_freq(myrpt, -500);
10029          return DC_COMPLETE;
10030       case 110: /* Bump up 20Hz */
10031          multimode_bump_freq(myrpt, 20);
10032          return DC_COMPLETE;
10033       case 111: /* Bump up 100Hz */
10034          multimode_bump_freq(myrpt, 100);
10035          return DC_COMPLETE;
10036       case 112: /* Bump up 500Hz */
10037          multimode_bump_freq(myrpt, 500);
10038          return DC_COMPLETE;
10039       case 113: /* Scan down slow */
10040          myrpt->scantimer = REM_SCANTIME;
10041          myrpt->hfscanmode = HF_SCAN_DOWN_SLOW;
10042          rpt_telemetry(myrpt,REMXXX,(void *)p);
10043          return DC_COMPLETEQUIET;
10044       case 114: /* Scan down quick */
10045          myrpt->scantimer = REM_SCANTIME;
10046          myrpt->hfscanmode = HF_SCAN_DOWN_QUICK;
10047          rpt_telemetry(myrpt,REMXXX,(void *)p);
10048          return DC_COMPLETEQUIET;
10049       case 115: /* Scan down fast */
10050          myrpt->scantimer = REM_SCANTIME;
10051          myrpt->hfscanmode = HF_SCAN_DOWN_FAST;
10052          rpt_telemetry(myrpt,REMXXX,(void *)p);
10053          return DC_COMPLETEQUIET;
10054       case 116: /* Scan up slow */
10055          myrpt->scantimer = REM_SCANTIME;
10056          myrpt->hfscanmode = HF_SCAN_UP_SLOW;
10057          rpt_telemetry(myrpt,REMXXX,(void *)p);
10058          return DC_COMPLETEQUIET;
10059       case 117: /* Scan up quick */
10060          myrpt->scantimer = REM_SCANTIME;
10061          myrpt->hfscanmode = HF_SCAN_UP_QUICK;
10062          rpt_telemetry(myrpt,REMXXX,(void *)p);
10063          return DC_COMPLETEQUIET;
10064       case 118: /* Scan up fast */
10065          myrpt->scantimer = REM_SCANTIME;
10066          myrpt->hfscanmode = HF_SCAN_UP_FAST;
10067          rpt_telemetry(myrpt,REMXXX,(void *)p);
10068          return DC_COMPLETEQUIET;
10069       case 119: /* Tune Request */
10070          if(debug > 3)
10071             ast_log(LOG_NOTICE,"TUNE REQUEST\n");
10072          /* if not currently going, and valid to do */
10073          if((!myrpt->tunerequest) && 
10074              ((!strcmp(myrpt->remoterig, remote_rig_ft897) || 
10075             !strcmp(myrpt->remoterig, remote_rig_ic706)) )) { 
10076             myrpt->remotetx = 0;
10077             ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
10078             myrpt->tunerequest = 1;
10079             rpt_telemetry(myrpt,TUNE,NULL);
10080             return DC_COMPLETEQUIET;
10081          }
10082          return DC_ERROR;        
10083       case 5: /* Long Status */
10084          rpt_telemetry(myrpt,REMLONGSTATUS,NULL);
10085          return DC_COMPLETEQUIET;
10086       case 140: /* Short Status */
10087          rpt_telemetry(myrpt,REMSHORTSTATUS,NULL);
10088          return DC_COMPLETEQUIET;
10089       case 200:
10090       case 201:
10091       case 202:
10092       case 203:
10093       case 204:
10094       case 205:
10095       case 206:
10096       case 207:
10097       case 208:
10098       case 209:
10099       case 210:
10100       case 211:
10101       case 212:
10102       case 213:
10103       case 214:
10104       case 215:
10105          do_dtmf_local(myrpt,remdtmfstr[p - 200]);
10106          return DC_COMPLETEQUIET;
10107       default:
10108          break;
10109    }
10110    return DC_INDETERMINATE;
10111 }
10112 
10113 
10114 static int handle_remote_dtmf_digit(struct rpt *myrpt,char c, char *keyed, int phonemode)
10115 {
10116 time_t   now;
10117 int   ret,res = 0,src;
10118 
10119    if(debug > 6)
10120       ast_log(LOG_NOTICE,"c=%c  phonemode=%i  dtmfidx=%i\n",c,phonemode,myrpt->dtmfidx);
10121 
10122    time(&myrpt->last_activity_time);
10123    /* Stop scan mode if in scan mode */
10124    if(myrpt->hfscanmode){
10125       stop_scan(myrpt);
10126       return 0;
10127    }
10128 
10129    time(&now);
10130    /* if timed-out */
10131    if ((myrpt->dtmf_time_rem + DTMF_TIMEOUT) < now)
10132    {
10133       myrpt->dtmfidx = -1;
10134       myrpt->dtmfbuf[0] = 0;
10135       myrpt->dtmf_time_rem = 0;
10136    }
10137    /* if decode not active */
10138    if (myrpt->dtmfidx == -1)
10139    {
10140       /* if not lead-in digit, dont worry */
10141       if (c != myrpt->p.funcchar)
10142       {
10143          if (!myrpt->p.propagate_dtmf)
10144          {
10145             rpt_mutex_lock(&myrpt->lock);
10146             do_dtmf_local(myrpt,c);
10147             rpt_mutex_unlock(&myrpt->lock);
10148          }
10149          return 0;
10150       }
10151       myrpt->dtmfidx = 0;
10152       myrpt->dtmfbuf[0] = 0;
10153       myrpt->dtmf_time_rem = now;
10154       return 0;
10155    }
10156    /* if too many in buffer, start over */
10157    if (myrpt->dtmfidx >= MAXDTMF)
10158    {
10159       myrpt->dtmfidx = 0;
10160       myrpt->dtmfbuf[0] = 0;
10161       myrpt->dtmf_time_rem = now;
10162    }
10163    if (c == myrpt->p.funcchar)
10164    {
10165       /* if star at beginning, or 2 together, erase buffer */
10166       if ((myrpt->dtmfidx < 1) || 
10167          (myrpt->dtmfbuf[myrpt->dtmfidx - 1] == myrpt->p.funcchar))
10168       {
10169          myrpt->dtmfidx = 0;
10170          myrpt->dtmfbuf[0] = 0;
10171          myrpt->dtmf_time_rem = now;
10172          return 0;
10173       }
10174    }
10175    myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
10176    myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
10177    myrpt->dtmf_time_rem = now;
10178    
10179    
10180    src = SOURCE_RMT;
10181    if (phonemode == 2) src = SOURCE_DPHONE;
10182    else if (phonemode) src = SOURCE_PHONE;
10183    else if (phonemode == 4) src = SOURCE_ALT;
10184    ret = collect_function_digits(myrpt, myrpt->dtmfbuf, src, NULL);
10185    
10186    switch(ret){
10187    
10188       case DC_INDETERMINATE:
10189          res = 0;
10190          break;
10191             
10192       case DC_DOKEY:
10193          if (keyed) *keyed = 1;
10194          res = 0;
10195          break;
10196             
10197       case DC_REQ_FLUSH:
10198          myrpt->dtmfidx = 0;
10199          myrpt->dtmfbuf[0] = 0;
10200          res = 0;
10201          break;
10202             
10203             
10204       case DC_COMPLETE:
10205          res = 1;
10206       case DC_COMPLETEQUIET:
10207          myrpt->totalexecdcommands++;
10208          myrpt->dailyexecdcommands++;
10209          strncpy(myrpt->lastdtmfcommand, myrpt->dtmfbuf, MAXDTMF-1);
10210          myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
10211          myrpt->dtmfbuf[0] = 0;
10212          myrpt->dtmfidx = -1;
10213          myrpt->dtmf_time_rem = 0;
10214          break;
10215             
10216       case DC_ERROR:
10217       default:
10218          myrpt->dtmfbuf[0] = 0;
10219          myrpt->dtmfidx = -1;
10220          myrpt->dtmf_time_rem = 0;
10221          res = 0;
10222          break;
10223    }
10224 
10225    return res;
10226 }
10227 
10228 static int handle_remote_data(struct rpt *myrpt, char *str)
10229 {
10230    /* XXX ATTENTION: if you change the size of these arrays you MUST
10231     * change the limits in corresponding sscanf() calls below. */
10232    char tmp[300], cmd[300], dest[300], src[300], c;
10233    int   seq,res;
10234 
10235    /* put string in our buffer */
10236    strncpy(tmp,str,sizeof(tmp) - 1);
10237    if (!strcmp(tmp,discstr)) return 0;
10238         if (!strcmp(tmp,newkeystr))
10239         {
10240       myrpt->newkey = 1;
10241                 return 0;
10242         }
10243 
10244 #ifndef  DO_NOT_NOTIFY_MDC1200_ON_REMOTE_BASES
10245    if (tmp[0] == 'I')
10246    {
10247       if (sscanf(tmp,"%s %s %x",cmd,src,&seq) != 3)
10248       {
10249          ast_log(LOG_WARNING, "Unable to parse ident string %s\n",str);
10250          return 0;
10251       }
10252       mdc1200_notify(myrpt,src,seq);
10253       return 0;
10254    }
10255 #endif
10256    /* XXX WARNING: be very careful with the limits on the folowing
10257     * sscanf() call, make sure they match the values defined above */
10258    if (sscanf(tmp, "%299s %299s %299s %30d %1c", cmd, dest, src, &seq, &c) != 5)
10259    {
10260       ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
10261       return 0;
10262    }
10263    if (strcmp(cmd,"D"))
10264    {
10265       ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
10266       return 0;
10267    }
10268    /* if not for me, ignore */
10269    if (strcmp(dest,myrpt->name)) return 0;
10270    if (myrpt->p.archivedir)
10271    {
10272       char dtmfstr[100];
10273 
10274       sprintf(dtmfstr,"DTMF,%c",c);
10275       donodelog(myrpt,dtmfstr);
10276    }
10277    c = func_xlat(myrpt,c,&myrpt->p.outxlat);
10278    if (!c) return(0);
10279    res = handle_remote_dtmf_digit(myrpt,c, NULL, 0);
10280    if (res != 1)
10281       return res;
10282    rpt_telemetry(myrpt,COMPLETE,NULL);
10283    return 0;
10284 }
10285 
10286 static int handle_remote_phone_dtmf(struct rpt *myrpt, char c, char *keyed, int phonemode)
10287 {
10288 int   res;
10289 
10290 
10291    if(phonemode == 3) /* simplex phonemode, funcchar key/unkey toggle */
10292    {
10293       if (keyed && *keyed && ((c == myrpt->p.funcchar) || (c == myrpt->p.endchar)))
10294       {
10295          *keyed = 0; /* UNKEY */
10296          return 0;
10297       }
10298       else if (keyed && !*keyed && (c = myrpt->p.funcchar))
10299       {
10300          *keyed = 1; /* KEY */
10301          return 0;
10302       }
10303    }
10304    else /* endchar unkey */
10305    {
10306 
10307       if (keyed && *keyed && (c == myrpt->p.endchar))
10308       {
10309          *keyed = 0;
10310          return DC_INDETERMINATE;
10311       }
10312    }
10313    if (myrpt->p.archivedir)
10314    {
10315       char str[100];
10316 
10317       sprintf(str,"DTMF(P),%c",c);
10318       donodelog(myrpt,str);
10319    }
10320    res = handle_remote_dtmf_digit(myrpt,c,keyed, phonemode);
10321    if (res != 1)
10322       return res;
10323    rpt_telemetry(myrpt,COMPLETE,NULL);
10324    return 0;
10325 }
10326 
10327 static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l)
10328 {
10329    char *val, *s, *s1, *s2, *tele;
10330    char tmp[300], deststr[300] = "";
10331    char sx[320],*sy;
10332 
10333 
10334    val = node_lookup(myrpt,l->name);
10335    if (!val)
10336    {
10337       fprintf(stderr,"attempt_reconnect: cannot find node %s\n",l->name);
10338       return -1;
10339    }
10340 
10341    rpt_mutex_lock(&myrpt->lock);
10342    /* remove from queue */
10343    remque((struct qelem *) l);
10344    rpt_mutex_unlock(&myrpt->lock);
10345    strncpy(tmp,val,sizeof(tmp) - 1);
10346    s = tmp;
10347    s1 = strsep(&s,",");
10348    if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
10349    {
10350       sy = strchr(s1,'/');    
10351       *sy = 0;
10352       sprintf(sx,"%s:4569/%s",s1,sy + 1);
10353       s1 = sx;
10354    }
10355    s2 = strsep(&s,",");
10356    snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
10357    tele = strchr(deststr, '/');
10358    if (!tele) {
10359       fprintf(stderr,"attempt_reconnect:Dial number (%s) must be in format tech/number\n",deststr);
10360       return -1;
10361    }
10362    *tele++ = 0;
10363    l->elaptime = 0;
10364    l->connecttime = 0;
10365    l->thisconnected = 0;
10366    l->newkey = 0;
10367    l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
10368    if (l->chan){
10369       ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
10370       ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
10371 #ifndef  NEW_ASTERISK
10372       l->chan->whentohangup = 0;
10373 #endif
10374       l->chan->appl = "Apprpt";
10375       l->chan->data = "(Remote Rx)";
10376       if (option_verbose > 2)
10377          ast_verbose(VERBOSE_PREFIX_3 "rpt (attempt_reconnect) initiating call to %s/%s on %s\n",
10378             deststr, tele, l->chan->name);
10379       if(l->chan->cid.cid_num)
10380          ast_free(l->chan->cid.cid_num);
10381       l->chan->cid.cid_num = ast_strdup(myrpt->name);
10382                 ast_call(l->chan,tele,999); 
10383 
10384    }
10385    else 
10386    {
10387       if (option_verbose > 2)
10388          ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
10389             deststr,tele,l->chan->name);
10390       return -1;
10391    }
10392    rpt_mutex_lock(&myrpt->lock);
10393    /* put back in queue */
10394    insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
10395    rpt_mutex_unlock(&myrpt->lock);
10396    ast_log(LOG_WARNING,"Reconnect Attempt to %s in process\n",l->name);
10397    if (!l->phonemode) send_newkey(l->chan);
10398    return 0;
10399 }
10400 
10401 /* 0 return=continue, 1 return = break, -1 return = error */
10402 static void local_dtmf_helper(struct rpt *myrpt,char c_in)
10403 {
10404 int   res;
10405 pthread_attr_t attr;
10406 char  cmd[MAXDTMF+1] = "",c;
10407 
10408 
10409    c = c_in & 0x7f;
10410    if (myrpt->p.archivedir)
10411    {
10412       char str[100];
10413 
10414       sprintf(str,"DTMF,MAIN,%c",c);
10415       donodelog(myrpt,str);
10416    }
10417    if (c == myrpt->p.endchar)
10418    {
10419    /* if in simple mode, kill autopatch */
10420       if (myrpt->p.simple && myrpt->callmode)
10421       {   
10422          if(debug)
10423             ast_log(LOG_WARNING, "simple mode autopatch kill\n");
10424          rpt_mutex_lock(&myrpt->lock);
10425          myrpt->callmode = 0;
10426          myrpt->macropatch=0;
10427          channel_revert(myrpt);
10428          rpt_mutex_unlock(&myrpt->lock);
10429          rpt_telemetry(myrpt,TERM,NULL);
10430          return;
10431       }
10432       rpt_mutex_lock(&myrpt->lock);
10433       myrpt->stopgen = 1;
10434       if (myrpt->cmdnode[0])
10435       {
10436          myrpt->cmdnode[0] = 0;
10437          myrpt->dtmfidx = -1;
10438          myrpt->dtmfbuf[0] = 0;
10439          rpt_mutex_unlock(&myrpt->lock);
10440          rpt_telemetry(myrpt,COMPLETE,NULL);
10441          return;
10442       } 
10443       else if(!myrpt->inpadtest)
10444                 {
10445                         rpt_mutex_unlock(&myrpt->lock);
10446                         if (myrpt->p.propagate_phonedtmf)
10447                                do_dtmf_phone(myrpt,NULL,c);
10448          return;
10449                 }
10450       else
10451          rpt_mutex_unlock(&myrpt->lock);
10452    }
10453    rpt_mutex_lock(&myrpt->lock);
10454    if (myrpt->cmdnode[0])
10455    {
10456       rpt_mutex_unlock(&myrpt->lock);
10457       send_link_dtmf(myrpt,c);
10458       return;
10459    }
10460    if (!myrpt->p.simple)
10461    {
10462       if ((!myrpt->inpadtest)&&(c == myrpt->p.funcchar))
10463       {
10464          myrpt->dtmfidx = 0;
10465          myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
10466          rpt_mutex_unlock(&myrpt->lock);
10467          time(&myrpt->dtmf_time);
10468          return;
10469       } 
10470       else if (((myrpt->inpadtest)||(c != myrpt->p.endchar)) && (myrpt->dtmfidx >= 0))
10471       {
10472          time(&myrpt->dtmf_time);
10473          
10474          if (myrpt->dtmfidx < MAXDTMF)
10475          {
10476             int src;
10477 
10478             myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
10479             myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
10480             
10481             strncpy(cmd, myrpt->dtmfbuf, sizeof(cmd) - 1);
10482             
10483             rpt_mutex_unlock(&myrpt->lock);
10484             src = SOURCE_RPT;
10485             if (c_in & 0x80) src = SOURCE_ALT;
10486             res = collect_function_digits(myrpt, cmd, src, NULL);
10487             rpt_mutex_lock(&myrpt->lock);
10488             switch(res){
10489                 case DC_INDETERMINATE:
10490                break;
10491                 case DC_REQ_FLUSH:
10492                myrpt->dtmfidx = 0;
10493                myrpt->dtmfbuf[0] = 0;
10494                break;
10495                 case DC_COMPLETE:
10496                 case DC_COMPLETEQUIET:
10497                myrpt->totalexecdcommands++;
10498                myrpt->dailyexecdcommands++;
10499                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
10500                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
10501                myrpt->dtmfbuf[0] = 0;
10502                myrpt->dtmfidx = -1;
10503                myrpt->dtmf_time = 0;
10504                break;
10505 
10506                 case DC_ERROR:
10507                 default:
10508                myrpt->dtmfbuf[0] = 0;
10509                myrpt->dtmfidx = -1;
10510                myrpt->dtmf_time = 0;
10511                break;
10512             }
10513             if(res != DC_INDETERMINATE) {
10514                rpt_mutex_unlock(&myrpt->lock);
10515                return;
10516             }
10517          } 
10518       }
10519    }
10520    else /* if simple */
10521    {
10522       if ((!myrpt->callmode) && (c == myrpt->p.funcchar))
10523       {
10524          myrpt->callmode = 1;
10525          myrpt->patchnoct = 0;
10526          myrpt->patchquiet = 0;
10527          myrpt->patchfarenddisconnect = 0;
10528          myrpt->patchdialtime = 0;
10529          strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
10530          myrpt->cidx = 0;
10531          myrpt->exten[myrpt->cidx] = 0;
10532          rpt_mutex_unlock(&myrpt->lock);
10533               pthread_attr_init(&attr);
10534               pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
10535          ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *)myrpt);
10536          return;
10537       }
10538    }
10539    if (myrpt->callmode == 1)
10540    {
10541       myrpt->exten[myrpt->cidx++] = c;
10542       myrpt->exten[myrpt->cidx] = 0;
10543       /* if this exists */
10544       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
10545       {
10546          /* if this really it, end now */
10547          if (!ast_matchmore_extension(myrpt->pchannel,myrpt->patchcontext,
10548             myrpt->exten,1,NULL)) 
10549          {
10550             myrpt->callmode = 2;
10551             rpt_mutex_unlock(&myrpt->lock);
10552             if(!myrpt->patchquiet)
10553                rpt_telemetry(myrpt,PROC,NULL); 
10554             return;
10555          }
10556          else /* othewise, reset timer */
10557          {
10558             myrpt->calldigittimer = 1;
10559          }
10560       }
10561       /* if can continue, do so */
10562       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
10563       {
10564          /* call has failed, inform user */
10565          myrpt->callmode = 4;
10566       }
10567       rpt_mutex_unlock(&myrpt->lock);
10568       return;
10569    }
10570    if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
10571    {
10572       myrpt->mydtmf = c;
10573    }
10574    rpt_mutex_unlock(&myrpt->lock);
10575    if ((myrpt->dtmfidx < 0) && myrpt->p.propagate_phonedtmf)
10576       do_dtmf_phone(myrpt,NULL,c);
10577    return;
10578 }
10579 
10580 
10581 /* place an ID event in the telemetry queue */
10582 
10583 static void queue_id(struct rpt *myrpt)
10584 {
10585    if(myrpt->p.idtime){ /* ID time must be non-zero */
10586       myrpt->mustid = myrpt->tailid = 0;
10587       myrpt->idtimer = myrpt->p.idtime; /* Reset our ID timer */
10588       rpt_mutex_unlock(&myrpt->lock);
10589       rpt_telemetry(myrpt,ID,NULL);
10590       rpt_mutex_lock(&myrpt->lock);
10591    }
10592 }
10593 
10594 /* Scheduler */
10595 /* must be called locked */
10596 
10597 static void do_scheduler(struct rpt *myrpt)
10598 {
10599    int i,res;
10600 
10601 #ifdef   NEW_ASTERISK
10602    struct ast_tm tmnow;
10603 #else
10604    struct tm tmnow;
10605 #endif
10606    struct ast_variable *skedlist;
10607    char *strs[5],*vp,*val,value[100];
10608 
10609    memcpy(&myrpt->lasttv, &myrpt->curtv, sizeof(struct timeval));
10610    
10611    if( (res = gettimeofday(&myrpt->curtv, NULL)) < 0)
10612       ast_log(LOG_NOTICE, "Scheduler gettime of day returned: %s\n", strerror(res));
10613 
10614    /* Try to get close to a 1 second resolution */
10615    
10616    if(myrpt->lasttv.tv_sec == myrpt->curtv.tv_sec)
10617       return;
10618 
10619    rpt_localtime(&myrpt->curtv.tv_sec, &tmnow);
10620 
10621    /* If midnight, then reset all daily statistics */
10622    
10623    if((tmnow.tm_hour == 0)&&(tmnow.tm_min == 0)&&(tmnow.tm_sec == 0)){
10624       myrpt->dailykeyups = 0;
10625       myrpt->dailytxtime = 0;
10626       myrpt->dailykerchunks = 0;
10627       myrpt->dailyexecdcommands = 0;
10628    }
10629 
10630    if(tmnow.tm_sec != 0)
10631       return;
10632 
10633    /* Code below only executes once per minute */
10634 
10635 
10636    /* Don't schedule if remote */
10637 
10638         if (myrpt->remote)
10639                 return;
10640 
10641    /* Don't schedule if disabled */
10642 
10643         if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable){
10644       if(debug > 6)
10645          ast_log(LOG_NOTICE, "Scheduler disabled\n");
10646       return;
10647    }
10648 
10649    if(!myrpt->p.skedstanzaname){ /* No stanza means we do nothing */
10650       if(debug > 6)
10651          ast_log(LOG_NOTICE,"No stanza for scheduler in rpt.conf\n");
10652       return;
10653    }
10654 
10655     /* get pointer to linked list of scheduler entries */
10656     skedlist = ast_variable_browse(myrpt->cfg, myrpt->p.skedstanzaname);
10657 
10658    if(debug > 6){
10659       ast_log(LOG_NOTICE, "Time now: %02d:%02d %02d %02d %02d\n",
10660          tmnow.tm_hour,tmnow.tm_min,tmnow.tm_mday,tmnow.tm_mon + 1, tmnow.tm_wday); 
10661    }
10662    /* walk the list */
10663    for(; skedlist; skedlist = skedlist->next){
10664       if(debug > 6)
10665          ast_log(LOG_NOTICE, "Scheduler entry %s = %s being considered\n",skedlist->name, skedlist->value);
10666       strncpy(value,skedlist->value,99);
10667       value[99] = 0;
10668       /* point to the substrings for minute, hour, dom, month, and dow */
10669       for( i = 0, vp = value ; i < 5; i++){
10670          if(!*vp)
10671             break;
10672          while((*vp == ' ') || (*vp == 0x09)) /* get rid of any leading white space */
10673             vp++;
10674          strs[i] = vp; /* save pointer to beginning of substring */
10675          while((*vp != ' ') && (*vp != 0x09) && (*vp != 0)) /* skip over substring */
10676             vp++;
10677          if(*vp)
10678             *vp++ = 0; /* mark end of substring */
10679       }
10680       if(debug > 6)
10681          ast_log(LOG_NOTICE, "i = %d, min = %s, hour = %s, mday=%s, mon=%s, wday=%s\n",i,
10682             strs[0], strs[1], strs[2], strs[3], strs[4]); 
10683       if(i == 5){
10684          if((*strs[0] != '*')&&(atoi(strs[0]) != tmnow.tm_min))
10685             continue;
10686          if((*strs[1] != '*')&&(atoi(strs[1]) != tmnow.tm_hour))
10687             continue;
10688          if((*strs[2] != '*')&&(atoi(strs[2]) != tmnow.tm_mday))
10689             continue;
10690          if((*strs[3] != '*')&&(atoi(strs[3]) != tmnow.tm_mon + 1))
10691             continue;
10692          if(atoi(strs[4]) == 7)
10693             strs[4] = "0";
10694          if((*strs[4] != '*')&&(atoi(strs[4]) != tmnow.tm_wday))
10695             continue;
10696          if(debug)
10697             ast_log(LOG_NOTICE, "Executing scheduler entry %s = %s\n", skedlist->name, skedlist->value);
10698          if(atoi(skedlist->name) == 0)
10699             return; /* Zero is reserved for the startup macro */
10700          val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, skedlist->name);
10701          if (!val){
10702             ast_log(LOG_WARNING,"Scheduler could not find macro %s\n",skedlist->name);
10703             return; /* Macro not found */
10704          }
10705          if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val)){
10706             ast_log(LOG_WARNING, "Scheduler could not execute macro %s: Macro buffer full\n",
10707                skedlist->name);
10708             return; /* Macro buffer full */
10709          }
10710          myrpt->macrotimer = MACROTIME;
10711          strncat(myrpt->macrobuf,val,MAXMACRO - 1);
10712       }
10713       else{
10714          ast_log(LOG_WARNING,"Malformed scheduler entry in rpt.conf: %s = %s\n",
10715             skedlist->name, skedlist->value);
10716       }
10717    }
10718 
10719 }
10720 
10721 /* single thread with one file (request) to dial */
10722 static void *rpt(void *this)
10723 {
10724 struct   rpt *myrpt = (struct rpt *)this;
10725 char *tele,*idtalkover,c,myfirst,*p;
10726 int ms = MSWAIT,i,lasttx=0,val,remrx=0,identqueued,othertelemqueued;
10727 int tailmessagequeued,ctqueued,dtmfed,lastmyrx,localmsgqueued;
10728 struct ast_channel *who;
10729 struct dahdi_confinfo ci;  /* conference info */
10730 time_t   t;
10731 struct rpt_link *l,*m;
10732 struct rpt_tele *telem;
10733 char tmpstr[300],lstr[MAXLINKLIST];
10734 
10735 
10736    if (myrpt->p.archivedir) mkdir(myrpt->p.archivedir,0600);
10737    sprintf(tmpstr,"%s/%s",myrpt->p.archivedir,myrpt->name);
10738    mkdir(tmpstr,0600);
10739    rpt_mutex_lock(&myrpt->lock);
10740 
10741    telem = myrpt->tele.next;
10742    while(telem != &myrpt->tele)
10743    {
10744       ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
10745       telem = telem->next;
10746    }
10747    rpt_mutex_unlock(&myrpt->lock);
10748    /* find our index, and load the vars initially */
10749    for(i = 0; i < nrpts; i++)
10750    {
10751       if (&rpt_vars[i] == myrpt)
10752       {
10753          load_rpt_vars(i,0);
10754          break;
10755       }
10756    }
10757 
10758    rpt_mutex_lock(&myrpt->lock);
10759    while(myrpt->xlink)
10760    {
10761       myrpt->xlink = 3;
10762       rpt_mutex_unlock(&myrpt->lock);
10763       usleep(100000);
10764       rpt_mutex_lock(&myrpt->lock);
10765    }
10766 #ifdef HAVE_IOPERM
10767    if ((!strcmp(myrpt->remoterig, remote_rig_rbi)) &&
10768      (ioperm(myrpt->p.iobase,1,1) == -1))
10769    {
10770       rpt_mutex_unlock(&myrpt->lock);
10771       ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
10772       myrpt->rpt_thread = AST_PTHREADT_STOP;
10773       pthread_exit(NULL);
10774    }
10775 #endif
10776    strncpy(tmpstr,myrpt->rxchanname,sizeof(tmpstr) - 1);
10777    tele = strchr(tmpstr,'/');
10778    if (!tele)
10779    {
10780       fprintf(stderr,"rpt:Rxchannel Dial number (%s) must be in format tech/number\n",myrpt->rxchanname);
10781       rpt_mutex_unlock(&myrpt->lock);
10782       myrpt->rpt_thread = AST_PTHREADT_STOP;
10783       pthread_exit(NULL);
10784    }
10785    *tele++ = 0;
10786    myrpt->rxchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
10787    myrpt->dahdirxchannel = NULL;
10788    if (!strcasecmp(tmpstr,"DAHDI"))
10789       myrpt->dahdirxchannel = myrpt->rxchannel;
10790    if (myrpt->rxchannel)
10791    {
10792       if (myrpt->rxchannel->_state == AST_STATE_BUSY)
10793       {
10794          fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
10795          rpt_mutex_unlock(&myrpt->lock);
10796          ast_hangup(myrpt->rxchannel);
10797          myrpt->rpt_thread = AST_PTHREADT_STOP;
10798          pthread_exit(NULL);
10799       }
10800       ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
10801       ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
10802 #ifdef   AST_CDR_FLAG_POST_DISABLED
10803       if (myrpt->rxchannel->cdr)
10804          ast_set_flag(myrpt->rxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10805 #endif
10806 #ifndef  NEW_ASTERISK
10807       myrpt->rxchannel->whentohangup = 0;
10808 #endif
10809       myrpt->rxchannel->appl = "Apprpt";
10810       myrpt->rxchannel->data = "(Repeater Rx)";
10811       if (option_verbose > 2)
10812          ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
10813             tmpstr,tele,myrpt->rxchannel->name);
10814       ast_call(myrpt->rxchannel,tele,999);
10815       if (myrpt->rxchannel->_state != AST_STATE_UP)
10816       {
10817          rpt_mutex_unlock(&myrpt->lock);
10818          ast_hangup(myrpt->rxchannel);
10819          myrpt->rpt_thread = AST_PTHREADT_STOP;
10820          pthread_exit(NULL);
10821       }
10822    }
10823    else
10824    {
10825       fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
10826       rpt_mutex_unlock(&myrpt->lock);
10827       myrpt->rpt_thread = AST_PTHREADT_STOP;
10828       pthread_exit(NULL);
10829    }
10830    myrpt->dahditxchannel = NULL;
10831    if (myrpt->txchanname)
10832    {
10833       strncpy(tmpstr,myrpt->txchanname,sizeof(tmpstr) - 1);
10834       tele = strchr(tmpstr,'/');
10835       if (!tele)
10836       {
10837          fprintf(stderr,"rpt:Txchannel Dial number (%s) must be in format tech/number\n",myrpt->txchanname);
10838          rpt_mutex_unlock(&myrpt->lock);
10839          ast_hangup(myrpt->rxchannel);
10840          myrpt->rpt_thread = AST_PTHREADT_STOP;
10841          pthread_exit(NULL);
10842       }
10843       *tele++ = 0;
10844       myrpt->txchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
10845       if (!strcasecmp(tmpstr,"DAHDI"))
10846          myrpt->dahditxchannel = myrpt->txchannel;
10847       if (myrpt->txchannel)
10848       {
10849          if (myrpt->txchannel->_state == AST_STATE_BUSY)
10850          {
10851             fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
10852             rpt_mutex_unlock(&myrpt->lock);
10853             ast_hangup(myrpt->txchannel);
10854             ast_hangup(myrpt->rxchannel);
10855             myrpt->rpt_thread = AST_PTHREADT_STOP;
10856             pthread_exit(NULL);
10857          }        
10858          ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
10859          ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
10860 #ifdef   AST_CDR_FLAG_POST_DISABLED
10861          if (myrpt->txchannel->cdr)
10862             ast_set_flag(myrpt->txchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10863 #endif
10864 #ifndef  NEW_ASTERISK
10865          myrpt->txchannel->whentohangup = 0;
10866 #endif
10867          myrpt->txchannel->appl = "Apprpt";
10868          myrpt->txchannel->data = "(Repeater Tx)";
10869          if (option_verbose > 2)
10870             ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
10871                tmpstr,tele,myrpt->txchannel->name);
10872          ast_call(myrpt->txchannel,tele,999);
10873          if (myrpt->rxchannel->_state != AST_STATE_UP)
10874          {
10875             rpt_mutex_unlock(&myrpt->lock);
10876             ast_hangup(myrpt->rxchannel);
10877             ast_hangup(myrpt->txchannel);
10878             myrpt->rpt_thread = AST_PTHREADT_STOP;
10879             pthread_exit(NULL);
10880          }
10881       }
10882       else
10883       {
10884          fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
10885          rpt_mutex_unlock(&myrpt->lock);
10886          ast_hangup(myrpt->rxchannel);
10887          myrpt->rpt_thread = AST_PTHREADT_STOP;
10888          pthread_exit(NULL);
10889       }
10890    }
10891    else
10892    {
10893       myrpt->txchannel = myrpt->rxchannel;
10894       if (!strncasecmp(myrpt->rxchanname,"DAHDI",3))
10895          myrpt->dahditxchannel = myrpt->txchannel;
10896    }
10897    ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
10898    ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
10899    /* allocate a pseudo-channel thru asterisk */
10900    myrpt->pchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
10901    if (!myrpt->pchannel)
10902    {
10903       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10904       rpt_mutex_unlock(&myrpt->lock);
10905       if (myrpt->txchannel != myrpt->rxchannel) 
10906          ast_hangup(myrpt->txchannel);
10907       ast_hangup(myrpt->rxchannel);
10908       myrpt->rpt_thread = AST_PTHREADT_STOP;
10909       pthread_exit(NULL);
10910    }
10911 #ifdef   AST_CDR_FLAG_POST_DISABLED
10912    if (myrpt->pchannel->cdr)
10913       ast_set_flag(myrpt->pchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10914 #endif
10915    if (!myrpt->dahdirxchannel) myrpt->dahdirxchannel = myrpt->pchannel;
10916    if (!myrpt->dahditxchannel)
10917    {
10918       /* allocate a pseudo-channel thru asterisk */
10919       myrpt->dahditxchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
10920       if (!myrpt->dahditxchannel)
10921       {
10922          fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10923          rpt_mutex_unlock(&myrpt->lock);
10924          if (myrpt->txchannel != myrpt->rxchannel) 
10925             ast_hangup(myrpt->txchannel);
10926          ast_hangup(myrpt->rxchannel);
10927          myrpt->rpt_thread = AST_PTHREADT_STOP;
10928          pthread_exit(NULL);
10929       }
10930       ast_set_read_format(myrpt->dahditxchannel,AST_FORMAT_SLINEAR);
10931       ast_set_write_format(myrpt->dahditxchannel,AST_FORMAT_SLINEAR);
10932 #ifdef   AST_CDR_FLAG_POST_DISABLED
10933       if (myrpt->dahditxchannel->cdr)
10934          ast_set_flag(myrpt->dahditxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10935 #endif
10936    }
10937    /* allocate a pseudo-channel thru asterisk */
10938    myrpt->monchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
10939    if (!myrpt->monchannel)
10940    {
10941       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10942       rpt_mutex_unlock(&myrpt->lock);
10943       if (myrpt->txchannel != myrpt->rxchannel) 
10944          ast_hangup(myrpt->txchannel);
10945       ast_hangup(myrpt->rxchannel);
10946       myrpt->rpt_thread = AST_PTHREADT_STOP;
10947       pthread_exit(NULL);
10948    }
10949    ast_set_read_format(myrpt->monchannel,AST_FORMAT_SLINEAR);
10950    ast_set_write_format(myrpt->monchannel,AST_FORMAT_SLINEAR);
10951 #ifdef   AST_CDR_FLAG_POST_DISABLED
10952    if (myrpt->monchannel->cdr)
10953       ast_set_flag(myrpt->monchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
10954 #endif
10955    /* make a conference for the tx */
10956    ci.chan = 0;
10957    ci.confno = -1; /* make a new conf */
10958    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER;
10959    /* first put the channel on the conference in proper mode */
10960    if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
10961    {
10962       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
10963       rpt_mutex_unlock(&myrpt->lock);
10964       ast_hangup(myrpt->pchannel);
10965       ast_hangup(myrpt->monchannel);
10966       if (myrpt->txchannel != myrpt->rxchannel) 
10967          ast_hangup(myrpt->txchannel);
10968       ast_hangup(myrpt->rxchannel);
10969       myrpt->rpt_thread = AST_PTHREADT_STOP;
10970       pthread_exit(NULL);
10971    }
10972    /* save tx conference number */
10973    myrpt->txconf = ci.confno;
10974    /* make a conference for the pseudo */
10975    ci.chan = 0;
10976    ci.confno = -1; /* make a new conf */
10977    ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
10978       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
10979    /* first put the channel on the conference in announce mode */
10980    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
10981    {
10982       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
10983       rpt_mutex_unlock(&myrpt->lock);
10984       ast_hangup(myrpt->pchannel);
10985       ast_hangup(myrpt->monchannel);
10986       if (myrpt->txchannel != myrpt->rxchannel) 
10987          ast_hangup(myrpt->txchannel);
10988       ast_hangup(myrpt->rxchannel);
10989       myrpt->rpt_thread = AST_PTHREADT_STOP;
10990       pthread_exit(NULL);
10991    }
10992    /* save pseudo channel conference number */
10993    myrpt->conf = ci.confno;
10994    /* make a conference for the pseudo */
10995    ci.chan = 0;
10996    if ((strstr(myrpt->txchannel->name,"pseudo") == NULL) &&
10997       (myrpt->dahditxchannel == myrpt->txchannel))
10998    {
10999       /* get tx channel's port number */
11000       if (ioctl(myrpt->txchannel->fds[0],DAHDI_CHANNO,&ci.confno) == -1)
11001       {
11002          ast_log(LOG_WARNING, "Unable to set tx channel's chan number\n");
11003          rpt_mutex_unlock(&myrpt->lock);
11004          ast_hangup(myrpt->pchannel);
11005          ast_hangup(myrpt->monchannel);
11006          if (myrpt->txchannel != myrpt->rxchannel) 
11007             ast_hangup(myrpt->txchannel);
11008          ast_hangup(myrpt->rxchannel);
11009          myrpt->rpt_thread = AST_PTHREADT_STOP;
11010          pthread_exit(NULL);
11011       }
11012       ci.confmode = DAHDI_CONF_MONITORTX;
11013    }
11014    else
11015    {
11016       ci.confno = myrpt->txconf;
11017       ci.confmode = DAHDI_CONF_CONFANNMON;
11018    }
11019    /* first put the channel on the conference in announce mode */
11020    if (ioctl(myrpt->monchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11021    {
11022       ast_log(LOG_WARNING, "Unable to set conference mode for monitor\n");
11023       rpt_mutex_unlock(&myrpt->lock);
11024       ast_hangup(myrpt->pchannel);
11025       ast_hangup(myrpt->monchannel);
11026       if (myrpt->txchannel != myrpt->rxchannel) 
11027          ast_hangup(myrpt->txchannel);
11028       ast_hangup(myrpt->rxchannel);
11029       myrpt->rpt_thread = AST_PTHREADT_STOP;
11030       pthread_exit(NULL);
11031    }
11032    /* allocate a pseudo-channel thru asterisk */
11033    myrpt->parrotchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
11034    if (!myrpt->parrotchannel)
11035    {
11036       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11037       rpt_mutex_unlock(&myrpt->lock);
11038       if (myrpt->txchannel != myrpt->rxchannel) 
11039          ast_hangup(myrpt->txchannel);
11040       ast_hangup(myrpt->rxchannel);
11041       myrpt->rpt_thread = AST_PTHREADT_STOP;
11042       pthread_exit(NULL);
11043    }
11044    ast_set_read_format(myrpt->parrotchannel,AST_FORMAT_SLINEAR);
11045    ast_set_write_format(myrpt->parrotchannel,AST_FORMAT_SLINEAR);
11046 #ifdef   AST_CDR_FLAG_POST_DISABLED
11047    if (myrpt->parrotchannel->cdr)
11048       ast_set_flag(myrpt->parrotchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11049 #endif
11050    /* allocate a pseudo-channel thru asterisk */
11051    myrpt->voxchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
11052    if (!myrpt->voxchannel)
11053    {
11054       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11055       rpt_mutex_unlock(&myrpt->lock);
11056       if (myrpt->txchannel != myrpt->rxchannel) 
11057          ast_hangup(myrpt->txchannel);
11058       ast_hangup(myrpt->rxchannel);
11059       myrpt->rpt_thread = AST_PTHREADT_STOP;
11060       pthread_exit(NULL);
11061    }
11062    ast_set_read_format(myrpt->voxchannel,AST_FORMAT_SLINEAR);
11063    ast_set_write_format(myrpt->voxchannel,AST_FORMAT_SLINEAR);
11064 #ifdef   AST_CDR_FLAG_POST_DISABLED
11065    if (myrpt->voxchannel->cdr)
11066       ast_set_flag(myrpt->voxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11067 #endif
11068    /* allocate a pseudo-channel thru asterisk */
11069    myrpt->txpchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
11070    if (!myrpt->txpchannel)
11071    {
11072       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11073       rpt_mutex_unlock(&myrpt->lock);
11074       ast_hangup(myrpt->pchannel);
11075       ast_hangup(myrpt->monchannel);
11076       if (myrpt->txchannel != myrpt->rxchannel) 
11077          ast_hangup(myrpt->txchannel);
11078       ast_hangup(myrpt->rxchannel);
11079       myrpt->rpt_thread = AST_PTHREADT_STOP;
11080       pthread_exit(NULL);
11081    }
11082 #ifdef   AST_CDR_FLAG_POST_DISABLED
11083    if (myrpt->txpchannel->cdr)
11084       ast_set_flag(myrpt->txpchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11085 #endif
11086    /* make a conference for the tx */
11087    ci.chan = 0;
11088    ci.confno = myrpt->txconf;
11089    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER ;
11090    /* first put the channel on the conference in proper mode */
11091    if (ioctl(myrpt->txpchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11092    {
11093       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
11094       rpt_mutex_unlock(&myrpt->lock);
11095       ast_hangup(myrpt->txpchannel);
11096       ast_hangup(myrpt->monchannel);
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    /* if serial io port, open it */
11104    myrpt->iofd = -1;
11105    if (myrpt->p.ioport && ((myrpt->iofd = openserial(myrpt,myrpt->p.ioport)) == -1))
11106    {
11107       ast_log(LOG_ERROR, "Unable to open %s\n",myrpt->p.ioport);
11108       rpt_mutex_unlock(&myrpt->lock);
11109       ast_hangup(myrpt->pchannel);
11110       if (myrpt->txchannel != myrpt->rxchannel) 
11111          ast_hangup(myrpt->txchannel);
11112       ast_hangup(myrpt->rxchannel);
11113       pthread_exit(NULL);
11114    }
11115    /* Now, the idea here is to copy from the physical rx channel buffer
11116       into the pseudo tx buffer, and from the pseudo rx buffer into the 
11117       tx channel buffer */
11118    myrpt->links.next = &myrpt->links;
11119    myrpt->links.prev = &myrpt->links;
11120    myrpt->tailtimer = 0;
11121    myrpt->totimer = 0;
11122    myrpt->tmsgtimer = myrpt->p.tailmessagetime;
11123    myrpt->idtimer = myrpt->p.politeid;
11124    myrpt->mustid = myrpt->tailid = 0;
11125    myrpt->callmode = 0;
11126    myrpt->tounkeyed = 0;
11127    myrpt->tonotify = 0;
11128    myrpt->retxtimer = 0;
11129    myrpt->rerxtimer = 0;
11130    myrpt->skedtimer = 0;
11131    myrpt->tailevent = 0;
11132    lasttx = 0;
11133    myrpt->keyed = 0;
11134    myrpt->txkeyed = 0;
11135    time(&myrpt->lastkeyedtime);
11136    myrpt->lastkeyedtime -= RPT_LOCKOUT_SECS;
11137    time(&myrpt->lasttxkeyedtime);
11138    myrpt->lasttxkeyedtime -= RPT_LOCKOUT_SECS;
11139    idtalkover = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover");
11140    myrpt->dtmfidx = -1;
11141    myrpt->dtmfbuf[0] = 0;
11142    myrpt->rem_dtmfidx = -1;
11143    myrpt->rem_dtmfbuf[0] = 0;
11144    myrpt->dtmf_time = 0;
11145    myrpt->rem_dtmf_time = 0;
11146    myrpt->inpadtest = 0;
11147    myrpt->disgorgetime = 0;
11148    myrpt->lastnodewhichkeyedusup[0] = '\0';
11149    myrpt->dailytxtime = 0;
11150    myrpt->totaltxtime = 0;
11151    myrpt->dailykeyups = 0;
11152    myrpt->totalkeyups = 0;
11153    myrpt->dailykerchunks = 0;
11154    myrpt->totalkerchunks = 0;
11155    myrpt->dailyexecdcommands = 0;
11156    myrpt->totalexecdcommands = 0;
11157    myrpt->timeouts = 0;
11158    myrpt->exten[0] = '\0';
11159    myrpt->lastdtmfcommand[0] = '\0';
11160    voxinit_rpt(myrpt,1);
11161    myrpt->wasvox = 0;
11162    if (myrpt->p.startupmacro)
11163    {
11164       snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
11165    }
11166    rpt_mutex_unlock(&myrpt->lock);
11167    val = 1;
11168    ast_channel_setoption(myrpt->rxchannel,AST_OPTION_RELAXDTMF,&val,sizeof(char),0);
11169    val = 1;
11170    ast_channel_setoption(myrpt->rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
11171    if (myrpt->p.archivedir) donodelog(myrpt,"STARTUP");
11172    dtmfed = 0;
11173    if (myrpt->remoterig && !ISRIG_RTX(myrpt->remoterig)) setrem(myrpt);
11174    lastmyrx = 0;
11175    myfirst = 0;
11176    while (ms >= 0)
11177    {
11178       struct ast_frame *f,*f1,*f2;
11179       struct ast_channel *cs[300],*cs1[300];
11180       int totx=0,elap=0,n,x,toexit=0;
11181 
11182       /* DEBUG Dump */
11183       if((myrpt->disgorgetime) && (time(NULL) >= myrpt->disgorgetime)){
11184          struct rpt_link *dl;
11185          struct rpt_tele *dt;
11186 
11187          myrpt->disgorgetime = 0;
11188          ast_log(LOG_NOTICE,"********** Variable Dump Start (app_rpt) **********\n");
11189          ast_log(LOG_NOTICE,"totx = %d\n",totx);
11190          ast_log(LOG_NOTICE,"remrx = %d\n",remrx);
11191          ast_log(LOG_NOTICE,"lasttx = %d\n",lasttx);
11192          ast_log(LOG_NOTICE,"elap = %d\n",elap);
11193          ast_log(LOG_NOTICE,"toexit = %d\n",toexit);
11194 
11195          ast_log(LOG_NOTICE,"myrpt->keyed = %d\n",myrpt->keyed);
11196          ast_log(LOG_NOTICE,"myrpt->localtx = %d\n",myrpt->localtx);
11197          ast_log(LOG_NOTICE,"myrpt->callmode = %d\n",myrpt->callmode);
11198          ast_log(LOG_NOTICE,"myrpt->mustid = %d\n",myrpt->mustid);
11199          ast_log(LOG_NOTICE,"myrpt->tounkeyed = %d\n",myrpt->tounkeyed);
11200          ast_log(LOG_NOTICE,"myrpt->tonotify = %d\n",myrpt->tonotify);
11201          ast_log(LOG_NOTICE,"myrpt->retxtimer = %ld\n",myrpt->retxtimer);
11202          ast_log(LOG_NOTICE,"myrpt->totimer = %d\n",myrpt->totimer);
11203          ast_log(LOG_NOTICE,"myrpt->tailtimer = %d\n",myrpt->tailtimer);
11204          ast_log(LOG_NOTICE,"myrpt->tailevent = %d\n",myrpt->tailevent);
11205 
11206          dl = myrpt->links.next;
11207                   while(dl != &myrpt->links){
11208             ast_log(LOG_NOTICE,"*** Link Name: %s ***\n",dl->name);
11209             ast_log(LOG_NOTICE,"        link->lasttx %d\n",dl->lasttx);
11210             ast_log(LOG_NOTICE,"        link->lastrx %d\n",dl->lastrx);
11211             ast_log(LOG_NOTICE,"        link->connected %d\n",dl->connected);
11212             ast_log(LOG_NOTICE,"        link->hasconnected %d\n",dl->hasconnected);
11213             ast_log(LOG_NOTICE,"        link->outbound %d\n",dl->outbound);
11214             ast_log(LOG_NOTICE,"        link->disced %d\n",dl->disced);
11215             ast_log(LOG_NOTICE,"        link->killme %d\n",dl->killme);
11216             ast_log(LOG_NOTICE,"        link->disctime %ld\n",dl->disctime);
11217             ast_log(LOG_NOTICE,"        link->retrytimer %ld\n",dl->retrytimer);
11218             ast_log(LOG_NOTICE,"        link->retries = %d\n",dl->retries);
11219             ast_log(LOG_NOTICE,"        link->reconnects = %d\n",dl->reconnects);
11220             ast_log(LOG_NOTICE,"        link->newkey = %d\n",dl->newkey);
11221                            dl = dl->next;
11222                   }
11223                                                                                                                                
11224          dt = myrpt->tele.next;
11225          if(dt != &myrpt->tele)
11226             ast_log(LOG_NOTICE,"*** Telemetry Queue ***\n");
11227                   while(dt != &myrpt->tele){
11228             ast_log(LOG_NOTICE,"        Telemetry mode: %d\n",dt->mode);
11229                            dt = dt->next;
11230                   }
11231          ast_log(LOG_NOTICE,"******* Variable Dump End (app_rpt) *******\n");
11232 
11233       }  
11234 
11235 
11236       if (myrpt->reload)
11237       {
11238          struct rpt_tele *inner_telem;
11239 
11240          rpt_mutex_lock(&myrpt->lock);
11241          inner_telem = myrpt->tele.next;
11242          while(inner_telem != &myrpt->tele)
11243          {
11244             ast_softhangup(inner_telem->chan,AST_SOFTHANGUP_DEV);
11245             inner_telem = inner_telem->next;
11246          }
11247          myrpt->reload = 0;
11248          rpt_mutex_unlock(&myrpt->lock);
11249          usleep(10000);
11250          /* find our index, and load the vars */
11251          for(i = 0; i < nrpts; i++)
11252          {
11253             if (&rpt_vars[i] == myrpt)
11254             {
11255                load_rpt_vars(i,0);
11256                break;
11257             }
11258          }
11259       }
11260 
11261       rpt_mutex_lock(&myrpt->lock);
11262       if (ast_check_hangup(myrpt->rxchannel)) break;
11263       if (ast_check_hangup(myrpt->txchannel)) break;
11264       if (ast_check_hangup(myrpt->pchannel)) break;
11265       if (ast_check_hangup(myrpt->monchannel)) break;
11266       if (myrpt->parrotchannel && 
11267          ast_check_hangup(myrpt->parrotchannel)) break;
11268       if (myrpt->voxchannel && 
11269          ast_check_hangup(myrpt->voxchannel)) break;
11270       if (ast_check_hangup(myrpt->txpchannel)) break;
11271       if (myrpt->dahditxchannel && ast_check_hangup(myrpt->dahditxchannel)) break;
11272 
11273       /* Set local tx with keyed */
11274       myrpt->localtx = myrpt->keyed;
11275       /* If someone's connected, and they're transmitting from their end to us, set remrx true */
11276       l = myrpt->links.next;
11277       remrx = 0;
11278       while(l != &myrpt->links)
11279       {
11280          if (l->lastrx){
11281             remrx = 1;
11282             if(l->name[0] != '0') /* Ignore '0' nodes */
11283                strcpy(myrpt->lastnodewhichkeyedusup, l->name); /* Note the node which is doing the key up */
11284          }
11285          l = l->next;
11286       }
11287       /* Create a "must_id" flag for the cleanup ID */      
11288       if(myrpt->p.idtime) /* ID time must be non-zero */
11289          myrpt->mustid |= (myrpt->idtimer) && (myrpt->keyed || remrx) ;
11290       /* Build a fresh totx from myrpt->keyed and autopatch activated */
11291       /* If full duplex, add local tx to totx */
11292       if (myrpt->p.duplex > 1) 
11293       {
11294          totx = myrpt->callmode;
11295          totx = totx || myrpt->localtx;
11296       }
11297       else
11298       {
11299          int myrx = myrpt->localtx || remrx || (!myrpt->callmode);
11300 
11301          if (lastmyrx != myrx)
11302          {
11303             voxinit_rpt(myrpt,!myrx);
11304             lastmyrx = myrx;
11305          }
11306          totx = 0;
11307          if (myrpt->callmode && (myrpt->voxtotimer <= 0))
11308          {
11309             if (myrpt->voxtostate)
11310             {
11311                myrpt->voxtotimer = myrpt->p.voxtimeout_ms;
11312                myrpt->voxtostate = 0;
11313             }           
11314             else
11315             {
11316                myrpt->voxtotimer = myrpt->p.voxrecover_ms;
11317                myrpt->voxtostate = 1;
11318             }
11319          }
11320          if (!myrpt->voxtostate)
11321             totx = myrpt->callmode && myrpt->wasvox;
11322       }
11323       /* Traverse the telemetry list to see what's queued */
11324       identqueued = 0;
11325       localmsgqueued = 0;
11326       othertelemqueued = 0;
11327       tailmessagequeued = 0;
11328       ctqueued = 0;
11329       telem = myrpt->tele.next;
11330       while(telem != &myrpt->tele)
11331       {
11332          if((telem->mode == ID) || (telem->mode == IDTALKOVER)){
11333             identqueued = 1; /* Identification telemetry */
11334          }
11335          else if(telem->mode == TAILMSG)
11336          {
11337             tailmessagequeued = 1; /* Tail message telemetry */
11338          }
11339          else if(telem->mode == STATS_TIME_LOCAL) 
11340          {
11341             localmsgqueued = 1; /* Local message */
11342          }
11343          else
11344          {
11345             if ((telem->mode != UNKEY) && (telem->mode != LINKUNKEY))
11346                othertelemqueued = 1;  /* Other telemetry */
11347             else
11348                ctqueued = 1; /* Courtesy tone telemetry */
11349          }
11350          telem = telem->next;
11351       }
11352    
11353       /* Add in any "other" telemetry, unless specified otherwise */
11354       if (!myrpt->p.notelemtx) totx = totx || othertelemqueued;
11355       /* Update external (to links) transmitter PTT state with everything but */
11356       /* ID, CT, local messages, and tailmessage telemetry */
11357       myrpt->exttx = totx;
11358       totx = totx || myrpt->dtmf_local_timer;
11359       /* If half or 3/4 duplex, add localtx to external link tx */
11360       if (myrpt->p.duplex < 2) myrpt->exttx = myrpt->exttx || myrpt->localtx;
11361       /* Add in ID telemetry to local transmitter */
11362       totx = totx || remrx;
11363       /* If 3/4 or full duplex, add in ident, CT telemetry, and local messages */
11364       if (myrpt->p.duplex > 0)
11365          totx = totx || identqueued || ctqueued || localmsgqueued;
11366       /* If full duplex, add local dtmf stuff active */
11367       if (myrpt->p.duplex > 1) 
11368       {
11369          totx = totx || (myrpt->dtmfidx > -1) ||
11370             myrpt->cmdnode[0];
11371       }
11372       /* add in parrot stuff */
11373       totx = totx || (myrpt->parrotstate > 1);
11374       /* Reset time out timer variables if there is no activity */
11375       if (!totx) 
11376       {
11377          myrpt->totimer = myrpt->p.totime;
11378          myrpt->tounkeyed = 0;
11379          myrpt->tonotify = 0;
11380       }
11381       else{
11382          myrpt->tailtimer = myrpt->p.s[myrpt->p.sysstate_cur].alternatetail ?
11383             myrpt->p.althangtime : /* Initialize tail timer */
11384             myrpt->p.hangtime;
11385       }
11386       /* Disable the local transmitter if we are timed out */
11387       totx = totx && myrpt->totimer;
11388       /* if timed-out and not said already, say it */
11389       if ((!myrpt->totimer) && (!myrpt->tonotify))
11390       {
11391          myrpt->tonotify = 1;
11392          myrpt->timeouts++;
11393          rpt_mutex_unlock(&myrpt->lock);
11394          rpt_telemetry(myrpt,TIMEOUT,NULL);
11395          rpt_mutex_lock(&myrpt->lock);
11396       }
11397 
11398       /* If unkey and re-key, reset time out timer */
11399       if ((!totx) && (!myrpt->totimer) && (!myrpt->tounkeyed) && (!myrpt->keyed))
11400       {
11401          myrpt->tounkeyed = 1;
11402       }
11403       if ((!totx) && (!myrpt->totimer) && myrpt->tounkeyed && myrpt->keyed)
11404       {
11405          myrpt->totimer = myrpt->p.totime;
11406          myrpt->tounkeyed = 0;
11407          myrpt->tonotify = 0;
11408          rpt_mutex_unlock(&myrpt->lock);
11409          continue;
11410       }
11411       /* if timed-out and in circuit busy after call */
11412       if ((!totx) && (!myrpt->totimer) && (myrpt->callmode == 4))
11413       {
11414           if(debug)
11415             ast_log(LOG_NOTICE, "timed-out and in circuit busy after call\n");
11416          myrpt->callmode = 0;
11417          myrpt->macropatch=0;
11418          channel_revert(myrpt);
11419       }
11420       /* get rid of tail if timed out */
11421       if (!myrpt->totimer) myrpt->tailtimer = 0;
11422       /* if not timed-out, add in tail */
11423       if (myrpt->totimer) totx = totx || myrpt->tailtimer;
11424       /* If user or links key up or are keyed up over standard ID, switch to talkover ID, if one is defined */
11425       /* If tail message, kill the message if someone keys up over it */ 
11426       if ((myrpt->keyed || remrx) && ((identqueued && idtalkover) || (tailmessagequeued))) {
11427          int hasid = 0,hastalkover = 0;
11428 
11429          telem = myrpt->tele.next;
11430          while(telem != &myrpt->tele){
11431             if(telem->mode == ID){
11432                if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
11433                hasid = 1;
11434             }
11435             if(telem->mode == TAILMSG){
11436                                         if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
11437                                 }
11438             if (telem->mode == IDTALKOVER) hastalkover = 1;
11439             telem = telem->next;
11440          }
11441          rpt_mutex_unlock(&myrpt->lock);
11442          if (hasid && (!hastalkover)) rpt_telemetry(myrpt, IDTALKOVER, NULL); /* Start Talkover ID */
11443          rpt_mutex_lock(&myrpt->lock);
11444       }
11445       /* Try to be polite */
11446       /* If the repeater has been inactive for longer than the ID time, do an initial ID in the tail*/
11447       /* If within 30 seconds of the time to ID, try do it in the tail */
11448       /* else if at ID time limit, do it right over the top of them */
11449       /* Lastly, if the repeater has been keyed, and the ID timer is expired, do a clean up ID */
11450       if(myrpt->mustid && (!myrpt->idtimer))
11451          queue_id(myrpt);
11452 
11453       if ((myrpt->p.idtime && totx && (!myrpt->exttx) &&
11454           (myrpt->idtimer <= myrpt->p.politeid) && myrpt->tailtimer)) /* ID time must be non-zero */ 
11455          {
11456             myrpt->tailid = 1;
11457          }
11458 
11459       /* If tail timer expires, then check for tail messages */
11460 
11461       if(myrpt->tailevent){
11462          myrpt->tailevent = 0;
11463          if(myrpt->tailid){
11464             totx = 1;
11465             queue_id(myrpt);
11466          }
11467          else if ((myrpt->p.tailmessages[0]) &&
11468             (myrpt->p.tailmessagetime) && (myrpt->tmsgtimer == 0)){
11469                totx = 1;
11470                myrpt->tmsgtimer = myrpt->p.tailmessagetime; 
11471                rpt_mutex_unlock(&myrpt->lock);
11472                rpt_telemetry(myrpt, TAILMSG, NULL);
11473                rpt_mutex_lock(&myrpt->lock);
11474          }  
11475       }
11476 
11477       /* Main TX control */
11478 
11479       /* let telemetry transmit anyway (regardless of timeout) */
11480       if (myrpt->p.duplex > 0) totx = totx || (myrpt->tele.next != &myrpt->tele);
11481       totx = totx && !myrpt->p.s[myrpt->p.sysstate_cur].txdisable;
11482       myrpt->txrealkeyed = totx;
11483       totx = totx || (!AST_LIST_EMPTY(&myrpt->txq));
11484       if (totx && (!lasttx))
11485       {
11486          char mydate[100],myfname[100];
11487          time_t myt;
11488 
11489          if (myrpt->monstream) ast_closestream(myrpt->monstream);
11490          if (myrpt->p.archivedir)
11491          {
11492             long blocksleft;
11493 
11494             time(&myt);
11495             strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
11496                localtime(&myt));
11497             sprintf(myfname,"%s/%s/%s",myrpt->p.archivedir,
11498                myrpt->name,mydate);
11499             myrpt->monstream = ast_writefile(myfname,"wav49",
11500                "app_rpt Air Archive",O_CREAT | O_APPEND,0,0600);
11501             if (myrpt->p.monminblocks)
11502             {
11503                blocksleft = diskavail(myrpt);
11504                if (blocksleft >= myrpt->p.monminblocks)
11505                   donodelog(myrpt,"TXKEY,MAIN");
11506             } else donodelog(myrpt,"TXKEY,MAIN");
11507          }
11508          lasttx = 1;
11509          myrpt->txkeyed = 1;
11510          time(&myrpt->lasttxkeyedtime);
11511          myrpt->dailykeyups++;
11512          myrpt->totalkeyups++;
11513          rpt_mutex_unlock(&myrpt->lock);
11514          ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
11515          rpt_mutex_lock(&myrpt->lock);
11516       }
11517       if ((!totx) && lasttx)
11518       {
11519          if (myrpt->monstream) ast_closestream(myrpt->monstream);
11520          myrpt->monstream = NULL;
11521 
11522          lasttx = 0;
11523          myrpt->txkeyed = 0;
11524          time(&myrpt->lasttxkeyedtime);
11525          rpt_mutex_unlock(&myrpt->lock);
11526          ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
11527          rpt_mutex_lock(&myrpt->lock);
11528          donodelog(myrpt,"TXUNKEY,MAIN");
11529       }
11530       time(&t);
11531       /* if DTMF timeout */
11532       if ((!myrpt->cmdnode[0]) && (myrpt->dtmfidx >= 0) && ((myrpt->dtmf_time + DTMF_TIMEOUT) < t))
11533       {
11534          myrpt->inpadtest = 0;
11535          myrpt->dtmfidx = -1;
11536          myrpt->dtmfbuf[0] = 0;
11537       }        
11538       /* if remote DTMF timeout */
11539       if ((myrpt->rem_dtmfidx >= 0) && ((myrpt->rem_dtmf_time + DTMF_TIMEOUT) < t))
11540       {
11541          myrpt->inpadtest = 0;
11542          myrpt->rem_dtmfidx = -1;
11543          myrpt->rem_dtmfbuf[0] = 0;
11544       }  
11545 
11546       if (myrpt->exttx && myrpt->parrotchannel && 
11547          myrpt->p.parrotmode && (!myrpt->parrotstate))
11548       {
11549          char myfname[300];
11550 
11551          ci.confno = myrpt->conf;
11552          ci.confmode = DAHDI_CONF_CONFANNMON;
11553          ci.chan = 0;
11554 
11555          /* first put the channel on the conference in announce mode */
11556          if (ioctl(myrpt->parrotchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11557          {
11558             ast_log(LOG_WARNING, "Unable to set conference mode for parrot\n");
11559             break;
11560          }
11561 
11562          sprintf(myfname,PARROTFILE,myrpt->name,myrpt->parrotcnt);
11563          strcat(myfname,".wav");
11564          unlink(myfname);        
11565          sprintf(myfname,PARROTFILE,myrpt->name,myrpt->parrotcnt);
11566          myrpt->parrotstate = 1;
11567          myrpt->parrottimer = myrpt->p.parrottime;
11568          if (myrpt->parrotstream) 
11569             ast_closestream(myrpt->parrotstream);
11570          myrpt->parrotstream = NULL;
11571          myrpt->parrotstream = ast_writefile(myfname,"wav",
11572             "app_rpt Parrot",O_CREAT | O_TRUNC,0,0600);
11573       }
11574 
11575       /* Reconnect */
11576    
11577       l = myrpt->links.next;
11578       while(l != &myrpt->links)
11579       {
11580          if (l->killme)
11581          {
11582             /* remove from queue */
11583             remque((struct qelem *) l);
11584             if (!strcmp(myrpt->cmdnode,l->name))
11585                myrpt->cmdnode[0] = 0;
11586             rpt_mutex_unlock(&myrpt->lock);
11587             /* hang-up on call to device */
11588             if (l->chan) ast_hangup(l->chan);
11589             ast_hangup(l->pchan);
11590             ast_free(l);
11591             rpt_mutex_lock(&myrpt->lock);
11592             /* re-start link traversal */
11593             l = myrpt->links.next;
11594             continue;
11595          }
11596          l = l->next;
11597       }
11598       n = 0;
11599       cs[n++] = myrpt->rxchannel;
11600       cs[n++] = myrpt->pchannel;
11601       cs[n++] = myrpt->monchannel;
11602       if (myrpt->parrotchannel) cs[n++] = myrpt->parrotchannel;
11603       if (myrpt->voxchannel) cs[n++] = myrpt->voxchannel;
11604       cs[n++] = myrpt->txpchannel;
11605       if (myrpt->txchannel != myrpt->rxchannel) cs[n++] = myrpt->txchannel;
11606       if (myrpt->dahditxchannel != myrpt->txchannel)
11607          cs[n++] = myrpt->dahditxchannel;
11608       l = myrpt->links.next;
11609       while(l != &myrpt->links)
11610       {
11611          if ((!l->killme) && (!l->disctime) && l->chan)
11612          {
11613             cs[n++] = l->chan;
11614             cs[n++] = l->pchan;
11615          }
11616          l = l->next;
11617       }
11618       if ((myrpt->topkeystate == 1) && 
11619           ((t - myrpt->topkeytime) > TOPKEYWAIT))
11620       {
11621          myrpt->topkeystate = 2;
11622          qsort(myrpt->topkey,TOPKEYN,sizeof(struct rpt_topkey),
11623             topcompar);
11624       }
11625       rpt_mutex_unlock(&myrpt->lock);
11626 
11627       if (myrpt->topkeystate == 2)
11628       {
11629          rpt_telemetry(myrpt,TOPKEY,NULL);
11630          myrpt->topkeystate = 3;
11631       }
11632       ms = MSWAIT;
11633       for(x = 0; x < n; x++)
11634       {
11635          int s = -(-x - myrpt->scram - 1) % n;
11636          cs1[x] = cs[s];
11637       }
11638       myrpt->scram++;
11639       who = ast_waitfor_n(cs1,n,&ms);
11640       if (who == NULL) ms = 0;
11641       elap = MSWAIT - ms;
11642       rpt_mutex_lock(&myrpt->lock);
11643       l = myrpt->links.next;
11644       while(l != &myrpt->links)
11645       {
11646          int myrx;
11647 
11648          if (l->voxtotimer) l->voxtotimer -= elap;
11649          if (l->voxtotimer < 0) l->voxtotimer = 0;
11650 
11651          if (l->lasttx != l->lasttx1)
11652          {
11653             voxinit_link(l,!l->lasttx);
11654             l->lasttx1 = l->lasttx;
11655          }
11656          myrx = l->lastrealrx;
11657          if ((l->phonemode) && (l->phonevox))
11658          {
11659             myrx = myrx || (!AST_LIST_EMPTY(&l->rxq));
11660             if (l->voxtotimer <= 0)
11661             {
11662                if (l->voxtostate)
11663                {
11664                   l->voxtotimer = myrpt->p.voxtimeout_ms;
11665                   l->voxtostate = 0;
11666                }           
11667                else
11668                {
11669                   l->voxtotimer = myrpt->p.voxrecover_ms;
11670                   l->voxtostate = 1;
11671                }
11672             }
11673             if (!l->voxtostate)
11674                myrx = myrx || l->wasvox ;
11675          }
11676          l->lastrx = myrx;
11677          if (l->linklisttimer)
11678          {
11679             l->linklisttimer -= elap;
11680             if (l->linklisttimer < 0) l->linklisttimer = 0;
11681          }
11682          if ((!l->linklisttimer) && (l->name[0] != '0') && (!l->isremote))
11683          {
11684             struct   ast_frame lf;
11685 
11686             memset(&lf,0,sizeof(lf));
11687             lf.frametype = AST_FRAME_TEXT;
11688             lf.subclass = 0;
11689             lf.offset = 0;
11690             lf.mallocd = 0;
11691             lf.samples = 0;
11692             l->linklisttimer = LINKLISTTIME;
11693             strcpy(lstr,"L ");
11694             __mklinklist(myrpt,l,lstr + 2);
11695             if (l->chan)
11696             {
11697                lf.datalen = strlen(lstr) + 1;
11698                lf.data.ptr = lstr;
11699                ast_write(l->chan,&lf);
11700                if (debug > 6) ast_log(LOG_NOTICE,
11701                   "@@@@ node %s sent node string %s to node %s\n",
11702                      myrpt->name,lstr,l->name);
11703             }
11704          }
11705          if (l->newkey)
11706          {
11707             if ((l->retxtimer += elap) >= REDUNDANT_TX_TIME)
11708             {
11709                l->retxtimer = 0;
11710                if (l->chan && l->phonemode == 0) 
11711                {
11712                   if (l->lasttx)
11713                      ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
11714                   else
11715                      ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
11716                }
11717             }
11718             if ((l->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 5))
11719             {
11720                if (debug == 7) printf("@@@@ rx un-key\n");
11721                l->lastrealrx = 0;
11722                l->rerxtimer = 0;
11723                if (l->lastrx1)
11724                {
11725                   if (myrpt->p.archivedir)
11726                   {
11727                      char str[100];
11728    
11729                      sprintf(str,"RXUNKEY(T),%s",l->name);
11730                      donodelog(myrpt,str);
11731                   }
11732                   if(myrpt->p.duplex) 
11733                      rpt_telemetry(myrpt,LINKUNKEY,l);
11734                   l->lastrx1 = 0;
11735                }
11736             }
11737          }
11738          if (l->disctime) /* Disconnect timer active on a channel ? */
11739          {
11740             l->disctime -= elap;
11741             if (l->disctime <= 0) /* Disconnect timer expired on inbound channel ? */
11742                l->disctime = 0; /* Yep */
11743          }
11744 
11745          if (l->retrytimer)
11746          {
11747             l->retrytimer -= elap;
11748             if (l->retrytimer < 0) l->retrytimer = 0;
11749          }
11750 
11751          /* Tally connect time */
11752          l->connecttime += elap;
11753 
11754          /* ignore non-timing channels */
11755          if (l->elaptime < 0)
11756          {
11757             l = l->next;
11758             continue;
11759          }
11760          l->elaptime += elap;
11761          /* if connection has taken too long */
11762          if ((l->elaptime > MAXCONNECTTIME) && 
11763             ((!l->chan) || (l->chan->_state != AST_STATE_UP)))
11764          {
11765             l->elaptime = 0;
11766             rpt_mutex_unlock(&myrpt->lock);
11767             if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
11768             rpt_mutex_lock(&myrpt->lock);
11769             break;
11770          }
11771          if ((!l->chan) && (!l->retrytimer) && l->outbound && 
11772             (l->retries++ < l->max_retries) && (l->hasconnected))
11773          {
11774             if (l->chan) ast_hangup(l->chan);
11775             l->chan = 0;
11776             rpt_mutex_unlock(&myrpt->lock);
11777             if ((l->name[0] != '0') && (!l->isremote))
11778             {
11779                if (attempt_reconnect(myrpt,l) == -1)
11780                {
11781                   l->retrytimer = RETRY_TIMER_MS;
11782                } 
11783             }
11784             else 
11785             {
11786                l->retrytimer = l->max_retries + 1;
11787             }
11788 
11789             rpt_mutex_lock(&myrpt->lock);
11790             break;
11791          }
11792          if ((!l->chan) && (!l->retrytimer) && l->outbound &&
11793             (l->retries >= l->max_retries))
11794          {
11795             /* remove from queue */
11796             remque((struct qelem *) l);
11797             if (!strcmp(myrpt->cmdnode,l->name))
11798                myrpt->cmdnode[0] = 0;
11799             rpt_mutex_unlock(&myrpt->lock);
11800             if (l->name[0] != '0')
11801             {
11802                if (!l->hasconnected)
11803                   rpt_telemetry(myrpt,CONNFAIL,l);
11804                else rpt_telemetry(myrpt,REMDISC,l);
11805             }
11806             if (myrpt->p.archivedir)
11807             {
11808                char str[100];
11809 
11810                if (!l->hasconnected)
11811                   sprintf(str,"LINKFAIL,%s",l->name);
11812                else
11813                   sprintf(str,"LINKDISC,%s",l->name);
11814                donodelog(myrpt,str);
11815             }
11816             /* hang-up on call to device */
11817             ast_hangup(l->pchan);
11818             ast_free(l);
11819                                 rpt_mutex_lock(&myrpt->lock);
11820             break;
11821          }
11822             if ((!l->chan) && (!l->disctime) && (!l->outbound))
11823             {
11824             if(debug)ast_log(LOG_NOTICE, "LINKDISC AA\n");
11825                 /* remove from queue */
11826                 remque((struct qelem *) l);
11827             if(myrpt->links.next==&myrpt->links)channel_revert(myrpt);
11828                 if (!strcmp(myrpt->cmdnode,l->name))myrpt->cmdnode[0] = 0;
11829                 rpt_mutex_unlock(&myrpt->lock);
11830             if (l->name[0] != '0') 
11831             {
11832                   rpt_telemetry(myrpt,REMDISC,l);
11833             }
11834             if (myrpt->p.archivedir)
11835             {
11836                char str[100];
11837                sprintf(str,"LINKDISC,%s",l->name);
11838                donodelog(myrpt,str);
11839             }
11840                 /* hang-up on call to device */
11841                 ast_hangup(l->pchan);
11842                 ast_free(l);
11843                 rpt_mutex_lock(&myrpt->lock);
11844                 break;
11845             }
11846          l = l->next;
11847       }
11848       if (myrpt->linkposttimer)
11849       {
11850          myrpt->linkposttimer -= elap;
11851          if (myrpt->linkposttimer < 0) myrpt->linkposttimer = 0;
11852       }
11853       if (myrpt->linkposttimer <= 0)
11854       {
11855          int nstr;
11856          char lst,*str;
11857          time_t now;
11858 
11859          myrpt->linkposttimer = LINKPOSTTIME;
11860          nstr = 0;
11861          for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
11862          {
11863             /* if is not a real link, ignore it */
11864             if (l->name[0] == '0') continue;
11865             nstr += strlen(l->name) + 1;
11866          }
11867          str = ast_malloc(nstr + 256);
11868          if (!str)
11869          {
11870             ast_log(LOG_NOTICE,"Cannot ast_malloc()\n");
11871             break;
11872          }
11873          nstr = 0;
11874          strcpy(str,"nodes=");
11875          for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
11876          {
11877             /* if is not a real link, ignore it */
11878             if (l->name[0] == '0') continue;
11879             lst = 'T';
11880             if (!l->mode) lst = 'R';
11881             if (!l->thisconnected) lst = 'C';
11882             if (nstr) strcat(str,",");
11883             sprintf(str + strlen(str),"%c%s",lst,l->name);
11884             nstr = 1;
11885          }
11886                   p = strstr(tdesc, "version");
11887                   if(p){
11888             int vmajor,vminor;
11889             if(sscanf(p, "version %30d.%30d", &vmajor, &vminor) == 2)
11890                sprintf(str + strlen(str),"&apprptvers=%d.%d",vmajor,vminor);
11891          }
11892          time(&now);
11893          sprintf(str + strlen(str),"&apprptuptime=%d",(int)(now-starttime));
11894          sprintf(str + strlen(str),
11895          "&totalkerchunks=%d&totalkeyups=%d&totaltxtime=%d&timeouts=%d&totalexecdcommands=%d",
11896          myrpt->totalkerchunks,myrpt->totalkeyups,(int) myrpt->totaltxtime/1000,
11897          myrpt->timeouts,myrpt->totalexecdcommands);
11898          rpt_mutex_unlock(&myrpt->lock);
11899          statpost(myrpt,str);
11900          rpt_mutex_lock(&myrpt->lock);
11901          ast_free(str);
11902       }
11903       if (myrpt->keyposttimer)
11904       {
11905          myrpt->keyposttimer -= elap;
11906          if (myrpt->keyposttimer < 0) myrpt->keyposttimer = 0;
11907       }
11908       if (myrpt->keyposttimer <= 0)
11909       {
11910          char str[100];
11911          int diff = 0;
11912          time_t now;
11913 
11914          myrpt->keyposttimer = KEYPOSTTIME;
11915          time(&now);
11916          if (myrpt->lastkeyedtime)
11917          {
11918             diff = (int)(now - myrpt->lastkeyedtime);
11919          }
11920          sprintf(str,"keyed=%d&keytime=%d",myrpt->keyed,diff);
11921          rpt_mutex_unlock(&myrpt->lock);
11922          statpost(myrpt,str);
11923          rpt_mutex_lock(&myrpt->lock);
11924       }
11925       if(totx){
11926          myrpt->dailytxtime += elap;
11927          myrpt->totaltxtime += elap;
11928       }
11929       i = myrpt->tailtimer;
11930       if (myrpt->tailtimer) myrpt->tailtimer -= elap;
11931       if (myrpt->tailtimer < 0) myrpt->tailtimer = 0;
11932       if((i) && (myrpt->tailtimer == 0))
11933          myrpt->tailevent = 1;
11934       if ((!myrpt->p.s[myrpt->p.sysstate_cur].totdisable) && myrpt->totimer) myrpt->totimer -= elap;
11935       if (myrpt->totimer < 0) myrpt->totimer = 0;
11936       if (myrpt->idtimer) myrpt->idtimer -= elap;
11937       if (myrpt->idtimer < 0) myrpt->idtimer = 0;
11938       if (myrpt->tmsgtimer) myrpt->tmsgtimer -= elap;
11939       if (myrpt->tmsgtimer < 0) myrpt->tmsgtimer = 0;
11940       if (myrpt->voxtotimer) myrpt->voxtotimer -= elap;
11941       if (myrpt->voxtotimer < 0) myrpt->voxtotimer = 0;
11942       if (myrpt->exttx)
11943       {
11944          myrpt->parrottimer = myrpt->p.parrottime;
11945       }
11946       else
11947       {
11948          if (myrpt->parrottimer) myrpt->parrottimer -= elap;
11949          if (myrpt->parrottimer < 0) myrpt->parrottimer = 0;
11950       }
11951       /* do macro timers */
11952       if (myrpt->macrotimer) myrpt->macrotimer -= elap;
11953       if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
11954       /* do local dtmf timer */
11955       if (myrpt->dtmf_local_timer)
11956       {
11957          if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
11958          if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
11959       }
11960       do_dtmf_local(myrpt,0);
11961       /* Execute scheduler appx. every 2 tenths of a second */
11962       if (myrpt->skedtimer <= 0){
11963          myrpt->skedtimer = 200;
11964          do_scheduler(myrpt);
11965       }
11966       else
11967          myrpt->skedtimer -=elap;
11968       if (!ms) 
11969       {
11970          rpt_mutex_unlock(&myrpt->lock);
11971          continue;
11972       }
11973       if (myrpt->p.parrotmode && (myrpt->parrotstate == 1) &&
11974          (myrpt->parrottimer <= 0))
11975       {
11976 
11977          ci.confno = 0;
11978          ci.confmode = 0;
11979          ci.chan = 0;
11980 
11981          /* first put the channel on the conference in announce mode */
11982          if (ioctl(myrpt->parrotchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11983          {
11984             ast_log(LOG_WARNING, "Unable to set conference mode for parrot\n");
11985             break;
11986          }
11987          if (myrpt->parrotstream) 
11988             ast_closestream(myrpt->parrotstream);
11989          myrpt->parrotstream = NULL;
11990          myrpt->parrotstate = 2;
11991          rpt_telemetry(myrpt,PARROT,(void *) ((intptr_t)myrpt->parrotcnt++)); 
11992       }        
11993       if (myrpt->cmdAction.state == CMD_STATE_READY)
11994       { /* there is a command waiting to be processed */
11995          int status;
11996          myrpt->cmdAction.state = CMD_STATE_EXECUTING;
11997          // lose the lock
11998          rpt_mutex_unlock(&myrpt->lock);
11999          // do the function
12000          status = (*function_table[myrpt->cmdAction.functionNumber].function)(myrpt,myrpt->cmdAction.param, myrpt->cmdAction.digits, myrpt->cmdAction.command_source, NULL);
12001          // get the lock again
12002          rpt_mutex_lock(&myrpt->lock);
12003          myrpt->cmdAction.state = CMD_STATE_IDLE;
12004       } /* if myrpt->cmdAction.state == CMD_STATE_READY */
12005       
12006       c = myrpt->macrobuf[0];
12007       time(&t);
12008       if (c && (!myrpt->macrotimer) && 
12009          starttime && (t > (starttime + START_DELAY)))
12010       {
12011          char cin = c & 0x7f;
12012          myrpt->macrotimer = MACROTIME;
12013          memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
12014          if ((cin == 'p') || (cin == 'P'))
12015             myrpt->macrotimer = MACROPTIME;
12016          rpt_mutex_unlock(&myrpt->lock);
12017          if (myrpt->p.archivedir)
12018          {
12019             char str[100];
12020 
12021             sprintf(str,"DTMF(M),MAIN,%c",cin);
12022             donodelog(myrpt,str);
12023          }
12024          local_dtmf_helper(myrpt,c);
12025       } else rpt_mutex_unlock(&myrpt->lock);
12026       if (who == myrpt->rxchannel) /* if it was a read from rx */
12027       {
12028          int ismuted;
12029 
12030          f = ast_read(myrpt->rxchannel);
12031          if (!f)
12032          {
12033             if (debug) printf("@@@@ rpt:Hung Up\n");
12034             break;
12035          }
12036          if (f->frametype == AST_FRAME_VOICE)
12037          {
12038 #ifdef   _MDC_DECODE_H_
12039             unsigned char ubuf[2560];
12040             short *sp;
12041             int n;
12042 #endif
12043 
12044             if ((!myrpt->localtx) && (!myrpt->p.linktolink)) {
12045                memset(f->data.ptr,0,f->datalen);
12046             }
12047 
12048 #ifdef   _MDC_DECODE_H_
12049             sp = (short *) f->data;
12050             /* convert block to unsigned char */
12051             for(n = 0; n < f->datalen / 2; n++)
12052             {
12053                ubuf[n] = (*sp++ >> 8) + 128;
12054             }
12055             n = mdc_decoder_process_samples(myrpt->mdc,ubuf,f->datalen / 2);
12056             if (n == 1)
12057             {
12058                   unsigned char op,arg;
12059                   unsigned short unitID;
12060 
12061                   mdc_decoder_get_packet(myrpt->mdc,&op,&arg,&unitID);
12062                   if (debug > 2)
12063                   {
12064                      ast_log(LOG_NOTICE,"Got (single-length) packet:\n");
12065                      ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
12066                         op & 255,arg & 255,unitID);
12067                   }
12068                   if ((op == 1) && (arg == 0))
12069                   {
12070                      myrpt->lastunit = unitID;
12071                      mdc1200_notify(myrpt,NULL,myrpt->lastunit);
12072                      mdc1200_send(myrpt,myrpt->lastunit);
12073                   }
12074             }
12075             if ((debug > 2) && (i == 2))
12076             {
12077                unsigned char op,arg,ex1,ex2,ex3,ex4;
12078                unsigned short unitID;
12079 
12080                mdc_decoder_get_double_packet(myrpt->mdc,&op,&arg,&unitID,
12081                   &ex1,&ex2,&ex3,&ex4);
12082                ast_log(LOG_NOTICE,"Got (double-length) packet:\n");
12083                ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
12084                   op & 255,arg & 255,unitID);
12085                ast_log(LOG_NOTICE,"ex1: %02x, ex2: %02x, ex3: %02x, ex4: %02x\n",
12086                   ex1 & 255, ex2 & 255, ex3 & 255, ex4 & 255);
12087             }
12088 #endif
12089 #ifdef   __RPT_NOTCH
12090             /* apply inbound filters, if any */
12091             rpt_filter(myrpt,f->data,f->datalen / 2);
12092 #endif
12093             if (ioctl(myrpt->dahdirxchannel->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
12094             {
12095                ismuted = 0;
12096             }
12097             if (dtmfed) ismuted = 1;
12098             dtmfed = 0;
12099             if (ismuted)
12100             {
12101                memset(f->data.ptr,0,f->datalen);
12102                if (myrpt->lastf1)
12103                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12104                if (myrpt->lastf2)
12105                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12106             } 
12107             if (f) f2 = ast_frdup(f);
12108             else f2 = NULL;
12109             f1 = myrpt->lastf2;
12110             myrpt->lastf2 = myrpt->lastf1;
12111             myrpt->lastf1 = f2;
12112             if (ismuted)
12113             {
12114                if (myrpt->lastf1)
12115                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12116                if (myrpt->lastf2)
12117                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12118             }
12119             if (f1)
12120             {
12121                ast_write(myrpt->pchannel,f1);
12122                ast_frfree(f1);
12123             }
12124          }
12125 #ifndef  OLD_ASTERISK
12126          else if (f->frametype == AST_FRAME_DTMF_BEGIN)
12127          {
12128             if (myrpt->lastf1)
12129                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12130             if (myrpt->lastf2)
12131                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12132             dtmfed = 1;
12133          }
12134 #endif
12135          else if (f->frametype == AST_FRAME_DTMF)
12136          {
12137             c = (char) f->subclass; /* get DTMF char */
12138             ast_frfree(f);
12139             if (myrpt->lastf1)
12140                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
12141             if (myrpt->lastf2)
12142                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
12143             dtmfed = 1;
12144             if (!myrpt->keyed) continue;
12145             c = func_xlat(myrpt,c,&myrpt->p.inxlat);
12146             if (c) local_dtmf_helper(myrpt,c);
12147             continue;
12148          }                 
12149          else if (f->frametype == AST_FRAME_CONTROL)
12150          {
12151             if (f->subclass == AST_CONTROL_HANGUP)
12152             {
12153                if (debug) printf("@@@@ rpt:Hung Up\n");
12154                ast_frfree(f);
12155                break;
12156             }
12157             /* if RX key */
12158             if (f->subclass == AST_CONTROL_RADIO_KEY)
12159             {
12160                if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink)) 
12161                {
12162                   if (debug == 7) printf("@@@@ rx key\n");
12163                   myrpt->keyed = 1;
12164                   time(&myrpt->lastkeyedtime);
12165                   myrpt->keyposttimer = KEYPOSTSHORTTIME;
12166                }
12167                if (myrpt->p.archivedir)
12168                {
12169                   donodelog(myrpt,"RXKEY,MAIN");
12170                }
12171                if (f->datalen && f->data.ptr)
12172                {
12173                   char busy = 0;
12174 
12175                   if (debug) ast_log(LOG_NOTICE,"Got PL %s on node %s\n",(char *)f->data.ptr,myrpt->name);
12176                   // ctcss code autopatch initiate
12177                   if (strstr((char *)f->data.ptr,"/M/")&& !myrpt->macropatch)
12178                   {
12179                       char value[16];
12180                      strcat(value,"*6");
12181                      myrpt->macropatch=1;
12182                      rpt_mutex_lock(&myrpt->lock);
12183                      if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(value)){
12184                         rpt_mutex_unlock(&myrpt->lock);
12185                         busy=1;
12186                      }
12187                      if(!busy){
12188                         myrpt->macrotimer = MACROTIME;
12189                         strncat(myrpt->macrobuf,value,MAXMACRO - 1);
12190                         if (!busy) strcpy(myrpt->lasttone,(char*)f->data.ptr);
12191                      }
12192                      rpt_mutex_unlock(&myrpt->lock);
12193                   }
12194                   else if (strcmp((char *)f->data.ptr,myrpt->lasttone))
12195                   {
12196                      char *value = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.tonemacro, (char *)f->data.ptr);
12197                      if (value)
12198                      {
12199                         if (debug) ast_log(LOG_NOTICE,"Tone %s doing %s on node %s\n",(char *) f->data.ptr,value,myrpt->name);
12200                         rpt_mutex_lock(&myrpt->lock);
12201                         if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(value)){
12202                            rpt_mutex_unlock(&myrpt->lock);
12203                            busy=1;
12204                         }
12205                         if(!busy){
12206                            myrpt->macrotimer = MACROTIME;
12207                            strncat(myrpt->macrobuf,value,MAXMACRO - 1);
12208                         }
12209                         rpt_mutex_unlock(&myrpt->lock);
12210                      }
12211                      if (!busy) strcpy(myrpt->lasttone,(char*)f->data.ptr);
12212                   }
12213                } else myrpt->lasttone[0] = 0;
12214             }
12215             /* if RX un-key */
12216             if (f->subclass == AST_CONTROL_RADIO_UNKEY)
12217             {
12218                if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink))
12219                {
12220                   if (debug == 7) printf("@@@@ rx un-key\n");
12221                   if(myrpt->p.duplex && myrpt->keyed) {
12222                      rpt_telemetry(myrpt,UNKEY,NULL);
12223                   }
12224                }
12225                myrpt->keyed = 0;
12226                time(&myrpt->lastkeyedtime);
12227                myrpt->keyposttimer = KEYPOSTSHORTTIME;
12228                if (myrpt->p.archivedir)
12229                {
12230                   donodelog(myrpt,"RXUNKEY,MAIN");
12231                }
12232             }
12233          }
12234          ast_frfree(f);
12235          continue;
12236       }
12237       if (who == myrpt->pchannel) /* if it was a read from pseudo */
12238       {
12239          f = ast_read(myrpt->pchannel);
12240          if (!f)
12241          {
12242             if (debug) printf("@@@@ rpt:Hung Up\n");
12243             break;
12244          }
12245          if (f->frametype == AST_FRAME_VOICE)
12246          {
12247             ast_write(myrpt->txpchannel,f);
12248          }
12249          if (f->frametype == AST_FRAME_CONTROL)
12250          {
12251             if (f->subclass == AST_CONTROL_HANGUP)
12252             {
12253                if (debug) printf("@@@@ rpt:Hung Up\n");
12254                ast_frfree(f);
12255                break;
12256             }
12257          }
12258          ast_frfree(f);
12259          continue;
12260       }
12261       if (who == myrpt->txchannel) /* if it was a read from tx */
12262       {
12263          f = ast_read(myrpt->txchannel);
12264          if (!f)
12265          {
12266             if (debug) printf("@@@@ rpt:Hung Up\n");
12267             break;
12268          }
12269          if (f->frametype == AST_FRAME_CONTROL)
12270          {
12271             if (f->subclass == AST_CONTROL_HANGUP)
12272             {
12273                if (debug) printf("@@@@ rpt:Hung Up\n");
12274                ast_frfree(f);
12275                break;
12276             }
12277          }
12278          ast_frfree(f);
12279          continue;
12280       }
12281       if (who == myrpt->dahditxchannel) /* if it was a read from pseudo-tx */
12282       {
12283          f = ast_read(myrpt->dahditxchannel);
12284          if (!f)
12285          {
12286             if (debug) printf("@@@@ rpt:Hung Up\n");
12287             break;
12288          }
12289          if (f->frametype == AST_FRAME_VOICE)
12290          {
12291             struct ast_frame *vframe;
12292 
12293             if (myrpt->p.duplex < 2)
12294             {
12295                if (myrpt->txrealkeyed) 
12296                {
12297                   if ((!myfirst) && myrpt->callmode)
12298                   {
12299                       x = 0;
12300                       AST_LIST_TRAVERSE(&myrpt->txq, vframe,
12301                      frame_list) x++;
12302                       for(;x < myrpt->p.simplexpatchdelay; x++)
12303                       {
12304                         vframe = ast_frdup(f);
12305                         memset(vframe->data.ptr,0,vframe->datalen);
12306                         AST_LIST_INSERT_TAIL(&myrpt->txq,vframe,frame_list);
12307                       }
12308                       myfirst = 1;
12309                   }
12310                   vframe = ast_frdup(f);
12311                   AST_LIST_INSERT_TAIL(&myrpt->txq,
12312                      vframe,frame_list);
12313                } else myfirst = 0;
12314                x = 0;
12315                AST_LIST_TRAVERSE(&myrpt->txq, vframe,
12316                   frame_list) x++;
12317                if (!x)
12318                {
12319                   memset(f->data.ptr,0,f->datalen);
12320                }
12321                else
12322                {
12323                   ast_frfree(f);
12324                   f = AST_LIST_REMOVE_HEAD(&myrpt->txq,
12325                      frame_list);
12326                }
12327             }
12328             else
12329             {
12330                while((vframe = AST_LIST_REMOVE_HEAD(&myrpt->txq,
12331                   frame_list))) ast_frfree(vframe);
12332             }
12333             ast_write(myrpt->txchannel,f);
12334          }
12335          if (f->frametype == AST_FRAME_CONTROL)
12336          {
12337             if (f->subclass == AST_CONTROL_HANGUP)
12338             {
12339                if (debug) printf("@@@@ rpt:Hung Up\n");
12340                ast_frfree(f);
12341                break;
12342             }
12343          }
12344          ast_frfree(f);
12345          continue;
12346       }
12347       toexit = 0;
12348       rpt_mutex_lock(&myrpt->lock);
12349       l = myrpt->links.next;
12350       while(l != &myrpt->links)
12351       {
12352          int remnomute;
12353          struct timeval now;
12354 
12355          if (l->disctime)
12356          {
12357             l = l->next;
12358             continue;
12359          }
12360 
12361          remrx = 0;
12362          /* see if any other links are receiving */
12363          m = myrpt->links.next;
12364          while(m != &myrpt->links)
12365          {
12366             /* if not us, count it */
12367             if ((m != l) && (m->lastrx)) remrx = 1;
12368             m = m->next;
12369          }
12370          rpt_mutex_unlock(&myrpt->lock);
12371          now = ast_tvnow();
12372          if ((who == l->chan) || (!l->lastlinktv.tv_sec) ||
12373             (ast_tvdiff_ms(now,l->lastlinktv) >= 19))
12374          {
12375             l->lastlinktv = now;
12376             remnomute = myrpt->localtx && 
12377                 (!(myrpt->cmdnode[0] || 
12378                (myrpt->dtmfidx > -1)));
12379             totx = (((l->isremote) ? (remnomute) : 
12380                myrpt->exttx) || remrx) && l->mode;
12381             if (l->phonemode == 0 && l->chan && (l->lasttx != totx))
12382             {
12383                if (totx)
12384                {
12385                   ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
12386                }
12387                else
12388                {
12389                   ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
12390                }
12391                if (myrpt->p.archivedir)
12392                {
12393                   char str[100];
12394 
12395                   if (totx)
12396                      sprintf(str,"TXKEY,%s",l->name);
12397                   else
12398                      sprintf(str,"TXUNKEY,%s",l->name);
12399                   donodelog(myrpt,str);
12400                }
12401             }
12402             l->lasttx = totx;
12403          }
12404          rpt_mutex_lock(&myrpt->lock);
12405          if (who == l->chan) /* if it was a read from rx */
12406          {
12407             rpt_mutex_unlock(&myrpt->lock);
12408             f = ast_read(l->chan);
12409             if (!f)
12410             {
12411                rpt_mutex_lock(&myrpt->lock);
12412                __kickshort(myrpt);
12413                rpt_mutex_unlock(&myrpt->lock);
12414                if ((!l->disced) && (!l->outbound))
12415                {
12416                   if ((l->name[0] == '0') || l->isremote)
12417                      l->disctime = 1;
12418                   else
12419                      l->disctime = DISC_TIME;
12420                   rpt_mutex_lock(&myrpt->lock);
12421                   ast_hangup(l->chan);
12422                   l->chan = 0;
12423                   break;
12424                }
12425 
12426                if (l->retrytimer) 
12427                {
12428                   ast_hangup(l->chan);
12429                   l->chan = 0;
12430                   rpt_mutex_lock(&myrpt->lock);
12431                   break; 
12432                }
12433                if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
12434                {
12435                   rpt_mutex_lock(&myrpt->lock);
12436                   if (l->chan) ast_hangup(l->chan);
12437                   l->chan = 0;
12438                   l->hasconnected = 1;
12439                   l->retrytimer = RETRY_TIMER_MS;
12440                   l->elaptime = 0;
12441                   l->connecttime = 0;
12442                   l->thisconnected = 0;
12443                   break;
12444                }
12445                rpt_mutex_lock(&myrpt->lock);
12446                /* remove from queue */
12447                remque((struct qelem *) l);
12448                if (!strcmp(myrpt->cmdnode,l->name))
12449                   myrpt->cmdnode[0] = 0;
12450                __kickshort(myrpt);
12451                rpt_mutex_unlock(&myrpt->lock);
12452                if (!l->hasconnected)
12453                   rpt_telemetry(myrpt,CONNFAIL,l);
12454                else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
12455                if (myrpt->p.archivedir)
12456                {
12457                   char str[100];
12458 
12459                   if (!l->hasconnected)
12460                      sprintf(str,"LINKFAIL,%s",l->name);
12461                   else
12462                      sprintf(str,"LINKDISC,%s",l->name);
12463                   donodelog(myrpt,str);
12464                }
12465                if (l->lastf1) ast_frfree(l->lastf1);
12466                l->lastf1 = NULL;
12467                if (l->lastf2) ast_frfree(l->lastf2);
12468                l->lastf2 = NULL;
12469                /* hang-up on call to device */
12470                ast_hangup(l->chan);
12471                ast_hangup(l->pchan);
12472                ast_free(l);
12473                rpt_mutex_lock(&myrpt->lock);
12474                break;
12475             }
12476             if (f->frametype == AST_FRAME_VOICE)
12477             {
12478                int ismuted,n1;
12479 
12480                if ((l->phonemode) && (l->phonevox))
12481                {
12482                   n1 = dovox(&l->vox,
12483                      f->data.ptr,f->datalen / 2);
12484                   if (n1 != l->wasvox)
12485                   {
12486                      if (debug)ast_log(LOG_DEBUG,"Link Node %s, vox %d\n",l->name,n1);
12487                      l->wasvox = n1;
12488                      l->voxtostate = 0;
12489                      if (n1) l->voxtotimer = myrpt->p.voxtimeout_ms;
12490                      else l->voxtotimer = 0;
12491                   }
12492                   if (l->lastrealrx || n1)
12493                   {
12494                      if (!myfirst)
12495                      {
12496                          x = 0;
12497                          AST_LIST_TRAVERSE(&l->rxq, f1,
12498                         frame_list) x++;
12499                          for(;x < myrpt->p.simplexphonedelay; x++)
12500                         {
12501                            f1 = ast_frdup(f);
12502                            memset(f1->data.ptr,0,f1->datalen);
12503                            AST_LIST_INSERT_TAIL(&l->rxq,
12504                               f1,frame_list);
12505                          }
12506                          myfirst = 1;
12507                      }
12508                      f1 = ast_frdup(f);
12509                      AST_LIST_INSERT_TAIL(&l->rxq,f1,frame_list);
12510                   } else myfirst = 0; 
12511                   x = 0;
12512                   AST_LIST_TRAVERSE(&l->rxq, f1,frame_list) x++;
12513                   if (!x)
12514                   {
12515                      memset(f->data.ptr,0,f->datalen);
12516                   }
12517                   else
12518                   {
12519                      ast_frfree(f);
12520                      f = AST_LIST_REMOVE_HEAD(&l->rxq,frame_list);
12521                   }
12522                   if (ioctl(l->chan->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
12523                   {
12524                      ismuted = 0;
12525                   }
12526                   /* if not receiving, zero-out audio */
12527                   ismuted |= (!l->lastrx);
12528                   if (l->dtmfed && l->phonemode) ismuted = 1;
12529                   l->dtmfed = 0;
12530                   if (ismuted)
12531                   {
12532                      memset(f->data.ptr,0,f->datalen);
12533                      if (l->lastf1)
12534                         memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12535                      if (l->lastf2)
12536                         memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12537                   } 
12538                   if (f) f2 = ast_frdup(f);
12539                   else f2 = NULL;
12540                   f1 = l->lastf2;
12541                   l->lastf2 = l->lastf1;
12542                   l->lastf1 = f2;
12543                   if (ismuted)
12544                   {
12545                      if (l->lastf1)
12546                         memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12547                      if (l->lastf2)
12548                         memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12549                   }
12550                   if (f1)
12551                   {
12552                      ast_write(l->pchan,f1);
12553                      ast_frfree(f1);
12554                   }
12555                }
12556                else
12557                {
12558                   if (!l->lastrx)
12559                      memset(f->data.ptr,0,f->datalen);
12560                   ast_write(l->pchan,f);
12561                }
12562             }
12563 #ifndef  OLD_ASTERISK
12564             else if (f->frametype == AST_FRAME_DTMF_BEGIN)
12565             {
12566                if (l->lastf1)
12567                   memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12568                if (l->lastf2)
12569                   memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12570                l->dtmfed = 1;
12571             }
12572 #endif
12573             if (f->frametype == AST_FRAME_TEXT)
12574             {
12575                handle_link_data(myrpt,l,f->data.ptr);
12576             }
12577             if (f->frametype == AST_FRAME_DTMF)
12578             {
12579                if (l->lastf1)
12580                   memset(l->lastf1->data.ptr,0,l->lastf1->datalen);
12581                if (l->lastf2)
12582                   memset(l->lastf2->data.ptr,0,l->lastf2->datalen);
12583                l->dtmfed = 1;
12584                handle_link_phone_dtmf(myrpt,l,f->subclass);
12585             }
12586             if (f->frametype == AST_FRAME_CONTROL)
12587             {
12588                if (f->subclass == AST_CONTROL_ANSWER)
12589                {
12590                   char lconnected = l->connected;
12591 
12592                   __kickshort(myrpt);
12593                   l->connected = 1;
12594                   l->hasconnected = 1;
12595                   l->thisconnected = 1;
12596                   l->elaptime = -1;
12597                   if (!l->phonemode) send_newkey(l->chan);
12598                   if (!l->isremote) l->retries = 0;
12599                   if (!lconnected) 
12600                   {
12601                      rpt_telemetry(myrpt,CONNECTED,l);
12602                      if (myrpt->p.archivedir)
12603                      {
12604                         char str[100];
12605 
12606                         if (l->mode)
12607                            sprintf(str,"LINKTRX,%s",l->name);
12608                         else
12609                            sprintf(str,"LINKMONITOR,%s",l->name);
12610                         donodelog(myrpt,str);
12611                      }
12612                   }     
12613                   else
12614                      l->reconnects++;
12615                }
12616                /* if RX key */
12617                if (f->subclass == AST_CONTROL_RADIO_KEY)
12618                {
12619                   if (debug == 7 ) printf("@@@@ rx key\n");
12620                   l->lastrealrx = 1;
12621                   l->rerxtimer = 0;
12622                   if (!l->lastrx1)
12623                   {
12624                      if (myrpt->p.archivedir)
12625                      {
12626                         char str[100];
12627 
12628                         sprintf(str,"RXKEY,%s",l->name);
12629                         donodelog(myrpt,str);
12630                      }
12631                      l->lastrx1 = 1;
12632                   }
12633                }
12634                /* if RX un-key */
12635                if (f->subclass == AST_CONTROL_RADIO_UNKEY)
12636                {
12637                   if (debug == 7) printf("@@@@ rx un-key\n");
12638                   l->lastrealrx = 0;
12639                   l->rerxtimer = 0;
12640                   if (l->lastrx1)
12641                   {
12642                      if (myrpt->p.archivedir)
12643                      {
12644                         char str[100];
12645 
12646                         sprintf(str,"RXUNKEY,%s",l->name);
12647                         donodelog(myrpt,str);
12648                      }
12649                      l->lastrx1 = 0;
12650                      if(myrpt->p.duplex) 
12651                         rpt_telemetry(myrpt,LINKUNKEY,l);
12652                   }
12653                }
12654                if (f->subclass == AST_CONTROL_HANGUP)
12655                {
12656                   ast_frfree(f);
12657                   rpt_mutex_lock(&myrpt->lock);
12658                   __kickshort(myrpt);
12659                   rpt_mutex_unlock(&myrpt->lock);
12660                   if ((!l->outbound) && (!l->disced))
12661                   {
12662                      if ((l->name[0] == '0') || l->isremote)
12663                         l->disctime = 1;
12664                      else
12665                         l->disctime = DISC_TIME;
12666                      rpt_mutex_lock(&myrpt->lock);
12667                      ast_hangup(l->chan);
12668                      l->chan = 0;
12669                      break;
12670                   }
12671                   if (l->retrytimer) 
12672                   {
12673                      if (l->chan) ast_hangup(l->chan);
12674                      l->chan = 0;
12675                      rpt_mutex_lock(&myrpt->lock);
12676                      break;
12677                   }
12678                   if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
12679                   {
12680                      rpt_mutex_lock(&myrpt->lock);
12681                      if (l->chan) ast_hangup(l->chan);
12682                      l->chan = 0;
12683                      l->hasconnected = 1;
12684                      l->elaptime = 0;
12685                      l->retrytimer = RETRY_TIMER_MS;
12686                      l->connecttime = 0;
12687                      l->thisconnected = 0;
12688                      break;
12689                   }
12690                   rpt_mutex_lock(&myrpt->lock);
12691                   /* remove from queue */
12692                   remque((struct qelem *) l);
12693                   if (!strcmp(myrpt->cmdnode,l->name))
12694                      myrpt->cmdnode[0] = 0;
12695                   __kickshort(myrpt);
12696                   rpt_mutex_unlock(&myrpt->lock);
12697                   if (!l->hasconnected)
12698                      rpt_telemetry(myrpt,CONNFAIL,l);
12699                   else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
12700                   if (myrpt->p.archivedir)
12701                   {
12702                      char str[100];
12703 
12704                      if (!l->hasconnected)
12705                         sprintf(str,"LINKFAIL,%s",l->name);
12706                      else
12707                         sprintf(str,"LINKDISC,%s",l->name);
12708                      donodelog(myrpt,str);
12709                   }
12710                   if (l->lastf1) ast_frfree(l->lastf1);
12711                   l->lastf1 = NULL;
12712                   if (l->lastf2) ast_frfree(l->lastf2);
12713                   l->lastf2 = NULL;
12714                   /* hang-up on call to device */
12715                   ast_hangup(l->chan);
12716                   ast_hangup(l->pchan);
12717                   ast_free(l);
12718                   rpt_mutex_lock(&myrpt->lock);
12719                   break;
12720                }
12721             }
12722             ast_frfree(f);
12723             rpt_mutex_lock(&myrpt->lock);
12724             break;
12725          }
12726          if (who == l->pchan) 
12727          {
12728             rpt_mutex_unlock(&myrpt->lock);
12729             f = ast_read(l->pchan);
12730             if (!f)
12731             {
12732                if (debug) printf("@@@@ rpt:Hung Up\n");
12733                toexit = 1;
12734                rpt_mutex_lock(&myrpt->lock);
12735                break;
12736             }
12737             if (f->frametype == AST_FRAME_VOICE)
12738             {
12739                if (l->chan) ast_write(l->chan,f);
12740             }
12741             if (f->frametype == AST_FRAME_CONTROL)
12742             {
12743                if (f->subclass == AST_CONTROL_HANGUP)
12744                {
12745                   if (debug) printf("@@@@ rpt:Hung Up\n");
12746                   ast_frfree(f);
12747                   toexit = 1;
12748                   rpt_mutex_lock(&myrpt->lock);
12749                   break;
12750                }
12751             }
12752             ast_frfree(f);
12753             rpt_mutex_lock(&myrpt->lock);
12754             break;
12755          }
12756          l = l->next;
12757       }
12758       rpt_mutex_unlock(&myrpt->lock);
12759       if (toexit) break;
12760       if (who == myrpt->monchannel) 
12761       {
12762          f = ast_read(myrpt->monchannel);
12763          if (!f)
12764          {
12765             if (debug) printf("@@@@ rpt:Hung Up\n");
12766             break;
12767          }
12768          if (f->frametype == AST_FRAME_VOICE)
12769          {
12770             if (myrpt->monstream) 
12771                ast_writestream(myrpt->monstream,f);
12772          }
12773          if (f->frametype == AST_FRAME_CONTROL)
12774          {
12775             if (f->subclass == AST_CONTROL_HANGUP)
12776             {
12777                if (debug) printf("@@@@ rpt:Hung Up\n");
12778                ast_frfree(f);
12779                break;
12780             }
12781          }
12782          ast_frfree(f);
12783          continue;
12784       }
12785       if (myrpt->parrotchannel && (who == myrpt->parrotchannel))
12786       {
12787          f = ast_read(myrpt->parrotchannel);
12788          if (!f)
12789          {
12790             if (debug) printf("@@@@ rpt:Hung Up\n");
12791             break;
12792          }
12793          if (!myrpt->p.parrotmode)
12794          {
12795             char myfname[300];
12796 
12797             if (myrpt->parrotstream)
12798             {
12799                ast_closestream(myrpt->parrotstream);
12800                myrpt->parrotstream = 0;
12801             }
12802             sprintf(myfname,PARROTFILE,myrpt->name,myrpt->parrotcnt);
12803             strcat(myfname,".wav");
12804             unlink(myfname);        
12805          } else if (f->frametype == AST_FRAME_VOICE)
12806          {
12807             if (myrpt->parrotstream) 
12808                ast_writestream(myrpt->parrotstream,f);
12809          }
12810          if (f->frametype == AST_FRAME_CONTROL)
12811          {
12812             if (f->subclass == AST_CONTROL_HANGUP)
12813             {
12814                if (debug) printf("@@@@ rpt:Hung Up\n");
12815                ast_frfree(f);
12816                break;
12817             }
12818          }
12819          ast_frfree(f);
12820          continue;
12821       }
12822       if (myrpt->voxchannel && (who == myrpt->voxchannel))
12823       {
12824          f = ast_read(myrpt->voxchannel);
12825          if (!f)
12826          {
12827             if (debug) printf("@@@@ rpt:Hung Up\n");
12828             break;
12829          }
12830          if (f->frametype == AST_FRAME_VOICE)
12831          {
12832             n = dovox(&myrpt->vox,f->data.ptr,f->datalen / 2);
12833             if (n != myrpt->wasvox)
12834             {
12835                if (debug) ast_log(LOG_DEBUG,"Node %s, vox %d\n",myrpt->name,n);
12836                myrpt->wasvox = n;
12837                myrpt->voxtostate = 0;
12838                if (n) myrpt->voxtotimer = myrpt->p.voxtimeout_ms;
12839                else myrpt->voxtotimer = 0;
12840             }
12841          }
12842          if (f->frametype == AST_FRAME_CONTROL)
12843          {
12844             if (f->subclass == AST_CONTROL_HANGUP)
12845             {
12846                if (debug) printf("@@@@ rpt:Hung Up\n");
12847                ast_frfree(f);
12848                break;
12849             }
12850          }
12851          ast_frfree(f);
12852          continue;
12853       }
12854       if (who == myrpt->txpchannel) /* if it was a read from remote tx */
12855       {
12856          f = ast_read(myrpt->txpchannel);
12857          if (!f)
12858          {
12859             if (debug) printf("@@@@ rpt:Hung Up\n");
12860             break;
12861          }
12862          if (f->frametype == AST_FRAME_CONTROL)
12863          {
12864             if (f->subclass == AST_CONTROL_HANGUP)
12865             {
12866                if (debug) printf("@@@@ rpt:Hung Up\n");
12867                ast_frfree(f);
12868                break;
12869             }
12870          }
12871          ast_frfree(f);
12872          continue;
12873       }
12874    }
12875    usleep(100000);
12876    ast_hangup(myrpt->pchannel);
12877    ast_hangup(myrpt->monchannel);
12878    if (myrpt->parrotchannel) ast_hangup(myrpt->parrotchannel);
12879    myrpt->parrotstate = 0;
12880    if (myrpt->voxchannel) ast_hangup(myrpt->voxchannel);
12881    ast_hangup(myrpt->txpchannel);
12882    if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel);
12883    if (myrpt->dahditxchannel != myrpt->txchannel) ast_hangup(myrpt->dahditxchannel);
12884    if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
12885    myrpt->lastf1 = NULL;
12886    if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
12887    myrpt->lastf2 = NULL;
12888    ast_hangup(myrpt->rxchannel);
12889    rpt_mutex_lock(&myrpt->lock);
12890    l = myrpt->links.next;
12891    while(l != &myrpt->links)
12892    {
12893       struct rpt_link *ll = l;
12894       /* remove from queue */
12895       remque((struct qelem *) l);
12896       /* hang-up on call to device */
12897       if (l->chan) ast_hangup(l->chan);
12898       ast_hangup(l->pchan);
12899       l = l->next;
12900       ast_free(ll);
12901    }
12902    if (myrpt->xlink  == 1) myrpt->xlink = 2;
12903    rpt_mutex_unlock(&myrpt->lock);
12904    if (debug) printf("@@@@ rpt:Hung up channel\n");
12905    myrpt->rpt_thread = AST_PTHREADT_STOP;
12906    pthread_exit(NULL); 
12907    return NULL;
12908 }
12909 
12910    
12911 static void *rpt_master(void *ignore)
12912 {
12913 int   i,n;
12914 pthread_attr_t attr;
12915 struct ast_config *cfg;
12916 char *this,*val;
12917 
12918    /* init nodelog queue */
12919    nodelog.next = nodelog.prev = &nodelog;
12920    /* go thru all the specified repeaters */
12921    this = NULL;
12922    n = 0;
12923 #ifndef OLD_ASTERISK
12924    /* wait until asterisk starts */
12925         while(!ast_test_flag(&ast_options,AST_OPT_FLAG_FULLY_BOOTED))
12926                 usleep(250000);
12927 #endif
12928 #ifdef   NEW_ASTERISK
12929    rpt_vars[n].cfg = ast_config_load("rpt.conf",config_flags);
12930 #else
12931    rpt_vars[n].cfg = ast_config_load("rpt.conf");
12932 #endif
12933    cfg = rpt_vars[n].cfg;
12934    if (!cfg) {
12935       ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
12936       pthread_exit(NULL);
12937    }
12938    while((this = ast_category_browse(cfg,this)) != NULL)
12939    {
12940       for(i = 0 ; i < strlen(this) ; i++){
12941          if((this[i] < '0') || (this[i] > '9'))
12942             break;
12943       }
12944       if(i != strlen(this)) continue; /* Not a node defn */
12945       memset(&rpt_vars[n],0,sizeof(rpt_vars[n]));
12946       rpt_vars[n].name = ast_strdup(this);
12947       val = (char *) ast_variable_retrieve(cfg,this,"rxchannel");
12948       if (val) rpt_vars[n].rxchanname = ast_strdup(val);
12949       val = (char *) ast_variable_retrieve(cfg,this,"txchannel");
12950       if (val) rpt_vars[n].txchanname = ast_strdup(val);
12951       rpt_vars[n].remote = 0;
12952       rpt_vars[n].remoterig = "";
12953       val = (char *) ast_variable_retrieve(cfg,this,"remote");
12954       if (val) 
12955       {
12956          rpt_vars[n].remoterig = ast_strdup(val);
12957          rpt_vars[n].remote = 1;
12958       }
12959       val = (char *) ast_variable_retrieve(cfg,this,"radiotype");
12960       if (val) rpt_vars[n].remoterig = ast_strdup(val);
12961       ast_mutex_init(&rpt_vars[n].lock);
12962       ast_mutex_init(&rpt_vars[n].remlock);
12963       ast_mutex_init(&rpt_vars[n].statpost_lock);
12964       rpt_vars[n].tele.next = &rpt_vars[n].tele;
12965       rpt_vars[n].tele.prev = &rpt_vars[n].tele;
12966       rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
12967       rpt_vars[n].tailmessagen = 0;
12968 #ifdef   _MDC_DECODE_H_
12969       rpt_vars[n].mdc = mdc_decoder_new(8000);
12970 #endif
12971       n++;
12972    }
12973    nrpts = n;
12974    ast_config_destroy(cfg);
12975 
12976    /* start em all */
12977    for(i = 0; i < n; i++)
12978    {
12979       load_rpt_vars(i,1);
12980 
12981       /* if is a remote, dont start one for it */
12982       if (rpt_vars[i].remote)
12983       {
12984          if(retreive_memory(&rpt_vars[i],"init")){ /* Try to retreive initial memory channel */
12985             if (!strcmp(rpt_vars[i].remoterig,remote_rig_rtx450))
12986                strncpy(rpt_vars[i].freq, "446.500", sizeof(rpt_vars[i].freq) - 1);
12987             else
12988                strncpy(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq) - 1);
12989             strncpy(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl) - 1);
12990 
12991             strncpy(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl) - 1);
12992             rpt_vars[i].remmode = REM_MODE_FM;
12993             rpt_vars[i].offset = REM_SIMPLEX;
12994             rpt_vars[i].powerlevel = REM_LOWPWR;
12995          }
12996          continue;
12997       }
12998       else /* is a normal repeater */
12999       {
13000           rpt_vars[i].p.memory = rpt_vars[i].name;
13001          if(retreive_memory(&rpt_vars[i],"radiofreq")){ /* Try to retreive initial memory channel */
13002             if (!strcmp(rpt_vars[i].remoterig,remote_rig_rtx450))
13003                strncpy(rpt_vars[i].freq, "446.500", sizeof(rpt_vars[i].freq) - 1);
13004             else if (!strcmp(rpt_vars[i].remoterig,remote_rig_rtx150))
13005                strncpy(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq) - 1);
13006             strncpy(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl) - 1);
13007 
13008             strncpy(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl) - 1);
13009             rpt_vars[i].remmode = REM_MODE_FM;
13010             rpt_vars[i].offset = REM_SIMPLEX;
13011             rpt_vars[i].powerlevel = REM_LOWPWR;
13012          }
13013          ast_log(LOG_NOTICE,"Normal Repeater Init  %s  %s  %s\n",rpt_vars[i].name, rpt_vars[i].remoterig, rpt_vars[i].freq);
13014       }
13015       if (!rpt_vars[i].p.ident)
13016       {
13017          ast_log(LOG_WARNING,"Did not specify ident for node %s\n",rpt_vars[i].name);
13018          ast_config_destroy(cfg);
13019          pthread_exit(NULL);
13020       }
13021            pthread_attr_init(&attr);
13022            pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
13023       ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
13024    }
13025    usleep(500000);
13026    time(&starttime);
13027    for(;;)
13028    {
13029       /* Now monitor each thread, and restart it if necessary */
13030       for(i = 0; i < n; i++)
13031       { 
13032          int rv;
13033          if (rpt_vars[i].remote) continue;
13034          if (rpt_vars[i].rpt_thread == AST_PTHREADT_STOP) 
13035             rv = -1;
13036          else
13037             rv = pthread_kill(rpt_vars[i].rpt_thread,0);
13038          if (rv)
13039          {
13040             if(time(NULL) - rpt_vars[i].lastthreadrestarttime <= 15)
13041             {
13042                if(rpt_vars[i].threadrestarts >= 5)
13043                {
13044                   ast_log(LOG_ERROR,"Continual RPT thread restarts, killing Asterisk\n");
13045                   exit(1); /* Stuck in a restart loop, kill Asterisk and start over */
13046                }
13047                else
13048                {
13049                   ast_log(LOG_NOTICE,"RPT thread restarted on %s\n",rpt_vars[i].name);
13050                   rpt_vars[i].threadrestarts++;
13051                }
13052             }
13053             else
13054                rpt_vars[i].threadrestarts = 0;
13055 
13056             rpt_vars[i].lastthreadrestarttime = time(NULL);
13057                  pthread_attr_init(&attr);
13058                  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
13059             ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
13060             /* if (!rpt_vars[i].xlink) */
13061                ast_log(LOG_WARNING, "rpt_thread restarted on node %s\n", rpt_vars[i].name);
13062          }
13063 
13064       }
13065       for(;;)
13066       {
13067          struct nodelog *nodep;
13068          char *space,datestr[100],fname[300];
13069          int fd;
13070 
13071          ast_mutex_lock(&nodeloglock);
13072          nodep = nodelog.next;
13073          if(nodep == &nodelog) /* if nothing in queue */
13074          {
13075             ast_mutex_unlock(&nodeloglock);
13076             break;
13077          }
13078          remque((struct qelem *)nodep);
13079          ast_mutex_unlock(&nodeloglock);
13080          space = strchr(nodep->str,' ');
13081          if (!space) 
13082          {
13083             ast_free(nodep);
13084             continue;
13085          }
13086          *space = 0;
13087          strftime(datestr,sizeof(datestr) - 1,"%Y%m%d",
13088             localtime(&nodep->timestamp));
13089          sprintf(fname,"%s/%s/%s.txt",nodep->archivedir,
13090             nodep->str,datestr);
13091          fd = open(fname,O_WRONLY | O_CREAT | O_APPEND,0600);
13092          if (fd == -1)
13093          {
13094             ast_log(LOG_ERROR,"Cannot open node log file %s for write",space + 1);
13095             ast_free(nodep);
13096             continue;
13097          }
13098          if (write(fd,space + 1,strlen(space + 1)) !=
13099             strlen(space + 1))
13100          {
13101             ast_log(LOG_ERROR,"Cannot write node log file %s for write",space + 1);
13102             ast_free(nodep);
13103             continue;
13104          }
13105          close(fd);
13106          ast_free(nodep);
13107       }
13108       sleep(2);
13109    }
13110    ast_config_destroy(cfg);
13111    pthread_exit(NULL);
13112 }
13113 
13114 static int rpt_exec(struct ast_channel *chan, void *data)
13115 {
13116    int res=-1,i,rem_totx,rem_rx,remkeyed,n,phone_mode = 0;
13117    int iskenwood_pci4,authtold,authreq,setting,notremming,reming;
13118    int ismuted,dtmfed,phone_vox = 0;
13119 #ifdef   OLD_ASTERISK
13120    struct localuser *u;
13121 #endif
13122    char tmp[256], keyed = 0,keyed1 = 0;
13123    char *options,*stringp,*tele,c,*altp,*memp;
13124    char sx[320],*sy;
13125    struct   rpt *myrpt;
13126    struct ast_frame *f,*f1,*f2;
13127    struct ast_channel *who;
13128    struct ast_channel *cs[20];
13129    struct   rpt_link *l;
13130    struct dahdi_confinfo ci;  /* conference info */
13131    struct dahdi_params par;
13132    int ms,elap,nullfd;
13133    time_t t,last_timeout_warning;
13134    struct   dahdi_radio_param z;
13135    struct rpt_tele *telem;
13136    int   numlinks;
13137 
13138    nullfd = open("/dev/null",O_RDWR);
13139    if (ast_strlen_zero(data)) {
13140       ast_log(LOG_WARNING, "Rpt requires an argument (system node)\n");
13141       return -1;
13142    }
13143 
13144    strncpy(tmp, (char *)data, sizeof(tmp)-1);
13145    time(&t);
13146    /* if time has externally shifted negative, screw it */
13147    if (t < starttime) t = starttime + START_DELAY;
13148    if ((!starttime) || (t < (starttime + START_DELAY)))
13149    {
13150       ast_log(LOG_NOTICE,"Node %s rejecting call: too soon!\n",tmp);
13151       ast_safe_sleep(chan,3000);
13152       return -1;
13153    }
13154 
13155    ast_log(LOG_NOTICE,"parsing argument=%s \n",tmp);
13156 
13157    altp=strstr(tmp, "|*");
13158    if(altp){
13159       altp[0]=0;
13160       altp++;
13161     }
13162 
13163    memp=strstr(tmp, "|M");
13164    if(memp){
13165       memp[0]=0;
13166       memp+=2;
13167     }
13168 
13169    stringp=tmp;
13170    strsep(&stringp, "|");
13171    options = stringp;
13172 
13173    ast_log(LOG_NOTICE,"options=%s \n",options);
13174    if(memp>0)ast_log(LOG_NOTICE,"memp=%s \n",memp);
13175    if(altp>0)ast_log(LOG_NOTICE,"altp=%s \n",altp);
13176 
13177    myrpt = NULL;
13178    /* see if we can find our specified one */
13179    for(i = 0; i < nrpts; i++)
13180    {
13181       /* if name matches, assign it and exit loop */
13182       if (!strcmp(tmp,rpt_vars[i].name))
13183       {
13184          myrpt = &rpt_vars[i];
13185          break;
13186       }
13187    }
13188 
13189    pbx_builtin_setvar_helper(chan, "RPT_STAT_ERR", "");
13190 
13191    if (myrpt == NULL)
13192    {
13193       pbx_builtin_setvar_helper(chan, "RPT_STAT_ERR", "NODE_NOT_FOUND");
13194       ast_log(LOG_WARNING, "Cannot find specified system node %s\n",tmp);
13195       return (priority_jump(NULL,chan));
13196    }
13197 
13198    numlinks=linkcount(myrpt);
13199 
13200    if(options && *options == 'q')
13201    {
13202       char buf2[128];
13203 
13204       if(myrpt->keyed)
13205          pbx_builtin_setvar_helper(chan, "RPT_STAT_RXKEYED", "1");
13206       else
13207          pbx_builtin_setvar_helper(chan, "RPT_STAT_RXKEYED", "0");   
13208 
13209       if(myrpt->txkeyed)
13210          pbx_builtin_setvar_helper(chan, "RPT_STAT_TXKEYED", "1");
13211       else
13212          pbx_builtin_setvar_helper(chan, "RPT_STAT_TXKEYED", "0");   
13213 
13214       snprintf(buf2,sizeof(buf2),"%s=%i", "RPT_STAT_XLINK", myrpt->xlink);
13215       pbx_builtin_setvar(chan, buf2);
13216       snprintf(buf2,sizeof(buf2),"%s=%i", "RPT_STAT_LINKS", numlinks);
13217       pbx_builtin_setvar(chan, buf2);
13218       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_WASCHAN", myrpt->waschan);
13219       pbx_builtin_setvar(chan, buf2);
13220       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_NOWCHAN", myrpt->nowchan);
13221       pbx_builtin_setvar(chan, buf2);
13222       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_DUPLEX", myrpt->p.duplex);
13223       pbx_builtin_setvar(chan, buf2);
13224       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_PARROT", myrpt->p.parrotmode);
13225       pbx_builtin_setvar(chan, buf2);
13226       //snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_PHONEVOX", myrpt->phonevox);
13227       //pbx_builtin_setvar(chan, buf2);
13228       //snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_CONNECTED", myrpt->connected);
13229       //pbx_builtin_setvar(chan, buf2);
13230       snprintf(buf2,sizeof(buf2),"%s=%d", "RPT_STAT_CALLMODE", myrpt->callmode);
13231       pbx_builtin_setvar(chan, buf2);
13232       snprintf(buf2,sizeof(buf2),"%s=%s", "RPT_STAT_LASTTONE", myrpt->lasttone);
13233       pbx_builtin_setvar(chan, buf2);
13234 
13235       return priority_jump(myrpt,chan);
13236    }
13237 
13238    if(options && *options == 'o')
13239    {
13240       return(channel_revert(myrpt));
13241    }
13242 
13243    #if 0
13244    if((altp)&&(*options == 'Z'))
13245    {
13246       rpt_push_alt_macro(myrpt,altp);
13247       return 0;
13248    }
13249    #endif
13250 
13251 
13252    /* if not phone access, must be an IAX connection */
13253    if (options && ((*options == 'P') || (*options == 'D') || (*options == 'R') || (*options == 'S')))
13254    {
13255       int val;
13256 
13257       pbx_builtin_setvar_helper(chan, "RPT_STAT_BUSY", "0");
13258        
13259       myrpt->bargechan=0;
13260       if(options && strstr(options, "f")>0)
13261       {
13262          myrpt->bargechan=1;     
13263       }
13264 
13265       if(memp>0)
13266       {
13267          char radiochan;
13268          radiochan=strtod(data,NULL);
13269          // if(myrpt->nowchan!=0 && radiochan!=myrpt->nowchan && !myrpt->bargechan)
13270 
13271          if(numlinks>0 && radiochan!=myrpt->nowchan && !myrpt->bargechan)
13272          {
13273             pbx_builtin_setvar_helper(chan, "RPT_STAT_BUSY", "1");
13274             ast_log(LOG_NOTICE, "Radio Channel Busy.\n");
13275             return (priority_jump(myrpt,chan));
13276          }
13277          else if(radiochan!=myrpt->nowchan || myrpt->bargechan)
13278          {
13279             channel_steer(myrpt,memp); 
13280          }
13281       }
13282       if(altp)rpt_push_alt_macro(myrpt,altp);
13283       phone_mode = 1;
13284       if (*options == 'D') phone_mode = 2;
13285       if (*options == 'S') phone_mode = 3;
13286       ast_set_callerid(chan,"0","app_rpt user","0");
13287       val = 1;
13288       ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
13289       if ((*(options + 1) == 'V') || (*(options + 1) == 'v')) phone_vox = 1;
13290    }
13291    else
13292    {
13293 #ifdef ALLOW_LOCAL_CHANNELS
13294            /* Check to insure the connection is IAX2 or Local*/
13295            if ( (strncmp(chan->name,"IAX2",4)) && (strncmp(chan->name,"Local",5)) ) {
13296                ast_log(LOG_WARNING, "We only accept links via IAX2 or Local!!\n");
13297                return -1;
13298            }
13299 #else
13300       if (strncmp(chan->name,"IAX2",4))
13301       {
13302          ast_log(LOG_WARNING, "We only accept links via IAX2!!\n");
13303          return -1;
13304       }
13305 #endif
13306            if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable){ /* Do not allow incoming radio connections if disabled */
13307                  ast_log(LOG_NOTICE, "Connect attempt to node %s  with tx disabled", myrpt->name);
13308                   return -1;
13309          }  
13310    }
13311    if (options && (*options == 'R'))
13312    {
13313       /* Parts of this section taken from app_parkandannounce */
13314       char *return_context;
13315       int length, m, lot, timeout = 0;
13316       char buffer[256],*template;
13317       char *working, *context, *exten, *priority;
13318       char *s,*orig_s;
13319 
13320       rpt_mutex_lock(&myrpt->lock);
13321       m = myrpt->callmode;
13322       rpt_mutex_unlock(&myrpt->lock);
13323 
13324       if ((!myrpt->p.nobusyout) && m)
13325       {
13326          if (chan->_state != AST_STATE_UP)
13327          {
13328             ast_indicate(chan,AST_CONTROL_BUSY);
13329          }
13330          while(ast_safe_sleep(chan,10000) != -1);
13331          return -1;
13332       }
13333 
13334       if (chan->_state != AST_STATE_UP)
13335       {
13336          ast_answer(chan);
13337          if (!phone_mode) send_newkey(chan);
13338       }
13339 
13340       length=strlen(options)+2;
13341       orig_s=ast_malloc(length);
13342       if(!orig_s) {
13343          ast_log(LOG_WARNING, "Out of memory\n");
13344          return -1;
13345       }
13346       s=orig_s;
13347       strncpy(s,options,length);
13348 
13349       template=strsep(&s,"|");
13350       if(!template) {
13351          ast_log(LOG_WARNING, "An announce template must be defined\n");
13352          ast_free(orig_s);
13353          return -1;
13354       } 
13355   
13356       if(s) {
13357          timeout = atoi(strsep(&s, "|"));
13358          timeout *= 1000;
13359       }
13360    
13361       return_context = s;
13362   
13363       if(return_context != NULL) {
13364          /* set the return context. Code borrowed from the Goto builtin */
13365     
13366          working = return_context;
13367          context = strsep(&working, "|");
13368          exten = strsep(&working, "|");
13369          if(!exten) {
13370             /* Only a priority in this one */
13371             priority = context;
13372             exten = NULL;
13373             context = NULL;
13374          } else {
13375             priority = strsep(&working, "|");
13376             if(!priority) {
13377                /* Only an extension and priority in this one */
13378                priority = exten;
13379                exten = context;
13380                context = NULL;
13381          }
13382       }
13383       if(atoi(priority) < 0) {
13384          ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", priority);
13385          ast_free(orig_s);
13386          return -1;
13387       }
13388       /* At this point we have a priority and maybe an extension and a context */
13389       chan->priority = atoi(priority);
13390 #ifdef OLD_ASTERISK
13391       if(exten && strcasecmp(exten, "BYEXTENSION"))
13392 #else
13393       if(exten)
13394 #endif
13395          strncpy(chan->exten, exten, sizeof(chan->exten)-1);
13396       if(context)
13397          strncpy(chan->context, context, sizeof(chan->context)-1);
13398       } else {  /* increment the priority by default*/
13399          chan->priority++;
13400       }
13401 
13402       if(option_verbose > 2) {
13403          ast_verbose( VERBOSE_PREFIX_3 "Return Context: (%s,%s,%d) ID: %s\n", chan->context,chan->exten, chan->priority, chan->cid.cid_num);
13404          if(!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
13405             ast_verbose( VERBOSE_PREFIX_3 "Warning: Return Context Invalid, call will return to default|s\n");
13406          }
13407       }
13408   
13409       /* we are using masq_park here to protect * from touching the channel once we park it.  If the channel comes out of timeout
13410       before we are done announcing and the channel is messed with, Kablooeee.  So we use Masq to prevent this.  */
13411 
13412       ast_masq_park_call(chan, NULL, timeout, &lot);
13413 
13414       if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, return_context);
13415 
13416       snprintf(buffer, sizeof(buffer) - 1, "%d,%s", lot, template + 1);
13417 
13418       rpt_telemetry(myrpt,REV_PATCH,buffer);
13419 
13420       ast_free(orig_s);
13421 
13422       return 0;
13423 
13424    }
13425 
13426    if (!options)
13427    {
13428         struct ast_hostent ahp;
13429         struct hostent *hp;
13430         struct in_addr ia;
13431         char hisip[100],nodeip[100],*val, *s, *s1, *s2, *s3, *b,*b1;
13432 
13433       /* look at callerid to see what node this comes from */
13434       if (!chan->cid.cid_num) /* if doesn't have caller id */
13435       {
13436          ast_log(LOG_WARNING, "Does not have callerid on %s\n",tmp);
13437          return -1;
13438       }
13439       /* get his IP from IAX2 module */
13440       memset(hisip,0,sizeof(hisip));
13441 #ifdef ALLOW_LOCAL_CHANNELS
13442         /* set IP address if this is a local connection*/
13443         if (strncmp(chan->name,"Local",5)==0) {
13444             strcpy(hisip,"127.0.0.1");
13445         } else {
13446          pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
13447       }
13448 #else
13449       pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
13450 #endif
13451 
13452       if (!hisip[0])
13453       {
13454          ast_log(LOG_WARNING, "Link IP address cannot be determined!!\n");
13455          return -1;
13456       }
13457       
13458       ast_callerid_parse(chan->cid.cid_num,&b,&b1);
13459       ast_shrink_phone_number(b1);
13460       if (!strcmp(myrpt->name,b1))
13461       {
13462          ast_log(LOG_WARNING, "Trying to link to self!!\n");
13463          return -1;
13464       }
13465 
13466       if (*b1 < '1')
13467       {
13468          ast_log(LOG_WARNING, "Node %s Invalid for connection here!!\n",b1);
13469          return -1;
13470       }
13471 
13472 
13473       /* look for his reported node string */
13474       val = node_lookup(myrpt,b1);
13475       if (!val)
13476       {
13477          ast_log(LOG_WARNING, "Reported node %s cannot be found!!\n",b1);
13478          return -1;
13479       }
13480       strncpy(tmp,val,sizeof(tmp) - 1);
13481       s = tmp;
13482       s1 = strsep(&s,",");
13483       if (!strchr(s1,':') && strchr(s1,'/') && strncasecmp(s1, "local/", 6))
13484       {
13485          sy = strchr(s1,'/');    
13486          *sy = 0;
13487          sprintf(sx,"%s:4569/%s",s1,sy + 1);
13488          s1 = sx;
13489       }
13490       s2 = strsep(&s,",");
13491       if (!s2)
13492       {
13493          ast_log(LOG_WARNING, "Reported node %s not in correct format!!\n",b1);
13494          return -1;
13495       }
13496                 if (strcmp(s2,"NONE")) {
13497          hp = ast_gethostbyname(s2, &ahp);
13498          if (!hp)
13499          {
13500             ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s2);
13501             return -1;
13502          }
13503          memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
13504 #ifdef   OLD_ASTERISK
13505          ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
13506 #else
13507          strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
13508 #endif
13509          s3 = strchr(hisip,':');
13510          if (s3) *s3 = 0;
13511          if (strcmp(hisip,nodeip))
13512          {
13513             s3 = strchr(s1,'@');
13514             if (s3) s1 = s3 + 1;
13515             s3 = strchr(s1,'/');
13516             if (s3) *s3 = 0;
13517             s3 = strchr(s1,':');
13518             if (s3) *s3 = 0;
13519             hp = ast_gethostbyname(s1, &ahp);
13520             if (!hp)
13521             {
13522                ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s1);
13523                return -1;
13524             }
13525             memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
13526 #ifdef   OLD_ASTERISK
13527             ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
13528 #else
13529             strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
13530 #endif
13531             if (strcmp(hisip,nodeip))
13532             {
13533                ast_log(LOG_WARNING, "Node %s IP %s does not match link IP %s!!\n",b1,nodeip,hisip);
13534                return -1;
13535             }
13536          }
13537       }
13538    }
13539 
13540    /* if is not a remote */
13541    if (!myrpt->remote)
13542    {
13543       char *b,*b1;
13544       int reconnects = 0;
13545 
13546       rpt_mutex_lock(&myrpt->lock);
13547       i = myrpt->xlink;
13548       rpt_mutex_unlock(&myrpt->lock);
13549       if (i)
13550       {
13551          ast_log(LOG_WARNING, "Cannot connect to node %s, system busy\n",myrpt->name);
13552          return -1;
13553       }
13554       /* look at callerid to see what node this comes from */
13555       if (!chan->cid.cid_num) /* if doesn't have caller id */
13556       {
13557          ast_log(LOG_WARNING, "Doesnt have callerid on %s\n",tmp);
13558          return -1;
13559       }
13560 
13561       ast_callerid_parse(chan->cid.cid_num,&b,&b1);
13562       ast_shrink_phone_number(b1);
13563       if (!strcmp(myrpt->name,b1))
13564       {
13565          ast_log(LOG_WARNING, "Trying to link to self!!\n");
13566          return -1;
13567       }
13568       rpt_mutex_lock(&myrpt->lock);
13569       l = myrpt->links.next;
13570       /* try to find this one in queue */
13571       while(l != &myrpt->links)
13572       {
13573          if (l->name[0] == '0') 
13574          {
13575             l = l->next;
13576             continue;
13577          }
13578          /* if found matching string */
13579          if (!strcmp(l->name,b1)) break;
13580          l = l->next;
13581       }
13582       /* if found */
13583       if (l != &myrpt->links) 
13584       {
13585          l->killme = 1;
13586          l->retries = l->max_retries + 1;
13587          l->disced = 2;
13588          reconnects = l->reconnects;
13589          reconnects++;
13590                         rpt_mutex_unlock(&myrpt->lock);
13591          usleep(500000);   
13592       } else 
13593          rpt_mutex_unlock(&myrpt->lock);
13594       /* establish call in tranceive mode */
13595       l = ast_malloc(sizeof(struct rpt_link));
13596       if (!l)
13597       {
13598          ast_log(LOG_WARNING, "Unable to malloc\n");
13599          pthread_exit(NULL);
13600       }
13601       /* zero the silly thing */
13602       memset((char *)l,0,sizeof(struct rpt_link));
13603       l->mode = 1;
13604       strncpy(l->name,b1,MAXNODESTR - 1);
13605       l->isremote = 0;
13606       l->chan = chan;
13607       l->connected = 1;
13608       l->thisconnected = 1;
13609       l->hasconnected = 1;
13610       l->reconnects = reconnects;
13611       l->phonemode = phone_mode;
13612       l->phonevox = phone_vox;
13613       l->lastf1 = NULL;
13614       l->lastf2 = NULL;
13615       l->dtmfed = 0;
13616       voxinit_link(l,1);
13617       ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
13618       ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
13619       /* allocate a pseudo-channel thru asterisk */
13620       l->pchan = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
13621       if (!l->pchan)
13622       {
13623          fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
13624          pthread_exit(NULL);
13625       }
13626       ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
13627       ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
13628 #ifdef   AST_CDR_FLAG_POST_DISABLED
13629       if (l->pchan->cdr)
13630          ast_set_flag(l->pchan->cdr,AST_CDR_FLAG_POST_DISABLED);
13631 #endif
13632       /* make a conference for the tx */
13633       ci.chan = 0;
13634       ci.confno = myrpt->conf;
13635       ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
13636       /* first put the channel on the conference in proper mode */
13637       if (ioctl(l->pchan->fds[0],DAHDI_SETCONF,&ci) == -1)
13638       {
13639          ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
13640          pthread_exit(NULL);
13641       }
13642       rpt_mutex_lock(&myrpt->lock);
13643       if ((phone_mode == 2) && (!phone_vox)) l->lastrealrx = 1;
13644       l->max_retries = MAX_RETRIES;
13645       /* insert at end of queue */
13646       insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
13647       __kickshort(myrpt);
13648       rpt_mutex_unlock(&myrpt->lock);
13649       if (chan->_state != AST_STATE_UP) {
13650          ast_answer(chan);
13651          if (!phone_mode) send_newkey(chan);
13652       }
13653       if (myrpt->p.archivedir)
13654       {
13655          char str[100];
13656 
13657          if (l->phonemode)
13658             sprintf(str,"LINK(P),%s",l->name);
13659          else
13660             sprintf(str,"LINK,%s",l->name);
13661          donodelog(myrpt,str);
13662       }
13663       if (!phone_mode) send_newkey(chan);
13664       return 0;
13665    }
13666    /* well, then it is a remote */
13667    rpt_mutex_lock(&myrpt->lock);
13668    /* if remote, error if anyone else already linked */
13669    if (myrpt->remoteon)
13670    {
13671       rpt_mutex_unlock(&myrpt->lock);
13672       usleep(500000);
13673       if (myrpt->remoteon)
13674       {
13675          ast_log(LOG_WARNING, "Trying to use busy link on %s\n",tmp);
13676 #ifdef   AST_CDR_FLAG_POST_DISABLED
13677          if (chan->cdr)
13678             ast_set_flag(chan->cdr,AST_CDR_FLAG_POST_DISABLED);
13679 #endif
13680          return -1;
13681       }     
13682       rpt_mutex_lock(&myrpt->lock);
13683    }
13684    if (myrpt->p.rptnode)
13685    {
13686       char killedit = 0;
13687       time_t now;
13688 
13689       time(&now);
13690       for(i = 0; i < nrpts; i++)
13691       {
13692          if (!strcasecmp(rpt_vars[i].name,myrpt->p.rptnode))
13693          {
13694             if ((rpt_vars[i].links.next != &rpt_vars[i].links) ||
13695                rpt_vars[i].keyed ||
13696                 ((rpt_vars[i].lastkeyedtime + RPT_LOCKOUT_SECS) > now) ||
13697                  rpt_vars[i].txkeyed ||
13698                   ((rpt_vars[i].lasttxkeyedtime + RPT_LOCKOUT_SECS) > now))
13699             {
13700                rpt_mutex_unlock(&myrpt->lock);
13701                ast_log(LOG_WARNING, "Trying to use busy link (repeater node %s) on %s\n",rpt_vars[i].name,tmp);
13702 #ifdef   AST_CDR_FLAG_POST_DISABLED
13703                if (chan->cdr)
13704                   ast_set_flag(chan->cdr,AST_CDR_FLAG_POST_DISABLED);
13705 #endif
13706                return -1;
13707             }
13708             while(rpt_vars[i].xlink != 3)
13709             {
13710                if (!killedit)
13711                {
13712                   ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
13713                   rpt_vars[i].xlink = 1;
13714                   killedit = 1;
13715                }
13716                rpt_mutex_unlock(&myrpt->lock);
13717                if (ast_safe_sleep(chan,500) == -1)
13718                {
13719 #ifdef   AST_CDR_FLAG_POST_DISABLED
13720                   if (chan->cdr)
13721                      ast_set_flag(chan->cdr,AST_CDR_FLAG_POST_DISABLED);
13722 #endif
13723                   return -1;
13724                }
13725                rpt_mutex_lock(&myrpt->lock);
13726             }
13727             break;
13728          }
13729       }
13730    }
13731 
13732 #ifdef HAVE_IOPERM
13733    if ( (!strcmp(myrpt->remoterig, remote_rig_rbi)||!strcmp(myrpt->remoterig, remote_rig_ppp16)) &&
13734      (ioperm(myrpt->p.iobase,1,1) == -1))
13735    {
13736       rpt_mutex_unlock(&myrpt->lock);
13737       ast_log(LOG_WARNING, "Can't get io permission on IO port %x hex\n",myrpt->p.iobase);
13738       return -1;
13739    }
13740 #endif
13741    myrpt->remoteon = 1;
13742 #ifdef   OLD_ASTERISK
13743    LOCAL_USER_ADD(u);
13744 #endif
13745    rpt_mutex_unlock(&myrpt->lock);
13746    /* find our index, and load the vars initially */
13747    for(i = 0; i < nrpts; i++)
13748    {
13749       if (&rpt_vars[i] == myrpt)
13750       {
13751          load_rpt_vars(i,0);
13752          break;
13753       }
13754    }
13755    rpt_mutex_lock(&myrpt->lock);
13756    tele = strchr(myrpt->rxchanname,'/');
13757    if (!tele)
13758    {
13759       fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
13760       rpt_mutex_unlock(&myrpt->lock);
13761       pthread_exit(NULL);
13762    }
13763    *tele++ = 0;
13764    myrpt->rxchannel = ast_request(myrpt->rxchanname,AST_FORMAT_SLINEAR,tele,NULL);
13765    myrpt->dahdirxchannel = NULL;
13766    if (!strcasecmp(myrpt->rxchanname,"DAHDI"))
13767       myrpt->dahdirxchannel = myrpt->rxchannel;
13768    if (myrpt->rxchannel)
13769    {
13770       ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
13771       ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
13772 #ifdef   AST_CDR_FLAG_POST_DISABLED
13773       if (myrpt->rxchannel->cdr)
13774          ast_set_flag(myrpt->rxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
13775 #endif
13776 #ifndef  NEW_ASTERISK
13777       myrpt->rxchannel->whentohangup = 0;
13778 #endif
13779       myrpt->rxchannel->appl = "Apprpt";
13780       myrpt->rxchannel->data = "(Link Rx)";
13781       if (option_verbose > 2)
13782          ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
13783             myrpt->rxchanname,tele,myrpt->rxchannel->name);
13784       rpt_mutex_unlock(&myrpt->lock);
13785       ast_call(myrpt->rxchannel,tele,999);
13786       rpt_mutex_lock(&myrpt->lock);
13787    }
13788    else
13789    {
13790       fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
13791       rpt_mutex_unlock(&myrpt->lock);
13792       pthread_exit(NULL);
13793    }
13794    *--tele = '/';
13795    myrpt->dahditxchannel = NULL;
13796    if (myrpt->txchanname)
13797    {
13798       tele = strchr(myrpt->txchanname,'/');
13799       if (!tele)
13800       {
13801          fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
13802          rpt_mutex_unlock(&myrpt->lock);
13803          ast_hangup(myrpt->rxchannel);
13804          pthread_exit(NULL);
13805       }
13806       *tele++ = 0;
13807       myrpt->txchannel = ast_request(myrpt->txchanname,AST_FORMAT_SLINEAR,tele,NULL);
13808       if (!strncasecmp(myrpt->txchanname,"DAHDI",3))
13809          myrpt->dahditxchannel = myrpt->txchannel;
13810       if (myrpt->txchannel)
13811       {
13812          ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
13813          ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
13814 #ifdef   AST_CDR_FLAG_POST_DISABLED
13815          if (myrpt->txchannel->cdr)
13816             ast_set_flag(myrpt->txchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
13817 #endif
13818 #ifndef  NEW_ASTERISK
13819          myrpt->txchannel->whentohangup = 0;
13820 #endif
13821          myrpt->txchannel->appl = "Apprpt";
13822          myrpt->txchannel->data = "(Link Tx)";
13823          if (option_verbose > 2)
13824             ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
13825                myrpt->txchanname,tele,myrpt->txchannel->name);
13826          rpt_mutex_unlock(&myrpt->lock);
13827          ast_call(myrpt->txchannel,tele,999);
13828          rpt_mutex_lock(&myrpt->lock);
13829       }
13830       else
13831       {
13832          fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
13833          rpt_mutex_unlock(&myrpt->lock);
13834          ast_hangup(myrpt->rxchannel);
13835          pthread_exit(NULL);
13836       }
13837       *--tele = '/';
13838    }
13839    else
13840    {
13841       myrpt->txchannel = myrpt->rxchannel;
13842       if (!strncasecmp(myrpt->rxchanname,"DAHDI",3))
13843          myrpt->dahditxchannel = myrpt->rxchannel;
13844    }
13845    /* allocate a pseudo-channel thru asterisk */
13846    myrpt->pchannel = ast_request("DAHDI",AST_FORMAT_SLINEAR,"pseudo",NULL);
13847    if (!myrpt->pchannel)
13848    {
13849       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
13850       rpt_mutex_unlock(&myrpt->lock);
13851       if (myrpt->txchannel != myrpt->rxchannel) 
13852          ast_hangup(myrpt->txchannel);
13853       ast_hangup(myrpt->rxchannel);
13854       pthread_exit(NULL);
13855    }
13856    ast_set_read_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
13857    ast_set_write_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
13858 #ifdef   AST_CDR_FLAG_POST_DISABLED
13859    if (myrpt->pchannel->cdr)
13860       ast_set_flag(myrpt->pchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
13861 #endif
13862    if (!myrpt->dahdirxchannel) myrpt->dahdirxchannel = myrpt->pchannel;
13863    if (!myrpt->dahditxchannel) myrpt->dahditxchannel = myrpt->pchannel;
13864    /* make a conference for the pseudo */
13865    ci.chan = 0;
13866    ci.confno = -1; /* make a new conf */
13867    ci.confmode = DAHDI_CONF_CONFANNMON ;
13868    /* first put the channel on the conference in announce/monitor mode */
13869    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
13870    {
13871       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
13872       rpt_mutex_unlock(&myrpt->lock);
13873       ast_hangup(myrpt->pchannel);
13874       if (myrpt->txchannel != myrpt->rxchannel) 
13875          ast_hangup(myrpt->txchannel);
13876       ast_hangup(myrpt->rxchannel);
13877       pthread_exit(NULL);
13878    }
13879    /* save pseudo channel conference number */
13880    myrpt->conf = myrpt->txconf = ci.confno;
13881    /* if serial io port, open it */
13882    myrpt->iofd = -1;
13883    if (myrpt->p.ioport && ((myrpt->iofd = openserial(myrpt,myrpt->p.ioport)) == -1))
13884    {
13885       rpt_mutex_unlock(&myrpt->lock);
13886       ast_hangup(myrpt->pchannel);
13887       if (myrpt->txchannel != myrpt->rxchannel) 
13888          ast_hangup(myrpt->txchannel);
13889       ast_hangup(myrpt->rxchannel);
13890       pthread_exit(NULL);
13891    }
13892    iskenwood_pci4 = 0;
13893    memset(&z,0,sizeof(z));
13894    if ((myrpt->iofd < 1) && (myrpt->txchannel == myrpt->dahditxchannel))
13895    {
13896       z.radpar = DAHDI_RADPAR_REMMODE;
13897       z.data = DAHDI_RADPAR_REM_NONE;
13898       res = ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z);
13899       /* if PCIRADIO and kenwood selected */
13900       if ((!res) && (!strcmp(myrpt->remoterig,remote_rig_kenwood)))
13901       {
13902          z.radpar = DAHDI_RADPAR_UIOMODE;
13903          z.data = 1;
13904          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13905          {
13906             ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
13907             return -1;
13908          }
13909          z.radpar = DAHDI_RADPAR_UIODATA;
13910          z.data = 3;
13911          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13912          {
13913             ast_log(LOG_ERROR,"Cannot set UIODATA\n");
13914             return -1;
13915          }
13916          i = DAHDI_OFFHOOK;
13917          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_HOOK,&i) == -1)
13918          {
13919             ast_log(LOG_ERROR,"Cannot set hook\n");
13920             return -1;
13921          }
13922          iskenwood_pci4 = 1;
13923       }
13924    }
13925    if (myrpt->txchannel == myrpt->dahditxchannel)
13926    {
13927       i = DAHDI_ONHOOK;
13928       ioctl(myrpt->dahditxchannel->fds[0],DAHDI_HOOK,&i);
13929       /* if PCIRADIO and Yaesu ft897/ICOM IC-706 selected */
13930       if ((myrpt->iofd < 1) && (!res) &&
13931          ((!strcmp(myrpt->remoterig,remote_rig_ft897)) ||
13932             (!strcmp(myrpt->remoterig,remote_rig_ic706)) ||
13933                (!strcmp(myrpt->remoterig,remote_rig_tm271))))
13934       {
13935          z.radpar = DAHDI_RADPAR_UIOMODE;
13936          z.data = 1;
13937          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13938          {
13939             ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
13940             return -1;
13941          }
13942          z.radpar = DAHDI_RADPAR_UIODATA;
13943          z.data = 3;
13944          if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
13945          {
13946             ast_log(LOG_ERROR,"Cannot set UIODATA\n");
13947             return -1;
13948          }
13949       }
13950    }
13951    myrpt->remoterx = 0;
13952    myrpt->remotetx = 0;
13953    myrpt->retxtimer = 0;
13954    myrpt->rerxtimer = 0;
13955    myrpt->remoteon = 1;
13956    myrpt->dtmfidx = -1;
13957    myrpt->dtmfbuf[0] = 0;
13958    myrpt->dtmf_time_rem = 0;
13959    myrpt->hfscanmode = 0;
13960    myrpt->hfscanstatus = 0;
13961    if (myrpt->p.startupmacro)
13962    {
13963       snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
13964    }
13965    time(&myrpt->start_time);
13966    myrpt->last_activity_time = myrpt->start_time;
13967    last_timeout_warning = 0;
13968    myrpt->reload = 0;
13969    myrpt->tele.next = &myrpt->tele;
13970    myrpt->tele.prev = &myrpt->tele;
13971    myrpt->newkey = 0;
13972    rpt_mutex_unlock(&myrpt->lock);
13973    ast_set_write_format(chan, AST_FORMAT_SLINEAR);
13974    ast_set_read_format(chan, AST_FORMAT_SLINEAR);
13975    rem_rx = 0;
13976    remkeyed = 0;
13977    /* if we are on 2w loop and are a remote, turn EC on */
13978    if (myrpt->remote && (myrpt->rxchannel == myrpt->txchannel))
13979    {
13980       i = 128;
13981       ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_ECHOCANCEL,&i);
13982    }
13983    if (chan->_state != AST_STATE_UP) {
13984       ast_answer(chan);
13985       if (!phone_mode) send_newkey(chan);
13986    }
13987 
13988    if (myrpt->rxchannel == myrpt->dahdirxchannel)
13989    {
13990       if (ioctl(myrpt->dahdirxchannel->fds[0],DAHDI_GET_PARAMS,&par) != -1)
13991       {
13992          if (par.rxisoffhook)
13993          {
13994             ast_indicate(chan,AST_CONTROL_RADIO_KEY);
13995             myrpt->remoterx = 1;
13996             remkeyed = 1;
13997          }
13998       }
13999    }
14000    if (myrpt->p.archivedir)
14001    {
14002       char mycmd[100],mydate[100],*b,*b1;
14003       time_t myt;
14004       long blocksleft;
14005 
14006 
14007       mkdir(myrpt->p.archivedir,0600);
14008       sprintf(mycmd,"%s/%s",myrpt->p.archivedir,myrpt->name);
14009       mkdir(mycmd,0600);
14010       time(&myt);
14011       strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
14012          localtime(&myt));
14013       sprintf(mycmd,"mixmonitor start %s %s/%s/%s.wav49 a",chan->name,
14014          myrpt->p.archivedir,myrpt->name,mydate);
14015       if (myrpt->p.monminblocks)
14016       {
14017          blocksleft = diskavail(myrpt);
14018          if (myrpt->p.remotetimeout)
14019          {
14020             blocksleft -= (myrpt->p.remotetimeout *
14021                MONITOR_DISK_BLOCKS_PER_MINUTE) / 60;
14022          }
14023          if (blocksleft >= myrpt->p.monminblocks)
14024             ast_cli_command(nullfd,mycmd);
14025       } else ast_cli_command(nullfd,mycmd);
14026       /* look at callerid to see what node this comes from */
14027       if (!chan->cid.cid_num) /* if doesn't have caller id */
14028       {
14029          b1 = "0";
14030       } else {
14031          ast_callerid_parse(chan->cid.cid_num,&b,&b1);
14032          ast_shrink_phone_number(b1);
14033       }
14034       sprintf(mycmd,"CONNECT,%s",b1);
14035       donodelog(myrpt,mycmd);
14036    }
14037    myrpt->loginuser[0] = 0;
14038    myrpt->loginlevel[0] = 0;
14039    myrpt->authtelltimer = 0;
14040    myrpt->authtimer = 0;
14041    authtold = 0;
14042    authreq = 0;
14043    if (myrpt->p.authlevel > 1) authreq = 1;
14044    setrem(myrpt); 
14045    n = 0;
14046    dtmfed = 0;
14047    cs[n++] = chan;
14048    cs[n++] = myrpt->rxchannel;
14049    cs[n++] = myrpt->pchannel;
14050    if (myrpt->rxchannel != myrpt->txchannel)
14051       cs[n++] = myrpt->txchannel;
14052    if (!phone_mode) send_newkey(chan);
14053    /* start un-locked */
14054    for(;;) 
14055    {
14056       if (ast_check_hangup(chan)) break;
14057       if (ast_check_hangup(myrpt->rxchannel)) break;
14058       notremming = 0;
14059       setting = 0;
14060       reming = 0;
14061       telem = myrpt->tele.next;
14062       while(telem != &myrpt->tele)
14063       {
14064          if (telem->mode == SETREMOTE) setting = 1;
14065          if ((telem->mode == SETREMOTE) ||
14066              (telem->mode == SCAN) ||
14067             (telem->mode == TUNE))  reming = 1;
14068          else notremming = 1;
14069          telem = telem->next;
14070       }
14071       if (myrpt->reload)
14072       {
14073          myrpt->reload = 0;
14074          /* find our index, and load the vars */
14075          for(i = 0; i < nrpts; i++)
14076          {
14077             if (&rpt_vars[i] == myrpt)
14078             {
14079                load_rpt_vars(i,0);
14080                break;
14081             }
14082          }
14083       }
14084       time(&t);
14085       if (myrpt->p.remotetimeout)
14086       { 
14087          time_t r;
14088 
14089          r = (t - myrpt->start_time);
14090          if (r >= myrpt->p.remotetimeout)
14091          {
14092             saynode(myrpt,chan,myrpt->name);
14093             sayfile(chan,"rpt/timeout");
14094             ast_safe_sleep(chan,1000);
14095             break;
14096          }
14097          if ((myrpt->p.remotetimeoutwarning) && 
14098              (r >= (myrpt->p.remotetimeout -
14099             myrpt->p.remotetimeoutwarning)) &&
14100                 (r <= (myrpt->p.remotetimeout - 
14101                   myrpt->p.remotetimeoutwarningfreq)))
14102          {
14103             if (myrpt->p.remotetimeoutwarningfreq)
14104             {
14105                 if ((t - last_timeout_warning) >=
14106                myrpt->p.remotetimeoutwarningfreq)
14107                 {
14108                time(&last_timeout_warning);
14109                rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
14110                 }
14111             }
14112             else
14113             {
14114                 if (!last_timeout_warning)
14115                 {
14116                time(&last_timeout_warning);
14117                rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
14118                 }
14119             }
14120          }
14121       }
14122       if (myrpt->p.remoteinacttimeout && myrpt->last_activity_time)
14123       { 
14124          time_t r;
14125 
14126          r = (t - myrpt->last_activity_time);
14127          if (r >= myrpt->p.remoteinacttimeout)
14128          {
14129             saynode(myrpt,chan,myrpt->name);
14130             ast_safe_sleep(chan,1000);
14131             break;
14132          }
14133          if ((myrpt->p.remotetimeoutwarning) && 
14134              (r >= (myrpt->p.remoteinacttimeout -
14135             myrpt->p.remotetimeoutwarning)) &&
14136                 (r <= (myrpt->p.remoteinacttimeout - 
14137                   myrpt->p.remotetimeoutwarningfreq)))
14138          {
14139             if (myrpt->p.remotetimeoutwarningfreq)
14140             {
14141                 if ((t - last_timeout_warning) >=
14142                myrpt->p.remotetimeoutwarningfreq)
14143                 {
14144                time(&last_timeout_warning);
14145                rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
14146                 }
14147             }
14148             else
14149             {
14150                 if (!last_timeout_warning)
14151                 {
14152                time(&last_timeout_warning);
14153                rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
14154                 }
14155             }
14156          }
14157       }
14158       ms = MSWAIT;
14159       who = ast_waitfor_n(cs,n,&ms);
14160       if (who == NULL) ms = 0;
14161       elap = MSWAIT - ms;
14162       if (myrpt->macrotimer) myrpt->macrotimer -= elap;
14163       if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
14164       if (!ms) continue;
14165       /* do local dtmf timer */
14166       if (myrpt->dtmf_local_timer)
14167       {
14168          if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
14169          if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
14170       }
14171       rpt_mutex_lock(&myrpt->lock);
14172       do_dtmf_local(myrpt,0);
14173       rpt_mutex_unlock(&myrpt->lock);
14174       //
14175       rem_totx =  myrpt->dtmf_local_timer && (!phone_mode);
14176       rem_totx |= keyed && (!myrpt->tunerequest);
14177       rem_rx = (remkeyed && (!setting)) || (myrpt->tele.next != &myrpt->tele);
14178       if(!strcmp(myrpt->remoterig, remote_rig_ic706))
14179          rem_totx |= myrpt->tunerequest;
14180       //
14181        if((debug > 6) && rem_totx) {
14182          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);
14183       }
14184       if (keyed && (!keyed1))
14185       {
14186          keyed1 = 1;
14187       }
14188 
14189       if (!keyed && (keyed1))
14190       {
14191          time_t myt;
14192 
14193          keyed1 = 0;
14194          time(&myt);
14195          /* if login necessary, and not too soon */
14196          if ((myrpt->p.authlevel) && 
14197              (!myrpt->loginlevel[0]) &&
14198             (myt > (t + 3)))
14199          {
14200             authreq = 1;
14201             authtold = 0;
14202             myrpt->authtelltimer = AUTHTELLTIME - AUTHTXTIME;
14203          }
14204       }
14205 
14206       if (rem_rx && (!myrpt->remoterx))
14207       {
14208          myrpt->remoterx = 1;
14209          ast_indicate(chan,AST_CONTROL_RADIO_KEY);
14210       }
14211       if ((!rem_rx) && (myrpt->remoterx))
14212       {
14213          myrpt->remoterx = 0;
14214          ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
14215       }
14216       /* if auth requested, and not authed yet */
14217       if (authreq && (!myrpt->loginlevel[0]))
14218       {
14219          if ((!authtold) && ((myrpt->authtelltimer += elap)
14220              >= AUTHTELLTIME))
14221          {
14222             authtold = 1;
14223             rpt_telemetry(myrpt,LOGINREQ,NULL);
14224          }
14225          if ((myrpt->authtimer += elap) >= AUTHLOGOUTTIME)
14226          {
14227             break; /* if not logged in, hang up after a time */
14228          }
14229       }
14230       if (myrpt->newkey)
14231       {
14232          if ((myrpt->retxtimer += elap) >= REDUNDANT_TX_TIME)
14233          {
14234             myrpt->retxtimer = 0;
14235             if ((myrpt->remoterx) && (!myrpt->remotetx))
14236                ast_indicate(chan,AST_CONTROL_RADIO_KEY);
14237             else
14238                ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
14239          }
14240 
14241          if ((myrpt->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 2))
14242          {
14243             keyed = 0;
14244             myrpt->rerxtimer = 0;
14245          }
14246       }
14247       if (rem_totx && (!myrpt->remotetx))
14248       {
14249          /* if not authed, and needed, do not transmit */
14250          if ((!myrpt->p.authlevel) || myrpt->loginlevel[0])
14251          {
14252             if(debug > 6)
14253                ast_log(LOG_NOTICE,"Handle rem_totx=%i.  dtmf_local_timer=%i  tunerequest=%i\n",rem_totx,myrpt->dtmf_local_timer,myrpt->tunerequest);
14254 
14255             myrpt->remotetx = 1;
14256             /* asdf maw ??? is this really what you want? Doesn't it always get executed? */
14257             if((myrpt->remtxfreqok = check_tx_freq(myrpt)))
14258             {
14259                time(&myrpt->last_activity_time);
14260                if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->dahditxchannel))
14261                {
14262                   z.radpar = DAHDI_RADPAR_UIODATA;
14263                   z.data = 1;
14264                   if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14265                   {
14266                      ast_log(LOG_ERROR,"Cannot set UIODATA\n");
14267                      return -1;
14268                   }
14269                }
14270                else
14271                {
14272                   ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
14273                }
14274                if (myrpt->p.archivedir) donodelog(myrpt,"TXKEY");
14275             }
14276          }
14277       }
14278       if ((!rem_totx) && myrpt->remotetx) /* Remote base radio TX unkey */
14279       {
14280          myrpt->remotetx = 0;
14281          if(!myrpt->remtxfreqok){
14282             rpt_telemetry(myrpt,UNAUTHTX,NULL);
14283          }
14284          if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->dahditxchannel))
14285          {
14286             z.radpar = DAHDI_RADPAR_UIODATA;
14287             z.data = 3;
14288             if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14289             {
14290                ast_log(LOG_ERROR,"Cannot set UIODATA\n");
14291                return -1;
14292             }
14293          }
14294          else
14295          {
14296             ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
14297          }
14298          if (myrpt->p.archivedir) donodelog(myrpt,"TXUNKEY");
14299       }
14300       if (myrpt->hfscanmode){
14301          myrpt->scantimer -= elap;
14302          if(myrpt->scantimer <= 0){
14303             if (!reming)
14304             {
14305                myrpt->scantimer = REM_SCANTIME;
14306                rpt_telemetry(myrpt,SCAN,0);
14307             } else myrpt->scantimer = 1;
14308          }
14309       }
14310       rpt_mutex_lock(&myrpt->lock);
14311       c = myrpt->macrobuf[0];
14312       if (c && (!myrpt->macrotimer))
14313       {
14314          myrpt->macrotimer = MACROTIME;
14315          memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
14316          if ((c == 'p') || (c == 'P'))
14317             myrpt->macrotimer = MACROPTIME;
14318          rpt_mutex_unlock(&myrpt->lock);
14319          if (myrpt->p.archivedir)
14320          {
14321             char str[100];
14322                sprintf(str,"DTMF(M),%c",c);
14323             donodelog(myrpt,str);
14324          }
14325          if (handle_remote_dtmf_digit(myrpt,c,&keyed,0) == -1) break;
14326          continue;
14327       } else rpt_mutex_unlock(&myrpt->lock);
14328       if (who == chan) /* if it was a read from incomming */
14329       {
14330          f = ast_read(chan);
14331          if (!f)
14332          {
14333             if (debug) printf("@@@@ link:Hung Up\n");
14334             break;
14335          }
14336          if (f->frametype == AST_FRAME_VOICE)
14337          {
14338             if (ioctl(chan->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
14339             {
14340                ismuted = 0;
14341             }
14342             /* if not transmitting, zero-out audio */
14343             ismuted |= (!myrpt->remotetx);
14344             if (dtmfed && phone_mode) ismuted = 1;
14345             dtmfed = 0;
14346             if (ismuted)
14347             {
14348                memset(f->data.ptr,0,f->datalen);
14349                if (myrpt->lastf1)
14350                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14351                if (myrpt->lastf2)
14352                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14353             } 
14354             if (f) f2 = ast_frdup(f);
14355             else f2 = NULL;
14356             f1 = myrpt->lastf2;
14357             myrpt->lastf2 = myrpt->lastf1;
14358             myrpt->lastf1 = f2;
14359             if (ismuted)
14360             {
14361                if (myrpt->lastf1)
14362                   memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14363                if (myrpt->lastf2)
14364                   memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14365             }
14366             if (f1)
14367             {
14368                if (phone_mode)
14369                   ast_write(myrpt->txchannel,f1);
14370                else
14371                   ast_write(myrpt->txchannel,f);
14372                ast_frfree(f1);
14373             }
14374          }
14375 #ifndef  OLD_ASTERISK
14376          else if (f->frametype == AST_FRAME_DTMF_BEGIN)
14377          {
14378             if (myrpt->lastf1)
14379                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14380             if (myrpt->lastf2)
14381                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14382             dtmfed = 1;
14383          }
14384 #endif
14385          if (f->frametype == AST_FRAME_DTMF)
14386          {
14387             if (myrpt->lastf1)
14388                memset(myrpt->lastf1->data.ptr,0,myrpt->lastf1->datalen);
14389             if (myrpt->lastf2)
14390                memset(myrpt->lastf2->data.ptr,0,myrpt->lastf2->datalen);
14391             dtmfed = 1;
14392             if (handle_remote_phone_dtmf(myrpt,f->subclass,&keyed,phone_mode) == -1)
14393             {
14394                if (debug) printf("@@@@ rpt:Hung Up\n");
14395                ast_frfree(f);
14396                break;
14397             }
14398          }
14399          if (f->frametype == AST_FRAME_TEXT)
14400          {
14401             if (handle_remote_data(myrpt,f->data.ptr) == -1)
14402             {
14403                if (debug) printf("@@@@ rpt:Hung Up\n");
14404                ast_frfree(f);
14405                break;
14406             }
14407          }
14408          if (f->frametype == AST_FRAME_CONTROL)
14409          {
14410             if (f->subclass == AST_CONTROL_HANGUP)
14411             {
14412                if (debug) printf("@@@@ rpt:Hung Up\n");
14413                ast_frfree(f);
14414                break;
14415             }
14416             /* if RX key */
14417             if (f->subclass == AST_CONTROL_RADIO_KEY)
14418             {
14419                if (debug == 7) printf("@@@@ rx key\n");
14420                keyed = 1;
14421                myrpt->rerxtimer = 0;
14422             }
14423             /* if RX un-key */
14424             if (f->subclass == AST_CONTROL_RADIO_UNKEY)
14425             {
14426                myrpt->rerxtimer = 0;
14427                if (debug == 7) printf("@@@@ rx un-key\n");
14428                keyed = 0;
14429             }
14430          }
14431          ast_frfree(f);
14432          continue;
14433       }
14434       if (who == myrpt->rxchannel) /* if it was a read from radio */
14435       {
14436          f = ast_read(myrpt->rxchannel);
14437          if (!f)
14438          {
14439             if (debug) printf("@@@@ link:Hung Up\n");
14440             break;
14441          }
14442          if (f->frametype == AST_FRAME_VOICE)
14443          {
14444             int myreming = 0;
14445 
14446             if(!strcmp(myrpt->remoterig, remote_rig_kenwood))
14447                myreming = reming;
14448 
14449             if (myreming || (!remkeyed) ||
14450             ((myrpt->remote) && (myrpt->remotetx)) ||
14451               ((myrpt->remmode != REM_MODE_FM) &&
14452                 notremming))
14453                memset(f->data.ptr,0,f->datalen); 
14454              ast_write(myrpt->pchannel,f);
14455          }
14456          else if (f->frametype == AST_FRAME_CONTROL)
14457          {
14458             if (f->subclass == AST_CONTROL_HANGUP)
14459             {
14460                if (debug) printf("@@@@ rpt:Hung Up\n");
14461                ast_frfree(f);
14462                break;
14463             }
14464             /* if RX key */
14465             if (f->subclass == AST_CONTROL_RADIO_KEY)
14466             {
14467                if (debug == 7) printf("@@@@ remote rx key\n");
14468                if (!myrpt->remotetx)
14469                {
14470                   remkeyed = 1;
14471                }
14472             }
14473             /* if RX un-key */
14474             if (f->subclass == AST_CONTROL_RADIO_UNKEY)
14475             {
14476                if (debug == 7) printf("@@@@ remote rx un-key\n");
14477                if (!myrpt->remotetx) 
14478                {
14479                   remkeyed = 0;
14480                }
14481             }
14482          }
14483          ast_frfree(f);
14484          continue;
14485       }
14486       if (who == myrpt->pchannel) /* if is remote mix output */
14487       {
14488          f = ast_read(myrpt->pchannel);
14489          if (!f)
14490          {
14491             if (debug) printf("@@@@ link:Hung Up\n");
14492             break;
14493          }
14494          if (f->frametype == AST_FRAME_VOICE)
14495          {
14496             ast_write(chan,f);
14497          }
14498          if (f->frametype == AST_FRAME_CONTROL)
14499          {
14500             if (f->subclass == AST_CONTROL_HANGUP)
14501             {
14502                if (debug) printf("@@@@ rpt:Hung Up\n");
14503                ast_frfree(f);
14504                break;
14505             }
14506          }
14507          ast_frfree(f);
14508          continue;
14509       }
14510       if ((myrpt->rxchannel != myrpt->txchannel) && 
14511          (who == myrpt->txchannel)) /* do this cuz you have to */
14512       {
14513          f = ast_read(myrpt->txchannel);
14514          if (!f)
14515          {
14516             if (debug) printf("@@@@ link:Hung Up\n");
14517             break;
14518          }
14519          if (f->frametype == AST_FRAME_CONTROL)
14520          {
14521             if (f->subclass == AST_CONTROL_HANGUP)
14522             {
14523                if (debug) printf("@@@@ rpt:Hung Up\n");
14524                ast_frfree(f);
14525                break;
14526             }
14527          }
14528          ast_frfree(f);
14529          continue;
14530       }
14531    }
14532    if (myrpt->p.archivedir)
14533    {
14534       char mycmd[100],*b,*b1;
14535 
14536       /* look at callerid to see what node this comes from */
14537       if (!chan->cid.cid_num) /* if doesn't have caller id */
14538       {
14539          b1 = "0";
14540       } else {
14541          ast_callerid_parse(chan->cid.cid_num,&b,&b1);
14542          ast_shrink_phone_number(b1);
14543       }
14544       sprintf(mycmd,"DISCONNECT,%s",b1);
14545       donodelog(myrpt,mycmd);
14546    }
14547    /* wait for telem to be done */
14548    while(myrpt->tele.next != &myrpt->tele) usleep(100000);
14549    sprintf(tmp,"mixmonitor stop %s",chan->name);
14550    ast_cli_command(nullfd,tmp);
14551    close(nullfd);
14552    rpt_mutex_lock(&myrpt->lock);
14553    myrpt->hfscanmode = 0;
14554    myrpt->hfscanstatus = 0;
14555    myrpt->remoteon = 0;
14556    rpt_mutex_unlock(&myrpt->lock);
14557    if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
14558    myrpt->lastf1 = NULL;
14559    if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
14560    myrpt->lastf2 = NULL;
14561    if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->dahditxchannel))
14562    {
14563       z.radpar = DAHDI_RADPAR_UIOMODE;
14564       z.data = 3;
14565       if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14566       {
14567          ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
14568          return -1;
14569       }
14570       z.radpar = DAHDI_RADPAR_UIODATA;
14571       z.data = 3;
14572       if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
14573       {
14574          ast_log(LOG_ERROR,"Cannot set UIODATA\n");
14575          return -1;
14576       }
14577       i = DAHDI_OFFHOOK;
14578       if (ioctl(myrpt->dahditxchannel->fds[0],DAHDI_HOOK,&i) == -1)
14579       {
14580          ast_log(LOG_ERROR,"Cannot set hook\n");
14581          return -1;
14582       }
14583    }
14584    if (myrpt->iofd) close(myrpt->iofd);
14585    myrpt->iofd = -1;
14586    ast_hangup(myrpt->pchannel);
14587    if (myrpt->rxchannel != myrpt->txchannel) ast_hangup(myrpt->txchannel);
14588    ast_hangup(myrpt->rxchannel);
14589    closerem(myrpt);
14590    if (myrpt->p.rptnode)
14591    {
14592       rpt_mutex_lock(&myrpt->lock);
14593       for(i = 0; i < nrpts; i++)
14594       {
14595          if (!strcasecmp(rpt_vars[i].name,myrpt->p.rptnode))
14596          {
14597             rpt_vars[i].xlink = 0;
14598             break;
14599          }
14600       }
14601       rpt_mutex_unlock(&myrpt->lock);
14602    }
14603 #ifdef   OLD_ASTERISK
14604    LOCAL_USER_REMOVE(u);
14605 #endif
14606    return res;
14607 }
14608 
14609 #ifndef OLD_ASTERISK
14610 /*!\brief callback to display list of locally configured nodes
14611    \addtogroup Group_AMI
14612  */
14613 static int manager_rpt_local_nodes(struct mansession *s, const struct message *m)
14614 {
14615     int i;
14616     astman_append(s, "<?xml version=\"1.0\"?>\r\n");
14617     astman_append(s, "<nodes>\r\n");
14618     for (i=0; i< nrpts; i++)
14619     {
14620         astman_append(s, "  <node>%s</node>\r\n", rpt_vars[i].name);        
14621     } /* for i */
14622     astman_append(s, "</nodes>\r\n");
14623     astman_append(s, "\r\n"); /* Properly terminate Manager output */
14624     return RESULT_SUCCESS;
14625 } /* manager_rpt_local_nodes() */
14626 
14627 
14628 
14629 /*
14630  * Append Success and ActionID to manager response message
14631  */
14632 
14633 static void rpt_manager_success(struct mansession *s, const struct message *m)
14634 {
14635    const char *id = astman_get_header(m, "ActionID");
14636    if (!ast_strlen_zero(id))
14637       astman_append(s, "ActionID: %s\r\n", id);
14638    astman_append(s, "Response: Success\r\n");
14639 }
14640 
14641 /*
14642 * Dump statistics to manager session
14643 */
14644 
14645 static int rpt_manager_do_stats(struct mansession *s, const struct message *m, char *str)
14646 {
14647    int i,j,numoflinks;
14648    int dailytxtime, dailykerchunks;
14649    time_t now;
14650    int totalkerchunks, dailykeyups, totalkeyups, timeouts;
14651    int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
14652    long long totaltxtime;
14653    struct   rpt_link *l;
14654    char *listoflinks[MAX_STAT_LINKS];  
14655    char *lastdtmfcommand,*parrot_ena;
14656    char *tot_state, *ider_state, *patch_state;
14657    char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
14658    char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
14659    char *transmitterkeyed;
14660    const char *node = astman_get_header(m, "Node");
14661    struct rpt *myrpt;
14662 
14663    static char *not_applicable = "N/A";
14664 
14665    tot_state = ider_state = 
14666    patch_state = reverse_patch_state = 
14667    input_signal = not_applicable;
14668    called_number = lastdtmfcommand = transmitterkeyed = NULL;
14669 
14670    time(&now);
14671    for(i = 0; i < nrpts; i++)
14672    {
14673       if ((node)&&(!strcmp(node,rpt_vars[i].name))){
14674          rpt_manager_success(s,m);
14675 
14676          myrpt = &rpt_vars[i];
14677 
14678          if(myrpt->remote){ /* Remote base ? */
14679             char *loginuser, *loginlevel, *freq, *rxpl, *txpl, *modestr;
14680             char offset = 0, powerlevel = 0, rxplon = 0, txplon = 0, remoteon, remmode = 0, reportfmstuff;
14681             char offsetc,powerlevelc;
14682 
14683             loginuser = loginlevel = freq = rxpl = txpl = NULL;
14684             /* Make a copy of all stat variables while locked */
14685             rpt_mutex_lock(&myrpt->lock); /* LOCK */
14686             if((remoteon = myrpt->remoteon)){
14687                if(!ast_strlen_zero(myrpt->loginuser))
14688                   loginuser = ast_strdup(myrpt->loginuser);
14689                if(!ast_strlen_zero(myrpt->loginlevel))
14690                   loginlevel = ast_strdup(myrpt->loginlevel);
14691                if(!ast_strlen_zero(myrpt->freq))
14692                   freq = ast_strdup(myrpt->freq);
14693                if(!ast_strlen_zero(myrpt->rxpl))
14694                   rxpl = ast_strdup(myrpt->rxpl);
14695                if(!ast_strlen_zero(myrpt->txpl))
14696                   txpl = ast_strdup(myrpt->txpl);
14697                remmode = myrpt->remmode;
14698                offset = myrpt->offset;
14699                powerlevel = myrpt->powerlevel;
14700                rxplon = myrpt->rxplon;
14701                txplon = myrpt->txplon;       
14702             }
14703             rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
14704             astman_append(s, "IsRemoteBase: YES\r\n");
14705             astman_append(s, "RemoteOn: %s\r\n",(remoteon) ? "YES": "NO");
14706             if(remoteon){
14707                if(loginuser){
14708                   astman_append(s, "LogInUser: %s\r\n", loginuser);
14709                   ast_free(loginuser);
14710                }
14711                if(loginlevel){
14712                   astman_append(s, "LogInLevel: %s\r\n", loginlevel);
14713                   ast_free(loginlevel);
14714                }
14715                if(freq){
14716                   astman_append(s, "Freq: %s\r\n", freq);
14717                   ast_free(freq);
14718                }
14719                reportfmstuff = 0;
14720                switch(remmode){
14721                   case REM_MODE_FM:
14722                      modestr = "FM";   
14723                      reportfmstuff = 1;
14724                      break;
14725                   case REM_MODE_AM:
14726                      modestr = "AM";
14727                      break;
14728                   case REM_MODE_USB:
14729                      modestr = "USB";
14730                      break;
14731                   default:
14732                      modestr = "LSB";
14733                      break;
14734                }
14735                astman_append(s, "RemMode: %s\r\n", modestr);
14736                if(reportfmstuff){
14737                   switch(offset){
14738                      case REM_SIMPLEX:
14739                         offsetc = 'S';
14740                         break;
14741                      case REM_MINUS:
14742                         offsetc = '-';
14743                         break;
14744                      default:
14745                         offsetc = '+';
14746                         break;
14747                   }
14748                   astman_append(s, "RemOffset: %c\r\n", offsetc);
14749                   if(rxplon && rxpl){
14750                      astman_append(s, "RxPl: %s\r\n",rxpl);
14751                      ast_free(rxpl);
14752                   }
14753                   if(txplon && txpl){
14754                      astman_append(s, "TxPl: %s\r\n",txpl);
14755                      ast_free(txpl);
14756                   }
14757                }
14758                switch(powerlevel){
14759                   case REM_LOWPWR:
14760                      powerlevelc = 'L';
14761                      break;
14762                   case REM_MEDPWR:
14763                      powerlevelc = 'M';
14764                      break;
14765                   default:
14766                      powerlevelc = 'H';
14767                      break;
14768                }
14769                astman_append(s,"PowerLevel: %c\r\n", powerlevelc);
14770             }
14771             astman_append(s, "\r\n");
14772             return 0; /* End of remote base status reporting */
14773          }  
14774 
14775          /* ELSE Process as a repeater node */
14776          /* Make a copy of all stat variables while locked */
14777          rpt_mutex_lock(&myrpt->lock); /* LOCK */
14778          dailytxtime = myrpt->dailytxtime;
14779          totaltxtime = myrpt->totaltxtime;
14780          dailykeyups = myrpt->dailykeyups;
14781          totalkeyups = myrpt->totalkeyups;
14782          dailykerchunks = myrpt->dailykerchunks;
14783          totalkerchunks = myrpt->totalkerchunks;
14784          dailyexecdcommands = myrpt->dailyexecdcommands;
14785          totalexecdcommands = myrpt->totalexecdcommands;
14786          timeouts = myrpt->timeouts;
14787 
14788 
14789          /* Traverse the list of connected nodes */
14790          reverse_patch_state = "DOWN";
14791          numoflinks = 0;
14792          l = myrpt->links.next;
14793          while(l && (l != &myrpt->links)){
14794             if(numoflinks >= MAX_STAT_LINKS){
14795                ast_log(LOG_NOTICE,
14796                "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
14797                break;
14798             }
14799             if (l->name[0] == '0'){ /* Skip '0' nodes */
14800                reverse_patch_state = "UP";
14801                l = l->next;
14802                continue;
14803             }
14804             listoflinks[numoflinks] = ast_strdup(l->name);
14805             if(listoflinks[numoflinks] == NULL){
14806                break;
14807             }
14808             else{
14809                numoflinks++;
14810             }
14811             l = l->next;
14812          }
14813 
14814          if(myrpt->keyed)
14815             input_signal = "YES";
14816          else
14817             input_signal = "NO";
14818          
14819          if(myrpt->txkeyed)
14820             transmitterkeyed = "YES";
14821          else
14822             transmitterkeyed = "NO";
14823 
14824          if(myrpt->p.parrotmode)
14825             parrot_ena = "ENABLED";
14826          else
14827             parrot_ena = "DISABLED";
14828 
14829          if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
14830             sys_ena = "DISABLED";
14831          else
14832             sys_ena = "ENABLED";
14833 
14834          if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
14835             tot_ena = "DISABLED";
14836          else
14837             tot_ena = "ENABLED";
14838 
14839          if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
14840             link_ena = "DISABLED";
14841          else
14842             link_ena = "ENABLED";
14843 
14844          if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
14845             patch_ena = "DISABLED";
14846          else
14847             patch_ena = "ENABLED";
14848 
14849          if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
14850             sch_ena = "DISABLED";
14851          else
14852             sch_ena = "ENABLED";
14853 
14854          if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
14855             user_funs = "DISABLED";
14856          else
14857             user_funs = "ENABLED";
14858 
14859          if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
14860             tail_type = "ALTERNATE";
14861          else
14862             tail_type = "STANDARD";
14863 
14864          if(!myrpt->totimer)
14865             tot_state = "TIMED OUT!";
14866          else if(myrpt->totimer != myrpt->p.totime)
14867             tot_state = "ARMED";
14868          else
14869             tot_state = "RESET";
14870 
14871          if(myrpt->tailid)
14872             ider_state = "QUEUED IN TAIL";
14873          else if(myrpt->mustid)
14874             ider_state = "QUEUED FOR CLEANUP";
14875          else
14876             ider_state = "CLEAN";
14877 
14878          switch(myrpt->callmode){
14879             case 1:
14880                patch_state = "DIALING";
14881                break;
14882             case 2:
14883                patch_state = "CONNECTING";
14884                break;
14885             case 3:
14886                patch_state = "UP";
14887                break;
14888 
14889             case 4:
14890                patch_state = "CALL FAILED";
14891                break;
14892 
14893             default:
14894                patch_state = "DOWN";
14895          }
14896 
14897          if(strlen(myrpt->exten)){
14898             called_number = ast_strdup(myrpt->exten);
14899          }
14900 
14901          if(strlen(myrpt->lastdtmfcommand)){
14902             lastdtmfcommand = ast_strdup(myrpt->lastdtmfcommand);
14903          }
14904          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
14905 
14906          astman_append(s, "IsRemoteBase: NO\r\n");
14907          astman_append(s, "NodeState: %d\r\n", myrpt->p.sysstate_cur);
14908          astman_append(s, "SignalOnInput: %s\r\n", input_signal);
14909          astman_append(s, "TransmitterKeyed: %s\r\n", transmitterkeyed);
14910          astman_append(s, "Transmitter: %s\r\n", sys_ena);
14911          astman_append(s, "Parrot: %s\r\n", parrot_ena);
14912          astman_append(s, "Scheduler: %s\r\n", sch_ena);
14913          astman_append(s, "TailLength: %s\r\n", tail_type);
14914          astman_append(s, "TimeOutTimer: %s\r\n", tot_ena);
14915          astman_append(s, "TimeOutTimerState: %s\r\n", tot_state);
14916          astman_append(s, "TimeOutsSinceSystemInitialization: %d\r\n", timeouts);
14917          astman_append(s, "IdentifierState: %s\r\n", ider_state);
14918          astman_append(s, "KerchunksToday: %d\r\n", dailykerchunks);
14919          astman_append(s, "KerchunksSinceSystemInitialization: %d\r\n", totalkerchunks);
14920          astman_append(s, "KeyupsToday: %d\r\n", dailykeyups);
14921          astman_append(s, "KeyupsSinceSystemInitialization: %d\r\n", totalkeyups);
14922          astman_append(s, "DtmfCommandsToday: %d\r\n", dailyexecdcommands);
14923          astman_append(s, "DtmfCommandsSinceSystemInitialization: %d\r\n", totalexecdcommands);
14924          astman_append(s, "LastDtmfCommandExecuted: %s\r\n", 
14925          (lastdtmfcommand && strlen(lastdtmfcommand)) ? lastdtmfcommand : not_applicable);
14926          hours = dailytxtime/3600000;
14927          dailytxtime %= 3600000;
14928          minutes = dailytxtime/60000;
14929          dailytxtime %= 60000;
14930          seconds = dailytxtime/1000;
14931          dailytxtime %= 1000;
14932 
14933          astman_append(s, "TxTimeToday: %02d:%02d:%02d.%d\r\n",
14934             hours, minutes, seconds, dailytxtime);
14935 
14936          hours = (int) totaltxtime/3600000;
14937          totaltxtime %= 3600000;
14938          minutes = (int) totaltxtime/60000;
14939          totaltxtime %= 60000;
14940          seconds = (int)  totaltxtime/1000;
14941          totaltxtime %= 1000;
14942 
14943          astman_append(s, "TxTimeSinceSystemInitialization: %02d:%02d:%02d.%d\r\n",
14944              hours, minutes, seconds, (int) totaltxtime);
14945 
14946          sprintf(str, "NodesCurrentlyConnectedToUs: ");
14947                         if(!numoflinks){
14948                          strcat(str,"<NONE>");
14949                         }
14950          else{
14951             for(j = 0 ;j < numoflinks; j++){
14952                sprintf(str+strlen(str), "%s", listoflinks[j]);
14953                if(j < numoflinks - 1)
14954                   strcat(str,",");
14955             }
14956          }
14957          astman_append(s,"%s\r\n", str);
14958 
14959          astman_append(s, "Autopatch: %s\r\n", patch_ena);
14960          astman_append(s, "AutopatchState: %s\r\n", patch_state);
14961          astman_append(s, "AutopatchCalledNumber: %s\r\n",
14962          (called_number && strlen(called_number)) ? called_number : not_applicable);
14963          astman_append(s, "ReversePatchIaxrptConnected: %s\r\n", reverse_patch_state);
14964          astman_append(s, "UserLinkingCommands: %s\r\n", link_ena);
14965          astman_append(s, "UserFunctions: %s\r\n", user_funs);
14966 
14967          for(j = 0; j < numoflinks; j++){ /* ast_free() all link names */
14968             ast_free(listoflinks[j]);
14969          }
14970          if(called_number){
14971             ast_free(called_number);
14972          }
14973          if(lastdtmfcommand){
14974             ast_free(lastdtmfcommand);
14975          }
14976          astman_append(s, "\r\n"); /* We're Done! */
14977               return 0;
14978       }
14979    }
14980    astman_send_error(s, m, "RptStatus unknown or missing node");
14981    return -1;
14982 }
14983 
14984 
14985 
14986 /*
14987  * Implement the RptStatus Manager Interface
14988  */
14989 
14990 static int manager_rpt_status(struct mansession *s, const struct message *m)
14991 {
14992    int i,res,len,idx;
14993    int uptime,hours,minutes;
14994    time_t now;
14995    const char *cmd = astman_get_header(m, "Command");
14996    char *str;
14997    enum {MGRCMD_RPTSTAT,MGRCMD_NODESTAT};
14998    struct mgrcmdtbl{
14999       const char *cmd;
15000       int index;
15001    };
15002    static struct mgrcmdtbl mct[] = {
15003       {"RptStat",MGRCMD_RPTSTAT},
15004       {"NodeStat",MGRCMD_NODESTAT},
15005       {NULL,0} /* NULL marks end of command table */
15006    };
15007 
15008    time(&now);
15009 
15010    len = 1024; /* Allocate a working buffer */
15011    if(!(str = ast_malloc(len)))
15012       return -1;
15013 
15014    /* Check for Command */
15015    if(ast_strlen_zero(cmd)){
15016       astman_send_error(s, m, "RptStatus missing command");
15017       ast_free(str);
15018       return 0;
15019    }
15020    /* Try to find the command in the table */
15021    for(i = 0 ; mct[i].cmd ; i++){
15022       if(!strcmp(mct[i].cmd, cmd))
15023          break;
15024    }
15025 
15026    if(!mct[i].cmd){ /* Found or not found ? */
15027       astman_send_error(s, m, "RptStatus unknown command");
15028       ast_free(str);
15029       return 0;
15030    }
15031    else
15032       idx = mct[i].index;
15033 
15034    switch(idx){ /* Use the index to go to the correct command */
15035 
15036       case MGRCMD_RPTSTAT:
15037          /* Return Nodes: and a comma separated list of nodes */
15038          if((res = snprintf(str, len, "Nodes: ")) > -1)
15039             len -= res;
15040          else{
15041             ast_free(str);
15042             return 0;
15043          }
15044          for(i = 0; i < nrpts; i++){
15045             if(i < nrpts - 1){
15046                if((res = snprintf(str+strlen(str), len, "%s,",rpt_vars[i].name)) < 0){
15047                   ast_free(str);
15048                   return 0;
15049                }
15050             }
15051             else{
15052                if((res = snprintf(str+strlen(str), len, "%s",rpt_vars[i].name)) < 0){
15053                   ast_free(str);
15054                   return 0;
15055                }
15056             }
15057             len -= res;
15058          }
15059 
15060          rpt_manager_success(s,m);
15061          
15062          if(!nrpts)
15063             astman_append(s, "<NONE>\r\n");
15064          else
15065             astman_append(s, "%s\r\n", str);
15066 
15067          uptime = (int)(now - starttime);
15068                         hours = uptime/3600;
15069                         uptime %= 3600;
15070                         minutes = uptime/60;
15071                         uptime %= 60;
15072 
15073                         astman_append(s, "RptUptime: %02d:%02d:%02d\r\n",
15074                                 hours, minutes, uptime);
15075 
15076          astman_append(s, "\r\n");
15077          break;      
15078 
15079       case  MGRCMD_NODESTAT:
15080          res = rpt_manager_do_stats(s,m,str);
15081          ast_free(str);
15082          return res;
15083 
15084       default:
15085          astman_send_error(s, m, "RptStatus invalid command");
15086          break;
15087    }
15088    ast_free(str);
15089    return 0;
15090 }
15091 
15092 #endif
15093 
15094 #ifdef   OLD_ASTERISK
15095 int unload_module()
15096 #else
15097 static int unload_module(void)
15098 #endif
15099 {
15100    int i, res;
15101 
15102 #ifdef   OLD_ASTERISK
15103    STANDARD_HANGUP_LOCALUSERS;
15104 #endif
15105    for(i = 0; i < nrpts; i++) {
15106       if (!strcmp(rpt_vars[i].name,rpt_vars[i].p.nodes)) continue;
15107                 ast_mutex_destroy(&rpt_vars[i].lock);
15108                 ast_mutex_destroy(&rpt_vars[i].remlock);
15109    }
15110    res = ast_unregister_application(app);
15111 
15112 #ifdef   NEW_ASTERISK
15113    ast_cli_unregister_multiple(rpt_cli,sizeof(rpt_cli) / 
15114       sizeof(struct ast_cli_entry));
15115 #else
15116    /* Unregister cli extensions */
15117    ast_cli_unregister(&cli_debug);
15118    ast_cli_unregister(&cli_dump);
15119    ast_cli_unregister(&cli_stats);
15120    ast_cli_unregister(&cli_lstats);
15121    ast_cli_unregister(&cli_nodes);
15122    ast_cli_unregister(&cli_local_nodes);
15123    ast_cli_unregister(&cli_reload);
15124    ast_cli_unregister(&cli_restart);
15125    ast_cli_unregister(&cli_fun);
15126    ast_cli_unregister(&cli_fun1);
15127    res |= ast_cli_unregister(&cli_cmd);
15128 #endif
15129 #ifndef OLD_ASTERISK
15130    res |= ast_manager_unregister("RptLocalNodes");
15131    res |= ast_manager_unregister("RptStatus");
15132 #endif
15133    return res;
15134 }
15135 
15136 #ifdef   OLD_ASTERISK
15137 int load_module()
15138 #else
15139 static int load_module(void)
15140 #endif
15141 {
15142    int res;
15143    ast_pthread_create(&rpt_master_thread,NULL,rpt_master,NULL);
15144 
15145 #ifdef   NEW_ASTERISK
15146    ast_cli_register_multiple(rpt_cli,sizeof(rpt_cli) / 
15147       sizeof(struct ast_cli_entry));
15148    res = 0;
15149 #else
15150    /* Register cli extensions */
15151    ast_cli_register(&cli_debug);
15152    ast_cli_register(&cli_dump);
15153    ast_cli_register(&cli_stats);
15154    ast_cli_register(&cli_lstats);
15155    ast_cli_register(&cli_nodes);
15156    ast_cli_register(&cli_local_nodes);
15157    ast_cli_register(&cli_reload);
15158    ast_cli_register(&cli_restart);
15159    ast_cli_register(&cli_fun);
15160    ast_cli_register(&cli_fun1);
15161    res = ast_cli_register(&cli_cmd);
15162 #endif
15163 #ifndef OLD_ASTERISK
15164    res |= ast_manager_register("RptLocalNodes", 0, manager_rpt_local_nodes, "List local node numbers");
15165    res |= ast_manager_register("RptStatus", 0, manager_rpt_status, "Return Rpt Status for CGI");
15166 
15167 #endif
15168    res |= ast_register_application(app, rpt_exec, synopsis, descrip);
15169    return res;
15170 }
15171 
15172 #ifdef   OLD_ASTERISK
15173 char *description()
15174 {
15175    return tdesc;
15176 }
15177 int usecount(void)
15178 {
15179    int res;
15180    STANDARD_USECOUNT(res);
15181    return res;
15182 }
15183 
15184 char *key()
15185 {
15186    return ASTERISK_GPL_KEY;
15187 }
15188 #endif
15189 
15190 #ifdef   OLD_ASTERISK
15191 int reload()
15192 #else
15193 static int reload(void)
15194 #endif
15195 {
15196 int   n;
15197 
15198    for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
15199    return(0);
15200 }
15201 
15202 
15203 #ifndef  OLD_ASTERISK
15204 /* STD_MOD(MOD_1, reload, NULL, NULL); */
15205 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Radio Repeater/Remote Base Application",
15206       .load = load_module,
15207       .unload = unload_module,
15208       .reload = reload,
15209           );
15210 #endif
15211 

Generated on Wed Aug 18 22:33:42 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7