Thu May 14 14:48:46 2009

Asterisk developer's documentation


app_rpt.c

Go to the documentation of this file.
00001 /* #define OLD_ASTERISK */
00002 #define  OLDKEY
00003 /*
00004  * Asterisk -- An open source telephony toolkit.
00005  *
00006  * Copyright (C) 2002-2007, 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.73 09/04/07
00025  * 
00026  * \author Jim Dixon, WB6NIL <jim@lambdatel.com>
00027  *
00028  * \note Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
00029  * 
00030  * See http://www.zapatatelephony.org/app_rpt.html
00031  *
00032  *
00033  * Repeater / Remote Functions:
00034  * "Simple" Mode:  * - autopatch access, # - autopatch hangup
00035  * Normal mode:
00036  * See the function list in rpt.conf (autopatchup, autopatchdn)
00037  * autopatchup can optionally take comma delimited setting=value pairs:
00038  *  
00039  *
00040  * context=string    :  Override default context with "string"
00041  * dialtime=ms       :  Specify the max number of milliseconds between phone number digits (1000 milliseconds = 1 second)
00042  * farenddisconnect=1      :  Automatically disconnect when called party hangs up
00043  * noct=1         :  Don't send repeater courtesy tone during autopatch calls
00044  * quiet=1        :  Don't send dial tone, or connect messages. Do not send patch down message when called party hangs up
00045  *
00046  *
00047  * Example: 123=autopatchup,dialtime=20000,noct=1,farenddisconnect=1
00048  *
00049  *  To send an asterisk (*) while dialing or talking on phone,
00050  *  use the autopatch acess code.
00051  *
00052  *
00053  * status cmds:
00054  *
00055  *  1 - Force ID
00056  *  2 - Give Time of Day
00057  *  3 - Give software Version
00058  *
00059  * cop (control operator) cmds:
00060  *
00061  *  1 - System warm boot
00062  *  2 - System enable
00063  *  3 - System disable
00064  *  4 - Test Tone On/Off
00065  *  5 - Dump System Variables on Console (debug)
00066  *  6 - PTT (phone mode only)
00067  *  7 - Time out timer enable
00068  *  8 - Time out timer disable
00069  *  9 - Autopatch enable
00070  *  10 - Autopatch disable
00071  *  11 - Link enable
00072  *  12 - Link disable
00073  *  13 - Query System State
00074  *  14 - Change System State
00075  *  15 - Scheduler Enable
00076  *  16 - Scheduler Disable
00077  *  17 - User functions (time, id, etc) enable
00078  *  18 - User functions (time, id, etc) disable
00079  *  19 - Select alternate hang timer
00080  *  20 - Select standard hang timer 
00081  *
00082  * ilink cmds:
00083  *
00084  *  1 - Disconnect specified link
00085  *  2 - Connect specified link -- monitor only
00086  *  3 - Connect specified link -- tranceive
00087  *  4 - Enter command mode on specified link
00088  *  5 - System status
00089  *  6 - Disconnect all links
00090  *  11 - Disconnect a previously permanently connected link
00091  *  12 - Permanently connect specified link -- monitor only
00092  *  13 - Permanently connect specified link -- tranceive
00093  *  15 - Full system status (all nodes)
00094  *  16 - Reconnect links disconnected with "disconnect all links"
00095  *  200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
00096  *
00097  * remote cmds:
00098  *
00099  *  1 - Recall Memory MM  (*000-*099) (Gets memory from rpt.conf)
00100  *  2 - Set VFO MMMMM*KKK*O   (Mhz digits, Khz digits, Offset)
00101  *  3 - Set Rx PL Tone HHH*D*
00102  *  4 - Set Tx PL Tone HHH*D* (Not currently implemented with DHE RBI-1)
00103  *  5 - Link Status (long)
00104  *  6 - Set operating mode M (FM, USB, LSB, AM, etc)
00105  *  100 - RX PL off (Default)
00106  *  101 - RX PL On
00107  *  102 - TX PL Off (Default)
00108  *  103 - TX PL On
00109  *  104 - Low Power
00110  *  105 - Med Power
00111  *  106 - Hi Power
00112  *  107 - Bump Down 20 Hz
00113  *  108 - Bump Down 100 Hz
00114  *  109 - Bump Down 500 Hz
00115  *  110 - Bump Up 20 Hz
00116  *  111 - Bump Up 100 Hz
00117  *  112 - Bump Up 500 Hz
00118  *  113 - Scan Down Slow
00119  *  114 - Scan Down Medium
00120  *  115 - Scan Down Fast
00121  *  116 - Scan Up Slow
00122  *  117 - Scan Up Medium
00123  *  118 - Scan Up Fast
00124  *  119 - Transmit allowing auto-tune
00125  *  140 - Link Status (brief)
00126  *  200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
00127  *
00128  *
00129  * 'duplex' modes:  (defaults to duplex=2)
00130  *
00131  * 0 - Only remote links key Tx and no main repeat audio.
00132  * 1 - Everything other then main Rx keys Tx, no main repeat audio.
00133  * 2 - Normal mode
00134  * 3 - Normal except no main repeat audio.
00135  * 4 - Normal except no main repeat audio during autopatch only
00136  *
00137 */
00138 
00139 /*** MODULEINFO
00140    <depend>dahdi</depend>
00141    <depend>tonezone</depend>
00142    <defaultenabled>no</defaultenabled>
00143  ***/
00144 
00145 /* Un-comment the following to include support for MDC-1200 digital tone
00146    signalling protocol (using KA6SQG's GPL'ed implementation) */
00147 /* #include "mdc_decode.c" */
00148 
00149 /* Un-comment the following to include support for notch filters in the
00150    rx audio stream (using Tony Fisher's mknotch (mkfilter) implementation) */
00151 /* #include "rpt_notch.c" */
00152 
00153 /* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
00154 
00155 #define  MAXDTMF 32
00156 #define  MAXMACRO 2048
00157 #define  MAXLINKLIST 512
00158 #define  LINKLISTTIME 10000
00159 #define  LINKLISTSHORTTIME 200
00160 #define  MACROTIME 100
00161 #define  MACROPTIME 500
00162 #define  DTMF_TIMEOUT 3
00163 #define  KENWOOD_RETRIES 5
00164 
00165 #define  AUTHTELLTIME 7000
00166 #define  AUTHTXTIME 1000
00167 #define  AUTHLOGOUTTIME 25000
00168 
00169 #ifdef   __RPT_NOTCH
00170 #define  MAXFILTERS 10
00171 #endif
00172 
00173 #define  DISC_TIME 10000  /* report disc after 10 seconds of no connect */
00174 #define  MAX_RETRIES 5
00175 #define  MAX_RETRIES_PERM 1000000000
00176 
00177 #define  REDUNDANT_TX_TIME 2000
00178 
00179 #define  RETRY_TIMER_MS 5000
00180 
00181 #define  START_DELAY 2
00182 
00183 #define MAXPEERSTR 31
00184 #define  MAXREMSTR 15
00185 
00186 #define  DELIMCHR ','
00187 #define  QUOTECHR 34
00188 
00189 #define  MONITOR_DISK_BLOCKS_PER_MINUTE 38
00190 
00191 #define  DEFAULT_MONITOR_MIN_DISK_BLOCKS 10000
00192 #define  DEFAULT_REMOTE_INACT_TIMEOUT (15 * 60)
00193 #define  DEFAULT_REMOTE_TIMEOUT (60 * 60)
00194 #define  DEFAULT_REMOTE_TIMEOUT_WARNING (3 * 60)
00195 #define  DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ 30
00196 
00197 #define  NODES "nodes"
00198 #define  EXTNODES "extnodes"
00199 #define MEMORY "memory"
00200 #define MACRO "macro"
00201 #define  FUNCTIONS "functions"
00202 #define TELEMETRY "telemetry"
00203 #define MORSE "morse"
00204 #define  FUNCCHAR '*'
00205 #define  ENDCHAR '#'
00206 #define  EXTNODEFILE "/var/lib/asterisk/rpt_extnodes"
00207 
00208 #define  DEFAULT_IOBASE 0x378
00209 
00210 #define  DEFAULT_CIV_ADDR 0x58
00211 
00212 #define  MAXCONNECTTIME 5000
00213 
00214 #define MAXNODESTR 300
00215 
00216 #define MAXPATCHCONTEXT 100
00217 
00218 #define ACTIONSIZE 32
00219 
00220 #define TELEPARAMSIZE 256
00221 
00222 #define REM_SCANTIME 100
00223 
00224 #define  DTMF_LOCAL_TIME 250
00225 #define  DTMF_LOCAL_STARTTIME 500
00226 
00227 #define  IC706_PL_MEMORY_OFFSET 50
00228 
00229 #define  ALLOW_LOCAL_CHANNELS
00230 
00231 enum {REM_OFF,REM_MONITOR,REM_TX};
00232 
00233 enum{ID,PROC,TERM,COMPLETE,UNKEY,REMDISC,REMALREADY,REMNOTFOUND,REMGO,
00234    CONNECTED,CONNFAIL,STATUS,TIMEOUT,ID1, STATS_TIME,
00235    STATS_VERSION, IDTALKOVER, ARB_ALPHA, TEST_TONE, REV_PATCH,
00236    TAILMSG, MACRO_NOTFOUND, MACRO_BUSY, LASTNODEKEY, FULLSTATUS,
00237    MEMNOTFOUND, INVFREQ, REMMODE, REMLOGIN, REMXXX, REMSHORTSTATUS,
00238    REMLONGSTATUS, LOGINREQ, SCAN, SCANSTAT, TUNE, SETREMOTE,
00239    TIMEOUT_WARNING, ACT_TIMEOUT_WARNING, LINKUNKEY, UNAUTHTX};
00240 
00241 
00242 enum {REM_SIMPLEX,REM_MINUS,REM_PLUS};
00243 
00244 enum {REM_LOWPWR,REM_MEDPWR,REM_HIPWR};
00245 
00246 enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_COMPLETEQUIET, DC_DOKEY};
00247 
00248 enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT, SOURCE_PHONE, SOURCE_DPHONE};
00249 
00250 enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM, DLY_COMP, DLY_LINKUNKEY};
00251 
00252 enum {REM_MODE_FM,REM_MODE_USB,REM_MODE_LSB,REM_MODE_AM};
00253 
00254 enum {HF_SCAN_OFF,HF_SCAN_DOWN_SLOW,HF_SCAN_DOWN_QUICK,
00255       HF_SCAN_DOWN_FAST,HF_SCAN_UP_SLOW,HF_SCAN_UP_QUICK,HF_SCAN_UP_FAST};
00256 
00257 #include "asterisk.h"
00258 
00259 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 174369 $")
00260 
00261 #include <signal.h>
00262 #include <stdio.h>
00263 #include <stdint.h>
00264 #include <unistd.h>
00265 #include <string.h>
00266 #include <stdlib.h>
00267 #include <search.h>
00268 #include <sys/types.h>
00269 #include <sys/stat.h>
00270 #include <errno.h>
00271 #include <dirent.h>
00272 #include <ctype.h>
00273 #include <sys/stat.h>
00274 #include <sys/time.h>
00275 #include <sys/file.h>
00276 #include <sys/ioctl.h>
00277 #ifdef HAVE_SYS_IO_H
00278 #include <sys/io.h>
00279 #endif
00280 #include <sys/vfs.h>
00281 #include <math.h>
00282 #include <netinet/in.h>
00283 #include <arpa/inet.h>
00284 #include <termios.h>
00285 
00286 #include "asterisk/utils.h"
00287 #include "asterisk/lock.h"
00288 #include "asterisk/file.h"
00289 #include "asterisk/logger.h"
00290 #include "asterisk/channel.h"
00291 #include "asterisk/callerid.h"
00292 #include "asterisk/pbx.h"
00293 #include "asterisk/module.h"
00294 #include "asterisk/translate.h"
00295 #include "asterisk/features.h"
00296 #include "asterisk/options.h"
00297 #include "asterisk/cli.h"
00298 #include "asterisk/config.h"
00299 #include "asterisk/say.h"
00300 #include "asterisk/localtime.h"
00301 #include "asterisk/cdr.h"
00302 #include "asterisk/options.h"
00303 
00304 #include "asterisk/dahdi_compat.h"
00305 #include "asterisk/tonezone_compat.h"
00306 
00307 /* Start a tone-list going */
00308 int ast_playtones_start(struct ast_channel *chan, int vol, const char* tonelist, int interruptible);
00309 /*! Stop the tones from playing */
00310 void ast_playtones_stop(struct ast_channel *chan);
00311 
00312 static  char *tdesc = "Radio Repeater / Remote Base  version 0.73  09/04/2007";
00313 
00314 static char *app = "Rpt";
00315 
00316 static char *synopsis = "Radio Repeater/Remote Base Control System";
00317 
00318 static char *descrip = 
00319 "  Rpt(nodename[|options]):  Radio Remote Link or Remote Base Link Endpoint Process.\n"
00320 "\n"
00321 "    Not specifying an option puts it in normal endpoint mode (where source\n"
00322 "    IP and nodename are verified).\n"
00323 "\n"
00324 "    Options are as follows:\n"
00325 "\n"
00326 "        X - Normal endpoint mode WITHOUT security check. Only specify\n"
00327 "            this if you have checked security already (like with an IAX2\n"
00328 "            user/password or something).\n"
00329 "\n"
00330 "        Rannounce-string[|timeout[|timeout-destination]] - Amateur Radio\n"
00331 "            Reverse Autopatch. Caller is put on hold, and announcement (as\n"
00332 "            specified by the 'announce-string') is played on radio system.\n"
00333 "            Users of radio system can access autopatch, dial specified\n"
00334 "            code, and pick up call. Announce-string is list of names of\n"
00335 "            recordings, or \"PARKED\" to substitute code for un-parking,\n"
00336 "            or \"NODE\" to substitute node number.\n"
00337 "\n"
00338 "        P - Phone Control mode. This allows a regular phone user to have\n"
00339 "            full control and audio access to the radio system. For the\n"
00340 "            user to have DTMF control, the 'phone_functions' parameter\n"
00341 "            must be specified for the node in 'rpt.conf'. An additional\n"
00342 "            function (cop,6) must be listed so that PTT control is available.\n"
00343 "\n"
00344 "        D - Dumb Phone Control mode. This allows a regular phone user to\n"
00345 "            have full control and audio access to the radio system. In this\n"
00346 "            mode, the PTT is activated for the entire length of the call.\n"
00347 "            For the user to have DTMF control (not generally recomended in\n"
00348 "            this mode), the 'dphone_functions' parameter must be specified\n"
00349 "            for the node in 'rpt.conf'. Otherwise no DTMF control will be\n"
00350 "            available to the phone user.\n"
00351 "\n";
00352 
00353 static int debug = 0;  /* Set this >0 for extra debug output */
00354 static int nrpts = 0;
00355 
00356 static char remdtmfstr[] = "0123456789*#ABCD";
00357 
00358 enum {TOP_TOP,TOP_WON,WON_BEFREAD,BEFREAD_AFTERREAD};
00359 
00360 int max_chan_stat [] = {22000,1000,22000,100,22000,2000,22000};
00361 
00362 #define NRPTSTAT 7
00363 
00364 struct rpt_chan_stat
00365 {
00366    struct timeval last;
00367    long long total;
00368    unsigned long count;
00369    unsigned long largest;
00370    struct timeval largest_time;
00371 };
00372 
00373 char *discstr = "!!DISCONNECT!!";
00374 static char *remote_rig_ft897="ft897";
00375 static char *remote_rig_rbi="rbi";
00376 static char *remote_rig_kenwood="kenwood";
00377 static char *remote_rig_ic706="ic706";
00378 
00379 #ifdef   OLD_ASTERISK
00380 STANDARD_LOCAL_USER;
00381 LOCAL_USER_DECL;
00382 #endif
00383 
00384 #define  MSWAIT 200
00385 #define  HANGTIME 5000
00386 #define  TOTIME 180000
00387 #define  IDTIME 300000
00388 #define  MAXRPTS 20
00389 #define MAX_STAT_LINKS 32
00390 #define POLITEID 30000
00391 #define FUNCTDELAY 1500
00392 
00393 #define  MAXXLAT 20
00394 #define  MAXXLATTIME 3
00395 
00396 #define MAX_SYSSTATES 10
00397 
00398 struct rpt_xlat
00399 {
00400 char  funccharseq[MAXXLAT];
00401 char  endcharseq[MAXXLAT];
00402 char  passchars[MAXXLAT];
00403 int   funcindex;
00404 int   endindex;
00405 time_t   lastone;
00406 } ;
00407 
00408 static time_t  starttime = 0;
00409 
00410 static  pthread_t rpt_master_thread;
00411 
00412 struct rpt;
00413 
00414 struct rpt_link
00415 {
00416    struct rpt_link *next;
00417    struct rpt_link *prev;
00418    char  mode;       /* 1 if in tx mode */
00419    char  isremote;
00420    char  phonemode;
00421    char  name[MAXNODESTR]; /* identifier (routing) string */
00422    char  lasttx;
00423    char  lastrx;
00424    char  lastrx1;
00425    char  connected;
00426    char  hasconnected;
00427    char  perma;
00428    char  thisconnected;
00429    char  outbound;
00430    char  disced;
00431    char  killme;
00432    long  elaptime;
00433    long  disctime;
00434    long  retrytimer;
00435    long  retxtimer;
00436    long  rerxtimer;
00437    int   retries;
00438    int   max_retries;
00439    int   reconnects;
00440    long long connecttime;
00441    struct ast_channel *chan;  
00442    struct ast_channel *pchan; 
00443    char  linklist[MAXLINKLIST];
00444    time_t   linklistreceived;
00445    long  linklisttimer;
00446    int   dtmfed;
00447    int linkunkeytocttimer;
00448    struct   ast_frame *lastf1,*lastf2;
00449    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00450 } ;
00451 
00452 struct rpt_lstat
00453 {
00454    struct   rpt_lstat *next;
00455    struct   rpt_lstat *prev;
00456    char  peer[MAXPEERSTR];
00457    char  name[MAXNODESTR];
00458    char  mode;
00459    char  outbound;
00460    char  reconnects;
00461    char  thisconnected;
00462    long long   connecttime;
00463    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00464 } ;
00465 
00466 struct rpt_tele
00467 {
00468    struct rpt_tele *next;
00469    struct rpt_tele *prev;
00470    struct rpt *rpt;
00471    struct ast_channel *chan;
00472    int   mode;
00473    struct rpt_link mylink;
00474    char param[TELEPARAMSIZE];
00475    intptr_t submode;
00476    pthread_t threadid;
00477 } ;
00478 
00479 struct function_table_tag
00480 {
00481    char action[ACTIONSIZE];
00482    int (*function)(struct rpt *myrpt, char *param, char *digitbuf, 
00483       int command_source, struct rpt_link *mylink);
00484 } ;
00485 
00486 /* Used to store the morse code patterns */
00487 
00488 struct morse_bits
00489 {       
00490    int len;
00491    int ddcomb;
00492 } ;
00493 
00494 struct telem_defaults
00495 {
00496    char name[20];
00497    char value[80];
00498 } ;
00499 
00500 
00501 struct sysstate
00502 {
00503    char txdisable;
00504    char totdisable;
00505    char linkfundisable;
00506    char autopatchdisable;
00507    char schedulerdisable;
00508    char userfundisable;
00509    char alternatetail;
00510 };
00511 
00512 static struct rpt
00513 {
00514    ast_mutex_t lock;
00515    ast_mutex_t remlock;
00516    struct ast_config *cfg;
00517    char reload;
00518 
00519    char *name;
00520    char *rxchanname;
00521    char *txchanname;
00522    char *remote;
00523    struct   rpt_chan_stat chan_stat[NRPTSTAT];
00524    unsigned int scram;
00525 
00526    struct {
00527       char *ourcontext;
00528       char *ourcallerid;
00529       char *acctcode;
00530       char *ident;
00531       char *tonezone;
00532       char simple;
00533       char *functions;
00534       char *link_functions;
00535       char *phone_functions;
00536       char *dphone_functions;
00537       char *nodes;
00538       char *extnodes;
00539       char *extnodefile;
00540       int hangtime;
00541       int althangtime;
00542       int totime;
00543       int idtime;
00544       int tailmessagetime;
00545       int tailsquashedtime;
00546       int duplex;
00547       int politeid;
00548       char *tailmessages[500];
00549       int tailmessagemax;
00550       char  *memory;
00551       char  *macro;
00552       char  *startupmacro;
00553       int iobase;
00554       char *ioport;
00555       char funcchar;
00556       char endchar;
00557       char nobusyout;
00558       char notelemtx;
00559       char propagate_dtmf;
00560       char propagate_phonedtmf;
00561       char linktolink;
00562       unsigned char civaddr;
00563       struct rpt_xlat inxlat;
00564       struct rpt_xlat outxlat;
00565       char *archivedir;
00566       int authlevel;
00567       char *csstanzaname;
00568       char *skedstanzaname;
00569       char *txlimitsstanzaname;
00570       long monminblocks;
00571       int remoteinacttimeout;
00572       int remotetimeout;
00573       int remotetimeoutwarning;
00574       int remotetimeoutwarningfreq;
00575       int sysstate_cur;
00576       struct sysstate s[MAX_SYSSTATES];
00577    } p;
00578    struct rpt_link links;
00579    int unkeytocttimer;
00580    char keyed;
00581    char exttx;
00582    char localtx;
00583    char remoterx;
00584    char remotetx;
00585    char remoteon;
00586    char remtxfreqok;
00587    char tounkeyed;
00588    char tonotify;
00589    char dtmfbuf[MAXDTMF];
00590    char macrobuf[MAXMACRO];
00591    char rem_dtmfbuf[MAXDTMF];
00592    char lastdtmfcommand[MAXDTMF];
00593    char cmdnode[50];
00594    struct ast_channel *rxchannel,*txchannel, *monchannel;
00595    struct ast_channel *pchannel,*txpchannel, *zaprxchannel, *zaptxchannel;
00596    struct ast_frame *lastf1,*lastf2;
00597    struct rpt_tele tele;
00598    struct timeval lasttv,curtv;
00599    pthread_t rpt_call_thread,rpt_thread;
00600    time_t dtmf_time,rem_dtmf_time,dtmf_time_rem;
00601    int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx,scantimer,tmsgtimer,skedtimer;
00602    int mustid,tailid;
00603    int tailevent;
00604    int telemrefcount;
00605    int dtmfidx,rem_dtmfidx;
00606    int dailytxtime,dailykerchunks,totalkerchunks,dailykeyups,totalkeyups,timeouts;
00607    int totalexecdcommands, dailyexecdcommands;
00608    long  retxtimer;
00609    long  rerxtimer;
00610    long long totaltxtime;
00611    char mydtmf;
00612    char exten[AST_MAX_EXTENSION];
00613    char freq[MAXREMSTR],rxpl[MAXREMSTR],txpl[MAXREMSTR];
00614    char offset;
00615    char powerlevel;
00616    char txplon;
00617    char rxplon;
00618    char remmode;
00619    char tunerequest;
00620    char hfscanmode;
00621    int hfscanstatus;
00622    char hfscanstop;
00623    char lastlinknode[MAXNODESTR];
00624    char savednodes[MAXNODESTR];
00625    int stopgen;
00626    char patchfarenddisconnect;
00627    char patchnoct;
00628    char patchquiet;
00629    char patchcontext[MAXPATCHCONTEXT];
00630    int patchdialtime;
00631    int macro_longest;
00632    int phone_longestfunc;
00633    int dphone_longestfunc;
00634    int link_longestfunc;
00635    int longestfunc;
00636    int longestnode;
00637    int threadrestarts;     
00638    int tailmessagen;
00639    time_t disgorgetime;
00640    time_t lastthreadrestarttime;
00641    long  macrotimer;
00642    char  lastnodewhichkeyedusup[MAXNODESTR];
00643    int   dtmf_local_timer;
00644    char  dtmf_local_str[100];
00645    struct ast_filestream *monstream;
00646    char  loginuser[50];
00647    char  loginlevel[10];
00648    long  authtelltimer;
00649    long  authtimer;
00650    int iofd;
00651    time_t start_time,last_activity_time;
00652 #ifdef   __RPT_NOTCH
00653    struct rptfilter
00654    {
00655       char  desc[100];
00656       float x0;
00657       float x1;
00658       float x2;
00659       float y0;
00660       float y1;
00661       float y2;
00662       float gain;
00663       float const0;
00664       float const1;
00665       float const2;
00666    } filters[MAXFILTERS];
00667 #endif
00668 #ifdef   _MDC_DECODE_H_
00669    mdc_decoder_t *mdc;
00670    unsigned short lastunit;
00671 #endif
00672 } rpt_vars[MAXRPTS]; 
00673 
00674 struct nodelog {
00675 struct nodelog *next;
00676 struct nodelog *prev;
00677 time_t   timestamp;
00678 char archivedir[MAXNODESTR];
00679 char str[MAXNODESTR * 2];
00680 } nodelog;
00681 
00682 static int service_scan(struct rpt *myrpt);
00683 static int set_mode_ft897(struct rpt *myrpt, char newmode);
00684 static int set_mode_ic706(struct rpt *myrpt, char newmode);
00685 static int simple_command_ft897(struct rpt *myrpt, char command);
00686 static int setrem(struct rpt *myrpt);
00687 
00688 AST_MUTEX_DEFINE_STATIC(nodeloglock);
00689 
00690 AST_MUTEX_DEFINE_STATIC(nodelookuplock);
00691 
00692 #ifdef   APP_RPT_LOCK_DEBUG
00693 
00694 #warning COMPILING WITH LOCK-DEBUGGING ENABLED!!
00695 
00696 #define  MAXLOCKTHREAD 100
00697 
00698 #define rpt_mutex_lock(x) _rpt_mutex_lock(x,myrpt,__LINE__)
00699 #define rpt_mutex_unlock(x) _rpt_mutex_unlock(x,myrpt,__LINE__)
00700 
00701 struct lockthread
00702 {
00703    pthread_t id;
00704    int lockcount;
00705    int lastlock;
00706    int lastunlock;
00707 } lockthreads[MAXLOCKTHREAD];
00708 
00709 
00710 struct by_lightning
00711 {
00712    int line;
00713    struct timeval tv;
00714    struct rpt *rpt;
00715    struct lockthread lockthread;
00716 } lock_ring[32];
00717 
00718 int lock_ring_index = 0;
00719 
00720 AST_MUTEX_DEFINE_STATIC(locklock);
00721 
00722 static struct lockthread *get_lockthread(pthread_t id)
00723 {
00724 int   i;
00725 
00726    for(i = 0; i < MAXLOCKTHREAD; i++)
00727    {
00728       if (lockthreads[i].id == id) return(&lockthreads[i]);
00729    }
00730    return(NULL);
00731 }
00732 
00733 static struct lockthread *put_lockthread(pthread_t id)
00734 {
00735 int   i;
00736 
00737    for(i = 0; i < MAXLOCKTHREAD; i++)
00738    {
00739       if (lockthreads[i].id == id)
00740          return(&lockthreads[i]);
00741    }
00742    for(i = 0; i < MAXLOCKTHREAD; i++)
00743    {
00744       if (!lockthreads[i].id)
00745       {
00746          lockthreads[i].lockcount = 0;
00747          lockthreads[i].lastlock = 0;
00748          lockthreads[i].lastunlock = 0;
00749          lockthreads[i].id = id;
00750          return(&lockthreads[i]);
00751       }
00752    }
00753    return(NULL);
00754 }
00755 
00756 
00757 static void rpt_mutex_spew(void)
00758 {
00759    struct by_lightning lock_ring_copy[32];
00760    int lock_ring_index_copy;
00761    int i,j;
00762    long long diff;
00763    char a[100];
00764    struct timeval lasttv;
00765 
00766    ast_mutex_lock(&locklock);
00767    memcpy(&lock_ring_copy, &lock_ring, sizeof(lock_ring_copy));
00768    lock_ring_index_copy = lock_ring_index;
00769    ast_mutex_unlock(&locklock);
00770 
00771    lasttv.tv_sec = lasttv.tv_usec = 0;
00772    for(i = 0 ; i < 32 ; i++)
00773    {
00774       j = (i + lock_ring_index_copy) % 32;
00775       strftime(a,sizeof(a) - 1,"%m/%d/%Y %H:%M:%S",
00776          localtime(&lock_ring_copy[j].tv.tv_sec));
00777       diff = 0;
00778       if(lasttv.tv_sec)
00779       {
00780          diff = (lock_ring_copy[j].tv.tv_sec - lasttv.tv_sec)
00781             * 1000000;
00782          diff += (lock_ring_copy[j].tv.tv_usec - lasttv.tv_usec);
00783       }
00784       lasttv.tv_sec = lock_ring_copy[j].tv.tv_sec;
00785       lasttv.tv_usec = lock_ring_copy[j].tv.tv_usec;
00786       if (!lock_ring_copy[j].tv.tv_sec) continue;
00787       if (lock_ring_copy[j].line < 0)
00788       {
00789          ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] UNLOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
00790             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);
00791       }
00792       else
00793       {
00794          ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] LOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
00795             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);
00796       }
00797    }
00798 }
00799 
00800 
00801 static void _rpt_mutex_lock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
00802 {
00803 struct lockthread *t;
00804 pthread_t id;
00805 
00806    id = pthread_self();
00807    ast_mutex_lock(&locklock);
00808    t = put_lockthread(id);
00809    if (!t)
00810    {
00811       ast_mutex_unlock(&locklock);
00812       return;
00813    }
00814    if (t->lockcount)
00815    {
00816       int lastline = t->lastlock;
00817       ast_mutex_unlock(&locklock);
00818       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);
00819       rpt_mutex_spew();
00820       return;
00821    }
00822    t->lastlock = line;
00823    t->lockcount = 1;
00824    gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
00825    lock_ring[lock_ring_index].rpt = myrpt;
00826    memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
00827    lock_ring[lock_ring_index++].line = line;
00828    if(lock_ring_index == 32)
00829       lock_ring_index = 0;
00830    ast_mutex_unlock(&locklock);
00831    ast_mutex_lock(lockp);
00832 }
00833 
00834 
00835 static void _rpt_mutex_unlock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
00836 {
00837 struct lockthread *t;
00838 pthread_t id;
00839 
00840    id = pthread_self();
00841    ast_mutex_lock(&locklock);
00842    t = put_lockthread(id);
00843    if (!t)
00844    {
00845       ast_mutex_unlock(&locklock);
00846       return;
00847    }
00848    if (!t->lockcount)
00849    {
00850       int lastline = t->lastunlock;
00851       ast_mutex_unlock(&locklock);
00852       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);
00853       rpt_mutex_spew();
00854       return;
00855    }
00856    t->lastunlock = line;
00857    t->lockcount = 0;
00858    gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
00859    lock_ring[lock_ring_index].rpt = myrpt;
00860    memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
00861    lock_ring[lock_ring_index++].line = -line;
00862    if(lock_ring_index == 32)
00863       lock_ring_index = 0;
00864    ast_mutex_unlock(&locklock);
00865    ast_mutex_unlock(lockp);
00866 }
00867 
00868 #else  /* APP_RPT_LOCK_DEBUG */
00869 
00870 #define rpt_mutex_lock(x) ast_mutex_lock(x)
00871 #define rpt_mutex_unlock(x) ast_mutex_unlock(x)
00872 
00873 #endif  /* APP_RPT_LOCK_DEBUG */
00874 
00875 /*
00876 * Return 1 if rig is multimode capable
00877 */
00878 
00879 static int multimode_capable(struct rpt *myrpt)
00880 {
00881    if(!strcmp(myrpt->remote, remote_rig_ft897))
00882       return 1;
00883    if(!strcmp(myrpt->remote, remote_rig_ic706))
00884       return 1;
00885    return 0;
00886 }  
00887 
00888 /*
00889 * CLI extensions
00890 */
00891 
00892 /* Debug mode */
00893 static int rpt_do_debug(int fd, int argc, char *argv[]);
00894 static int rpt_do_dump(int fd, int argc, char *argv[]);
00895 static int rpt_do_stats(int fd, int argc, char *argv[]);
00896 static int rpt_do_lstats(int fd, int argc, char *argv[]);
00897 static int rpt_do_nodes(int fd, int argc, char *argv[]);
00898 static int rpt_do_reload(int fd, int argc, char *argv[]);
00899 static int rpt_do_restart(int fd, int argc, char *argv[]);
00900 static int rpt_do_fun(int fd, int argc, char *argv[]);
00901 
00902 static char debug_usage[] =
00903 "Usage: rpt debug level {0-7}\n"
00904 "       Enables debug messages in app_rpt\n";
00905 
00906 static char dump_usage[] =
00907 "Usage: rpt dump <nodename>\n"
00908 "       Dumps struct debug info to log\n";
00909 
00910 static char dump_stats[] =
00911 "Usage: rpt stats <nodename>\n"
00912 "       Dumps node statistics to console\n";
00913 
00914 static char dump_lstats[] =
00915 "Usage: rpt lstats <nodename>\n"
00916 "       Dumps link statistics to console\n";
00917 
00918 static char dump_nodes[] =
00919 "Usage: rpt nodes <nodename>\n"
00920 "       Dumps a list of directly and indirectly connected nodes to the console\n";
00921 
00922 static char reload_usage[] =
00923 "Usage: rpt reload\n"
00924 "       Reloads app_rpt running config parameters\n";
00925 
00926 static char restart_usage[] =
00927 "Usage: rpt restart\n"
00928 "       Restarts app_rpt\n";
00929 
00930 static char fun_usage[] =
00931 "Usage: rpt fun <nodename> <command>\n"
00932 "       Send a DTMF function to a node\n";
00933 
00934 
00935 static struct ast_cli_entry  cli_debug =
00936         { { "rpt", "debug", "level" }, rpt_do_debug, 
00937       "Enable app_rpt debugging", debug_usage };
00938 
00939 static struct ast_cli_entry  cli_dump =
00940         { { "rpt", "dump" }, rpt_do_dump,
00941       "Dump app_rpt structs for debugging", dump_usage };
00942 
00943 static struct ast_cli_entry  cli_stats =
00944         { { "rpt", "stats" }, rpt_do_stats,
00945       "Dump node statistics", dump_stats };
00946 
00947 static struct ast_cli_entry  cli_nodes =
00948         { { "rpt", "nodes" }, rpt_do_nodes,
00949       "Dump node list", dump_nodes };
00950 
00951 static struct ast_cli_entry  cli_lstats =
00952         { { "rpt", "lstats" }, rpt_do_lstats,
00953       "Dump link statistics", dump_lstats };
00954 
00955 static struct ast_cli_entry  cli_reload =
00956         { { "rpt", "reload" }, rpt_do_reload,
00957       "Reload app_rpt config", reload_usage };
00958 
00959 static struct ast_cli_entry  cli_restart =
00960         { { "rpt", "restart" }, rpt_do_restart,
00961       "Restart app_rpt", restart_usage };
00962 
00963 static struct ast_cli_entry  cli_fun =
00964         { { "rpt", "fun" }, rpt_do_fun,
00965       "Execute a DTMF function", fun_usage };
00966 
00967 /*
00968 * Telemetry defaults
00969 */
00970 
00971 
00972 static struct telem_defaults tele_defs[] = {
00973    {"ct1","|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
00974    {"ct2","|t(660,880,150,3072)"},
00975    {"ct3","|t(440,0,150,3072)"},
00976    {"ct4","|t(550,0,150,3072)"},
00977    {"ct5","|t(660,0,150,3072)"},
00978    {"ct6","|t(880,0,150,3072)"},
00979    {"ct7","|t(660,440,150,3072)"},
00980    {"ct8","|t(700,1100,150,3072)"},
00981    {"remotemon","|t(1600,0,75,2048)"},
00982    {"remotetx","|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
00983    {"cmdmode","|t(900,904,200,2048)"},
00984    {"functcomplete","|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
00985 } ;
00986 
00987 /*
00988 * Forward decl's - these suppress compiler warnings when funcs coded further down the file than thier invokation
00989 */
00990 
00991 static int setrbi(struct rpt *myrpt);
00992 static int set_ft897(struct rpt *myrpt);
00993 static int set_ic706(struct rpt *myrpt);
00994 static int setkenwood(struct rpt *myrpt);
00995 static int setrbi_check(struct rpt *myrpt);
00996 
00997 
00998 
00999 /*
01000 * Define function protos for function table here
01001 */
01002 
01003 static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01004 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01005 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01006 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01007 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01008 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01009 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
01010 /*
01011 * Function table
01012 */
01013 
01014 static struct function_table_tag function_table[] = {
01015    {"cop", function_cop},
01016    {"autopatchup", function_autopatchup},
01017    {"autopatchdn", function_autopatchdn},
01018    {"ilink", function_ilink},
01019    {"status", function_status},
01020    {"remote", function_remote},
01021    {"macro", function_macro}
01022 } ;
01023 
01024 static long diskavail(struct rpt *myrpt)
01025 {
01026 struct   statfs statfsbuf;
01027 
01028    if (!myrpt->p.archivedir) return(0);
01029    if (statfs(myrpt->p.archivedir,&statfsbuf) == -1)
01030    {
01031       ast_log(LOG_WARNING,"Cannot get filesystem size for %s node %s\n",
01032          myrpt->p.archivedir,myrpt->name);
01033       return(-1);
01034    }
01035    return(statfsbuf.f_bavail);
01036 }
01037 
01038 static void do_dtmf_phone(struct rpt *myrpt, struct rpt_link *mylink, char c)
01039 {
01040 struct        rpt_link *l;
01041 
01042        l = myrpt->links.next;
01043        /* go thru all the links */
01044        while(l != &myrpt->links)
01045        {
01046                if (!l->phonemode)
01047                {
01048                        l = l->next;
01049                        continue;
01050                }
01051                /* dont send to self */
01052                if (mylink && (l == mylink))
01053                {
01054                        l = l->next;
01055                        continue;
01056                }
01057                if (l->chan) ast_senddigit(l->chan,c);
01058                l = l->next;
01059        }
01060        return;
01061 }
01062 
01063 /* node logging function */
01064 static void donodelog(struct rpt *myrpt,char *str)
01065 {
01066 struct nodelog *nodep;
01067 char  datestr[100];
01068 
01069    if (!myrpt->p.archivedir) return;
01070    nodep = (struct nodelog *)malloc(sizeof(struct nodelog));
01071    if (nodep == NULL)
01072    {
01073       ast_log(LOG_ERROR,"Cannot get memory for node log");
01074       return;
01075    }
01076    time(&nodep->timestamp);
01077    strncpy(nodep->archivedir,myrpt->p.archivedir,
01078       sizeof(nodep->archivedir) - 1);
01079    strftime(datestr,sizeof(datestr) - 1,"%Y%m%d%H%M%S",
01080       localtime(&nodep->timestamp));
01081    snprintf(nodep->str,sizeof(nodep->str) - 1,"%s %s,%s\n",
01082       myrpt->name,datestr,str);
01083    ast_mutex_lock(&nodeloglock);
01084    insque((struct qelem *) nodep, (struct qelem *) nodelog.prev);
01085    ast_mutex_unlock(&nodeloglock);
01086 }
01087 
01088 /* must be called locked */
01089 static void do_dtmf_local(struct rpt *myrpt, char c)
01090 {
01091 int   i;
01092 char  digit;
01093 static const char* dtmf_tones[] = {
01094    "!941+1336/200,!0/200", /* 0 */
01095    "!697+1209/200,!0/200", /* 1 */
01096    "!697+1336/200,!0/200", /* 2 */
01097    "!697+1477/200,!0/200", /* 3 */
01098    "!770+1209/200,!0/200", /* 4 */
01099    "!770+1336/200,!0/200", /* 5 */
01100    "!770+1477/200,!0/200", /* 6 */
01101    "!852+1209/200,!0/200", /* 7 */
01102    "!852+1336/200,!0/200", /* 8 */
01103    "!852+1477/200,!0/200", /* 9 */
01104    "!697+1633/200,!0/200", /* A */
01105    "!770+1633/200,!0/200", /* B */
01106    "!852+1633/200,!0/200", /* C */
01107    "!941+1633/200,!0/200", /* D */
01108    "!941+1209/200,!0/200", /* * */
01109    "!941+1477/200,!0/200" };  /* # */
01110 
01111 
01112    if (c)
01113    {
01114       snprintf(myrpt->dtmf_local_str + strlen(myrpt->dtmf_local_str),sizeof(myrpt->dtmf_local_str) - 1,"%c",c);
01115       if (!myrpt->dtmf_local_timer) 
01116           myrpt->dtmf_local_timer = DTMF_LOCAL_STARTTIME;
01117    }
01118    /* if at timeout */
01119    if (myrpt->dtmf_local_timer == 1)
01120    {
01121       /* if anything in the string */
01122       if (myrpt->dtmf_local_str[0])
01123       {
01124          digit = myrpt->dtmf_local_str[0];
01125          myrpt->dtmf_local_str[0] = 0;
01126          for(i = 1; myrpt->dtmf_local_str[i]; i++)
01127          {
01128             myrpt->dtmf_local_str[i - 1] =
01129                myrpt->dtmf_local_str[i];
01130          }
01131          myrpt->dtmf_local_str[i - 1] = 0;
01132          myrpt->dtmf_local_timer = DTMF_LOCAL_TIME;
01133          rpt_mutex_unlock(&myrpt->lock);
01134          if (digit >= '0' && digit <='9')
01135             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'0'], 0);
01136          else if (digit >= 'A' && digit <= 'D')
01137             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'A'+10], 0);
01138          else if (digit == '*')
01139             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[14], 0);
01140          else if (digit == '#')
01141             ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[15], 0);
01142          else {
01143             /* not handled */
01144             ast_log(LOG_DEBUG, "Unable to generate DTMF tone '%c' for '%s'\n", digit, myrpt->txchannel->name);
01145          }
01146          rpt_mutex_lock(&myrpt->lock);
01147       }
01148       else
01149       {
01150          myrpt->dtmf_local_timer = 0;
01151       }
01152    }
01153 }
01154 
01155 static int openserial(char *fname)
01156 {
01157    struct termios mode;
01158    int fd;
01159 
01160    fd = open(fname,O_RDWR);
01161    if (fd == -1)
01162    {
01163       ast_log(LOG_WARNING,"Cannot open serial port %s\n",fname);
01164       return -1;
01165    }
01166    memset(&mode, 0, sizeof(mode));
01167    if (tcgetattr(fd, &mode)) {
01168       ast_log(LOG_WARNING, "Unable to get serial parameters on %s: %s\n", fname, strerror(errno));
01169       return -1;
01170    }
01171 #ifndef SOLARIS
01172    cfmakeraw(&mode);
01173 #else
01174         mode.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
01175                         |INLCR|IGNCR|ICRNL|IXON);
01176         mode.c_oflag &= ~OPOST;
01177         mode.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
01178         mode.c_cflag &= ~(CSIZE|PARENB|CRTSCTS);
01179         mode.c_cflag |= CS8;
01180    mode.c_cc[TIME] = 3;
01181    mode.c_cc[MAX] = 1;
01182 #endif
01183 
01184    cfsetispeed(&mode, B9600);
01185    cfsetospeed(&mode, B9600);
01186    if (tcsetattr(fd, TCSANOW, &mode)) 
01187       ast_log(LOG_WARNING, "Unable to set serial parameters on %s: %s\n", fname, strerror(errno));
01188    return(fd); 
01189 }
01190 
01191 static void mdc1200_notify(struct rpt *myrpt,char *fromnode, unsigned int unit)
01192 {
01193    if (!fromnode)
01194    {
01195       ast_verbose("Got MDC-1200 ID %04X from local system (%s)\n",
01196          unit,myrpt->name);
01197    }
01198    else
01199    {
01200       ast_verbose("Got MDC-1200 ID %04X from node %s (%s)\n",
01201          unit,fromnode,myrpt->name);
01202    }
01203 }
01204 
01205 #ifdef   _MDC_DECODE_H_
01206 
01207 static void mdc1200_send(struct rpt *myrpt, unsigned int unit)
01208 {
01209 struct rpt_link *l;
01210 struct   ast_frame wf;
01211 char  str[200];
01212 
01213 
01214    sprintf(str,"I %s %04X",myrpt->name,unit);
01215 
01216    wf.frametype = AST_FRAME_TEXT;
01217    wf.subclass = 0;
01218    wf.offset = 0;
01219    wf.mallocd = 0;
01220    wf.datalen = strlen(str) + 1;
01221    wf.samples = 0;
01222 
01223 
01224    l = myrpt->links.next;
01225    /* otherwise, send it to all of em */
01226    while(l != &myrpt->links)
01227    {
01228       if (l->name[0] == '0') 
01229       {
01230          l = l->next;
01231          continue;
01232       }
01233       wf.data = str;
01234       if (l->chan) ast_write(l->chan,&wf); 
01235       l = l->next;
01236    }
01237    return;
01238 }
01239 
01240 #endif
01241 
01242 static char func_xlat(struct rpt *myrpt,char c,struct rpt_xlat *xlat)
01243 {
01244 time_t   now;
01245 int   gotone;
01246 
01247    time(&now);
01248    gotone = 0;
01249    /* if too much time, reset the skate machine */
01250    if ((now - xlat->lastone) > MAXXLATTIME)
01251    {
01252       xlat->funcindex = xlat->endindex = 0;
01253    }
01254    if (xlat->funccharseq[0] && (c == xlat->funccharseq[xlat->funcindex++]))
01255    {
01256       time(&xlat->lastone);
01257       gotone = 1;
01258       if (!xlat->funccharseq[xlat->funcindex])
01259       {
01260          xlat->funcindex = xlat->endindex = 0;
01261          return(myrpt->p.funcchar);
01262       }
01263    } else xlat->funcindex = 0;
01264    if (xlat->endcharseq[0] && (c == xlat->endcharseq[xlat->endindex++]))
01265    {
01266       time(&xlat->lastone);
01267       gotone = 1;
01268       if (!xlat->endcharseq[xlat->endindex])
01269       {
01270          xlat->funcindex = xlat->endindex = 0;
01271          return(myrpt->p.endchar);
01272       }
01273    } else xlat->endindex = 0;
01274    /* if in middle of decode seq, send nothing back */
01275    if (gotone) return(0);
01276    /* if no pass chars specified, return em all */
01277    if (!xlat->passchars[0]) return(c);
01278    /* if a "pass char", pass it */
01279    if (strchr(xlat->passchars,c)) return(c);
01280    return(0);
01281 }
01282 
01283 /*
01284  * Return a pointer to the first non-whitespace character
01285  */
01286 
01287 static char *eatwhite(char *s)
01288 {
01289    while((*s == ' ') || (*s == 0x09)){ /* get rid of any leading white space */
01290       if(!*s)
01291          break;
01292       s++;
01293    }
01294    return s;
01295 }
01296 
01297 /*
01298 * Break up a delimited string into a table of substrings
01299 *
01300 * str - delimited string ( will be modified )
01301 * strp- list of pointers to substrings (this is built by this function), NULL will be placed at end of list
01302 * limit- maximum number of substrings to process
01303 */
01304    
01305 
01306 
01307 static int finddelim(char *str, char *strp[], int limit)
01308 {
01309 int     i,l,inquo;
01310 
01311         inquo = 0;
01312         i = 0;
01313         strp[i++] = str;
01314         if (!*str)
01315            {
01316                 strp[0] = 0;
01317                 return(0);
01318            }
01319         for(l = 0; *str && (l < limit) ; str++)
01320            {
01321                 if (*str == QUOTECHR)
01322                    {
01323                         if (inquo)
01324                            {
01325                                 *str = 0;
01326                                 inquo = 0;
01327                            }
01328                         else
01329                            {
01330                                 strp[i - 1] = str + 1;
01331                                 inquo = 1;
01332                            }
01333       }
01334                 if ((*str == DELIMCHR) && (!inquo))
01335                 {
01336                         *str = 0;
01337          l++;
01338                         strp[i++] = str + 1;
01339                 }
01340            }
01341         strp[i] = 0;
01342         return(i);
01343 
01344 }
01345 
01346 /* must be called locked */
01347 static void __mklinklist(struct rpt *myrpt, struct rpt_link *mylink, char *buf)
01348 {
01349 struct rpt_link *l;
01350 char mode;
01351 int   i,spos;
01352 
01353    buf[0] = 0; /* clear output buffer */
01354    /* go thru all links */
01355    for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
01356    {
01357       /* if is not a real link, ignore it */
01358       if (l->name[0] == '0') continue;
01359       /* dont count our stuff */
01360       if (l == mylink) continue;
01361       if (mylink && (!strcmp(l->name,mylink->name))) continue;
01362       /* figure out mode to report */
01363       mode = 'T'; /* use Tranceive by default */
01364       if (!l->mode) mode = 'R'; /* indicate RX for our mode */
01365       if (!l->thisconnected)  mode = 'C'; /* indicate connecting */
01366       spos = strlen(buf); /* current buf size (b4 we add our stuff) */
01367       if (spos)
01368       {
01369          strcat(buf,",");
01370          spos++;
01371       }
01372       /* add nodes into buffer */
01373       if (l->linklist[0])
01374       {
01375          snprintf(buf + spos,MAXLINKLIST - spos,
01376             "%c%s,%s",mode,l->name,l->linklist);
01377       }
01378       else /* if no nodes, add this node into buffer */
01379       {
01380          snprintf(buf + spos,MAXLINKLIST - spos,
01381             "%c%s",mode,l->name);
01382       }
01383       /* if we are in tranceive mode, let all modes stand */
01384       if (mode == 'T') continue;
01385       /* downgrade everyone on this node if appropriate */
01386       for(i = spos; buf[i]; i++)
01387       {
01388          if (buf[i] == 'T') buf[i] = mode;
01389          if ((buf[i] == 'R') && (mode == 'C')) buf[i] = mode;
01390       }
01391    }
01392    return;
01393 }
01394 
01395 /* must be called locked */
01396 static void __kickshort(struct rpt *myrpt)
01397 {
01398 struct rpt_link *l;
01399 
01400    for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
01401    {
01402       /* if is not a real link, ignore it */
01403       if (l->name[0] == '0') continue;
01404       l->linklisttimer = LINKLISTSHORTTIME;
01405    }
01406    return;
01407 }
01408 
01409 static char *node_lookup(struct rpt *myrpt,char *digitbuf)
01410 {
01411 
01412 char *val;
01413 int longestnode,j;
01414 struct stat mystat;
01415 static time_t last = 0;
01416 static struct ast_config *ourcfg = NULL;
01417 struct ast_variable *vp;
01418 
01419    /* try to look it up locally first */
01420    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
01421    if (val) return(val);
01422    ast_mutex_lock(&nodelookuplock);
01423    /* if file does not exist */
01424    if (stat(myrpt->p.extnodefile,&mystat) == -1)
01425    {
01426       if (ourcfg) ast_config_destroy(ourcfg);
01427       ourcfg = NULL;
01428       ast_mutex_unlock(&nodelookuplock);
01429       return(NULL);
01430    }
01431    /* if we need to reload */
01432    if (mystat.st_mtime > last)
01433    {
01434       if (ourcfg) ast_config_destroy(ourcfg);
01435       ourcfg = ast_config_load(myrpt->p.extnodefile);
01436       /* if file not there, just bail */
01437       if (!ourcfg)
01438       {
01439          ast_mutex_unlock(&nodelookuplock);
01440          return(NULL);
01441       }
01442       /* reset "last" time */
01443       last = mystat.st_mtime;
01444 
01445       /* determine longest node length again */    
01446       longestnode = 0;
01447       vp = ast_variable_browse(myrpt->cfg, myrpt->p.nodes);
01448       while(vp){
01449          j = strlen(vp->name);
01450          if (j > longestnode)
01451             longestnode = j;
01452          vp = vp->next;
01453       }
01454 
01455       vp = ast_variable_browse(ourcfg, myrpt->p.extnodes);
01456       while(vp){
01457          j = strlen(vp->name);
01458          if (j > longestnode)
01459             longestnode = j;
01460          vp = vp->next;
01461       }
01462 
01463       myrpt->longestnode = longestnode;
01464    }
01465    val = NULL;
01466    if (ourcfg)
01467       val = (char *) ast_variable_retrieve(ourcfg, myrpt->p.extnodes, digitbuf);
01468    ast_mutex_unlock(&nodelookuplock);
01469    return(val);
01470 }
01471 
01472 /*
01473 * Match a keyword in a list, and return index of string plus 1 if there was a match,* else return 0.
01474 * If param is passed in non-null, then it will be set to the first character past the match
01475 */
01476 
01477 static int matchkeyword(char *string, char **param, char *keywords[])
01478 {
01479 int   i,ls;
01480    for( i = 0 ; keywords[i] ; i++){
01481       ls = strlen(keywords[i]);
01482       if(!ls){
01483          *param = NULL;
01484          return 0;
01485       }
01486       if(!strncmp(string, keywords[i], ls)){
01487          if(param)
01488             *param = string + ls;
01489          return i + 1; 
01490       }
01491    }
01492    param = NULL;
01493    return 0;
01494 }
01495 
01496 /*
01497 * Skip characters in string which are in charlist, and return a pointer to the
01498 * first non-matching character
01499 */
01500 
01501 static char *skipchars(char *string, char *charlist)
01502 {
01503 int i;   
01504    while(*string){
01505       for(i = 0; charlist[i] ; i++){
01506          if(*string == charlist[i]){
01507             string++;
01508             break;
01509          }
01510       }
01511       if(!charlist[i])
01512          return string;
01513    }
01514    return string;
01515 }  
01516                
01517 
01518 
01519 static int myatoi(char *str)
01520 {
01521 int   ret;
01522 
01523    if (str == NULL) return -1;
01524    /* leave this %i alone, non-base-10 input is useful here */
01525    if (sscanf(str,"%i",&ret) != 1) return -1;
01526    return ret;
01527 }
01528 
01529 static int mycompar(const void *a, const void *b)
01530 {
01531 char  **x = (char **) a;
01532 char  **y = (char **) b;
01533 int   xoff,yoff;
01534 
01535    if ((**x < '0') || (**x > '9')) xoff = 1; else xoff = 0;
01536    if ((**y < '0') || (**y > '9')) yoff = 1; else yoff = 0;
01537    return(strcmp((*x) + xoff,(*y) + yoff));
01538 }
01539 
01540 #ifdef   __RPT_NOTCH
01541 
01542 /* rpt filter routine */
01543 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
01544 {
01545 int   i,j;
01546 struct   rptfilter *f;
01547 
01548    for(i = 0; i < len; i++)
01549    {
01550       for(j = 0; j < MAXFILTERS; j++)
01551       {
01552          f = &myrpt->filters[j];
01553          if (!*f->desc) continue;
01554          f->x0 = f->x1; f->x1 = f->x2;
01555               f->x2 = ((float)buf[i]) / f->gain;
01556               f->y0 = f->y1; f->y1 = f->y2;
01557               f->y2 =   (f->x0 + f->x2) +   f->const0 * f->x1
01558                            + (f->const1 * f->y0) + (f->const2 * f->y1);
01559          buf[i] = (short)f->y2;
01560       }
01561    }
01562 }
01563 
01564 #endif
01565 
01566 
01567 /*
01568  Get the time for the machine's time zone
01569  Note: Asterisk requires a copy of localtime
01570  in the /etc directory for this to work properly.
01571  If /etc/localtime is not present, you will get
01572  GMT time! This is especially important on systems
01573  running embedded linux distributions as they don't usually
01574  have support for locales. 
01575 
01576  If OLD_ASTERISK is defined, then the older localtime_r
01577  function will be used. The /etc/localtime file is not
01578  required in this case. This provides backward compatibility
01579  with Asterisk 1.2 systems.
01580 
01581 */
01582 
01583 static void rpt_localtime( time_t * t, struct tm *lt)
01584 {
01585 #ifdef OLD_ASTERISK
01586    localtime_r(t, lt);
01587 #else
01588    ast_localtime(t, lt, NULL);
01589 #endif
01590 }
01591 
01592 /* Retrieve an int from a config file */
01593                                                                                 
01594 static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl)
01595 {
01596         char *var;
01597         int ret;
01598    char include_zero = 0;
01599 
01600    if(min < 0){ /* If min is negative, this means include 0 as a valid entry */
01601       min = -min;
01602       include_zero = 1;
01603    }           
01604                                                                      
01605         var = (char *) ast_variable_retrieve(myrpt->cfg, category, name);
01606         if(var){
01607                 ret = myatoi(var);
01608       if(include_zero && !ret)
01609          return 0;
01610                 if(ret < min)
01611                         ret = min;
01612                 if(ret > max)
01613                         ret = max;
01614         }
01615         else
01616                 ret = defl;
01617         return ret;
01618 }
01619 
01620 
01621 static void load_rpt_vars(int n,int init)
01622 {
01623 char *this,*val;
01624 int   i,j,longestnode;
01625 struct ast_variable *vp;
01626 struct ast_config *cfg;
01627 char *strs[100];
01628 char s1[256];
01629 static char *cs_keywords[] = {"rptena","rptdis","apena","apdis","lnkena","lnkdis","totena","totdis","skena","skdis",
01630             "ufena","ufdis","atena","atdis",NULL};
01631 
01632    if (option_verbose > 2)
01633       ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n",
01634          (init) ? "Loading initial" : "Re-Loading",rpt_vars[n].name);
01635    ast_mutex_lock(&rpt_vars[n].lock);
01636    if (rpt_vars[n].cfg) ast_config_destroy(rpt_vars[n].cfg);
01637    cfg = ast_config_load("rpt.conf");
01638    if (!cfg) {
01639       ast_mutex_unlock(&rpt_vars[n].lock);
01640       ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
01641       pthread_exit(NULL);
01642    }
01643    rpt_vars[n].cfg = cfg; 
01644    this = rpt_vars[n].name;
01645    memset(&rpt_vars[n].p,0,sizeof(rpt_vars[n].p));
01646    if (init)
01647    {
01648       /* clear all the fields in the structure after 'p' */
01649       memset(&rpt_vars[n].p + sizeof(rpt_vars[0].p), 0, sizeof(rpt_vars[0]) - sizeof(rpt_vars[0].p) - offsetof(typeof(rpt_vars[0]), p));
01650       rpt_vars[n].tele.next = &rpt_vars[n].tele;
01651       rpt_vars[n].tele.prev = &rpt_vars[n].tele;
01652       rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
01653       rpt_vars[n].tailmessagen = 0;
01654    }
01655 #ifdef   __RPT_NOTCH
01656    /* zot out filters stuff */
01657    memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
01658 #endif
01659    val = (char *) ast_variable_retrieve(cfg,this,"context");
01660    if (val) rpt_vars[n].p.ourcontext = val;
01661    else rpt_vars[n].p.ourcontext = this;
01662    val = (char *) ast_variable_retrieve(cfg,this,"callerid");
01663    if (val) rpt_vars[n].p.ourcallerid = val;
01664    val = (char *) ast_variable_retrieve(cfg,this,"accountcode");
01665    if (val) rpt_vars[n].p.acctcode = val;
01666    val = (char *) ast_variable_retrieve(cfg,this,"idrecording");
01667    if (val) rpt_vars[n].p.ident = val;
01668    val = (char *) ast_variable_retrieve(cfg,this,"hangtime");
01669    if (val) rpt_vars[n].p.hangtime = atoi(val);
01670       else rpt_vars[n].p.hangtime = HANGTIME;
01671    val = (char *) ast_variable_retrieve(cfg,this,"althangtime");
01672    if (val) rpt_vars[n].p.althangtime = atoi(val);
01673       else rpt_vars[n].p.althangtime = HANGTIME;
01674    val = (char *) ast_variable_retrieve(cfg,this,"totime");
01675    if (val) rpt_vars[n].p.totime = atoi(val);
01676       else rpt_vars[n].p.totime = TOTIME;
01677    rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0);    
01678    rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0);     
01679    rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2);
01680    rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", -60000, 2400000, IDTIME);   /* Enforce a min max including zero */
01681    rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
01682    val = (char *) ast_variable_retrieve(cfg,this,"tonezone");
01683    if (val) rpt_vars[n].p.tonezone = val;
01684    rpt_vars[n].p.tailmessages[0] = 0;
01685    rpt_vars[n].p.tailmessagemax = 0;
01686    val = (char *) ast_variable_retrieve(cfg,this,"tailmessagelist");
01687    if (val) rpt_vars[n].p.tailmessagemax = finddelim(val, rpt_vars[n].p.tailmessages, 500);
01688    val = (char *) ast_variable_retrieve(cfg,this,"memory");
01689    if (!val) val = MEMORY;
01690    rpt_vars[n].p.memory = val;
01691    val = (char *) ast_variable_retrieve(cfg,this,"macro");
01692    if (!val) val = MACRO;
01693    rpt_vars[n].p.macro = val;
01694    val = (char *) ast_variable_retrieve(cfg,this,"startup_macro");
01695    if (val) rpt_vars[n].p.startupmacro = val;
01696    val = (char *) ast_variable_retrieve(cfg,this,"iobase");
01697    /* do not use atoi() here, we need to be able to have
01698       the input specified in hex or decimal so we use
01699       sscanf with a %i */
01700    if ((!val) || (sscanf(val,"%i",&rpt_vars[n].p.iobase) != 1))
01701    rpt_vars[n].p.iobase = DEFAULT_IOBASE;
01702    val = (char *) ast_variable_retrieve(cfg,this,"ioport");
01703    rpt_vars[n].p.ioport = val;
01704    val = (char *) ast_variable_retrieve(cfg,this,"functions");
01705    if (!val)
01706       {
01707          val = FUNCTIONS;
01708          rpt_vars[n].p.simple = 1;
01709       } 
01710    rpt_vars[n].p.functions = val;
01711    val =  (char *) ast_variable_retrieve(cfg,this,"link_functions");
01712    if (val) rpt_vars[n].p.link_functions = val;
01713    else 
01714       rpt_vars[n].p.link_functions = rpt_vars[n].p.functions;
01715    val = (char *) ast_variable_retrieve(cfg,this,"phone_functions");
01716    if (val) rpt_vars[n].p.phone_functions = val;
01717    val = (char *) ast_variable_retrieve(cfg,this,"dphone_functions");
01718    if (val) rpt_vars[n].p.dphone_functions = val;
01719    val = (char *) ast_variable_retrieve(cfg,this,"funcchar");
01720    if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else 
01721       rpt_vars[n].p.funcchar = *val;      
01722    val = (char *) ast_variable_retrieve(cfg,this,"endchar");
01723    if (!val) rpt_vars[n].p.endchar = ENDCHAR; else 
01724       rpt_vars[n].p.endchar = *val;    
01725    val = (char *) ast_variable_retrieve(cfg,this,"nobusyout");
01726    if (val) rpt_vars[n].p.nobusyout = ast_true(val);
01727    val = (char *) ast_variable_retrieve(cfg,this,"notelemtx");
01728    if (val) rpt_vars[n].p.notelemtx = ast_true(val);
01729    val = (char *) ast_variable_retrieve(cfg,this,"propagate_dtmf");
01730    if (val) rpt_vars[n].p.propagate_dtmf = ast_true(val);
01731    val = (char *) ast_variable_retrieve(cfg,this,"propagate_phonedtmf");
01732    if (val) rpt_vars[n].p.propagate_phonedtmf = ast_true(val);
01733    val = (char *) ast_variable_retrieve(cfg,this,"linktolink");
01734    if (val) rpt_vars[n].p.linktolink = ast_true(val);
01735    val = (char *) ast_variable_retrieve(cfg,this,"nodes");
01736    if (!val) val = NODES;
01737    rpt_vars[n].p.nodes = val;
01738    val = (char *) ast_variable_retrieve(cfg,this,"extnodes");
01739    if (!val) val = EXTNODES;
01740    rpt_vars[n].p.extnodes = val;
01741    val = (char *) ast_variable_retrieve(cfg,this,"extnodefile");
01742    if (!val) val = EXTNODEFILE;
01743    rpt_vars[n].p.extnodefile = val;
01744    val = (char *) ast_variable_retrieve(cfg,this,"archivedir");
01745    if (val) rpt_vars[n].p.archivedir = val;
01746    val = (char *) ast_variable_retrieve(cfg,this,"authlevel");
01747    if (val) rpt_vars[n].p.authlevel = atoi(val); 
01748    else rpt_vars[n].p.authlevel = 0;
01749    val = (char *) ast_variable_retrieve(cfg,this,"monminblocks");
01750    if (val) rpt_vars[n].p.monminblocks = atol(val); 
01751    else rpt_vars[n].p.monminblocks = DEFAULT_MONITOR_MIN_DISK_BLOCKS;
01752    val = (char *) ast_variable_retrieve(cfg,this,"remote_inact_timeout");
01753    if (val) rpt_vars[n].p.remoteinacttimeout = atoi(val); 
01754    else rpt_vars[n].p.remoteinacttimeout = DEFAULT_REMOTE_INACT_TIMEOUT;
01755    val = (char *) ast_variable_retrieve(cfg,this,"civaddr");
01756    if (val) rpt_vars[n].p.civaddr = atoi(val); 
01757    else rpt_vars[n].p.civaddr = DEFAULT_CIV_ADDR;
01758    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout");
01759    if (val) rpt_vars[n].p.remotetimeout = atoi(val); 
01760    else rpt_vars[n].p.remotetimeout = DEFAULT_REMOTE_TIMEOUT;
01761    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning");
01762    if (val) rpt_vars[n].p.remotetimeoutwarning = atoi(val); 
01763    else rpt_vars[n].p.remotetimeoutwarning = DEFAULT_REMOTE_TIMEOUT_WARNING;
01764    val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning_freq");
01765    if (val) rpt_vars[n].p.remotetimeoutwarningfreq = atoi(val); 
01766    else rpt_vars[n].p.remotetimeoutwarningfreq = DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ;
01767 #ifdef   __RPT_NOTCH
01768    val = (char *) ast_variable_retrieve(cfg,this,"rxnotch");
01769    if (val) {
01770       i = finddelim(val,strs,MAXFILTERS * 2);
01771       i &= ~1; /* force an even number, rounded down */
01772       if (i >= 2) for(j = 0; j < i; j += 2)
01773       {
01774          rpt_mknotch(atof(strs[j]),atof(strs[j + 1]),
01775            &rpt_vars[n].filters[j >> 1].gain,
01776              &rpt_vars[n].filters[j >> 1].const0,
01777             &rpt_vars[n].filters[j >> 1].const1,
01778                 &rpt_vars[n].filters[j >> 1].const2);
01779          sprintf(rpt_vars[n].filters[j >> 1].desc,"%s Hz, BW = %s",
01780             strs[j],strs[j + 1]);
01781       }
01782 
01783    }
01784 #endif
01785    val = (char *) ast_variable_retrieve(cfg,this,"inxlat");
01786    if (val) {
01787       memset(&rpt_vars[n].p.inxlat,0,sizeof(struct rpt_xlat));
01788       i = finddelim(val,strs,3);
01789       if (i) strncpy(rpt_vars[n].p.inxlat.funccharseq,strs[0],MAXXLAT - 1);
01790       if (i > 1) strncpy(rpt_vars[n].p.inxlat.endcharseq,strs[1],MAXXLAT - 1);
01791       if (i > 2) strncpy(rpt_vars[n].p.inxlat.passchars,strs[2],MAXXLAT - 1);
01792    }
01793    val = (char *) ast_variable_retrieve(cfg,this,"outxlat");
01794    if (val) {
01795       memset(&rpt_vars[n].p.outxlat,0,sizeof(struct rpt_xlat));
01796       i = finddelim(val,strs,3);
01797       if (i) strncpy(rpt_vars[n].p.outxlat.funccharseq,strs[0],MAXXLAT - 1);
01798       if (i > 1) strncpy(rpt_vars[n].p.outxlat.endcharseq,strs[1],MAXXLAT - 1);
01799       if (i > 2) strncpy(rpt_vars[n].p.outxlat.passchars,strs[2],MAXXLAT - 1);
01800    }
01801    /* retreive the stanza name for the control states if there is one */
01802    val = (char *) ast_variable_retrieve(cfg,this,"controlstates");
01803    rpt_vars[n].p.csstanzaname = val;
01804       
01805    /* retreive the stanza name for the scheduler if there is one */
01806    val = (char *) ast_variable_retrieve(cfg,this,"scheduler");
01807    rpt_vars[n].p.skedstanzaname = val;
01808 
01809    /* retreive the stanza name for the txlimits */
01810    val = (char *) ast_variable_retrieve(cfg,this,"txlimits");
01811    rpt_vars[n].p.txlimitsstanzaname = val;
01812 
01813    longestnode = 0;
01814 
01815    vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
01816       
01817    while(vp){
01818       j = strlen(vp->name);
01819       if (j > longestnode)
01820          longestnode = j;
01821       vp = vp->next;
01822    }
01823 
01824    rpt_vars[n].longestnode = longestnode;
01825       
01826    /*
01827    * For this repeater, Determine the length of the longest function 
01828    */
01829    rpt_vars[n].longestfunc = 0;
01830    vp = ast_variable_browse(cfg, rpt_vars[n].p.functions);
01831    while(vp){
01832       j = strlen(vp->name);
01833       if (j > rpt_vars[n].longestfunc)
01834          rpt_vars[n].longestfunc = j;
01835       vp = vp->next;
01836    }
01837    /*
01838    * For this repeater, Determine the length of the longest function 
01839    */
01840    rpt_vars[n].link_longestfunc = 0;
01841    vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions);
01842    while(vp){
01843       j = strlen(vp->name);
01844       if (j > rpt_vars[n].link_longestfunc)
01845          rpt_vars[n].link_longestfunc = j;
01846       vp = vp->next;
01847    }
01848    rpt_vars[n].phone_longestfunc = 0;
01849    if (rpt_vars[n].p.phone_functions)
01850    {
01851       vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions);
01852       while(vp){
01853          j = strlen(vp->name);
01854          if (j > rpt_vars[n].phone_longestfunc)
01855             rpt_vars[n].phone_longestfunc = j;
01856          vp = vp->next;
01857       }
01858    }
01859    rpt_vars[n].dphone_longestfunc = 0;
01860    if (rpt_vars[n].p.dphone_functions)
01861    {
01862       vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions);
01863       while(vp){
01864          j = strlen(vp->name);
01865          if (j > rpt_vars[n].dphone_longestfunc)
01866             rpt_vars[n].dphone_longestfunc = j;
01867          vp = vp->next;
01868       }
01869    }
01870    rpt_vars[n].macro_longest = 1;
01871    vp = ast_variable_browse(cfg, rpt_vars[n].p.macro);
01872    while(vp){
01873       j = strlen(vp->name);
01874       if (j > rpt_vars[n].macro_longest)
01875          rpt_vars[n].macro_longest = j;
01876       vp = vp->next;
01877    }
01878    
01879    /* Browse for control states */
01880    if(rpt_vars[n].p.csstanzaname)
01881       vp = ast_variable_browse(cfg, rpt_vars[n].p.csstanzaname);
01882    else
01883       vp = NULL;
01884    for( i = 0 ; vp && (i < MAX_SYSSTATES) ; i++){ /* Iterate over the number of control state lines in the stanza */
01885       int k,nukw,statenum;
01886       statenum=atoi(vp->name);
01887       strncpy(s1, vp->value, 255);
01888       s1[255] = 0;
01889       nukw  = finddelim(s1,strs,32);
01890       
01891       for (k = 0 ; k < nukw ; k++){ /* for each user specified keyword */  
01892          for(j = 0 ; cs_keywords[j] != NULL ; j++){ /* try to match to one in our internal table */
01893             if(!strcmp(strs[k],cs_keywords[j])){
01894                switch(j){
01895                   case 0: /* rptena */
01896                      rpt_vars[n].p.s[statenum].txdisable = 0;
01897                      break;
01898                   case 1: /* rptdis */
01899                      rpt_vars[n].p.s[statenum].txdisable = 1;
01900                      break;
01901          
01902                   case 2: /* apena */
01903                      rpt_vars[n].p.s[statenum].autopatchdisable = 0;
01904                      break;
01905 
01906                   case 3: /* apdis */
01907                      rpt_vars[n].p.s[statenum].autopatchdisable = 1;
01908                      break;
01909 
01910                   case 4: /* lnkena */
01911                      rpt_vars[n].p.s[statenum].linkfundisable = 0;
01912                      break;
01913    
01914                   case 5: /* lnkdis */
01915                      rpt_vars[n].p.s[statenum].linkfundisable = 1;
01916                      break;
01917 
01918                   case 6: /* totena */
01919                      rpt_vars[n].p.s[statenum].totdisable = 0;
01920                      break;
01921                
01922                   case 7: /* totdis */
01923                      rpt_vars[n].p.s[statenum].totdisable = 1;
01924                      break;
01925 
01926                   case 8: /* skena */
01927                      rpt_vars[n].p.s[statenum].schedulerdisable = 0;
01928                      break;
01929 
01930                   case 9: /* skdis */
01931                      rpt_vars[n].p.s[statenum].schedulerdisable = 1;
01932                      break;
01933 
01934                   case 10: /* ufena */
01935                      rpt_vars[n].p.s[statenum].userfundisable = 0;
01936                      break;
01937 
01938                   case 11: /* ufdis */
01939                      rpt_vars[n].p.s[statenum].userfundisable = 1;
01940                      break;
01941 
01942                   case 12: /* atena */
01943                      rpt_vars[n].p.s[statenum].alternatetail = 1;
01944                      break;
01945 
01946                   case 13: /* atdis */
01947                      rpt_vars[n].p.s[statenum].alternatetail = 0;
01948                      break;
01949          
01950                   default:
01951                      ast_log(LOG_WARNING,
01952                         "Unhandled control state keyword %s", cs_keywords[i]);
01953                      break;
01954                }
01955             }
01956          }
01957       }
01958       vp = vp->next;
01959    }
01960    ast_mutex_unlock(&rpt_vars[n].lock);
01961 }
01962 
01963 /*
01964 * Enable or disable debug output at a given level at the console
01965 */
01966                                                                                                                                  
01967 static int rpt_do_debug(int fd, int argc, char *argv[])
01968 {
01969    int newlevel;
01970 
01971         if (argc != 4)
01972                 return RESULT_SHOWUSAGE;
01973         newlevel = myatoi(argv[3]);
01974         if((newlevel < 0) || (newlevel > 7))
01975                 return RESULT_SHOWUSAGE;
01976         if(newlevel)
01977                 ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
01978         else
01979                 ast_cli(fd, "app_rpt Debugging disabled\n");
01980 
01981         debug = newlevel;                                                                                                                          
01982         return RESULT_SUCCESS;
01983 }
01984 
01985 /*
01986 * Dump rpt struct debugging onto console
01987 */
01988                                                                                                                                  
01989 static int rpt_do_dump(int fd, int argc, char *argv[])
01990 {
01991    int i;
01992 
01993         if (argc != 3)
01994                 return RESULT_SHOWUSAGE;
01995 
01996    for(i = 0; i < nrpts; i++)
01997    {
01998       if (!strcmp(argv[2],rpt_vars[i].name))
01999       {
02000          rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
02001               ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
02002               return RESULT_SUCCESS;
02003       }
02004    }
02005    return RESULT_FAILURE;
02006 }
02007 
02008 /*
02009 * Dump statistics onto console
02010 */
02011 
02012 static int rpt_do_stats(int fd, int argc, char *argv[])
02013 {
02014    int i,j;
02015    int dailytxtime, dailykerchunks;
02016    int totalkerchunks, dailykeyups, totalkeyups, timeouts;
02017    int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
02018    long long totaltxtime;
02019    struct   rpt_link *l;
02020    char *listoflinks[MAX_STAT_LINKS];  
02021    char *lastnodewhichkeyedusup, *lastdtmfcommand;
02022    char *tot_state, *ider_state, *patch_state;
02023    char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
02024    char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
02025    struct rpt *myrpt;
02026 
02027    static char *not_applicable = "N/A";
02028 
02029    if(argc != 3)
02030       return RESULT_SHOWUSAGE;
02031 
02032    for(i = 0 ; i < MAX_STAT_LINKS; i++)
02033       listoflinks[i] = NULL;
02034 
02035    tot_state = ider_state = 
02036    patch_state = reverse_patch_state = 
02037    input_signal = called_number = 
02038    lastdtmfcommand = not_applicable;
02039 
02040    for(i = 0; i < nrpts; i++)
02041    {
02042       if (!strcmp(argv[2],rpt_vars[i].name)){
02043          /* Make a copy of all stat variables while locked */
02044          myrpt = &rpt_vars[i];
02045          rpt_mutex_lock(&myrpt->lock); /* LOCK */
02046 
02047          dailytxtime = myrpt->dailytxtime;
02048          totaltxtime = myrpt->totaltxtime;
02049          dailykeyups = myrpt->dailykeyups;
02050          totalkeyups = myrpt->totalkeyups;
02051          dailykerchunks = myrpt->dailykerchunks;
02052          totalkerchunks = myrpt->totalkerchunks;
02053          dailyexecdcommands = myrpt->dailyexecdcommands;
02054          totalexecdcommands = myrpt->totalexecdcommands;
02055          timeouts = myrpt->timeouts;
02056 
02057          /* Traverse the list of connected nodes */
02058          reverse_patch_state = "DOWN";
02059          j = 0;
02060          l = myrpt->links.next;
02061          while(l && (l != &myrpt->links)){
02062             if (l->name[0] == '0'){ /* Skip '0' nodes */
02063                reverse_patch_state = "UP";
02064                l = l->next;
02065                continue;
02066             }
02067             listoflinks[j] = ast_strdupa(l->name);
02068             if(listoflinks[j])
02069                j++;
02070             l = l->next;
02071          }
02072 
02073          lastnodewhichkeyedusup = ast_strdupa(myrpt->lastnodewhichkeyedusup);       
02074          if((!lastnodewhichkeyedusup) || (!strlen(lastnodewhichkeyedusup)))
02075             lastnodewhichkeyedusup = not_applicable;
02076 
02077          if(myrpt->keyed)
02078             input_signal = "YES";
02079          else
02080             input_signal = "NO";
02081 
02082          if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
02083             sys_ena = "DISABLED";
02084          else
02085             sys_ena = "ENABLED";
02086 
02087          if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
02088             tot_ena = "DISABLED";
02089          else
02090             tot_ena = "ENABLED";
02091 
02092          if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
02093             link_ena = "DISABLED";
02094          else
02095             link_ena = "ENABLED";
02096 
02097          if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
02098             patch_ena = "DISABLED";
02099          else
02100             patch_ena = "ENABLED";
02101 
02102          if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
02103             sch_ena = "DISABLED";
02104          else
02105             sch_ena = "ENABLED";
02106 
02107          if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
02108             user_funs = "DISABLED";
02109          else
02110             user_funs = "ENABLED";
02111 
02112          if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
02113             tail_type = "ALTERNATE";
02114          else
02115             tail_type = "STANDARD";
02116 
02117          if(!myrpt->totimer)
02118             tot_state = "TIMED OUT!";
02119          else if(myrpt->totimer != myrpt->p.totime)
02120             tot_state = "ARMED";
02121          else
02122             tot_state = "RESET";
02123 
02124          if(myrpt->tailid)
02125             ider_state = "QUEUED IN TAIL";
02126          else if(myrpt->mustid)
02127             ider_state = "QUEUED FOR CLEANUP";
02128          else
02129             ider_state = "CLEAN";
02130 
02131          switch(myrpt->callmode){
02132             case 1:
02133                patch_state = "DIALING";
02134                break;
02135             case 2:
02136                patch_state = "CONNECTING";
02137                break;
02138             case 3:
02139                patch_state = "UP";
02140                break;
02141 
02142             case 4:
02143                patch_state = "CALL FAILED";
02144                break;
02145 
02146             default:
02147                patch_state = "DOWN";
02148          }
02149 
02150          if(strlen(myrpt->exten)){
02151             called_number = ast_strdupa(myrpt->exten);
02152             if(!called_number)
02153                called_number = not_applicable;
02154          }
02155 
02156          if(strlen(myrpt->lastdtmfcommand)){
02157             lastdtmfcommand = ast_strdupa(myrpt->lastdtmfcommand);
02158             if(!lastdtmfcommand)
02159                lastdtmfcommand = not_applicable;
02160          }
02161 
02162          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02163 
02164          ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
02165          ast_cli(fd, "Selected system state............................: %d\n", myrpt->p.sysstate_cur);
02166          ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
02167          ast_cli(fd, "System...........................................: %s\n", sys_ena);
02168          ast_cli(fd, "Scheduler........................................: %s\n", sch_ena);
02169          ast_cli(fd, "Tail Time........................................: %s\n", tail_type);
02170          ast_cli(fd, "Time out timer...................................: %s\n", tot_ena);
02171          ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
02172          ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
02173          ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
02174          ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
02175          ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
02176          ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
02177          ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
02178          ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
02179          ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
02180          ast_cli(fd, "Last DTMF command executed.......................: %s\n", lastdtmfcommand);
02181          hours = dailytxtime/3600000;
02182          dailytxtime %= 3600000;
02183          minutes = dailytxtime/60000;
02184          dailytxtime %= 60000;
02185          seconds = dailytxtime/1000;
02186          dailytxtime %= 1000;
02187 
02188          ast_cli(fd, "TX time today ...................................: %02d:%02d:%02d.%d\n",
02189             hours, minutes, seconds, dailytxtime);
02190 
02191          hours = (int) totaltxtime/3600000;
02192          totaltxtime %= 3600000;
02193          minutes = (int) totaltxtime/60000;
02194          totaltxtime %= 60000;
02195          seconds = (int)  totaltxtime/1000;
02196          totaltxtime %= 1000;
02197 
02198          ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
02199              hours, minutes, seconds, (int) totaltxtime);
02200          ast_cli(fd, "Nodes currently connected to us..................: ");
02201          for(j = 0 ;; j++){
02202             if(!listoflinks[j]){
02203                if(!j){
02204                   ast_cli(fd,"<NONE>");
02205                }
02206                break;
02207             }
02208             ast_cli(fd, "%s", listoflinks[j]);
02209             if(j % 4 == 3){
02210                ast_cli(fd, "\n");
02211                ast_cli(fd, "                                                 : ");
02212             }
02213             else{
02214                if(listoflinks[j + 1])
02215                   ast_cli(fd, ", ");
02216             }
02217          }
02218          ast_cli(fd,"\n");
02219 
02220          ast_cli(fd, "Last node which transmitted to us................: %s\n", lastnodewhichkeyedusup);
02221          ast_cli(fd, "Autopatch........................................: %s\n", patch_ena);
02222          ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
02223          ast_cli(fd, "Autopatch called number..........................: %s\n", called_number);
02224          ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n", reverse_patch_state);
02225          ast_cli(fd, "User linking commands............................: %s\n", link_ena);
02226          ast_cli(fd, "User functions...................................: %s\n\n", user_funs);
02227               return RESULT_SUCCESS;
02228       }
02229    }
02230    return RESULT_FAILURE;
02231 }
02232 
02233 /*
02234 * Link stats function
02235 */
02236 
02237 static int rpt_do_lstats(int fd, int argc, char *argv[])
02238 {
02239    int i,j;
02240    char *connstate;
02241    struct rpt *myrpt;
02242    struct rpt_link *l;
02243    struct rpt_lstat *s,*t;
02244    struct rpt_lstat s_head;
02245    if(argc != 3)
02246       return RESULT_SHOWUSAGE;
02247 
02248    s = NULL;
02249    s_head.next = &s_head;
02250    s_head.prev = &s_head;
02251 
02252    for(i = 0; i < nrpts; i++)
02253    {
02254       if (!strcmp(argv[2],rpt_vars[i].name)){
02255          /* Make a copy of all stat variables while locked */
02256          myrpt = &rpt_vars[i];
02257          rpt_mutex_lock(&myrpt->lock); /* LOCK */
02258          /* Traverse the list of connected nodes */
02259          j = 0;
02260          l = myrpt->links.next;
02261          while(l && (l != &myrpt->links)){
02262             if (l->name[0] == '0'){ /* Skip '0' nodes */
02263                l = l->next;
02264                continue;
02265             }
02266             if((s = (struct rpt_lstat *) malloc(sizeof(struct rpt_lstat))) == NULL){
02267                ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
02268                rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02269                return RESULT_FAILURE;
02270             }
02271             memset(s, 0, sizeof(struct rpt_lstat));
02272             strncpy(s->name, l->name, MAXREMSTR - 1);
02273             if (l->chan) pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
02274             else strcpy(s->peer,"(none)");
02275             s->mode = l->mode;
02276             s->outbound = l->outbound;
02277             s->reconnects = l->reconnects;
02278             s->connecttime = l->connecttime;
02279             s->thisconnected = l->thisconnected;
02280             memcpy(s->chan_stat,l->chan_stat,NRPTSTAT * sizeof(struct rpt_chan_stat));
02281             insque((struct qelem *) s, (struct qelem *) s_head.next);
02282             memset(l->chan_stat,0,NRPTSTAT * sizeof(struct rpt_chan_stat));
02283             l = l->next;
02284          }
02285          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02286          ast_cli(fd, "NODE      PEER                RECONNECTS  DIRECTION  CONNECT TIME        CONNECT STATE\n");
02287          ast_cli(fd, "----      ----                ----------  ---------  ------------        -------------\n");
02288 
02289          for(s = s_head.next; s != &s_head; s = s->next){
02290             int hours, minutes, seconds;
02291             long long connecttime = s->connecttime;
02292             char conntime[21];
02293             hours = (int) connecttime/3600000;
02294             connecttime %= 3600000;
02295             minutes = (int) connecttime/60000;
02296             connecttime %= 60000;
02297             seconds = (int)  connecttime/1000;
02298             connecttime %= 1000;
02299             snprintf(conntime, 20, "%02d:%02d:%02d.%d",
02300                hours, minutes, seconds, (int) connecttime);
02301             conntime[20] = 0;
02302             if(s->thisconnected)
02303                connstate  = "ESTABLISHED";
02304             else
02305                connstate = "CONNECTING";
02306             ast_cli(fd, "%-10s%-20s%-12d%-11s%-20s%-20s\n",
02307                s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime, connstate);
02308          }  
02309          /* destroy our local link queue */
02310          s = s_head.next;
02311          while(s != &s_head){
02312             t = s;
02313             s = s->next;
02314             remque((struct qelem *)t);
02315             free(t);
02316          }        
02317          return RESULT_SUCCESS;
02318       }
02319    }
02320    return RESULT_FAILURE;
02321 }
02322 
02323 /*
02324 * List all nodes connected, directly or indirectly
02325 */
02326 
02327 static int rpt_do_nodes(int fd, int argc, char *argv[])
02328 {
02329    int i,j;
02330    char ns;
02331    char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
02332    struct rpt *myrpt;
02333    if(argc != 3)
02334       return RESULT_SHOWUSAGE;
02335 
02336    for(i = 0; i < nrpts; i++)
02337    {
02338       if (!strcmp(argv[2],rpt_vars[i].name)){
02339          /* Make a copy of all stat variables while locked */
02340          myrpt = &rpt_vars[i];
02341          rpt_mutex_lock(&myrpt->lock); /* LOCK */
02342          __mklinklist(myrpt,NULL,lbuf);
02343          rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
02344          /* parse em */
02345          ns = finddelim(lbuf,strs,MAXLINKLIST);
02346          /* sort em */
02347          if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
02348          ast_cli(fd,"\n");
02349          ast_cli(fd, "************************* CONNECTED NODES *************************\n\n");
02350          for(j = 0 ;; j++){
02351             if(!strs[j]){
02352                if(!j){
02353                   ast_cli(fd,"<NONE>");
02354                }
02355                break;
02356             }
02357             ast_cli(fd, "%s", strs[j]);
02358             if(j % 8 == 7){
02359                ast_cli(fd, "\n");
02360             }
02361             else{
02362                if(strs[j + 1])
02363                   ast_cli(fd, ", ");
02364             }
02365          }
02366          ast_cli(fd,"\n\n");
02367          return RESULT_SUCCESS;
02368       }
02369    }
02370    return RESULT_FAILURE;
02371 }
02372 
02373 /*
02374 * reload vars 
02375 */
02376 
02377 static int rpt_do_reload(int fd, int argc, char *argv[])
02378 {
02379 int   n;
02380 
02381         if (argc > 2) return RESULT_SHOWUSAGE;
02382 
02383    for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
02384 
02385    return RESULT_FAILURE;
02386 }
02387 
02388 /*
02389 * restart app_rpt
02390 */
02391                                                                                                                                  
02392 static int rpt_do_restart(int fd, int argc, char *argv[])
02393 {
02394 int   i;
02395 
02396         if (argc > 2) return RESULT_SHOWUSAGE;
02397    for(i = 0; i < nrpts; i++)
02398    {
02399       if (rpt_vars[i].rxchannel) ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
02400    }
02401    return RESULT_FAILURE;
02402 }
02403 
02404 
02405 /*
02406 * send an app_rpt DTMF function from the CLI
02407 */
02408                                                                                                                                  
02409 static int rpt_do_fun(int fd, int argc, char *argv[])
02410 {
02411    int   i,busy=0;
02412 
02413         if (argc != 4) return RESULT_SHOWUSAGE;
02414 
02415    for(i = 0; i < nrpts; i++){
02416       if(!strcmp(argv[2], rpt_vars[i].name)){
02417          struct rpt *myrpt = &rpt_vars[i];
02418          rpt_mutex_lock(&myrpt->lock);
02419          if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(argv[3])){
02420             rpt_mutex_unlock(&myrpt->lock);
02421             busy=1;
02422          }
02423          if(!busy){
02424             myrpt->macrotimer = MACROTIME;
02425             strncat(myrpt->macrobuf, argv[3], MAXMACRO - strlen(myrpt->macrobuf) - 1);
02426          }
02427          rpt_mutex_unlock(&myrpt->lock);
02428       }
02429    }
02430    if(busy){
02431       ast_cli(fd, "Function decoder busy");
02432    }
02433    return RESULT_FAILURE;
02434 }
02435 
02436 
02437 
02438 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
02439 {
02440    int res;
02441 
02442         if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
02443                 return res;
02444                                                                                                                                             
02445         while(chan->generatordata) {
02446       if (ast_safe_sleep(chan,1)) return -1;
02447    }
02448 
02449         return 0;
02450 }
02451 
02452 static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
02453 {
02454    return play_tone_pair(chan, freq, 0, duration, amplitude);
02455 }
02456 
02457 static int play_silence(struct ast_channel *chan, int duration)
02458 {
02459    return play_tone_pair(chan, 0, 0, duration, 0);
02460 }
02461 
02462 
02463 static int send_morse(struct ast_channel *chan, char *string, int speed, int freq, int amplitude)
02464 {
02465 
02466 static struct morse_bits mbits[] = {
02467       {0, 0}, /* SPACE */
02468       {0, 0}, 
02469       {6, 18},/* " */
02470       {0, 0},
02471       {7, 72},/* $ */
02472       {0, 0},
02473       {0, 0},
02474       {6, 30},/* ' */
02475       {5, 13},/* ( */
02476       {6, 29},/* ) */
02477       {0, 0},
02478       {5, 10},/* + */
02479       {6, 51},/* , */
02480       {6, 33},/* - */
02481       {6, 42},/* . */
02482       {5, 9}, /* / */
02483       {5, 31},/* 0 */
02484       {5, 30},/* 1 */
02485       {5, 28},/* 2 */
02486       {5, 24},/* 3 */
02487       {5, 16},/* 4 */
02488       {5, 0}, /* 5 */
02489       {5, 1}, /* 6 */
02490       {5, 3}, /* 7 */
02491       {5, 7}, /* 8 */
02492       {5, 15},/* 9 */
02493       {6, 7}, /* : */
02494       {6, 21},/* ; */
02495       {0, 0},
02496       {5, 33},/* = */
02497       {0, 0},
02498       {6, 12},/* ? */
02499       {0, 0},
02500          {2, 2}, /* A */
02501       {4, 1}, /* B */
02502       {4, 5}, /* C */
02503       {3, 1}, /* D */
02504       {1, 0}, /* E */
02505       {4, 4}, /* F */
02506       {3, 3}, /* G */
02507       {4, 0}, /* H */
02508       {2, 0}, /* I */
02509       {4, 14},/* J */
02510       {3, 5}, /* K */
02511       {4, 2}, /* L */
02512       {2, 3}, /* M */
02513       {2, 1}, /* N */
02514       {3, 7}, /* O */
02515       {4, 6}, /* P */
02516       {4, 11},/* Q */
02517       {3, 2}, /* R */
02518       {3, 0}, /* S */
02519       {1, 1}, /* T */
02520       {3, 4}, /* U */
02521       {4, 8}, /* V */
02522       {3, 6}, /* W */
02523       {4, 9}, /* X */
02524       {4, 13},/* Y */
02525       {4, 3}  /* Z */
02526    };
02527 
02528 
02529    int dottime;
02530    int dashtime;
02531    int intralettertime;
02532    int interlettertime;
02533    int interwordtime;
02534    int len, ddcomb;
02535    int res;
02536    int c;
02537    int i;
02538    int flags;
02539          
02540    res = 0;
02541    
02542    /* Approximate the dot time from the speed arg. */
02543    
02544    dottime = 900/speed;
02545    
02546    /* Establish timing releationships */
02547    
02548    dashtime = 3 * dottime;
02549    intralettertime = dottime;
02550    interlettertime = dottime * 4 ;
02551    interwordtime = dottime * 7;
02552    
02553    for(;(*string) && (!res); string++){
02554    
02555       c = *string;
02556       
02557       /* Convert lower case to upper case */
02558       
02559       if((c >= 'a') && (c <= 'z'))
02560          c -= 0x20;
02561       
02562       /* Can't deal with any char code greater than Z, skip it */
02563       
02564       if(c  > 'Z')
02565          continue;
02566       
02567       /* If space char, wait the inter word time */
02568                
02569       if(c == ' '){
02570          if(!res)
02571             res = play_silence(chan, interwordtime);
02572          continue;
02573       }
02574       
02575       /* Subtract out control char offset to match our table */
02576       
02577       c -= 0x20;
02578       
02579       /* Get the character data */
02580       
02581       len = mbits[c].len;
02582       ddcomb = mbits[c].ddcomb;
02583       
02584       /* Send the character */
02585       
02586       for(; len ; len--){
02587          if(!res)
02588             res = play_tone(chan, freq, (ddcomb & 1) ? dashtime : dottime, amplitude);
02589          if(!res)
02590             res = play_silence(chan, intralettertime);
02591          ddcomb >>= 1;
02592       }
02593       
02594       /* Wait the interletter time */
02595       
02596       if(!res)
02597          res = play_silence(chan, interlettertime - intralettertime);
02598    }
02599    
02600    /* Wait for all the frames to be sent */
02601    
02602    if (!res) 
02603       res = ast_waitstream(chan, "");
02604    ast_stopstream(chan);
02605    
02606    /*
02607    * Wait for the zaptel driver to physically write the tone blocks to the hardware
02608    */
02609 
02610    for(i = 0; i < 20 ; i++){
02611       flags =  DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT; 
02612       res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
02613       if(flags & DAHDI_IOMUX_WRITEEMPTY)
02614          break;
02615       if( ast_safe_sleep(chan, 50)){
02616          res = -1;
02617          break;
02618       }
02619    }
02620 
02621    
02622    return res;
02623 }
02624 
02625 static int send_tone_telemetry(struct ast_channel *chan, char *tonestring)
02626 {
02627    char *stringp;
02628    char *tonesubset;
02629    int f1,f2;
02630    int duration;
02631    int amplitude;
02632    int res;
02633    int i;
02634    int flags;
02635    
02636    res = 0;
02637    
02638    stringp = ast_strdupa(tonestring);
02639 
02640    for(;tonestring;){
02641       tonesubset = strsep(&stringp,")");
02642       if(!tonesubset)
02643          break;
02644       if(sscanf(tonesubset,"(%d,%d,%d,%d", &f1, &f2, &duration, &amplitude) != 4)
02645          break;
02646       res = play_tone_pair(chan, f1, f2, duration, amplitude);
02647       if(res)
02648          break;
02649    }
02650    if(!res)
02651       res = play_tone_pair(chan, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
02652    
02653    if (!res) 
02654       res = ast_waitstream(chan, "");
02655    ast_stopstream(chan);
02656 
02657    /*
02658    * Wait for the zaptel driver to physically write the tone blocks to the hardware
02659    */
02660 
02661    for(i = 0; i < 20 ; i++){
02662       flags =  DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT; 
02663       res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
02664       if(flags & DAHDI_IOMUX_WRITEEMPTY)
02665          break;
02666       if( ast_safe_sleep(chan, 50)){
02667          res = -1;
02668          break;
02669       }
02670    }
02671       
02672    return res;
02673       
02674 }
02675 
02676 static int sayfile(struct ast_channel *mychannel,char *fname)
02677 {
02678 int   res;
02679 
02680    res = ast_streamfile(mychannel, fname, mychannel->language);
02681    if (!res) 
02682       res = ast_waitstream(mychannel, "");
02683    else
02684        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02685    ast_stopstream(mychannel);
02686    return res;
02687 }
02688 
02689 static int saycharstr(struct ast_channel *mychannel,char *str)
02690 {
02691 int   res;
02692 
02693    res = ast_say_character_str(mychannel,str,NULL,mychannel->language);
02694    if (!res) 
02695       res = ast_waitstream(mychannel, "");
02696    else
02697        ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02698    ast_stopstream(mychannel);
02699    return res;
02700 }
02701 
02702 static int saynum(struct ast_channel *mychannel, int num)
02703 {
02704    int res;
02705    res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
02706    if(!res)
02707       res = ast_waitstream(mychannel, "");
02708    else
02709       ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02710    ast_stopstream(mychannel);
02711    return res;
02712 }
02713 
02714 
02715 static int telem_any(struct rpt *myrpt,struct ast_channel *chan, char *entry)
02716 {
02717    int res;
02718    char c;
02719    
02720    static int morsespeed;
02721    static int morsefreq;
02722    static int morseampl;
02723    static int morseidfreq = 0;
02724    static int morseidampl;
02725    static char mcat[] = MORSE;
02726    
02727    res = 0;
02728    
02729    if(!morseidfreq){ /* Get the morse parameters if not already loaded */
02730       morsespeed = retrieve_astcfgint(myrpt, mcat, "speed", 5, 20, 20);
02731          morsefreq = retrieve_astcfgint(myrpt, mcat, "frequency", 300, 3000, 800);
02732          morseampl = retrieve_astcfgint(myrpt, mcat, "amplitude", 200, 8192, 4096);
02733       morseidampl = retrieve_astcfgint(myrpt, mcat, "idamplitude", 200, 8192, 2048);
02734       morseidfreq = retrieve_astcfgint(myrpt, mcat, "idfrequency", 300, 3000, 330); 
02735    }
02736    
02737    /* Is it a file, or a tone sequence? */
02738          
02739    if(entry[0] == '|'){
02740       c = entry[1];
02741       if((c >= 'a')&&(c <= 'z'))
02742          c -= 0x20;
02743    
02744       switch(c){
02745          case 'I': /* Morse ID */
02746             res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
02747             break;
02748          
02749          case 'M': /* Morse Message */
02750             res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
02751             break;
02752          
02753          case 'T': /* Tone sequence */
02754             res = send_tone_telemetry(chan, entry + 2);
02755             break;
02756          default:
02757             res = -1;
02758       }
02759    }
02760    else
02761       res = sayfile(chan, entry); /* File */
02762    return res;
02763 }
02764 
02765 /*
02766 * This function looks up a telemetry name in the config file, and does a telemetry response as configured.
02767 *
02768 * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
02769 */
02770 
02771 static int telem_lookup(struct rpt *myrpt,struct ast_channel *chan, char *node, char *name)
02772 {
02773    
02774    int res;
02775    int i;
02776    char *entry;
02777    char *telemetry;
02778    char *telemetry_save;
02779 
02780    res = 0;
02781    telemetry_save = NULL;
02782    entry = NULL;
02783    
02784    /* Retrieve the section name for telemetry from the node section */
02785    telemetry = (char *) ast_variable_retrieve(myrpt->cfg, node, TELEMETRY);
02786    if(telemetry ){
02787       telemetry_save = ast_strdupa(telemetry);
02788       if(!telemetry_save){
02789          ast_log(LOG_WARNING,"ast_strdupa() failed in telem_lookup()\n");
02790          return res;
02791       }
02792       entry = (char *) ast_variable_retrieve(myrpt->cfg, telemetry_save, name);
02793    }
02794    
02795    /* Try to look up the telemetry name */   
02796 
02797    if(!entry){
02798       /* Telemetry name wasn't found in the config file, use the default */
02799       for(i = 0; i < sizeof(tele_defs)/sizeof(struct telem_defaults) ; i++){
02800          if(!strcasecmp(tele_defs[i].name, name))
02801             entry = tele_defs[i].value;
02802       }
02803    }
02804    if(entry){  
02805       if(strlen(entry))
02806          telem_any(myrpt,chan, entry);
02807    }
02808    else{
02809       res = -1;
02810    }
02811    return res;
02812 }
02813 
02814 /*
02815 * Retrieve a wait interval
02816 */
02817 
02818 static int get_wait_interval(struct rpt *myrpt, int type)
02819 {
02820         int interval;
02821         char *wait_times;
02822         char *wait_times_save;
02823                                                                                                                   
02824         wait_times_save = NULL;
02825         wait_times = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
02826                                                                                                                   
02827         if(wait_times){
02828                 wait_times_save = ast_strdupa(wait_times);
02829                 if(!wait_times_save){
02830                         ast_log(LOG_WARNING, "Out of memory in wait_interval()\n");
02831                         wait_times = NULL;
02832                 }
02833         }
02834                                                                                                                   
02835         switch(type){
02836                 case DLY_TELEM:
02837                         if(wait_times)
02838                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "telemwait", 500, 5000, 1000);
02839                         else
02840                                 interval = 1000;
02841                         break;
02842                                                                                                                   
02843                 case DLY_ID:
02844                         if(wait_times)
02845                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "idwait",250,5000,500);
02846                         else
02847                                 interval = 500;
02848                         break;
02849                                                                                                                   
02850                 case DLY_UNKEY:
02851                         if(wait_times)
02852                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "unkeywait",500,5000,1000);
02853                         else
02854                                 interval = 1000;
02855                         break;
02856                                                                                                                   
02857                 case DLY_LINKUNKEY:
02858                         if(wait_times)
02859                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "linkunkeywait",500,5000,1000);
02860                         else
02861                                 interval = 1000;
02862                         break;
02863                                                                                                                   
02864                 case DLY_CALLTERM:
02865                         if(wait_times)
02866                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "calltermwait",500,5000,1500);
02867                         else
02868                                 interval = 1500;
02869                         break;
02870                                                                                                                   
02871                 case DLY_COMP:
02872                         if(wait_times)
02873                                 interval = retrieve_astcfgint(myrpt,wait_times_save, "compwait",500,5000,200);
02874                         else
02875                                 interval = 200;
02876                         break;
02877                                                                                                                   
02878                 default:
02879                         return 0;
02880         }
02881    return interval;
02882 }                                                                                                                  
02883 
02884 
02885 /*
02886 * Wait a configurable interval of time 
02887 */
02888 
02889 
02890 static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
02891 {
02892    int interval;
02893    interval = get_wait_interval(myrpt, type);
02894    if(debug)
02895       ast_log(LOG_NOTICE," Delay interval = %d\n", interval);
02896    if(interval)
02897       ast_safe_sleep(chan,interval);
02898    if(debug)
02899       ast_log(LOG_NOTICE,"Delay complete\n");
02900    return;
02901 }
02902 
02903 static int split_freq(char *mhz, char *decimals, char *freq);
02904 
02905 static void *rpt_tele_thread(void *this)
02906 {
02907 struct dahdi_confinfo ci;  /* conference info */
02908 int   res = 0,haslink,hastx,hasremote,imdone = 0, unkeys_queued, x;
02909 struct   rpt_tele *mytele = (struct rpt_tele *)this;
02910 struct  rpt_tele *tlist;
02911 struct   rpt *myrpt;
02912 struct   rpt_link *l,*l1,linkbase;
02913 struct   ast_channel *mychannel;
02914 int vmajor, vminor, m;
02915 char *p,*ct,*ct_copy,*ident, *nodename,*cp;
02916 time_t t;
02917 struct tm localtm;
02918 char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
02919 int   i,ns,rbimode;
02920 char mhz[MAXREMSTR];
02921 char decimals[MAXREMSTR];
02922 struct dahdi_params par;
02923 
02924 
02925    /* get a pointer to myrpt */
02926    myrpt = mytele->rpt;
02927 
02928    /* Snag copies of a few key myrpt variables */
02929    rpt_mutex_lock(&myrpt->lock);
02930    nodename = ast_strdupa(myrpt->name);
02931    if (myrpt->p.ident) ident = ast_strdupa(myrpt->p.ident);
02932    else ident = "";
02933    rpt_mutex_unlock(&myrpt->lock);
02934    
02935    /* allocate a pseudo-channel thru asterisk */
02936    mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
02937    if (!mychannel)
02938    {
02939       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
02940       rpt_mutex_lock(&myrpt->lock);
02941       remque((struct qelem *)mytele);
02942       ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
02943       rpt_mutex_unlock(&myrpt->lock);
02944       free(mytele);     
02945       pthread_exit(NULL);
02946    }
02947 #ifdef   AST_CDR_FLAG_POST_DISABLED
02948    ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
02949 #endif
02950    rpt_mutex_lock(&myrpt->lock);
02951    mytele->chan = mychannel;
02952    rpt_mutex_unlock(&myrpt->lock);
02953    /* make a conference for the tx */
02954    ci.chan = 0;
02955    /* If there's an ID queued, or tail message queued, */
02956    /* only connect the ID audio to the local tx conference so */
02957    /* linked systems can't hear it */
02958    ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) || 
02959       (mytele->mode == TAILMSG) || (mytele->mode == LINKUNKEY)) || (mytele->mode == TIMEOUT) ?
02960          myrpt->txconf : myrpt->conf);
02961    ci.confmode = DAHDI_CONF_CONFANN;
02962    /* first put the channel on the conference in announce mode */
02963    if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
02964    {
02965       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02966       rpt_mutex_lock(&myrpt->lock);
02967       remque((struct qelem *)mytele);
02968       rpt_mutex_unlock(&myrpt->lock);
02969       ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
02970       free(mytele);     
02971       ast_hangup(mychannel);
02972       pthread_exit(NULL);
02973    }
02974    ast_stopstream(mychannel);
02975    switch(mytele->mode)
02976    {
02977        case ID:
02978        case ID1:
02979       /* wait a bit */
02980       wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM,mychannel);
02981       res = telem_any(myrpt,mychannel, ident); 
02982       imdone=1;   
02983       break;
02984       
02985        case TAILMSG:
02986       res = ast_streamfile(mychannel, myrpt->p.tailmessages[myrpt->tailmessagen], mychannel->language); 
02987       break;
02988       
02989        case IDTALKOVER:
02990          p = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "idtalkover");
02991          if(p)
02992          res = telem_any(myrpt,mychannel, p); 
02993       imdone=1;   
02994          break;
02995             
02996        case PROC:
02997       /* wait a little bit longer */
02998       wait_interval(myrpt, DLY_TELEM, mychannel);
02999       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchup");
03000       if(res < 0){ /* Then default message */
03001          res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
03002       }
03003       break;
03004        case TERM:
03005       /* wait a little bit longer */
03006       wait_interval(myrpt, DLY_CALLTERM, mychannel);
03007       res = telem_lookup(myrpt, mychannel, myrpt->name, "patchdown");
03008       if(res < 0){ /* Then default message */
03009          res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
03010       }
03011       break;
03012        case COMPLETE:
03013       /* wait a little bit */
03014       wait_interval(myrpt, DLY_TELEM, mychannel);
03015       res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
03016       break;
03017        case MACRO_NOTFOUND:
03018       /* wait a little bit */
03019       wait_interval(myrpt, DLY_TELEM, mychannel);
03020       res = ast_streamfile(mychannel, "rpt/macro_notfound", mychannel->language);
03021       break;
03022        case MACRO_BUSY:
03023       /* wait a little bit */
03024       wait_interval(myrpt, DLY_TELEM, mychannel);
03025       res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
03026       break;
03027        case UNKEY:
03028       if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
03029          imdone = 1;
03030          break;
03031       }
03032          
03033       /*
03034       * Reset the Unkey to CT timer
03035       */
03036 
03037       x = get_wait_interval(myrpt, DLY_UNKEY);
03038       rpt_mutex_lock(&myrpt->lock);
03039       myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
03040       rpt_mutex_unlock(&myrpt->lock);
03041 
03042       /*
03043       * If there's one already queued, don't do another
03044       */
03045 
03046       tlist = myrpt->tele.next;
03047       unkeys_queued = 0;
03048                 if (tlist != &myrpt->tele)
03049                 {
03050                         rpt_mutex_lock(&myrpt->lock);
03051                         while(tlist != &myrpt->tele){
03052                                 if (tlist->mode == UNKEY) unkeys_queued++;
03053                                 tlist = tlist->next;
03054                         }
03055                         rpt_mutex_unlock(&myrpt->lock);
03056       }
03057       if( unkeys_queued > 1){
03058          imdone = 1;
03059          break;
03060       }
03061 
03062       /* Wait for the telemetry timer to expire */
03063       /* Periodically check the timer since it can be re-initialized above */
03064       while(myrpt->unkeytocttimer)
03065       {
03066          int ctint;
03067          if(myrpt->unkeytocttimer > 100)
03068             ctint = 100;
03069          else
03070             ctint = myrpt->unkeytocttimer;
03071          ast_safe_sleep(mychannel, ctint);
03072          rpt_mutex_lock(&myrpt->lock);
03073          if(myrpt->unkeytocttimer < ctint)
03074             myrpt->unkeytocttimer = 0;
03075          else
03076             myrpt->unkeytocttimer -= ctint;
03077          rpt_mutex_unlock(&myrpt->lock);
03078       }
03079    
03080       /*
03081       * Now, the carrier on the rptr rx should be gone. 
03082       * If it re-appeared, then forget about sending the CT
03083       */
03084       if(myrpt->keyed){
03085          imdone = 1;
03086          break;
03087       }
03088       
03089       rpt_mutex_lock(&myrpt->lock); /* Update the kerchunk counters */
03090       myrpt->dailykerchunks++;
03091       myrpt->totalkerchunks++;
03092       rpt_mutex_unlock(&myrpt->lock);
03093    
03094       haslink = 0;
03095       hastx = 0;
03096       hasremote = 0;    
03097       l = myrpt->links.next;
03098       if (l != &myrpt->links)
03099       {
03100          rpt_mutex_lock(&myrpt->lock);
03101          while(l != &myrpt->links)
03102          {
03103             if (l->name[0] == '0')
03104             {
03105                l = l->next;
03106                continue;
03107             }
03108             haslink = 1;
03109             if (l->mode) {
03110                hastx++;
03111                if (l->isremote) hasremote++;
03112             }
03113             l = l->next;
03114          }
03115          rpt_mutex_unlock(&myrpt->lock);
03116       }
03117       if (haslink)
03118       {
03119 
03120          res = telem_lookup(myrpt,mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
03121          if(res)
03122             ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
03123          
03124       
03125          /* if in remote cmd mode, indicate it */
03126          if (myrpt->cmdnode[0])
03127          {
03128             ast_safe_sleep(mychannel,200);
03129             res = telem_lookup(myrpt,mychannel, myrpt->name, "cmdmode");
03130             if(res)
03131                ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
03132             ast_stopstream(mychannel);
03133          }
03134       }
03135       else if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */
03136          ct_copy = ast_strdupa(ct);
03137          res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
03138          if(res)
03139             ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
03140       }  
03141       if (hasremote && (!myrpt->cmdnode[0]))
03142       {
03143          /* set for all to hear */
03144          ci.chan = 0;
03145          ci.confno = myrpt->conf;
03146          ci.confmode = DAHDI_CONF_CONFANN;
03147          /* first put the channel on the conference in announce mode */
03148          if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
03149          {
03150             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
03151             rpt_mutex_lock(&myrpt->lock);
03152             remque((struct qelem *)mytele);
03153             rpt_mutex_unlock(&myrpt->lock);
03154             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
03155             free(mytele);     
03156             ast_hangup(mychannel);
03157             pthread_exit(NULL);
03158          }
03159          if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
03160             ast_safe_sleep(mychannel,200);
03161             ct_copy = ast_strdupa(ct);
03162             res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
03163             if(res)
03164                ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
03165          }  
03166       }
03167 #if   defined(_MDC_DECODE_H_) && defined(MDC_SAY_WHEN_DOING_CT)
03168       if (myrpt->lastunit)
03169       {
03170          char mystr[10];
03171 
03172          ast_safe_sleep(mychannel,200);
03173          /* set for all to hear */
03174          ci.chan = 0;
03175          ci.confno = myrpt->txconf;
03176          ci.confmode = DAHDI_CONF_CONFANN;
03177          /* first put the channel on the conference in announce mode */
03178          if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
03179          {
03180             ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
03181             rpt_mutex_lock(&myrpt->lock);
03182             remque((struct qelem *)mytele);
03183             rpt_mutex_unlock(&myrpt->lock);
03184             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
03185             free(mytele);     
03186             ast_hangup(mychannel);
03187             pthread_exit(NULL);
03188          }
03189          sprintf(mystr,"%04x",myrpt->lastunit);
03190          myrpt->lastunit = 0;
03191          ast_say_character_str(mychannel,mystr,NULL,mychannel->language);
03192          break;
03193       }
03194 #endif
03195       imdone = 1;
03196       break;
03197        case LINKUNKEY:
03198       if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
03199          imdone = 1;
03200          break;
03201       }
03202          
03203       /*
03204       * Reset the Unkey to CT timer
03205       */
03206 
03207       x = get_wait_interval(myrpt, DLY_LINKUNKEY);
03208       mytele->mylink.linkunkeytocttimer = x; /* Must be protected as it is changed below */
03209 
03210       /*
03211       * If there's one already queued, don't do another
03212       */
03213 
03214       tlist = myrpt->tele.next;
03215       unkeys_queued = 0;
03216                 if (tlist != &myrpt->tele)
03217                 {
03218                         rpt_mutex_lock(&myrpt->lock);
03219                         while(tlist != &myrpt->tele){
03220                                 if (tlist->mode == LINKUNKEY) unkeys_queued++;
03221                                 tlist = tlist->next;
03222                         }
03223                         rpt_mutex_unlock(&myrpt->lock);
03224       }
03225       if( unkeys_queued > 1){
03226          imdone = 1;
03227          break;
03228       }
03229 
03230       /* Wait for the telemetry timer to expire */
03231       /* Periodically check the timer since it can be re-initialized above */
03232       while(mytele->mylink.linkunkeytocttimer)
03233       {
03234          int ctint;
03235          if(mytele->mylink.linkunkeytocttimer > 100)
03236             ctint = 100;
03237          else
03238             ctint = mytele->mylink.linkunkeytocttimer;
03239          ast_safe_sleep(mychannel, ctint);
03240          rpt_mutex_lock(&myrpt->lock);
03241          if(mytele->mylink.linkunkeytocttimer < ctint)
03242             mytele->mylink.linkunkeytocttimer = 0;
03243          else
03244             mytele->mylink.linkunkeytocttimer -= ctint;
03245          rpt_mutex_unlock(&myrpt->lock);
03246       }
03247    
03248       if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "linkunkeyct"))){ /* Unlinked Courtesy Tone */
03249          ct_copy = ast_strdupa(ct);
03250          res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
03251          if(res)
03252             ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);     
03253       }  
03254       imdone = 1;
03255       break;
03256        case REMDISC:
03257       /* wait a little bit */
03258       wait_interval(myrpt, DLY_TELEM, mychannel);
03259       l = myrpt->links.next;
03260       haslink = 0;
03261       /* dont report if a link for this one still on system */
03262       if (l != &myrpt->links)
03263       {
03264          rpt_mutex_lock(&myrpt->lock);
03265          while(l != &myrpt->links)
03266          {
03267             if (l->name[0] == '0')
03268             {
03269                l = l->next;
03270                continue;
03271             }
03272             if (!strcmp(l->name,mytele->mylink.name))
03273             {
03274                haslink = 1;
03275                break;
03276             }
03277             l = l->next;
03278          }
03279          rpt_mutex_unlock(&myrpt->lock);
03280       }
03281       if (haslink)
03282       {
03283          imdone = 1;
03284          break;
03285       }
03286       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03287       if (!res) 
03288          res = ast_waitstream(mychannel, "");
03289       else
03290           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03291       ast_stopstream(mychannel);
03292       ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
03293       res = ast_streamfile(mychannel, ((mytele->mylink.hasconnected) ? 
03294          "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
03295       break;
03296        case REMALREADY:
03297       /* wait a little bit */
03298       wait_interval(myrpt, DLY_TELEM, mychannel);
03299       res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
03300       break;
03301        case REMNOTFOUND:
03302       /* wait a little bit */
03303       wait_interval(myrpt, DLY_TELEM, mychannel);
03304       res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
03305       break;
03306        case REMGO:
03307       /* wait a little bit */
03308       wait_interval(myrpt, DLY_TELEM, mychannel);
03309       res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
03310       break;
03311        case CONNECTED:
03312       /* wait a little bit */
03313       wait_interval(myrpt, DLY_TELEM,  mychannel);
03314       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03315       if (!res) 
03316          res = ast_waitstream(mychannel, "");
03317       else
03318           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03319       ast_stopstream(mychannel);
03320       ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
03321       res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
03322       if (!res) 
03323          res = ast_waitstream(mychannel, "");
03324       else
03325           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03326       ast_stopstream(mychannel);
03327       res = ast_streamfile(mychannel, "digits/2", mychannel->language);
03328       if (!res) 
03329          res = ast_waitstream(mychannel, "");
03330       else
03331           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03332       ast_stopstream(mychannel);
03333       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03334       if (!res) 
03335          res = ast_waitstream(mychannel, "");
03336       else
03337           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03338       ast_stopstream(mychannel);
03339       ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
03340       imdone = 1;
03341       break;
03342        case CONNFAIL:
03343       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03344       if (!res) 
03345          res = ast_waitstream(mychannel, "");
03346       else
03347           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03348       ast_stopstream(mychannel);
03349       ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
03350       res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
03351       break;
03352        case MEMNOTFOUND:
03353       /* wait a little bit */
03354       wait_interval(myrpt, DLY_TELEM, mychannel);
03355       res = ast_streamfile(mychannel, "rpt/memory_notfound", mychannel->language);
03356       break;
03357        case SETREMOTE:
03358       ast_mutex_lock(&myrpt->remlock);
03359       res = 0;
03360       if(!strcmp(myrpt->remote, remote_rig_ft897))
03361       {
03362          res = set_ft897(myrpt);
03363       }
03364       if(!strcmp(myrpt->remote, remote_rig_ic706))
03365       {
03366          res = set_ic706(myrpt);
03367       }
03368 #ifdef HAVE_IOPERM
03369       else if(!strcmp(myrpt->remote, remote_rig_rbi))
03370       {
03371          if (ioperm(myrpt->p.iobase,1,1) == -1)
03372          {
03373             rpt_mutex_unlock(&myrpt->lock);
03374             ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
03375             res = -1;
03376          }
03377          else res = setrbi(myrpt);
03378       }
03379 #endif
03380       else if(!strcmp(myrpt->remote, remote_rig_kenwood))
03381       {
03382          res = setkenwood(myrpt);
03383          if (ast_safe_sleep(mychannel,200) == -1)
03384          {
03385             ast_mutex_unlock(&myrpt->remlock);
03386             res = -1;
03387             break;
03388          }
03389          i = DAHDI_FLUSH_EVENT;
03390          if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_FLUSH,&i) == -1)
03391          {
03392             ast_mutex_unlock(&myrpt->remlock);
03393             ast_log(LOG_ERROR,"Cant flush events");
03394             res = -1;
03395             break;
03396          }
03397          if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_GET_PARAMS,&par) == -1)
03398          {
03399             ast_mutex_unlock(&myrpt->remlock);
03400             ast_log(LOG_ERROR,"Cant get params");
03401             res = -1;
03402             break;
03403          }
03404          myrpt->remoterx = 
03405             (par.rxisoffhook || (myrpt->tele.next != &myrpt->tele));
03406       }
03407       ast_mutex_unlock(&myrpt->remlock);
03408       if (!res)
03409       {
03410          imdone = 1;
03411          break;
03412       }
03413       /* fall thru to invalid freq */
03414        case INVFREQ:
03415       /* wait a little bit */
03416       wait_interval(myrpt, DLY_TELEM, mychannel);
03417       res = ast_streamfile(mychannel, "rpt/invalid-freq", mychannel->language);
03418       break;
03419        case REMMODE:
03420       cp = 0;
03421       wait_interval(myrpt, DLY_TELEM, mychannel);
03422       switch(myrpt->remmode)
03423       {
03424           case REM_MODE_FM:
03425          saycharstr(mychannel,"FM");
03426          break;
03427           case REM_MODE_USB:
03428          saycharstr(mychannel,"USB");
03429          break;
03430           case REM_MODE_LSB:
03431          saycharstr(mychannel,"LSB");
03432          break;
03433           case REM_MODE_AM:
03434          saycharstr(mychannel,"AM");
03435          break;
03436       }
03437       wait_interval(myrpt, DLY_COMP, mychannel);
03438       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
03439       break;
03440        case LOGINREQ:
03441       wait_interval(myrpt, DLY_TELEM, mychannel);
03442       sayfile(mychannel,"rpt/login");
03443       saycharstr(mychannel,myrpt->name);
03444       break;
03445        case REMLOGIN:
03446       wait_interval(myrpt, DLY_TELEM, mychannel);
03447       saycharstr(mychannel,myrpt->loginuser);
03448       sayfile(mychannel,"rpt/node");
03449       saycharstr(mychannel,myrpt->name);
03450       wait_interval(myrpt, DLY_COMP, mychannel);
03451       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
03452       break;
03453        case REMXXX:
03454       wait_interval(myrpt, DLY_TELEM, mychannel);
03455       res = 0;
03456       switch(mytele->submode)
03457       {
03458           case 100: /* RX PL Off */
03459          sayfile(mychannel, "rpt/rxpl");
03460          sayfile(mychannel, "rpt/off");
03461          break;
03462           case 101: /* RX PL On */
03463          sayfile(mychannel, "rpt/rxpl");
03464          sayfile(mychannel, "rpt/on");
03465          break;
03466           case 102: /* TX PL Off */
03467          sayfile(mychannel, "rpt/txpl");
03468          sayfile(mychannel, "rpt/off");
03469          break;
03470           case 103: /* TX PL On */
03471          sayfile(mychannel, "rpt/txpl");
03472          sayfile(mychannel, "rpt/on");
03473          break;
03474           case 104: /* Low Power */
03475          sayfile(mychannel, "rpt/lopwr");
03476          break;
03477           case 105: /* Medium Power */
03478          sayfile(mychannel, "rpt/medpwr");
03479          break;
03480           case 106: /* Hi Power */
03481          sayfile(mychannel, "rpt/hipwr");
03482          break;
03483           case 113: /* Scan down slow */
03484          sayfile(mychannel,"rpt/down");
03485          sayfile(mychannel, "rpt/slow");
03486          break;
03487           case 114: /* Scan down quick */
03488          sayfile(mychannel,"rpt/down");
03489          sayfile(mychannel, "rpt/quick");
03490          break;
03491           case 115: /* Scan down fast */
03492          sayfile(mychannel,"rpt/down");
03493          sayfile(mychannel, "rpt/fast");
03494          break;
03495           case 116: /* Scan up slow */
03496          sayfile(mychannel,"rpt/up");
03497          sayfile(mychannel, "rpt/slow");
03498          break;
03499           case 117: /* Scan up quick */
03500          sayfile(mychannel,"rpt/up");
03501          sayfile(mychannel, "rpt/quick");
03502          break;
03503           case 118: /* Scan up fast */
03504          sayfile(mychannel,"rpt/up");
03505          sayfile(mychannel, "rpt/fast");
03506          break;
03507           default:
03508          res = -1;
03509       }
03510       wait_interval(myrpt, DLY_COMP, mychannel);
03511       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
03512       break;
03513        case SCAN:
03514       ast_mutex_lock(&myrpt->remlock);
03515       if (myrpt->hfscanstop)
03516       {
03517          myrpt->hfscanstatus = 0;
03518          myrpt->hfscanmode = 0;
03519          myrpt->hfscanstop = 0;
03520          mytele->mode = SCANSTAT;
03521          ast_mutex_unlock(&myrpt->remlock);
03522          if (ast_safe_sleep(mychannel,1000) == -1) break;
03523          sayfile(mychannel, "rpt/stop"); 
03524          imdone = 1;
03525          break;
03526       }
03527       if (myrpt->hfscanstatus > -2) service_scan(myrpt);
03528       i = myrpt->hfscanstatus;
03529       myrpt->hfscanstatus = 0;
03530       if (i) mytele->mode = SCANSTAT;
03531       ast_mutex_unlock(&myrpt->remlock);
03532       if (i < 0) sayfile(mychannel, "rpt/stop"); 
03533       else if (i > 0) saynum(mychannel,i);
03534       imdone = 1;
03535       break;
03536        case TUNE:
03537       ast_mutex_lock(&myrpt->remlock);
03538       if (!strcmp(myrpt->remote,remote_rig_ic706))
03539       {
03540          set_mode_ic706(myrpt, REM_MODE_AM);
03541          if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
03542          ast_safe_sleep(mychannel,500);
03543          set_mode_ic706(myrpt, myrpt->remmode);
03544          myrpt->tunerequest = 0;
03545          ast_mutex_unlock(&myrpt->remlock);
03546          imdone = 1;
03547          break;
03548       }
03549       set_mode_ft897(myrpt, REM_MODE_AM);
03550       simple_command_ft897(myrpt, 8);
03551       if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
03552       simple_command_ft897(myrpt, 0x88);
03553       ast_safe_sleep(mychannel,500);
03554       set_mode_ft897(myrpt, myrpt->remmode);
03555       myrpt->tunerequest = 0;
03556       ast_mutex_unlock(&myrpt->remlock);
03557       imdone = 1;
03558       break;
03559        case REMSHORTSTATUS:
03560        case REMLONGSTATUS: 
03561       wait_interval(myrpt, DLY_TELEM, mychannel);
03562       res = sayfile(mychannel,"rpt/node");
03563       if(!res)
03564          res = saycharstr(mychannel, myrpt->name);
03565       if(!res)
03566          res = sayfile(mychannel,"rpt/frequency");
03567       if(!res)
03568          res = split_freq(mhz, decimals, myrpt->freq);
03569       if (!multimode_capable(myrpt)) decimals[3] = 0;
03570       if(!res){
03571          m = atoi(mhz);
03572          if(m < 100)
03573             res = saynum(mychannel, m);
03574          else
03575             res = saycharstr(mychannel, mhz);
03576       }
03577       if(!res)
03578          res = sayfile(mychannel, "letters/dot");
03579       if(!res)
03580          res = saycharstr(mychannel, decimals);
03581    
03582       if(res)  break;
03583       if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
03584          switch(myrpt->offset){
03585    
03586             case REM_MINUS:
03587                res = sayfile(mychannel,"rpt/minus");
03588                break;
03589             
03590             case REM_SIMPLEX:
03591                res = sayfile(mychannel,"rpt/simplex");
03592                break;
03593                
03594             case REM_PLUS:
03595                res = sayfile(mychannel,"rpt/plus");
03596                break;
03597                
03598             default:
03599                break;
03600          }
03601       }
03602       else{ /* Must be USB, LSB, or AM */
03603          switch(myrpt->remmode){
03604 
03605             case REM_MODE_USB:
03606                res = saycharstr(mychannel, "USB");
03607                break;
03608 
03609             case REM_MODE_LSB:
03610                res = saycharstr(mychannel, "LSB");
03611                break;
03612 
03613             case REM_MODE_AM:
03614                res = saycharstr(mychannel, "AM");
03615                break;
03616 
03617 
03618             default:
03619                break;
03620          }
03621       }
03622 
03623       if (res == -1) break;
03624 
03625       if(mytele->mode == REMSHORTSTATUS){ /* Short status? */
03626          wait_interval(myrpt, DLY_COMP, mychannel);
03627          if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
03628          break;
03629       }
03630 
03631       if (strcmp(myrpt->remote,remote_rig_ic706))
03632       {
03633          switch(myrpt->powerlevel){
03634 
03635             case REM_LOWPWR:
03636                res = sayfile(mychannel,"rpt/lopwr") ;
03637                break;
03638             case REM_MEDPWR:
03639                res = sayfile(mychannel,"rpt/medpwr");
03640                break;
03641             case REM_HIPWR:
03642                res = sayfile(mychannel,"rpt/hipwr"); 
03643                break;
03644             }
03645       }
03646 
03647       rbimode = ((!strncmp(myrpt->remote,remote_rig_rbi,3))
03648         || (!strncmp(myrpt->remote,remote_rig_ic706,3)));
03649       if (res || (sayfile(mychannel,"rpt/rxpl") == -1)) break;
03650       if (rbimode && (sayfile(mychannel,"rpt/txpl") == -1)) break;
03651       if ((sayfile(mychannel,"rpt/frequency") == -1) ||
03652          (saycharstr(mychannel,myrpt->rxpl) == -1)) break;
03653       if ((!rbimode) && ((sayfile(mychannel,"rpt/txpl") == -1) ||
03654          (sayfile(mychannel,"rpt/frequency") == -1) ||
03655          (saycharstr(mychannel,myrpt->txpl) == -1))) break;
03656       if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
03657          if ((sayfile(mychannel,"rpt/rxpl") == -1) ||
03658             (sayfile(mychannel,((myrpt->rxplon) ? "rpt/on" : "rpt/off")) == -1) ||
03659             (sayfile(mychannel,"rpt/txpl") == -1) ||
03660             (sayfile(mychannel,((myrpt->txplon) ? "rpt/on" : "rpt/off")) == -1))
03661             {
03662                break;
03663             }
03664       }
03665       wait_interval(myrpt, DLY_COMP, mychannel);
03666       if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
03667       break;
03668        case STATUS:
03669       /* wait a little bit */
03670       wait_interval(myrpt, DLY_TELEM, mychannel);
03671       hastx = 0;
03672       linkbase.next = &linkbase;
03673       linkbase.prev = &linkbase;
03674       rpt_mutex_lock(&myrpt->lock);
03675       /* make our own list of links */
03676       l = myrpt->links.next;
03677       while(l != &myrpt->links)
03678       {
03679          if (l->name[0] == '0')
03680          {
03681             l = l->next;
03682             continue;
03683          }
03684          l1 = malloc(sizeof(struct rpt_link));
03685          if (!l1)
03686          {
03687             ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
03688             remque((struct qelem *)mytele);
03689             rpt_mutex_unlock(&myrpt->lock);
03690             ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
03691             free(mytele);     
03692             ast_hangup(mychannel);
03693             pthread_exit(NULL);
03694          }
03695          memcpy(l1,l,sizeof(struct rpt_link));
03696          l1->next = l1->prev = NULL;
03697          insque((struct qelem *)l1,(struct qelem *)linkbase.next);
03698          l = l->next;
03699       }
03700       rpt_mutex_unlock(&myrpt->lock);
03701       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03702       if (!res) 
03703          res = ast_waitstream(mychannel, "");
03704       else
03705           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03706       ast_stopstream(mychannel);
03707       ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
03708       if (!res) 
03709          res = ast_waitstream(mychannel, "");
03710       else
03711           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03712       ast_stopstream(mychannel);
03713       if (myrpt->callmode)
03714       {
03715          hastx = 1;
03716          res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
03717          if (!res) 
03718             res = ast_waitstream(mychannel, "");
03719          else
03720              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03721          ast_stopstream(mychannel);
03722       }
03723       l = linkbase.next;
03724       while(l != &linkbase)
03725       {
03726          char *s;
03727 
03728          hastx = 1;
03729          res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03730          if (!res) 
03731             res = ast_waitstream(mychannel, "");
03732          else
03733             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03734          ast_stopstream(mychannel);
03735          ast_say_character_str(mychannel,l->name,NULL,mychannel->language);
03736          if (!res) 
03737             res = ast_waitstream(mychannel, "");
03738          else
03739              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03740          ast_stopstream(mychannel);
03741          s = "rpt/tranceive";
03742          if (!l->mode) s = "rpt/monitor";
03743          if (!l->thisconnected) s = "rpt/connecting";
03744          res = ast_streamfile(mychannel, s, mychannel->language);
03745          if (!res) 
03746             res = ast_waitstream(mychannel, "");
03747          else
03748             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03749          ast_stopstream(mychannel);
03750          l = l->next;
03751       }        
03752       if (!hastx)
03753       {
03754          res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
03755          if (!res) 
03756             res = ast_waitstream(mychannel, "");
03757          else
03758              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03759          ast_stopstream(mychannel);
03760       }
03761       /* destroy our local link queue */
03762       l = linkbase.next;
03763       while(l != &linkbase)
03764       {
03765          l1 = l;
03766          l = l->next;
03767          remque((struct qelem *)l1);
03768          free(l1);
03769       }        
03770       imdone = 1;
03771       break;
03772        case FULLSTATUS:
03773       rpt_mutex_lock(&myrpt->lock);
03774       /* get all the nodes */
03775       __mklinklist(myrpt,NULL,lbuf);
03776       rpt_mutex_unlock(&myrpt->lock);
03777       /* parse em */
03778       ns = finddelim(lbuf,strs,MAXLINKLIST);
03779       /* sort em */
03780       if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
03781       /* wait a little bit */
03782       wait_interval(myrpt, DLY_TELEM, mychannel);
03783       hastx = 0;
03784       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03785       if (!res) 
03786          res = ast_waitstream(mychannel, "");
03787       else
03788           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03789       ast_stopstream(mychannel);
03790       ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
03791       if (!res) 
03792          res = ast_waitstream(mychannel, "");
03793       else
03794           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03795       ast_stopstream(mychannel);
03796       if (myrpt->callmode)
03797       {
03798          hastx = 1;
03799          res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
03800          if (!res) 
03801             res = ast_waitstream(mychannel, "");
03802          else
03803              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03804          ast_stopstream(mychannel);
03805       }
03806       /* go thru all the nodes in list */
03807       for(i = 0; i < ns; i++)
03808       {
03809          char *s,mode = 'T';
03810 
03811          /* if a mode spec at first, handle it */
03812          if ((*strs[i] < '0') || (*strs[i] > '9'))
03813          {
03814             mode = *strs[i];
03815             strs[i]++;
03816          }
03817 
03818          hastx = 1;
03819          res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03820          if (!res) 
03821             res = ast_waitstream(mychannel, "");
03822          else
03823             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03824          ast_stopstream(mychannel);
03825          ast_say_character_str(mychannel,strs[i],NULL,mychannel->language);
03826          if (!res) 
03827             res = ast_waitstream(mychannel, "");
03828          else
03829              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03830          ast_stopstream(mychannel);
03831          s = "rpt/tranceive";
03832          if (mode == 'R') s = "rpt/monitor";
03833          if (mode == 'C') s = "rpt/connecting";
03834          res = ast_streamfile(mychannel, s, mychannel->language);
03835          if (!res) 
03836             res = ast_waitstream(mychannel, "");
03837          else
03838             ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03839          ast_stopstream(mychannel);
03840       }        
03841       if (!hastx)
03842       {
03843          res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
03844          if (!res) 
03845             res = ast_waitstream(mychannel, "");
03846          else
03847              ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03848          ast_stopstream(mychannel);
03849       }
03850       imdone = 1;
03851       break;
03852 
03853        case LASTNODEKEY: /* Identify last node which keyed us up */
03854       rpt_mutex_lock(&myrpt->lock);
03855       if(myrpt->lastnodewhichkeyedusup)
03856          p = ast_strdupa(myrpt->lastnodewhichkeyedusup); /* Make a local copy of the node name */
03857       else
03858          p = NULL;
03859       rpt_mutex_unlock(&myrpt->lock);
03860       if(!p){
03861          imdone = 1; /* no node previously keyed us up, or the node which did has been disconnected */
03862          break;
03863       }
03864       wait_interval(myrpt, DLY_TELEM, mychannel);
03865       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03866       if (!res) 
03867          res = ast_waitstream(mychannel, "");
03868       else
03869           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03870       ast_stopstream(mychannel);
03871       ast_say_character_str(mychannel, p, NULL, mychannel->language);
03872       if (!res) 
03873          res = ast_waitstream(mychannel, "");
03874       else
03875          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03876       ast_stopstream(mychannel);
03877       imdone = 1;
03878       break;      
03879 
03880        case UNAUTHTX: /* Say unauthorized transmit frequency */
03881       wait_interval(myrpt, DLY_TELEM, mychannel);
03882       res = ast_streamfile(mychannel, "rpt/unauthtx", mychannel->language);
03883       if (!res) 
03884          res = ast_waitstream(mychannel, "");
03885       else
03886           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03887       ast_stopstream(mychannel);
03888       imdone = 1;
03889       break;
03890       
03891 
03892        case TIMEOUT:
03893       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03894       if (!res) 
03895          res = ast_waitstream(mychannel, "");
03896       else
03897           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03898       ast_stopstream(mychannel);
03899       ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
03900       res = ast_streamfile(mychannel, "rpt/timeout", mychannel->language);
03901       break;
03902       
03903        case TIMEOUT_WARNING:
03904       time(&t);
03905       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03906       if (!res) 
03907          res = ast_waitstream(mychannel, "");
03908       else
03909           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03910       ast_stopstream(mychannel);
03911       ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
03912       res = ast_streamfile(mychannel, "rpt/timeout-warning", mychannel->language);
03913       if (!res) 
03914          res = ast_waitstream(mychannel, "");
03915       else
03916           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03917       ast_stopstream(mychannel);
03918       if(!res) /* Say number of seconds */
03919          ast_say_number(mychannel, myrpt->p.remotetimeout - 
03920              (t - myrpt->last_activity_time), 
03921             "", mychannel->language, (char *) NULL);
03922       if (!res) 
03923          res = ast_waitstream(mychannel, "");
03924       ast_stopstream(mychannel); 
03925       res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
03926       break;
03927 
03928        case ACT_TIMEOUT_WARNING:
03929       time(&t);
03930       res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
03931       if (!res) 
03932          res = ast_waitstream(mychannel, "");
03933       else
03934           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03935       ast_stopstream(mychannel);
03936       ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
03937       res = ast_streamfile(mychannel, "rpt/act-timeout-warning", mychannel->language);
03938       if (!res) 
03939          res = ast_waitstream(mychannel, "");
03940       else
03941           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
03942       ast_stopstream(mychannel);
03943       if(!res) /* Say number of seconds */
03944          ast_say_number(mychannel, myrpt->p.remoteinacttimeout - 
03945              (t - myrpt->last_activity_time), 
03946             "", mychannel->language, (char *) NULL);
03947       if (!res) 
03948          res = ast_waitstream(mychannel, "");
03949       ast_stopstream(mychannel); 
03950       res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
03951       break;
03952       
03953        case STATS_TIME:
03954          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
03955       t = time(NULL);
03956       rpt_localtime(&t, &localtm);
03957       /* Say the phase of the day is before the time */
03958       if((localtm.tm_hour >= 0) && (localtm.tm_hour < 12))
03959          p = "rpt/goodmorning";
03960       else if((localtm.tm_hour >= 12) && (localtm.tm_hour < 18))
03961          p = "rpt/goodafternoon";
03962       else
03963          p = "rpt/goodevening";
03964       if (sayfile(mychannel,p) == -1)
03965       {
03966          imdone = 1;
03967          break;
03968       }
03969       /* Say the time is ... */     
03970       if (sayfile(mychannel,"rpt/thetimeis") == -1)
03971       {
03972          imdone = 1;
03973          break;
03974       }
03975       /* Say the time */            
03976          res = ast_say_time(mychannel, t, "", mychannel->language);
03977       if (!res) 
03978          res = ast_waitstream(mychannel, "");
03979       ast_stopstream(mychannel);    
03980       imdone = 1;
03981          break;
03982        case STATS_VERSION:
03983       p = strstr(tdesc, "version"); 
03984       if(!p)
03985          break;   
03986       if(sscanf(p, "version %d.%d", &vmajor, &vminor) != 2)
03987          break;
03988          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
03989       /* Say "version" */
03990       if (sayfile(mychannel,"rpt/version") == -1)
03991       {
03992          imdone = 1;
03993          break;
03994       }
03995       if(!res) /* Say "X" */
03996          ast_say_number(mychannel, vmajor, "", mychannel->language, (char *) NULL);
03997       if (!res) 
03998          res = ast_waitstream(mychannel, "");
03999       ast_stopstream(mychannel); 
04000       if (saycharstr(mychannel,".") == -1)
04001       {
04002          imdone = 1;
04003          break;
04004       }
04005       if(!res) /* Say "Y" */
04006          ast_say_number(mychannel, vminor, "", mychannel->language, (char *) NULL);
04007       if (!res){
04008          res = ast_waitstream(mychannel, "");
04009          ast_stopstream(mychannel);
04010       }  
04011       else
04012           ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04013       imdone = 1;
04014          break;
04015        case ARB_ALPHA:
04016          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
04017          if(mytele->param)
04018             saycharstr(mychannel, mytele->param);
04019          imdone = 1;
04020       break;
04021        case REV_PATCH:
04022          wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
04023          if(mytele->param) {
04024 
04025          /* Parts of this section taken from app_parkandannounce */
04026          char *tpl_working, *tpl_current;
04027          char *tmp[100], *myparm;
04028          int looptemp=0,i=0, dres = 0;
04029    
04030 
04031          tpl_working = strdupa(mytele->param);
04032          myparm = strsep(&tpl_working,",");
04033          tpl_current=strsep(&tpl_working, ":");
04034 
04035          while(tpl_current && looptemp < sizeof(tmp)) {
04036             tmp[looptemp]=tpl_current;
04037             looptemp++;
04038             tpl_current=strsep(&tpl_working,":");
04039          }
04040 
04041          for(i=0; i<looptemp; i++) {
04042             if(!strcmp(tmp[i], "PARKED")) {
04043                ast_say_digits(mychannel, atoi(myparm), "", mychannel->language);
04044             } else if(!strcmp(tmp[i], "NODE")) {
04045                ast_say_digits(mychannel, atoi(myrpt->name), "", mychannel->language);
04046             } else {
04047                dres = ast_streamfile(mychannel, tmp[i], mychannel->language);
04048                if(!dres) {
04049                   dres = ast_waitstream(mychannel, "");
04050                } else {
04051                   ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], mychannel->name);
04052                   dres = 0;
04053                }
04054             }
04055          }
04056       }
04057          imdone = 1;
04058       break;
04059        case TEST_TONE:
04060       imdone = 1;
04061       if (myrpt->stopgen) break;
04062       myrpt->stopgen = -1;
04063            if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0))) 
04064       {
04065          myrpt->stopgen = 0;
04066          break;
04067       }
04068            while(mychannel->generatordata && (myrpt->stopgen <= 0)) {
04069          if (ast_safe_sleep(mychannel,1)) break;
04070             imdone = 1;
04071          }
04072       myrpt->stopgen = 0;
04073       break;
04074        default:
04075          break;
04076    }
04077    if (!imdone)
04078    {
04079       if (!res) 
04080          res = ast_waitstream(mychannel, "");
04081       else {
04082          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
04083          res = 0;
04084       }
04085    }
04086    ast_stopstream(mychannel);
04087    rpt_mutex_lock(&myrpt->lock);
04088    if (mytele->mode == TAILMSG)
04089    {
04090       if (!res)
04091       {
04092          myrpt->tailmessagen++;
04093          if(myrpt->tailmessagen >= myrpt->p.tailmessagemax) myrpt->tailmessagen = 0;
04094       }
04095       else
04096       {
04097          myrpt->tmsgtimer = myrpt->p.tailsquashedtime;
04098       }
04099    }
04100    remque((struct qelem *)mytele);
04101    rpt_mutex_unlock(&myrpt->lock);
04102    free(mytele);     
04103    ast_hangup(mychannel);
04104 #ifdef  APP_RPT_LOCK_DEBUG
04105    {
04106       struct lockthread *t;
04107 
04108       sleep(5);
04109       ast_mutex_lock(&locklock);
04110       t = get_lockthread(pthread_self());
04111       if (t) memset(t,0,sizeof(struct lockthread));
04112       ast_mutex_unlock(&locklock);
04113    }        
04114 #endif
04115    pthread_exit(NULL);
04116 }
04117 
04118 static void rpt_telemetry(struct rpt *myrpt,int mode, void *data)
04119 {
04120 struct rpt_tele *tele;
04121 struct rpt_link *mylink = (struct rpt_link *) data;
04122 int res;
04123 pthread_attr_t attr;
04124 
04125    tele = malloc(sizeof(struct rpt_tele));
04126    if (!tele)
04127    {
04128       ast_log(LOG_WARNING, "Unable to allocate memory\n");
04129       pthread_exit(NULL);
04130       return;
04131    }
04132    /* zero it out */
04133    memset((char *)tele,0,sizeof(struct rpt_tele));
04134    tele->rpt = myrpt;
04135    tele->mode = mode;
04136    rpt_mutex_lock(&myrpt->lock);
04137    if((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED) ||
04138        (mode == LINKUNKEY)){
04139       memset(&tele->mylink,0,sizeof(struct rpt_link));
04140       if (mylink){
04141          memcpy(&tele->mylink,mylink,sizeof(struct rpt_link));
04142       }
04143    }
04144    else if ((mode == ARB_ALPHA) || (mode == REV_PATCH)) {
04145       strncpy(tele->param, (char *) data, TELEPARAMSIZE - 1);
04146       tele->param[TELEPARAMSIZE - 1] = 0;
04147    }
04148    if (mode == REMXXX) tele->submode = (intptr_t) data;
04149    insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next);
04150    rpt_mutex_unlock(&myrpt->lock);
04151         pthread_attr_init(&attr);
04152         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
04153    res = ast_pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
04154    if(res < 0){
04155       rpt_mutex_lock(&myrpt->lock);
04156       remque((struct qlem *) tele); /* We don't like stuck transmitters, remove it from the queue */
04157       rpt_mutex_unlock(&myrpt->lock);  
04158       ast_log(LOG_WARNING, "Could not create telemetry thread: %s",strerror(res));
04159    }
04160    return;
04161 }
04162 
04163 static void *rpt_call(void *this)
04164 {
04165 struct dahdi_confinfo ci;  /* conference info */
04166 struct   rpt *myrpt = (struct rpt *)this;
04167 int   res;
04168 int stopped,congstarted,dialtimer,lastcidx,aborted;
04169 struct ast_channel *mychannel,*genchannel;
04170 
04171 
04172    myrpt->mydtmf = 0;
04173    /* allocate a pseudo-channel thru asterisk */
04174    mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
04175    if (!mychannel)
04176    {
04177       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
04178       pthread_exit(NULL);
04179    }
04180 #ifdef   AST_CDR_FLAG_POST_DISABLED
04181    ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
04182 #endif
04183    ci.chan = 0;
04184    ci.confno = myrpt->conf; /* use the pseudo conference */
04185    ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
04186       | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER; 
04187    /* first put the channel on the conference */
04188    if (ioctl(mychannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04189    {
04190       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04191       ast_hangup(mychannel);
04192       myrpt->callmode = 0;
04193       pthread_exit(NULL);
04194    }
04195    /* allocate a pseudo-channel thru asterisk */
04196    genchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
04197    if (!genchannel)
04198    {
04199       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
04200       ast_hangup(mychannel);
04201       pthread_exit(NULL);
04202    }
04203 #ifdef   AST_CDR_FLAG_POST_DISABLED
04204    ast_set_flag(genchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
04205 #endif
04206    ci.chan = 0;
04207    ci.confno = myrpt->conf;
04208    ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
04209       | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER; 
04210    /* first put the channel on the conference */
04211    if (ioctl(genchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04212    {
04213       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04214       ast_hangup(mychannel);
04215       ast_hangup(genchannel);
04216       myrpt->callmode = 0;
04217       pthread_exit(NULL);
04218    }
04219    if (myrpt->p.tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->p.tonezone) == -1))
04220    {
04221       ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
04222       ast_hangup(mychannel);
04223       ast_hangup(genchannel);
04224       myrpt->callmode = 0;
04225       pthread_exit(NULL);
04226    }
04227    if (myrpt->p.tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->p.tonezone) == -1))
04228    {
04229       ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
04230       ast_hangup(mychannel);
04231       ast_hangup(genchannel);
04232       myrpt->callmode = 0;
04233       pthread_exit(NULL);
04234    }
04235    /* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
04236    if ((!myrpt->patchquiet) && (tone_zone_play_tone(mychannel->fds[0],DAHDI_TONE_DIALTONE) < 0))
04237    {
04238       ast_log(LOG_WARNING, "Cannot start dialtone\n");
04239       ast_hangup(mychannel);
04240       ast_hangup(genchannel);
04241       myrpt->callmode = 0;
04242       pthread_exit(NULL);
04243    }
04244    stopped = 0;
04245    congstarted = 0;
04246    dialtimer = 0;
04247    lastcidx = 0;
04248    aborted = 0;
04249 
04250 
04251    while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
04252    {
04253 
04254       if((myrpt->patchdialtime)&&(myrpt->callmode == 1)&&(myrpt->cidx != lastcidx)){
04255          dialtimer = 0;
04256          lastcidx = myrpt->cidx;
04257       }     
04258 
04259       if((myrpt->patchdialtime)&&(dialtimer >= myrpt->patchdialtime)){ 
04260          rpt_mutex_lock(&myrpt->lock);
04261          aborted = 1;
04262          myrpt->callmode = 0;
04263          rpt_mutex_unlock(&myrpt->lock);
04264          break;
04265       }
04266    
04267       if ((!myrpt->patchquiet) && (!stopped) && (myrpt->callmode == 1) && (myrpt->cidx > 0))
04268       {
04269          stopped = 1;
04270          /* stop dial tone */
04271          tone_zone_play_tone(mychannel->fds[0],-1);
04272       }
04273       if (myrpt->callmode == 4)
04274       {
04275          if(!congstarted){
04276             congstarted = 1;
04277             /* start congestion tone */
04278             tone_zone_play_tone(mychannel->fds[0],DAHDI_TONE_CONGESTION);
04279          }
04280       }
04281       res = ast_safe_sleep(mychannel, MSWAIT);
04282       if (res < 0)
04283       {
04284          ast_hangup(mychannel);
04285          ast_hangup(genchannel);
04286          rpt_mutex_lock(&myrpt->lock);
04287          myrpt->callmode = 0;
04288          rpt_mutex_unlock(&myrpt->lock);
04289          pthread_exit(NULL);
04290       }
04291       dialtimer += MSWAIT;
04292    }
04293    /* stop any tone generation */
04294    tone_zone_play_tone(mychannel->fds[0],-1);
04295    /* end if done */
04296    if (!myrpt->callmode)
04297    {
04298       ast_hangup(mychannel);
04299       ast_hangup(genchannel);
04300       rpt_mutex_lock(&myrpt->lock);
04301       myrpt->callmode = 0;
04302       rpt_mutex_unlock(&myrpt->lock);
04303       if((!myrpt->patchquiet) && aborted)
04304          rpt_telemetry(myrpt, TERM, NULL);
04305       pthread_exit(NULL);        
04306    }
04307 
04308    if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid){
04309       char *name, *loc, *instr;
04310       instr = strdup(myrpt->p.ourcallerid);
04311       if(instr){
04312          ast_callerid_parse(instr, &name, &loc);
04313          if(loc){
04314             if(mychannel->cid.cid_num)
04315                free(mychannel->cid.cid_num);
04316             mychannel->cid.cid_num = strdup(loc);
04317          }
04318          if(name){
04319             if(mychannel->cid.cid_name)
04320                free(mychannel->cid.cid_name);
04321             mychannel->cid.cid_name = strdup(name);
04322          }
04323          free(instr);
04324       }
04325    }
04326 
04327    ast_copy_string(mychannel->exten, myrpt->exten, sizeof(mychannel->exten) - 1);
04328    ast_copy_string(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context) - 1);
04329    
04330    if (myrpt->p.acctcode)
04331       ast_cdr_setaccount(mychannel,myrpt->p.acctcode);
04332    mychannel->priority = 1;
04333    ast_channel_undefer_dtmf(mychannel);
04334    if (ast_pbx_start(mychannel) < 0)
04335    {
04336       ast_log(LOG_WARNING, "Unable to start PBX!!\n");
04337       ast_hangup(mychannel);
04338       ast_hangup(genchannel);
04339       rpt_mutex_lock(&myrpt->lock);
04340       myrpt->callmode = 0;
04341       rpt_mutex_unlock(&myrpt->lock);
04342       pthread_exit(NULL);
04343    }
04344    usleep(10000);
04345    rpt_mutex_lock(&myrpt->lock);
04346    myrpt->callmode = 3;
04347    /* set appropriate conference for the pseudo */
04348    ci.chan = 0;
04349    ci.confno = myrpt->conf;
04350    ci.confmode = (myrpt->p.duplex == 2) ? DAHDI_CONF_CONFANNMON :
04351       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
04352    /* first put the channel on the conference in announce mode */
04353    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04354    {
04355       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04356       ast_hangup(mychannel);
04357       ast_hangup(genchannel);
04358       myrpt->callmode = 0;
04359       pthread_exit(NULL);
04360    }
04361    while(myrpt->callmode)
04362    {
04363       if ((!mychannel->pbx) && (myrpt->callmode != 4))
04364       {
04365          if(myrpt->patchfarenddisconnect){ /* If patch is setup for far end disconnect */
04366             myrpt->callmode = 0;
04367             if(!myrpt->patchquiet){
04368                rpt_mutex_unlock(&myrpt->lock);
04369                rpt_telemetry(myrpt, TERM, NULL);
04370                rpt_mutex_lock(&myrpt->lock);
04371             }
04372          }
04373          else{ /* Send congestion until patch is downed by command */
04374             myrpt->callmode = 4;
04375             rpt_mutex_unlock(&myrpt->lock);
04376             /* start congestion tone */
04377             tone_zone_play_tone(genchannel->fds[0],DAHDI_TONE_CONGESTION);
04378             rpt_mutex_lock(&myrpt->lock);
04379          }
04380       }
04381       if (myrpt->mydtmf)
04382       {
04383          struct ast_frame wf = {AST_FRAME_DTMF, } ;
04384          wf.subclass = myrpt->mydtmf;
04385          rpt_mutex_unlock(&myrpt->lock);
04386          ast_queue_frame(mychannel,&wf);
04387          ast_senddigit(genchannel,myrpt->mydtmf);
04388          rpt_mutex_lock(&myrpt->lock);
04389          myrpt->mydtmf = 0;
04390       }
04391       rpt_mutex_unlock(&myrpt->lock);
04392       usleep(MSWAIT * 1000);
04393       rpt_mutex_lock(&myrpt->lock);
04394    }
04395    rpt_mutex_unlock(&myrpt->lock);
04396    tone_zone_play_tone(genchannel->fds[0],-1);
04397    if (mychannel->pbx) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV);
04398    ast_hangup(genchannel);
04399    rpt_mutex_lock(&myrpt->lock);
04400    myrpt->callmode = 0;
04401    rpt_mutex_unlock(&myrpt->lock);
04402    /* set appropriate conference for the pseudo */
04403    ci.chan = 0;
04404    ci.confno = myrpt->conf;
04405    ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
04406       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
04407    /* first put the channel on the conference in announce mode */
04408    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
04409    {
04410       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04411    }
04412    pthread_exit(NULL);
04413 }
04414 
04415 static void send_link_dtmf(struct rpt *myrpt,char c)
04416 {
04417 char  str[300];
04418 struct   ast_frame wf;
04419 struct   rpt_link *l;
04420 
04421    snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c);
04422    wf.frametype = AST_FRAME_TEXT;
04423    wf.subclass = 0;
04424    wf.offset = 0;
04425    wf.mallocd = 0;
04426    wf.datalen = strlen(str) + 1;
04427    wf.samples = 0;
04428    l = myrpt->links.next;
04429    /* first, see if our dude is there */
04430    while(l != &myrpt->links)
04431    {
04432       if (l->name[0] == '0') 
04433       {
04434          l = l->next;
04435          continue;
04436       }
04437       /* if we found it, write it and were done */
04438       if (!strcmp(l->name,myrpt->cmdnode))
04439       {
04440          wf.data = str;
04441          if (l->chan) ast_write(l->chan,&wf);
04442          return;
04443       }
04444       l = l->next;
04445    }
04446    l = myrpt->links.next;
04447    /* if not, give it to everyone */
04448    while(l != &myrpt->links)
04449    {
04450       wf.data = str;
04451       if (l->chan) ast_write(l->chan,&wf);
04452       l = l->next;
04453    }
04454    return;
04455 }
04456 
04457 /* 
04458  * Connect a link 
04459  *
04460  * Return values:
04461  * -1: Error
04462  *  0: Success
04463  *  1: No match yet
04464  *  2: Already connected to this node
04465  */
04466 
04467 static int connect_link(struct rpt *myrpt, char* node, int mode, int perma)
04468 {
04469    char *val, *s, *s1, *s2, *tele;
04470    char lstr[MAXLINKLIST],*strs[MAXLINKLIST];
04471    char tmp[300], deststr[300] = "",modechange = 0;
04472    struct rpt_link *l;
04473    int reconnects = 0;
04474    int i,n;
04475    struct dahdi_confinfo ci;  /* conference info */
04476 
04477    val = node_lookup(myrpt,node);
04478    if (!val){
04479       if(strlen(node) >= myrpt->longestnode)
04480          return -1; /* No such node */
04481       return 1; /* No match yet */
04482    }
04483    if(debug > 3){
04484       ast_log(LOG_NOTICE,"Connect attempt to node %s\n", node);
04485       ast_log(LOG_NOTICE,"Mode: %s\n",(mode)?"Transceive":"Monitor");
04486       ast_log(LOG_NOTICE,"Connection type: %s\n",(perma)?"Permalink":"Normal");
04487    }
04488 
04489    strncpy(tmp,val,sizeof(tmp) - 1);
04490    s = tmp;
04491    s1 = strsep(&s,",");
04492    s2 = strsep(&s,",");
04493    rpt_mutex_lock(&myrpt->lock);
04494    l = myrpt->links.next;
04495    /* try to find this one in queue */
04496    while(l != &myrpt->links){
04497       if (l->name[0] == '0') 
04498       {
04499          l = l->next;
04500          continue;
04501       }
04502    /* if found matching string */
04503       if (!strcmp(l->name, node))
04504          break;
04505       l = l->next;
04506    }
04507    /* if found */
04508    if (l != &myrpt->links){ 
04509    /* if already in this mode, just ignore */
04510       if ((l->mode) || (!l->chan)) {
04511          rpt_mutex_unlock(&myrpt->lock);
04512          return 2; /* Already linked */
04513       }
04514       reconnects = l->reconnects;
04515       rpt_mutex_unlock(&myrpt->lock);
04516       if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
04517       l->retries = l->max_retries + 1;
04518       l->disced = 2;
04519       modechange = 1;
04520    } else
04521    {
04522       __mklinklist(myrpt,NULL,lstr);
04523       rpt_mutex_unlock(&myrpt->lock);
04524       n = finddelim(lstr,strs,MAXLINKLIST);
04525       for(i = 0; i < n; i++)
04526       {
04527          if ((*strs[i] < '0') || 
04528              (*strs[i] > '9')) strs[i]++;
04529          if (!strcmp(strs[i],node))
04530          {
04531             return 2; /* Already linked */
04532          }
04533       }
04534    }
04535    strncpy(myrpt->lastlinknode,node,MAXNODESTR - 1);
04536    /* establish call */
04537    l = malloc(sizeof(struct rpt_link));
04538    if (!l)
04539    {
04540       ast_log(LOG_WARNING, "Unable to malloc\n");
04541       return -1;
04542    }
04543    /* zero the silly thing */
04544    memset((char *)l,0,sizeof(struct rpt_link));
04545    l->mode = mode;
04546    l->outbound = 1;
04547    l->thisconnected = 0;
04548    strncpy(l->name, node, MAXNODESTR - 1);
04549    l->isremote = (s && ast_true(s));
04550    if (modechange) l->connected = 1;
04551    l->hasconnected = l->perma = perma;
04552 #ifdef ALLOW_LOCAL_CHANNELS
04553    if ((strncasecmp(s1,"iax2/", 5) == 0) || (strncasecmp(s1, "local/", 6) == 0))
04554          strncpy(deststr, s1, sizeof(deststr));
04555    else
04556            snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
04557 #else
04558    snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
04559 #endif
04560    tele = strchr(deststr, '/');
04561    if (!tele){
04562       ast_log(LOG_WARNING,"link3:Dial number (%s) must be in format tech/number\n",deststr);
04563       free(l);
04564       return -1;
04565    }
04566    *tele++ = 0;
04567    l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
04568    if (l->chan){
04569       ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
04570       ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
04571 #ifdef   AST_CDR_FLAG_POST_DISABLED
04572       ast_set_flag(l->chan->cdr,AST_CDR_FLAG_POST_DISABLED);
04573 #endif
04574       l->chan->whentohangup = 0;
04575       l->chan->appl = "Apprpt";
04576       l->chan->data = "(Remote Rx)";
04577       if (debug > 3)
04578          ast_log(LOG_NOTICE, "rpt (remote) initiating call to %s/%s on %s\n",
04579       deststr, tele, l->chan->name);
04580       if(l->chan->cid.cid_num)
04581          free(l->chan->cid.cid_num);
04582       l->chan->cid.cid_num = strdup(myrpt->name);
04583       ast_call(l->chan,tele,999);
04584    }
04585    else {
04586       if(debug > 3) 
04587          ast_log(LOG_NOTICE, "Unable to place call to %s/%s on %s\n",
04588       deststr,tele,l->chan->name);
04589       if (myrpt->p.archivedir)
04590       {
04591          char str[100];
04592          sprintf(str,"LINKFAIL,%s",l->name);
04593          donodelog(myrpt,str);
04594       }
04595       free(l);
04596       return -1;
04597    }
04598    /* allocate a pseudo-channel thru asterisk */
04599    l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
04600    if (!l->pchan){
04601       ast_log(LOG_WARNING,"rpt connect: Sorry unable to obtain pseudo channel\n");
04602       ast_hangup(l->chan);
04603       free(l);
04604       return -1;
04605    }
04606    ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
04607    ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
04608 #ifdef   AST_CDR_FLAG_POST_DISABLED
04609    ast_set_flag(l->pchan->cdr,AST_CDR_FLAG_POST_DISABLED);
04610 #endif
04611    /* make a conference for the tx */
04612    ci.chan = 0;
04613    ci.confno = myrpt->conf;
04614    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
04615    /* first put the channel on the conference in proper mode */
04616    if (ioctl(l->pchan->fds[0], DAHDI_SETCONF, &ci) == -1)
04617    {
04618       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
04619       ast_hangup(l->chan);
04620       ast_hangup(l->pchan);
04621       free(l);
04622       return -1;
04623    }
04624    rpt_mutex_lock(&myrpt->lock);
04625    l->reconnects = reconnects;
04626    /* insert at end of queue */
04627    l->max_retries = MAX_RETRIES;
04628    if (perma)
04629       l->max_retries = MAX_RETRIES_PERM;
04630    if (l->isremote) l->retries = l->max_retries + 1;
04631    insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
04632    __kickshort(myrpt);
04633    rpt_mutex_unlock(&myrpt->lock);
04634    return 0;
04635 }
04636 
04637 
04638 
04639 /*
04640 * Internet linking function 
04641 */
04642 
04643 static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink)
04644 {
04645 
04646    char *val, *s, *s1, *s2;
04647    char tmp[300];
04648    char digitbuf[MAXNODESTR],*strs[MAXLINKLIST];
04649    char mode,perma;
04650    struct rpt_link *l;
04651    int i,r;
04652 
04653    if(!param)
04654       return DC_ERROR;
04655       
04656          
04657    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable )
04658       return DC_ERROR;
04659 
04660    strncpy(digitbuf,digits,MAXNODESTR - 1);
04661 
04662    if(debug > 6)
04663       printf("@@@@ ilink param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
04664       
04665    switch(myatoi(param)){
04666       case 11: /* Perm Link off */
04667       case 1: /* Link off */
04668          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
04669             strcpy(digitbuf,myrpt->lastlinknode);
04670          val = node_lookup(myrpt,digitbuf);
04671          if (!val){
04672             if(strlen(digitbuf) >= myrpt->longestnode)
04673                return DC_ERROR;
04674             break;
04675          }
04676          strncpy(tmp,val,sizeof(tmp) - 1);
04677          s = tmp;
04678          s1 = strsep(&s,",");
04679          s2 = strsep(&s,",");
04680          rpt_mutex_lock(&myrpt->lock);
04681          l = myrpt->links.next;
04682          /* try to find this one in queue */
04683          while(l != &myrpt->links){
04684             if (l->name[0] == '0') 
04685             {
04686                l = l->next;
04687                continue;
04688             }
04689             /* if found matching string */
04690             if (!strcmp(l->name, digitbuf))
04691                break;
04692             l = l->next;
04693          }
04694          if (l != &myrpt->links){ /* if found */
04695             struct   ast_frame wf;
04696 
04697             /* must use perm command on perm link */
04698             if ((myatoi(param) < 10) && 
04699                 (l->max_retries > MAX_RETRIES))
04700             {
04701                rpt_mutex_unlock(&myrpt->lock);
04702                return DC_COMPLETE;
04703             }
04704             strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
04705             l->retries = l->max_retries + 1;
04706             l->disced = 1;
04707             rpt_mutex_unlock(&myrpt->lock);
04708             wf.frametype = AST_FRAME_TEXT;
04709             wf.subclass = 0;
04710             wf.offset = 0;
04711             wf.mallocd = 0;
04712             wf.datalen = strlen(discstr) + 1;
04713             wf.samples = 0;
04714             wf.data = discstr;
04715             if (l->chan)
04716             {
04717                ast_write(l->chan,&wf);
04718                if (ast_safe_sleep(l->chan,250) == -1) return DC_ERROR;
04719                ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
04720             }
04721             rpt_telemetry(myrpt, COMPLETE, NULL);
04722             return DC_COMPLETE;
04723          }
04724          rpt_mutex_unlock(&myrpt->lock);  
04725          return DC_COMPLETE;
04726       case 2: /* Link Monitor */
04727       case 3: /* Link transceive */
04728       case 12: /* Link Monitor permanent */
04729       case 13: /* Link transceive permanent */
04730          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
04731             strcpy(digitbuf,myrpt->lastlinknode);
04732          /* Attempt connection  */
04733          perma = (atoi(param) > 10) ? 1 : 0;
04734          mode = (atoi(param) & 1) ? 1 : 0;
04735          r = connect_link(myrpt, digitbuf, mode, perma);
04736          switch(r){
04737             case 0:
04738                rpt_telemetry(myrpt, COMPLETE, NULL);
04739                return DC_COMPLETE;
04740 
04741             case 1:
04742                break;
04743             
04744             case 2:
04745                rpt_telemetry(myrpt, REMALREADY, NULL);
04746                return DC_COMPLETE;
04747             
04748             default:
04749                rpt_telemetry(myrpt, CONNFAIL, NULL);
04750                return DC_COMPLETE;
04751          }
04752          break;
04753 
04754       case 4: /* Enter Command Mode */
04755       
04756          /* if doesnt allow link cmd, or no links active, return */
04757          if (((command_source != SOURCE_RPT) && 
04758             (command_source != SOURCE_PHONE) &&
04759             (command_source != SOURCE_DPHONE)) ||
04760              (myrpt->links.next == &myrpt->links))
04761             return DC_COMPLETE;
04762          
04763          /* if already in cmd mode, or selected self, fughetabahtit */
04764          if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name, digitbuf))){
04765          
04766             rpt_telemetry(myrpt, REMALREADY, NULL);
04767             return DC_COMPLETE;
04768          }
04769          if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
04770             strcpy(digitbuf,myrpt->lastlinknode);
04771          /* node must at least exist in list */
04772          val = node_lookup(myrpt,digitbuf);
04773          if (!val){
04774             if(strlen(digitbuf) >= myrpt->longestnode)
04775                return DC_ERROR;
04776             break;
04777          
04778          }
04779          rpt_mutex_lock(&myrpt->lock);
04780          strcpy(myrpt->lastlinknode,digitbuf);
04781          strncpy(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode) - 1);
04782          rpt_mutex_unlock(&myrpt->lock);
04783          rpt_telemetry(myrpt, REMGO, NULL);  
04784          return DC_COMPLETE;
04785          
04786       case 5: /* Status */
04787          rpt_telemetry(myrpt, STATUS, NULL);
04788          return DC_COMPLETE;
04789 
04790       case 15: /* Full Status */
04791          rpt_telemetry(myrpt, FULLSTATUS, NULL);
04792          return DC_COMPLETE;
04793          
04794          
04795       case 6: /* All Links Off, including permalinks */
04796                        rpt_mutex_lock(&myrpt->lock);
04797          myrpt->savednodes[0] = 0;
04798                         l = myrpt->links.next;
04799                         /* loop through all links */
04800                         while(l != &myrpt->links){
04801             struct   ast_frame wf;
04802                                 if (l->name[0] == '0') /* Skip any IAXRPT monitoring */
04803                                 {
04804                                         l = l->next;
04805                                         continue;
04806                                 }
04807             /* Make a string of disconnected nodes for possible restoration */
04808             sprintf(tmp,"%c%c%s",(l->mode) ? 'X' : 'M',(l->perma) ? 'P':'T',l->name);
04809             if(strlen(tmp) + strlen(myrpt->savednodes) + 1 < MAXNODESTR){ 
04810                if(myrpt->savednodes[0])
04811                   strcat(myrpt->savednodes, ",");
04812                strcat(myrpt->savednodes, tmp);
04813             }
04814                               l->retries = l->max_retries + 1;
04815                                 l->disced = 2; /* Silently disconnect */
04816                                 rpt_mutex_unlock(&myrpt->lock);
04817             /* ast_log(LOG_NOTICE,"dumping link %s\n",l->name); */
04818                                 
04819                                 wf.frametype = AST_FRAME_TEXT;
04820                                 wf.subclass = 0;
04821                                 wf.offset = 0;
04822                                 wf.mallocd = 0;
04823                                 wf.datalen = strlen(discstr) + 1;
04824                                 wf.samples = 0;
04825                                 wf.data = discstr;
04826                                 if (l->chan)
04827                                 {
04828                                         ast_write(l->chan,&wf);
04829                                         ast_safe_sleep(l->chan,250); /* It's dead already, why check the return value? */
04830                                         ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
04831                                 }
04832             rpt_mutex_lock(&myrpt->lock);
04833                                 l = l->next;
04834                         }
04835          rpt_mutex_unlock(&myrpt->lock);
04836          if(debug > 3)
04837             ast_log(LOG_NOTICE,"Nodes disconnected: %s\n",myrpt->savednodes);
04838                         rpt_telemetry(myrpt, COMPLETE, NULL);
04839          return DC_COMPLETE;
04840 
04841       case 7: /* Identify last node which keyed us up */
04842          rpt_telemetry(myrpt, LASTNODEKEY, NULL);
04843          break;
04844 
04845 
04846 #ifdef   _MDC_DECODE_H_
04847       case 8:
04848          myrpt->lastunit = 0xd00d; 
04849          mdc1200_notify(myrpt,NULL,myrpt->lastunit);
04850          mdc1200_send(myrpt,myrpt->lastunit);
04851          break;
04852 #endif
04853 
04854       case 16: /* Restore links disconnected with "disconnect all links" command */
04855          strcpy(tmp, myrpt->savednodes); /* Make a copy */
04856          finddelim(tmp, strs, MAXLINKLIST); /* convert into substrings */
04857          for(i = 0; tmp[0] && strs[i] != NULL && i < MAXLINKLIST; i++){
04858             s1 = strs[i];
04859             mode = (s1[0] == 'X') ? 1 : 0;
04860             perma = (s1[1] == 'P') ? 1 : 0;
04861             connect_link(myrpt, s1 + 2, mode, perma); /* Try to reconnect */
04862          }
04863                         rpt_telemetry(myrpt, COMPLETE, NULL);
04864          break;
04865    
04866       case 200:
04867       case 201:
04868       case 202:
04869       case 203:
04870       case 204:
04871       case 205:
04872       case 206:
04873       case 207:
04874       case 208:
04875       case 209:
04876       case 210:
04877       case 211:
04878       case 212:
04879       case 213:
04880       case 214:
04881       case 215:
04882          if (((myrpt->p.propagate_dtmf) && 
04883               (command_source == SOURCE_LNK)) ||
04884              ((myrpt->p.propagate_phonedtmf) &&
04885             ((command_source == SOURCE_PHONE) ||
04886                 (command_source == SOURCE_DPHONE))))
04887                do_dtmf_local(myrpt,
04888                   remdtmfstr[myatoi(param) - 200]);
04889       default:
04890          return DC_ERROR;
04891          
04892    }
04893    
04894    return DC_INDETERMINATE;
04895 }  
04896 
04897 /*
04898 * Autopatch up
04899 */
04900 
04901 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
04902 {
04903    pthread_attr_t attr;
04904    int i, index, paramlength;
04905    char *lparam;
04906    char *value = NULL;
04907    char *paramlist[20];
04908 
04909    static char *keywords[] = {
04910    "context",
04911    "dialtime",
04912    "farenddisconnect",
04913    "noct",
04914    "quiet",
04915    NULL
04916    };
04917       
04918    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
04919       return DC_ERROR;
04920       
04921    if(debug)
04922       printf("@@@@ Autopatch up\n");
04923 
04924    if(!myrpt->callmode){
04925       /* Set defaults */
04926       myrpt->patchnoct = 0;
04927       myrpt->patchdialtime = 0;
04928       myrpt->patchfarenddisconnect = 0;
04929       myrpt->patchquiet = 0;
04930       strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
04931 
04932       if(param){
04933          /* Process parameter list */
04934          lparam = ast_strdupa(param);
04935          if(!lparam){
04936             ast_log(LOG_ERROR,"App_rpt out of memory on line %d\n",__LINE__);
04937             return DC_ERROR;  
04938          }
04939          paramlength = finddelim(lparam, paramlist, 20);          
04940          for(i = 0; i < paramlength; i++){
04941             index = matchkeyword(paramlist[i], &value, keywords);
04942             if(value)
04943                value = skipchars(value, "= ");
04944             switch(index){
04945 
04946                case 1: /* context */
04947                   strncpy(myrpt->patchcontext, value, MAXPATCHCONTEXT - 1) ;
04948                   break;
04949                   
04950                case 2: /* dialtime */
04951                   myrpt->patchdialtime = atoi(value);
04952                   break;
04953 
04954                case 3: /* farenddisconnect */
04955                   myrpt->patchfarenddisconnect = atoi(value);
04956                   break;
04957 
04958                case 4:  /* noct */
04959                   myrpt->patchnoct = atoi(value);
04960                   break;
04961 
04962                case 5: /* quiet */
04963                   myrpt->patchquiet = atoi(value);
04964                   break;
04965                            
04966                default:
04967                   break;
04968             }
04969          }
04970       }
04971    }
04972                
04973    rpt_mutex_lock(&myrpt->lock);
04974 
04975    /* if on call, force * into current audio stream */
04976    
04977    if ((myrpt->callmode == 2) || (myrpt->callmode == 3)){
04978       myrpt->mydtmf = myrpt->p.endchar;
04979    }
04980    if (myrpt->callmode){
04981       rpt_mutex_unlock(&myrpt->lock);
04982       return DC_COMPLETE;
04983    }
04984    myrpt->callmode = 1;
04985    myrpt->cidx = 0;
04986    myrpt->exten[myrpt->cidx] = 0;
04987    rpt_mutex_unlock(&myrpt->lock);
04988    pthread_attr_init(&attr);
04989    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
04990    ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *) myrpt);
04991    return DC_COMPLETE;
04992 }
04993 
04994 /*
04995 * Autopatch down
04996 */
04997 
04998 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
04999 {
05000    if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
05001       return DC_ERROR;
05002    
05003    if(debug)
05004       printf("@@@@ Autopatch down\n");
05005       
05006    rpt_mutex_lock(&myrpt->lock);
05007    
05008    if (!myrpt->callmode){
05009       rpt_mutex_unlock(&myrpt->lock);
05010       return DC_COMPLETE;
05011    }
05012    
05013    myrpt->callmode = 0;
05014    rpt_mutex_unlock(&myrpt->lock);
05015    rpt_telemetry(myrpt, TERM, NULL);
05016    return DC_COMPLETE;
05017 }
05018 
05019 /*
05020 * Status
05021 */
05022 
05023 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
05024 {
05025 
05026    if (!param)
05027       return DC_ERROR;
05028 
05029    if ((myrpt->p.s[myrpt->p.sysstate_cur].txdisable) || (myrpt->p.s[myrpt->p.sysstate_cur].userfundisable))
05030       return DC_ERROR;
05031 
05032    if(debug)
05033       printf("@@@@ status param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
05034    
05035    switch(myatoi(param)){
05036       case 1: /* System ID */
05037          rpt_telemetry(myrpt, ID1, NULL);
05038          return DC_COMPLETE;
05039       case 2: /* System Time */
05040          rpt_telemetry(myrpt, STATS_TIME, NULL);
05041          return DC_COMPLETE;
05042       case 3: /* app_rpt.c version */
05043          rpt_telemetry(myrpt, STATS_VERSION, NULL);
05044       default:
05045          return DC_ERROR;
05046    }
05047    return DC_INDETERMINATE;
05048 }
05049 
05050 /*
05051 *  Macro-oni (without Salami)
05052 */
05053 
05054 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
05055 {
05056 
05057 char  *val;
05058 int   i;
05059    if (myrpt->remote)
05060       return DC_ERROR;
05061 
05062    if(debug) 
05063       printf("@@@@ macro-oni param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
05064    
05065    if(strlen(digitbuf) < 1) /* needs 1 digit */
05066       return DC_INDETERMINATE;
05067          
05068    for(i = 0 ; i < digitbuf[i] ; i++) {
05069       if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
05070          return DC_ERROR;
05071    }
05072    
05073    if (*digitbuf == '0') val = myrpt->p.startupmacro;
05074    else val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, digitbuf);
05075    /* param was 1 for local buf */
05076    if (!val){
05077                 if (strlen(digitbuf) < myrpt->macro_longest)
05078                         return DC_INDETERMINATE;
05079       rpt_telemetry(myrpt, MACRO_NOTFOUND, NULL);
05080       return DC_COMPLETE;
05081    }        
05082    rpt_mutex_lock(&myrpt->lock);
05083    if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val))
05084    {
05085       rpt_mutex_unlock(&myrpt->lock);
05086       rpt_telemetry(myrpt, MACRO_BUSY, NULL);
05087       return DC_ERROR;
05088    }
05089    myrpt->macrotimer = MACROTIME;
05090    strncat(myrpt->macrobuf, val, MAXMACRO - strlen(myrpt->macrobuf) - 1);
05091    rpt_mutex_unlock(&myrpt->lock);
05092    return DC_COMPLETE;  
05093 }
05094 
05095 /*
05096 * COP - Control operator
05097 */
05098 
05099 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
05100 {
05101    char string[16];
05102    int res;
05103 
05104    if(!param)
05105       return DC_ERROR;
05106    
05107    switch(myatoi(param)){
05108       case 1: /* System reset */
05109          res = system("killall -9 asterisk");
05110          return DC_COMPLETE;
05111 
05112       case 2:
05113          myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 0;
05114          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "RPTENA");
05115          return DC_COMPLETE;
05116          
05117       case 3:
05118          myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 1;
05119          return DC_COMPLETE;
05120          
05121       case 4: /* test tone on */
05122          if (myrpt->stopgen < 0) 
05123          {
05124             myrpt->stopgen = 1;
05125          }
05126          else 
05127          {
05128             myrpt->stopgen = 0;
05129             rpt_telemetry(myrpt, TEST_TONE, NULL);
05130          }
05131          return DC_COMPLETE;
05132 
05133       case 5: /* Disgorge variables to log for debug purposes */
05134          myrpt->disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
05135          return DC_COMPLETE;
05136 
05137       case 6: /* Simulate COR being activated (phone only) */
05138          if (command_source != SOURCE_PHONE) return DC_INDETERMINATE;
05139          return DC_DOKEY;  
05140 
05141 
05142       case 7: /* Time out timer enable */
05143          myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 0;
05144          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTENA");
05145          return DC_COMPLETE;
05146          
05147       case 8: /* Time out timer disable */
05148          myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 1;
05149          rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTDIS");
05150          return DC_COMPLETE;
05151 
05152                 case 9: /* Autopatch enable */
05153                         myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 0;
05154                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APENA");
05155                         return DC_COMPLETE;
05156 
05157                 case 10: /* Autopatch disable */
05158                         myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 1;
05159                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APDIS");
05160                         return DC_COMPLETE;
05161 
05162                 case 11: /* Link Enable */
05163                         myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 0;
05164                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKENA");
05165                         return DC_COMPLETE;
05166 
05167                 case 12: /* Link Disable */
05168                         myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 1;
05169                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKDIS");
05170                         return DC_COMPLETE;
05171 
05172       case 13: /* Query System State */
05173          string[0] = string[1] = 'S';
05174          string[2] = myrpt->p.sysstate_cur + '0';
05175          string[3] = '\0';
05176          rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
05177          return DC_COMPLETE;
05178 
05179       case 14: /* Change System State */
05180          if(strlen(digitbuf) == 0)
05181             break;
05182          if((digitbuf[0] < '0') || (digitbuf[0] > '9'))
05183             return DC_ERROR;
05184          myrpt->p.sysstate_cur = digitbuf[0] - '0';
05185                         string[0] = string[1] = 'S';
05186                         string[2] = myrpt->p.sysstate_cur + '0';
05187                         string[3] = '\0';
05188                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
05189                         return DC_COMPLETE;
05190 
05191                 case 15: /* Scheduler Enable */
05192                         myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 0;
05193                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKENA");
05194                         return DC_COMPLETE;
05195 
05196                 case 16: /* Scheduler Disable */
05197                         myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 1;
05198                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKDIS");
05199                         return DC_COMPLETE;
05200 
05201                 case 17: /* User functions Enable */
05202                         myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 0;
05203                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFENA");
05204                         return DC_COMPLETE;
05205 
05206                 case 18: /* User Functions Disable */
05207                         myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 1;
05208                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFDIS");
05209                         return DC_COMPLETE;
05210 
05211                 case 19: /* Alternate Tail Enable */
05212                         myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 1;
05213                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATENA");
05214                         return DC_COMPLETE;
05215 
05216                 case 20: /* Alternate Tail Disable */
05217                         myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 0;
05218                         rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATDIS");
05219                         return DC_COMPLETE;
05220    }  
05221    return DC_INDETERMINATE;
05222 }
05223 
05224 /*
05225 * Collect digits one by one until something matches
05226 */
05227 
05228 static int collect_function_digits(struct rpt *myrpt, char *digits, 
05229    int command_source, struct rpt_link *mylink)
05230 {
05231    int i;
05232    char *stringp,*action,*param,*functiondigits;
05233    char function_table_name[30] = "";
05234    char workstring[200];
05235    
05236    struct ast_variable *vp;
05237    
05238    if(debug)   
05239       printf("@@@@ Digits collected: %s, source: %d\n", digits, command_source);
05240    
05241    if (command_source == SOURCE_DPHONE) {
05242       if (!myrpt->p.dphone_functions) return DC_INDETERMINATE;
05243       strncpy(function_table_name, myrpt->p.dphone_functions, sizeof(function_table_name) - 1);
05244       }
05245    else if (command_source == SOURCE_PHONE) {
05246       if (!myrpt->p.phone_functions) return DC_INDETERMINATE;
05247       strncpy(function_table_name, myrpt->p.phone_functions, sizeof(function_table_name) - 1);
05248       }
05249    else if (command_source == SOURCE_LNK)
05250       strncpy(function_table_name, myrpt->p.link_functions, sizeof(function_table_name) - 1);
05251    else
05252       strncpy(function_table_name, myrpt->p.functions, sizeof(function_table_name) - 1);
05253    vp = ast_variable_browse(myrpt->cfg, function_table_name);
05254    while(vp) {
05255       if(!strncasecmp(vp->name, digits, strlen(vp->name)))
05256          break;
05257       vp = vp->next;
05258    }  
05259    if(!vp) {
05260       int n;
05261 
05262       n = myrpt->longestfunc;
05263       if (command_source == SOURCE_LNK) n = myrpt->link_longestfunc;
05264       else 
05265       if (command_source == SOURCE_PHONE) n = myrpt->phone_longestfunc;
05266       else 
05267       if (command_source == SOURCE_DPHONE) n = myrpt->dphone_longestfunc;
05268       
05269       if(strlen(digits) >= n)
05270          return DC_ERROR;
05271       else
05272          return DC_INDETERMINATE;
05273    }  
05274    /* Found a match, retrieve value part and parse */
05275    strncpy(workstring, vp->value, sizeof(workstring) - 1 );
05276    stringp = workstring;
05277    action = strsep(&stringp, ",");
05278    param = stringp;
05279    if(debug)
05280       printf("@@@@ action: %s, param = %s\n",action, (param) ? param : "(null)");
05281    /* Look up the action */
05282    for(i = 0 ; i < (sizeof(function_table)/sizeof(struct function_table_tag)); i++){
05283       if(!strncasecmp(action, function_table[i].action, strlen(action)))
05284          break;
05285    }
05286    if(debug)
05287       printf("@@@@ table index i = %d\n",i);
05288    if(i == (sizeof(function_table)/sizeof(struct function_table_tag))){
05289       /* Error, action not in table */
05290       return DC_ERROR;
05291    }
05292    if(function_table[i].function == NULL){
05293       /* Error, function undefined */
05294       if(debug)
05295          printf("@@@@ NULL for action: %s\n",action);
05296       return DC_ERROR;
05297    }
05298    functiondigits = digits + strlen(vp->name);
05299    return (*function_table[i].function)(myrpt, param, functiondigits, command_source, mylink);
05300 }
05301 
05302 
05303 static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink,
05304    char *str)
05305 {
05306 char  tmp[512],cmd[300] = "",dest[300],src[300],c;
05307 int   seq, res;
05308 struct rpt_link *l;
05309 struct   ast_frame wf;
05310 
05311    wf.frametype = AST_FRAME_TEXT;
05312    wf.subclass = 0;
05313    wf.offset = 0;
05314    wf.mallocd = 0;
05315    wf.datalen = strlen(str) + 1;
05316    wf.samples = 0;
05317    /* put string in our buffer */
05318    strncpy(tmp,str,sizeof(tmp) - 1);
05319 
05320         if (!strcmp(tmp,discstr))
05321         {
05322                 mylink->disced = 1;
05323       mylink->retries = mylink->max_retries + 1;
05324                 ast_softhangup(mylink->chan,AST_SOFTHANGUP_DEV);
05325                 return;
05326         }
05327    if (tmp[0] == 'L')
05328    {
05329       rpt_mutex_lock(&myrpt->lock);
05330       strcpy(mylink->linklist,tmp + 2);
05331       time(&mylink->linklistreceived);
05332       rpt_mutex_unlock(&myrpt->lock);
05333       if (debug > 6) ast_log(LOG_NOTICE,"@@@@ node %s recieved node list %s from node %s\n",
05334          myrpt->name,tmp,mylink->name);
05335       return;
05336    }
05337    if (tmp[0] == 'I')
05338    {
05339       if (sscanf(tmp,"%s %s %x",cmd,src,&seq) != 3)
05340       {
05341          ast_log(LOG_WARNING, "Unable to parse ident string %s\n",str);
05342          return;
05343       }
05344       mdc1200_notify(myrpt,src,seq);
05345       strcpy(dest,"*");
05346    }
05347    else
05348    {
05349       if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
05350       {
05351          ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
05352          return;
05353       }
05354       if (strcmp(cmd,"D"))
05355       {
05356          ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
05357          return;
05358       }
05359    }
05360    if (dest[0] == '0')
05361    {
05362       strcpy(dest,myrpt->name);
05363    }     
05364 
05365    /* if not for me, redistribute to all links */
05366    if (strcmp(dest,myrpt->name))
05367    {
05368       l = myrpt->links.next;
05369       /* see if this is one in list */
05370       while(l != &myrpt->links)
05371       {
05372          if (l->name[0] == '0') 
05373          {
05374             l = l->next;
05375             continue;
05376          }
05377          /* dont send back from where it came */
05378          if ((l == mylink) || (!strcmp(l->name,mylink->name)))
05379          {
05380             l = l->next;
05381             continue;
05382          }
05383          /* if it is, send it and we're done */
05384          if (!strcmp(l->name,dest))
05385          {
05386             /* send, but not to src */
05387             if (strcmp(l->name,src)) {
05388                wf.data = str;
05389                if (l->chan) ast_write(l->chan,&wf);
05390             }
05391             return;
05392          }
05393          l = l->next;
05394       }
05395       l = myrpt->links.next;
05396       /* otherwise, send it to all of em */
05397       while(l != &myrpt->links)
05398       {
05399          if (l->name[0] == '0') 
05400          {
05401             l = l->next;
05402             continue;
05403          }
05404          /* dont send back from where it came */
05405          if ((l == mylink) || (!strcmp(l->name,mylink->name)))
05406          {
05407             l = l->next;
05408             continue;
05409          }
05410          /* send, but not to src */
05411          if (strcmp(l->name,src)) {
05412             wf.data = str;
05413             if (l->chan) ast_write(l->chan,&wf); 
05414          }
05415          l = l->next;
05416       }
05417       return;
05418    }
05419    if (myrpt->p.archivedir)
05420    {
05421       char str[100];
05422 
05423       sprintf(str,"DTMF,%s,%c",mylink->name,c);
05424       donodelog(myrpt,str);
05425    }
05426    c = func_xlat(myrpt,c,&myrpt->p.outxlat);
05427    if (!c) return;
05428    rpt_mutex_lock(&myrpt->lock);
05429    if (c == myrpt->p.endchar) myrpt->stopgen = 1;
05430    if (myrpt->callmode == 1)
05431    {
05432       myrpt->exten[myrpt->cidx++] = c;
05433       myrpt->exten[myrpt->cidx] = 0;
05434       /* if this exists */
05435       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
05436       {
05437          myrpt->callmode = 2;
05438          if(!myrpt->patchquiet){
05439             rpt_mutex_unlock(&myrpt->lock);
05440             rpt_telemetry(myrpt,PROC,NULL); 
05441             rpt_mutex_lock(&myrpt->lock);
05442          }
05443       }
05444       /* if can continue, do so */
05445       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL)) 
05446       {
05447          /* call has failed, inform user */
05448          myrpt->callmode = 4;
05449       }
05450    }
05451    if (c == myrpt->p.funcchar)
05452    {
05453       myrpt->rem_dtmfidx = 0;
05454       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
05455       time(&myrpt->rem_dtmf_time);
05456       rpt_mutex_unlock(&myrpt->lock);
05457       return;
05458    } 
05459    else if (myrpt->rem_dtmfidx < 0)
05460    {
05461       if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
05462       {
05463          myrpt->mydtmf = c;
05464       }
05465       if (myrpt->p.propagate_dtmf) do_dtmf_local(myrpt,c);
05466       if (myrpt->p.propagate_phonedtmf) do_dtmf_phone(myrpt,mylink,c);
05467       rpt_mutex_unlock(&myrpt->lock);
05468       return;
05469    }
05470    else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0))
05471    {
05472       time(&myrpt->rem_dtmf_time);
05473       if (myrpt->rem_dtmfidx < MAXDTMF)
05474       {
05475          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
05476          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
05477          
05478          rpt_mutex_unlock(&myrpt->lock);
05479          strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
05480          res = collect_function_digits(myrpt, cmd, SOURCE_LNK, mylink);
05481          rpt_mutex_lock(&myrpt->lock);
05482          
05483          switch(res){
05484 
05485             case DC_INDETERMINATE:
05486                break;
05487             
05488             case DC_REQ_FLUSH:
05489                myrpt->rem_dtmfidx = 0;
05490                myrpt->rem_dtmfbuf[0] = 0;
05491                break;
05492             
05493             
05494             case DC_COMPLETE:
05495             case DC_COMPLETEQUIET:
05496                myrpt->totalexecdcommands++;
05497                myrpt->dailyexecdcommands++;
05498                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
05499                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
05500                myrpt->rem_dtmfbuf[0] = 0;
05501                myrpt->rem_dtmfidx = -1;
05502                myrpt->rem_dtmf_time = 0;
05503                break;
05504             
05505             case DC_ERROR:
05506             default:
05507                myrpt->rem_dtmfbuf[0] = 0;
05508                myrpt->rem_dtmfidx = -1;
05509                myrpt->rem_dtmf_time = 0;
05510                break;
05511          }
05512       }
05513 
05514    }
05515    rpt_mutex_unlock(&myrpt->lock);
05516    return;
05517 }
05518 
05519 static void handle_link_phone_dtmf(struct rpt *myrpt, struct rpt_link *mylink,
05520    char c)
05521 {
05522 
05523 char  cmd[300];
05524 int   res;
05525 
05526    if (myrpt->p.archivedir)
05527    {
05528       char str[100];
05529 
05530       sprintf(str,"DTMF(P),%s,%c",mylink->name,c);
05531       donodelog(myrpt,str);
05532    }
05533    rpt_mutex_lock(&myrpt->lock);
05534    if (c == myrpt->p.endchar)
05535    {
05536       if (mylink->lastrx)
05537       {
05538          mylink->lastrx = 0;
05539          rpt_mutex_unlock(&myrpt->lock);
05540          return;
05541       }
05542       myrpt->stopgen = 1;
05543       if (myrpt->cmdnode[0])
05544       {
05545          myrpt->cmdnode[0] = 0;
05546          myrpt->dtmfidx = -1;
05547          myrpt->dtmfbuf[0] = 0;
05548          rpt_mutex_unlock(&myrpt->lock);
05549          rpt_telemetry(myrpt,COMPLETE,NULL);
05550          return;
05551       }
05552    }
05553    if (myrpt->cmdnode[0])
05554    {
05555       rpt_mutex_unlock(&myrpt->lock);
05556       send_link_dtmf(myrpt,c);
05557       return;
05558    }
05559    if (myrpt->callmode == 1)
05560    {
05561       myrpt->exten[myrpt->cidx++] = c;
05562       myrpt->exten[myrpt->cidx] = 0;
05563       /* if this exists */
05564       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
05565       {
05566          myrpt->callmode = 2;
05567          if(!myrpt->patchquiet){
05568             rpt_mutex_unlock(&myrpt->lock);
05569             rpt_telemetry(myrpt,PROC,NULL); 
05570             rpt_mutex_lock(&myrpt->lock);
05571          }
05572       }
05573       /* if can continue, do so */
05574       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL)) 
05575       {
05576          /* call has failed, inform user */
05577          myrpt->callmode = 4;
05578       }
05579    }
05580    if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
05581    {
05582       myrpt->mydtmf = c;
05583    }
05584    if (c == myrpt->p.funcchar)
05585    {
05586       myrpt->rem_dtmfidx = 0;
05587       myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
05588       time(&myrpt->rem_dtmf_time);
05589       rpt_mutex_unlock(&myrpt->lock);
05590       return;
05591    } 
05592    else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0))
05593    {
05594       time(&myrpt->rem_dtmf_time);
05595       if (myrpt->rem_dtmfidx < MAXDTMF)
05596       {
05597          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
05598          myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
05599          
05600          rpt_mutex_unlock(&myrpt->lock);
05601          strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
05602          switch(mylink->phonemode)
05603          {
05604              case 1:
05605             res = collect_function_digits(myrpt, cmd, 
05606                SOURCE_PHONE, mylink);
05607             break;
05608              case 2:
05609             res = collect_function_digits(myrpt, cmd, 
05610                SOURCE_DPHONE,mylink);
05611             break;
05612              default:
05613             res = collect_function_digits(myrpt, cmd, 
05614                SOURCE_LNK, mylink);
05615             break;
05616          }
05617 
05618          rpt_mutex_lock(&myrpt->lock);
05619          
05620          switch(res){
05621 
05622             case DC_INDETERMINATE:
05623                break;
05624             
05625             case DC_DOKEY:
05626                mylink->lastrx = 1;
05627                break;
05628             
05629             case DC_REQ_FLUSH:
05630                myrpt->rem_dtmfidx = 0;
05631                myrpt->rem_dtmfbuf[0] = 0;
05632                break;
05633             
05634             
05635             case DC_COMPLETE:
05636             case DC_COMPLETEQUIET:
05637                myrpt->totalexecdcommands++;
05638                myrpt->dailyexecdcommands++;
05639                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
05640                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
05641                myrpt->rem_dtmfbuf[0] = 0;
05642                myrpt->rem_dtmfidx = -1;
05643                myrpt->rem_dtmf_time = 0;
05644                break;
05645             
05646             case DC_ERROR:
05647             default:
05648                myrpt->rem_dtmfbuf[0] = 0;
05649                myrpt->rem_dtmfidx = -1;
05650                myrpt->rem_dtmf_time = 0;
05651                break;
05652          }
05653       }
05654 
05655    }
05656    rpt_mutex_unlock(&myrpt->lock);
05657    return;
05658 }
05659 
05660 /* Doug Hall RBI-1 serial data definitions:
05661  *
05662  * Byte 0: Expansion external outputs 
05663  * Byte 1: 
05664  * Bits 0-3 are BAND as follows:
05665  * Bits 4-5 are POWER bits as follows:
05666  *    00 - Low Power
05667  *    01 - Hi Power
05668  *    02 - Med Power
05669  * Bits 6-7 are always set
05670  * Byte 2:
05671  * Bits 0-3 MHZ in BCD format
05672  * Bits 4-5 are offset as follows:
05673  *    00 - minus
05674  *    01 - plus
05675  *    02 - simplex
05676  *    03 - minus minus (whatever that is)
05677  * Bit 6 is the 0/5 KHZ bit
05678  * Bit 7 is always set
05679  * Byte 3:
05680  * Bits 0-3 are 10 KHZ in BCD format
05681  * Bits 4-7 are 100 KHZ in BCD format
05682  * Byte 4: PL Tone code and encode/decode enable bits
05683  * Bits 0-5 are PL tone code (comspec binary codes)
05684  * Bit 6 is encode enable/disable
05685  * Bit 7 is decode enable/disable
05686  */
05687 
05688 /* take the frequency from the 10 mhz digits (and up) and convert it
05689    to a band number */
05690 
05691 static int rbi_mhztoband(char *str)
05692 {
05693 int   i;
05694 
05695    i = atoi(str) / 10; /* get the 10's of mhz */
05696    switch(i)
05697    {
05698        case 2:
05699       return 10;
05700        case 5:
05701       return 11;
05702        case 14:
05703       return 2;
05704        case 22:
05705       return 3;
05706        case 44:
05707       return 4;
05708        case 124:
05709       return 0;
05710        case 125:
05711       return 1;
05712        case 126:
05713       return 8;
05714        case 127:
05715       return 5;
05716        case 128:
05717       return 6;
05718        case 129:
05719       return 7;
05720        default:
05721       break;
05722    }
05723    return -1;
05724 }
05725 
05726 /* take a PL frequency and turn it into a code */
05727 static int rbi_pltocode(char *str)
05728 {
05729 int i;
05730 char *s;
05731 
05732    s = strchr(str,'.');
05733    i = 0;
05734    if (s) i = atoi(s + 1);
05735    i += atoi(str) * 10;
05736    switch(i)
05737    {
05738        case 670:
05739       return 0;
05740        case 719:
05741       return 1;
05742        case 744:
05743       return 2;
05744        case 770:
05745       return 3;
05746        case 797:
05747       return 4;
05748        case 825:
05749       return 5;
05750        case 854:
05751       return 6;
05752        case 885:
05753       return 7;
05754        case 915:
05755       return 8;
05756        case 948:
05757       return 9;
05758        case 974:
05759       return 10;
05760        case 1000:
05761       return 11;
05762        case 1035:
05763       return 12;
05764        case 1072:
05765       return 13;
05766        case 1109:
05767       return 14;
05768        case 1148:
05769       return 15;
05770        case 1188:
05771       return 16;
05772        case 1230:
05773       return 17;
05774        case 1273:
05775       return 18;
05776        case 1318:
05777       return 19;
05778        case 1365:
05779       return 20;
05780        case 1413:
05781       return 21;
05782        case 1462:
05783       return 22;
05784        case 1514:
05785       return 23;
05786        case 1567:
05787       return 24;
05788        case 1622:
05789       return 25;
05790        case 1679:
05791       return 26;
05792        case 1738:
05793       return 27;
05794        case 1799:
05795       return 28;
05796        case 1862:
05797       return 29;
05798        case 1928:
05799       return 30;
05800        case 2035:
05801       return 31;
05802        case 2107:
05803       return 32;
05804        case 2181:
05805       return 33;
05806        case 2257:
05807       return 34;
05808        case 2336:
05809       return 35;
05810        case 2418:
05811       return 36;
05812        case 2503:
05813       return 37;
05814    }
05815    return -1;
05816 }
05817 
05818 /*
05819 * Shift out a formatted serial bit stream
05820 */
05821 
05822 static void rbi_out_parallel(struct rpt *myrpt,unsigned char *data)
05823     {
05824 #ifdef __i386__
05825     int i,j;
05826     unsigned char od,d;
05827     static volatile long long delayvar;
05828 
05829     for(i = 0 ; i < 5 ; i++){
05830         od = *data++; 
05831         for(j = 0 ; j < 8 ; j++){
05832             d = od & 1;
05833             outb(d,myrpt->p.iobase);
05834        /* >= 15 us */
05835        for(delayvar = 1; delayvar < 15000; delayvar++); 
05836             od >>= 1;
05837             outb(d | 2,myrpt->p.iobase);
05838        /* >= 30 us */
05839        for(delayvar = 1; delayvar < 30000; delayvar++); 
05840             outb(d,myrpt->p.iobase);
05841        /* >= 10 us */
05842        for(delayvar = 1; delayvar < 10000; delayvar++); 
05843             }
05844         }
05845    /* >= 50 us */
05846         for(delayvar = 1; delayvar < 50000; delayvar++); 
05847 #endif
05848     }
05849 
05850 static void rbi_out(struct rpt *myrpt,unsigned char *data)
05851 {
05852 struct dahdi_radio_param r;
05853 
05854    memset(&r,0,sizeof(struct dahdi_radio_param));
05855    r.radpar = DAHDI_RADPAR_REMMODE;
05856    r.data = DAHDI_RADPAR_REM_RBI1;
05857    /* if setparam ioctl fails, its probably not a pciradio card */
05858    if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&r) == -1)
05859    {
05860       rbi_out_parallel(myrpt,data);
05861       return;
05862    }
05863    r.radpar = DAHDI_RADPAR_REMCOMMAND;
05864    memcpy(&r.data,data,5);
05865    if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&r) == -1)
05866    {
05867       ast_log(LOG_WARNING,"Cannot send RBI command for channel %s\n",myrpt->zaprxchannel->name);
05868       return;
05869    }
05870 }
05871 
05872 static int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes, 
05873    unsigned char *rxbuf, int rxmaxbytes, int asciiflag)
05874 {
05875    int i,j,index,oldmode,olddata;
05876    struct dahdi_radio_param prm;
05877    char c;
05878 
05879    if(debug){
05880       printf("String output was: ");
05881       for(i = 0; i < txbytes; i++)
05882          printf("%02X ", (unsigned char ) txbuf[i]);
05883       printf("\n");
05884    }
05885    if (myrpt->iofd > 0)  /* if to do out a serial port */
05886    {
05887       if (rxmaxbytes && rxbuf) tcflush(myrpt->iofd,TCIFLUSH);     
05888       if (write(myrpt->iofd,txbuf,txbytes) != txbytes) return -1;
05889       if ((!rxmaxbytes) || (rxbuf == NULL)) return(0);
05890       memset(rxbuf,0,rxmaxbytes);
05891       for(i = 0; i < rxmaxbytes; i++)
05892       {
05893          j = read(myrpt->iofd,&c,1);
05894          if (j < 1) return(i);
05895          rxbuf[i] = c;
05896          if (asciiflag & 1)
05897          {
05898             rxbuf[i + 1] = 0;
05899             if (c == '\r') break;
05900          }
05901       }              
05902       if(debug){
05903          printf("String returned was: ");
05904          for(j = 0; j < i; j++)
05905             printf("%02X ", (unsigned char ) rxbuf[j]);
05906          printf("\n");
05907       }
05908       return(i);
05909    }
05910 
05911    /* if not a zap channel, cant use pciradio stuff */
05912    if (myrpt->rxchannel != myrpt->zaprxchannel) return -1;  
05913 
05914    prm.radpar = DAHDI_RADPAR_UIOMODE;
05915    if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_GETPARAM,&prm) == -1) return -1;
05916    oldmode = prm.data;
05917    prm.radpar = DAHDI_RADPAR_UIODATA;
05918    if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_GETPARAM,&prm) == -1) return -1;
05919    olddata = prm.data;
05920         prm.radpar = DAHDI_RADPAR_REMMODE;
05921         if (asciiflag & 1)  prm.data = DAHDI_RADPAR_REM_SERIAL_ASCII;
05922         else prm.data = DAHDI_RADPAR_REM_SERIAL;
05923    if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
05924    if (asciiflag & 2)
05925    {
05926       i = DAHDI_ONHOOK;
05927       if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_HOOK,&i) == -1) return -1;
05928       usleep(100000);
05929    }
05930         prm.radpar = DAHDI_RADPAR_REMCOMMAND;
05931         prm.data = rxmaxbytes;
05932         memcpy(prm.buf,txbuf,txbytes);
05933         prm.index = txbytes;
05934    if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
05935         if (rxbuf)
05936         {
05937                 *rxbuf = 0;
05938                 memcpy(rxbuf,prm.buf,prm.index);
05939         }
05940    index = prm.index;
05941         prm.radpar = DAHDI_RADPAR_REMMODE;
05942         prm.data = DAHDI_RADPAR_REM_NONE;
05943    if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
05944    if (asciiflag & 2)
05945    {
05946       i = DAHDI_OFFHOOK;
05947       if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_HOOK,&i) == -1) return -1;
05948    }
05949    prm.radpar = DAHDI_RADPAR_UIOMODE;
05950    prm.data = oldmode;
05951    if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
05952    prm.radpar = DAHDI_RADPAR_UIODATA;
05953    prm.data = olddata;
05954    if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_RADIO_SETPARAM,&prm) == -1) return -1;
05955         return(index);
05956 }
05957 
05958 static int civ_cmd(struct rpt *myrpt,unsigned char *cmd, int cmdlen)
05959 {
05960 unsigned char rxbuf[100];
05961 int   i,rv ;
05962 
05963    rv = serial_remote_io(myrpt,cmd,cmdlen,rxbuf,cmdlen + 6,0);
05964    if (rv == -1) return(-1);
05965    if (rv != (cmdlen + 6)) return(1);
05966    for(i = 0; i < 6; i++)
05967       if (rxbuf[i] != cmd[i]) return(1);
05968    if (rxbuf[cmdlen] != 0xfe) return(1);
05969    if (rxbuf[cmdlen + 1] != 0xfe) return(1);
05970    if (rxbuf[cmdlen + 4] != 0xfb) return(1);
05971    if (rxbuf[cmdlen + 5] != 0xfd) return(1);
05972    return(0);
05973 }
05974 
05975 static int sendkenwood(struct rpt *myrpt,char *txstr, char *rxstr)
05976 {
05977 int   i;
05978 
05979    if (debug) printf("Send to kenwood: %s\n",txstr);
05980    i = serial_remote_io(myrpt, (unsigned char *)txstr, strlen(txstr), 
05981       (unsigned char *)rxstr,RAD_SERIAL_BUFLEN - 1,3);
05982    if (i < 0) return -1;
05983    if ((i > 0) && (rxstr[i - 1] == '\r'))
05984       rxstr[i-- - 1] = 0;
05985    if (debug) printf("Got from kenwood: %s\n",rxstr);
05986    return(i);
05987 }
05988 
05989 /* take a PL frequency and turn it into a code */
05990 static int kenwood_pltocode(char *str)
05991 {
05992 int i;
05993 char *s;
05994 
05995    s = strchr(str,'.');
05996    i = 0;
05997    if (s) i = atoi(s + 1);
05998    i += atoi(str) * 10;
05999    switch(i)
06000    {
06001        case 670:
06002       return 1;
06003        case 719:
06004       return 3;
06005        case 744:
06006       return 4;
06007        case 770:
06008       return 5;
06009        case 797:
06010       return 6;
06011        case 825:
06012       return 7;
06013        case 854:
06014       return 8;
06015        case 885:
06016       return 9;
06017        case 915:
06018       return 10;
06019        case 948:
06020       return 11;
06021        case 974:
06022       return 12;
06023        case 1000:
06024       return 13;
06025        case 1035:
06026       return 14;
06027        case 1072:
06028       return 15;
06029        case 1109:
06030       return 16;
06031        case 1148:
06032       return 17;
06033        case 1188:
06034       return 18;
06035        case 1230:
06036       return 19;
06037        case 1273:
06038       return 20;
06039        case 1318:
06040       return 21;
06041        case 1365:
06042       return 22;
06043        case 1413:
06044       return 23;
06045        case 1462:
06046       return 24;
06047        case 1514:
06048       return 25;
06049        case 1567:
06050       return 26;
06051        case 1622:
06052       return 27;
06053        case 1679:
06054       return 28;
06055        case 1738:
06056       return 29;
06057        case 1799:
06058       return 30;
06059        case 1862:
06060       return 31;
06061        case 1928:
06062       return 32;
06063        case 2035:
06064       return 33;
06065        case 2107:
06066       return 34;
06067        case 2181:
06068       return 35;
06069        case 2257:
06070       return 36;
06071        case 2336:
06072       return 37;
06073        case 2418:
06074       return 38;
06075        case 2503:
06076       return 39;
06077    }
06078    return -1;
06079 }
06080 
06081 static int sendrxkenwood(struct rpt *myrpt, char *txstr, char *rxstr, 
06082    char *cmpstr)
06083 {
06084 int   i,j;
06085 
06086    for(i = 0;i < KENWOOD_RETRIES;i++)
06087    {
06088       j = sendkenwood(myrpt,txstr,rxstr);
06089       if (j < 0) return(j);
06090       if (j == 0) continue;
06091       if (!strncmp(rxstr,cmpstr,strlen(cmpstr))) return(0);
06092    }
06093    return(-1);
06094 }     
06095 
06096 static int setkenwood(struct rpt *myrpt)
06097 {
06098 char rxstr[RAD_SERIAL_BUFLEN],txstr[RAD_SERIAL_BUFLEN],freq[20];
06099 char mhz[MAXREMSTR],offset[20],band,decimals[MAXREMSTR],band1,band2;
06100    
06101 int offsets[] = {0,2,1};
06102 int powers[] = {2,1,0};
06103 
06104    if (sendrxkenwood(myrpt,"VMC 0,0\r",rxstr,"VMC") < 0) return -1;
06105    split_freq(mhz, decimals, myrpt->freq);
06106    if (atoi(mhz) > 400)
06107    {
06108       band = '6';
06109       band1 = '1';
06110       band2 = '5';
06111       strcpy(offset,"005000000");
06112    }
06113    else
06114    {
06115       band = '2';
06116       band1 = '0';
06117       band2 = '2';
06118       strcpy(offset,"000600000");
06119    }
06120    strcpy(freq,"000000");
06121    strncpy(freq,decimals,strlen(decimals));
06122    sprintf(txstr,"VW %c,%05d%s,0,%d,0,%d,%d,,%02d,,%02d,%s\r",
06123       band,atoi(mhz),freq,offsets[(int)myrpt->offset],
06124       (myrpt->txplon != 0),(myrpt->rxplon != 0),
06125       kenwood_pltocode(myrpt->txpl),kenwood_pltocode(myrpt->rxpl),
06126       offset);
06127    if (sendrxkenwood(myrpt,txstr,rxstr,"VW") < 0) return -1;
06128    sprintf(txstr,"RBN %c\r",band2);
06129    if (sendrxkenwood(myrpt,txstr,rxstr,"RBN") < 0) return -1;
06130    sprintf(txstr,"PC %c,%d\r",band1,powers[(int)myrpt->powerlevel]);
06131    if (sendrxkenwood(myrpt,txstr,rxstr,"PC") < 0) return -1;
06132    return 0;
06133 }
06134 
06135 static int setrbi(struct rpt *myrpt)
06136 {
06137 char tmp[MAXREMSTR] = "",*s;
06138 unsigned char rbicmd[5];
06139 int   band,txoffset = 0,txpower = 0,rxpl;
06140 
06141    /* must be a remote system */
06142    if (!myrpt->remote) return(0);
06143    /* must have rbi hardware */
06144    if (strncmp(myrpt->remote,remote_rig_rbi,3)) return(0);
06145    if (setrbi_check(myrpt) == -1) return(-1);
06146    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
06147    s = strchr(tmp,'.');
06148    /* if no decimal, is invalid */
06149    
06150    if (s == NULL){
06151       if(debug)
06152          printf("@@@@ Frequency needs a decimal\n");
06153       return -1;
06154    }
06155    
06156    *s++ = 0;
06157    if (strlen(tmp) < 2){
06158       if(debug)
06159          printf("@@@@ Bad MHz digits: %s\n", tmp);
06160       return -1;
06161    }
06162     
06163    if (strlen(s) < 3){
06164       if(debug)
06165          printf("@@@@ Bad KHz digits: %s\n", s);
06166       return -1;
06167    }
06168 
06169    if ((s[2] != '0') && (s[2] != '5')){
06170       if(debug)
06171          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
06172       return -1;
06173    }
06174     
06175    band = rbi_mhztoband(tmp);
06176    if (band == -1){
06177       if(debug)
06178          printf("@@@@ Bad Band: %s\n", tmp);
06179       return -1;
06180    }
06181    
06182    rxpl = rbi_pltocode(myrpt->rxpl);
06183    
06184    if (rxpl == -1){
06185       if(debug)
06186          printf("@@@@ Bad TX PL: %s\n", myrpt->rxpl);
06187       return -1;
06188    }
06189 
06190    
06191    switch(myrpt->offset)
06192    {
06193        case REM_MINUS:
06194       txoffset = 0;
06195       break;
06196        case REM_PLUS:
06197       txoffset = 0x10;
06198       break;
06199        case REM_SIMPLEX:
06200       txoffset = 0x20;
06201       break;
06202    }
06203    switch(myrpt->powerlevel)
06204    {
06205        case REM_LOWPWR:
06206       txpower = 0;
06207       break;
06208        case REM_MEDPWR:
06209       txpower = 0x20;
06210       break;
06211        case REM_HIPWR:
06212       txpower = 0x10;
06213       break;
06214    }
06215    rbicmd[0] = 0;
06216    rbicmd[1] = band | txpower | 0xc0;
06217    rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80;
06218    if (s[2] == '5') rbicmd[2] |= 0x40;
06219    rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0');
06220    rbicmd[4] = rxpl;
06221    if (myrpt->txplon) rbicmd[4] |= 0x40;
06222    if (myrpt->rxplon) rbicmd[4] |= 0x80;
06223    rbi_out(myrpt,rbicmd);
06224    return 0;
06225 }
06226 
06227 static int setrbi_check(struct rpt *myrpt)
06228 {
06229 char tmp[MAXREMSTR] = "",*s;
06230 int   band,txpl;
06231 
06232    /* must be a remote system */
06233    if (!myrpt->remote) return(0);
06234    /* must have rbi hardware */
06235    if (strncmp(myrpt->remote,remote_rig_rbi,3)) return(0);
06236    strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
06237    s = strchr(tmp,'.');
06238    /* if no decimal, is invalid */
06239    
06240    if (s == NULL){
06241       if(debug)
06242          printf("@@@@ Frequency needs a decimal\n");
06243       return -1;
06244    }
06245    
06246    *s++ = 0;
06247    if (strlen(tmp) < 2){
06248       if(debug)
06249          printf("@@@@ Bad MHz digits: %s\n", tmp);
06250       return -1;
06251    }
06252     
06253    if (strlen(s) < 3){
06254       if(debug)
06255          printf("@@@@ Bad KHz digits: %s\n", s);
06256       return -1;
06257    }
06258 
06259    if ((s[2] != '0') && (s[2] != '5')){
06260       if(debug)
06261          printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
06262       return -1;
06263    }
06264     
06265    band = rbi_mhztoband(tmp);
06266    if (band == -1){
06267       if(debug)
06268          printf("@@@@ Bad Band: %s\n", tmp);
06269       return -1;
06270    }
06271    
06272    txpl = rbi_pltocode(myrpt->txpl);
06273    
06274    if (txpl == -1){
06275       if(debug)
06276          printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
06277       return -1;
06278    }
06279    return 0;
06280 }
06281 
06282 static int check_freq_kenwood(int m, int d, int *defmode)
06283 {
06284    int dflmd = REM_MODE_FM;
06285 
06286    if (m == 144){ /* 2 meters */
06287       if(d < 10100)
06288          return -1;
06289    }
06290    else if((m >= 145) && (m < 148)){
06291       ;
06292    }
06293    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
06294       ;
06295    }
06296    else
06297       return -1;
06298    
06299    if(defmode)
06300       *defmode = dflmd; 
06301 
06302 
06303    return 0;
06304 }
06305 
06306 
06307 /* Check for valid rbi frequency */
06308 /* Hard coded limits now, configurable later, maybe? */
06309 
06310 static int check_freq_rbi(int m, int d, int *defmode)
06311 {
06312    int dflmd = REM_MODE_FM;
06313 
06314    if(m == 50){ /* 6 meters */
06315       if(d < 10100)
06316          return -1;
06317    }
06318    else if((m >= 51) && ( m < 54)){
06319                 ;
06320    }
06321    else if(m == 144){ /* 2 meters */
06322       if(d < 10100)
06323          return -1;
06324    }
06325    else if((m >= 145) && (m < 148)){
06326       ;
06327    }
06328    else if((m >= 222) && (m < 225)){ /* 1.25 meters */
06329       ;
06330    }
06331    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
06332       ;
06333    }
06334    else if((m >= 1240) && (m < 1300)){ /* 23 centimeters */
06335       ;
06336    }
06337    else
06338       return -1;
06339    
06340    if(defmode)
06341       *defmode = dflmd; 
06342 
06343 
06344    return 0;
06345 }
06346 
06347 /*
06348  * Convert decimals of frequency to int
06349  */
06350 
06351 static int decimals2int(char *fraction)
06352 {
06353    int i;
06354    char len = strlen(fraction);
06355    int multiplier = 100000;
06356    int res = 0;
06357 
06358    if(!len)
06359       return 0;
06360    for( i = 0 ; i < len ; i++, multiplier /= 10)
06361       res += (fraction[i] - '0') * multiplier;
06362    return res;
06363 }
06364 
06365 
06366 /*
06367 * Split frequency into mhz and decimals
06368 */
06369  
06370 static int split_freq(char *mhz, char *decimals, char *freq)
06371 {
06372    char freq_copy[MAXREMSTR];
06373    char *decp;
06374 
06375    decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
06376    if(decp){
06377       *decp++ = 0;
06378       strncpy(mhz, freq_copy, MAXREMSTR);
06379       strcpy(decimals, "00000");
06380       strncpy(decimals, decp, strlen(decp));
06381       decimals[5] = 0;
06382       return 0;
06383    }
06384    else
06385       return -1;
06386 
06387 }
06388    
06389 /*
06390 * Split ctcss frequency into hertz and decimal
06391 */
06392  
06393 static int split_ctcss_freq(char *hertz, char *decimal, char *freq)
06394 {
06395    char freq_copy[MAXREMSTR];
06396    char *decp;
06397 
06398    decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
06399    if(decp){
06400       *decp++ = 0;
06401       strncpy(hertz, freq_copy, MAXREMSTR);
06402       strncpy(decimal, decp, strlen(decp));
06403       decimal[strlen(decp)] = '\0';
06404       return 0;
06405    }
06406    else
06407       return -1;
06408 }
06409 
06410 
06411 
06412 /*
06413 * FT-897 I/O handlers
06414 */
06415 
06416 /* Check to see that the frequency is valid */
06417 /* Hard coded limits now, configurable later, maybe? */
06418 
06419 
06420 static int check_freq_ft897(int m, int d, int *defmode)
06421 {
06422    int dflmd = REM_MODE_FM;
06423 
06424    if(m == 1){ /* 160 meters */
06425       dflmd =  REM_MODE_LSB; 
06426       if(d < 80000)
06427          return -1;
06428    }
06429    else if(m == 3){ /* 80 meters */
06430       dflmd = REM_MODE_LSB;
06431       if(d < 50000)
06432          return -1;
06433    }
06434    else if(m == 7){ /* 40 meters */
06435       dflmd = REM_MODE_LSB;
06436       if(d > 30000)
06437          return -1;
06438    }
06439    else if(m == 14){ /* 20 meters */
06440       dflmd = REM_MODE_USB;
06441       if(d > 35000)
06442          return -1;
06443    }
06444    else if(m == 18){ /* 17 meters */
06445       dflmd = REM_MODE_USB;
06446       if((d < 6800) || (d > 16800))
06447          return -1;
06448    }
06449    else if(m == 21){ /* 15 meters */
06450       dflmd = REM_MODE_USB;
06451       if((d < 20000) || (d > 45000))
06452          return -1;
06453    }
06454    else if(m == 24){ /* 12 meters */
06455       dflmd = REM_MODE_USB;
06456       if((d < 89000) || (d > 99000))
06457          return -1;
06458    }
06459    else if(m == 28){ /* 10 meters */
06460       dflmd = REM_MODE_USB;
06461    }
06462    else if(m == 29){ 
06463       if(d >= 51000)
06464          dflmd = REM_MODE_FM;
06465       else
06466          dflmd = REM_MODE_USB;
06467       if(d > 70000)
06468          return -1;
06469    }
06470    else if(m == 50){ /* 6 meters */
06471       if(d >= 30000)
06472          dflmd = REM_MODE_FM;
06473       else
06474          dflmd = REM_MODE_USB;
06475 
06476    }
06477    else if((m >= 51) && ( m < 54)){
06478       dflmd = REM_MODE_FM;
06479    }
06480    else if(m == 144){ /* 2 meters */
06481       if(d >= 30000)
06482          dflmd = REM_MODE_FM;
06483       else
06484          dflmd = REM_MODE_USB;
06485    }
06486    else if((m >= 145) && (m < 148)){
06487       dflmd = REM_MODE_FM;
06488    }
06489    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
06490       if(m  < 438)
06491          dflmd = REM_MODE_USB;
06492       else
06493          dflmd = REM_MODE_FM;
06494       ;
06495    }
06496    else
06497       return -1;
06498 
06499    if(defmode)
06500       *defmode = dflmd;
06501 
06502    return 0;
06503 }
06504 
06505 /*
06506 * Set a new frequency for the FT897
06507 */
06508 
06509 static int set_freq_ft897(struct rpt *myrpt, char *newfreq)
06510 {
06511    unsigned char cmdstr[5];
06512    int fd,m,d;
06513    char mhz[MAXREMSTR];
06514    char decimals[MAXREMSTR];
06515 
06516    fd = 0;
06517    if(debug) 
06518       printf("New frequency: %s\n",newfreq);
06519 
06520    if(split_freq(mhz, decimals, newfreq))
06521       return -1; 
06522 
06523    m = atoi(mhz);
06524    d = atoi(decimals);
06525 
06526    /* The FT-897 likes packed BCD frequencies */
06527 
06528    cmdstr[0] = ((m / 100) << 4) + ((m % 100)/10);        /* 100MHz 10Mhz */
06529    cmdstr[1] = ((m % 10) << 4) + (d / 10000);         /* 1MHz 100KHz */
06530    cmdstr[2] = (((d % 10000)/1000) << 4) + ((d % 1000)/ 100);  /* 10KHz 1KHz */
06531    cmdstr[3] = (((d % 100)/10) << 4) + (d % 10);         /* 100Hz 10Hz */
06532    cmdstr[4] = 0x01;                /* command */
06533 
06534    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
06535 
06536 }
06537 
06538 /* ft-897 simple commands */
06539 
06540 static int simple_command_ft897(struct rpt *myrpt, char command)
06541 {
06542    unsigned char cmdstr[5];
06543    
06544    memset(cmdstr, 0, 5);
06545 
06546    cmdstr[4] = command; 
06547 
06548    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
06549 
06550 }
06551 
06552 /* ft-897 offset */
06553 
06554 static int set_offset_ft897(struct rpt *myrpt, char offset)
06555 {
06556    unsigned char cmdstr[5];
06557    
06558    memset(cmdstr, 0, 5);
06559 
06560    switch(offset){
06561       case  REM_SIMPLEX:
06562          cmdstr[0] = 0x89;
06563          break;
06564 
06565       case  REM_MINUS:
06566          cmdstr[0] = 0x09;
06567          break;
06568       
06569       case  REM_PLUS:
06570          cmdstr[0] = 0x49;
06571          break;   
06572 
06573       default:
06574          return -1;
06575    }
06576 
06577    cmdstr[4] = 0x09; 
06578 
06579    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
06580 }
06581 
06582 /* ft-897 mode */
06583 
06584 static int set_mode_ft897(struct rpt *myrpt, char newmode)
06585 {
06586    unsigned char cmdstr[5];
06587    
06588    memset(cmdstr, 0, 5);
06589    
06590    switch(newmode){
06591       case  REM_MODE_FM:
06592          cmdstr[0] = 0x08;
06593          break;
06594 
06595       case  REM_MODE_USB:
06596          cmdstr[0] = 0x01;
06597          break;
06598 
06599       case  REM_MODE_LSB:
06600          cmdstr[0] = 0x00;
06601          break;
06602 
06603       case  REM_MODE_AM:
06604          cmdstr[0] = 0x04;
06605          break;
06606       
06607       default:
06608          return -1;
06609    }
06610    cmdstr[4] = 0x07; 
06611 
06612    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
06613 }
06614 
06615 /* Set tone encode and decode modes */
06616 
06617 static int set_ctcss_mode_ft897(struct rpt *myrpt, char txplon, char rxplon)
06618 {
06619    unsigned char cmdstr[5];
06620    
06621    memset(cmdstr, 0, 5);
06622    
06623    if(rxplon && txplon)
06624       cmdstr[0] = 0x2A; /* Encode and Decode */
06625    else if (!rxplon && txplon)
06626       cmdstr[0] = 0x4A; /* Encode only */
06627    else if (rxplon && !txplon)
06628       cmdstr[0] = 0x3A; /* Encode only */
06629    else
06630       cmdstr[0] = 0x8A; /* OFF */
06631 
06632    cmdstr[4] = 0x0A; 
06633 
06634    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
06635 }
06636 
06637 
06638 /* Set transmit and receive ctcss tone frequencies */
06639 
06640 static int set_ctcss_freq_ft897(struct rpt *myrpt, char *txtone, char *rxtone)
06641 {
06642    unsigned char cmdstr[5];
06643    char hertz[MAXREMSTR],decimal[MAXREMSTR];
06644    int h,d; 
06645 
06646    memset(cmdstr, 0, 5);
06647 
06648    if(split_ctcss_freq(hertz, decimal, txtone))
06649       return -1; 
06650 
06651    h = atoi(hertz);
06652    d = atoi(decimal);
06653    
06654    cmdstr[0] = ((h / 100) << 4) + (h % 100)/ 10;
06655    cmdstr[1] = ((h % 10) << 4) + (d % 10);
06656    
06657    if(rxtone){
06658    
06659       if(split_ctcss_freq(hertz, decimal, rxtone))
06660          return -1; 
06661 
06662       h = atoi(hertz);
06663       d = atoi(decimal);
06664    
06665       cmdstr[2] = ((h / 100) << 4) + (h % 100)/ 10;
06666       cmdstr[3] = ((h % 10) << 4) + (d % 10);
06667    }
06668    cmdstr[4] = 0x0B; 
06669 
06670    return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
06671 }  
06672 
06673 
06674 
06675 static int set_ft897(struct rpt *myrpt)
06676 {
06677    int res;
06678    
06679    if(debug)
06680       printf("@@@@ lock on\n");
06681 
06682    res = simple_command_ft897(myrpt, 0x00);  /* LOCK on */  
06683 
06684    if(debug)
06685       printf("@@@@ ptt off\n");
06686 
06687    if(!res)
06688       res = simple_command_ft897(myrpt, 0x88);     /* PTT off */
06689 
06690    if(debug)
06691       printf("Modulation mode\n");
06692 
06693    if(!res)
06694       res = set_mode_ft897(myrpt, myrpt->remmode);    /* Modulation mode */
06695 
06696    if(debug)
06697       printf("Split off\n");
06698 
06699    if(!res)
06700       simple_command_ft897(myrpt, 0x82);        /* Split off */
06701 
06702    if(debug)
06703       printf("Frequency\n");
06704 
06705    if(!res)
06706       res = set_freq_ft897(myrpt, myrpt->freq);    /* Frequency */
06707    if((myrpt->remmode == REM_MODE_FM)){
06708       if(debug)
06709          printf("Offset\n");
06710       if(!res)
06711          res = set_offset_ft897(myrpt, myrpt->offset);   /* Offset if FM */
06712       if((!res)&&(myrpt->rxplon || myrpt->txplon)){
06713          if(debug)
06714             printf("CTCSS tone freqs.\n");
06715          res = set_ctcss_freq_ft897(myrpt, myrpt->txpl, myrpt->rxpl); /* CTCSS freqs if CTCSS is enabled */
06716       }
06717       if(!res){
06718          if(debug)
06719             printf("CTCSS mode\n");
06720          res = set_ctcss_mode_ft897(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
06721       }
06722    }
06723    if((myrpt->remmode == REM_MODE_USB)||(myrpt->remmode == REM_MODE_LSB)){
06724       if(debug)
06725          printf("Clarifier off\n");
06726       simple_command_ft897(myrpt, 0x85);        /* Clarifier off if LSB or USB */
06727    }
06728    return res;
06729 }
06730 
06731 static int closerem_ft897(struct rpt *myrpt)
06732 {
06733    simple_command_ft897(myrpt, 0x88); /* PTT off */
06734    return 0;
06735 }  
06736 
06737 /*
06738 * Bump frequency up or down by a small amount 
06739 * Return 0 if the new frequnecy is valid, or -1 if invalid
06740 * Interval is in Hz, resolution is 10Hz 
06741 */
06742 
06743 static int multimode_bump_freq_ft897(struct rpt *myrpt, int interval)
06744 {
06745    int m,d;
06746    char mhz[MAXREMSTR], decimals[MAXREMSTR];
06747 
06748    if(debug)
06749       printf("Before bump: %s\n", myrpt->freq);
06750 
06751    if(split_freq(mhz, decimals, myrpt->freq))
06752       return -1;
06753    
06754    m = atoi(mhz);
06755    d = atoi(decimals);
06756 
06757    d += (interval / 10); /* 10Hz resolution */
06758    if(d < 0){
06759       m--;
06760       d += 100000;
06761    }
06762    else if(d >= 100000){
06763       m++;
06764       d -= 100000;
06765    }
06766 
06767    if(check_freq_ft897(m, d, NULL)){
06768       if(debug)
06769          printf("Bump freq invalid\n");
06770       return -1;
06771    }
06772 
06773    snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
06774 
06775    if(debug)
06776       printf("After bump: %s\n", myrpt->freq);
06777 
06778    return set_freq_ft897(myrpt, myrpt->freq);   
06779 }
06780 
06781 
06782 
06783 /*
06784 * IC-706 I/O handlers
06785 */
06786 
06787 /* Check to see that the frequency is valid */
06788 /* Hard coded limits now, configurable later, maybe? */
06789 
06790 
06791 static int check_freq_ic706(int m, int d, int *defmode)
06792 {
06793    int dflmd = REM_MODE_FM;
06794 
06795    if(m == 1){ /* 160 meters */
06796       dflmd =  REM_MODE_LSB; 
06797       if(d < 80000)
06798          return -1;
06799    }
06800    else if(m == 3){ /* 80 meters */
06801       dflmd = REM_MODE_LSB;
06802       if(d < 50000)
06803          return -1;
06804    }
06805    else if(m == 7){ /* 40 meters */
06806       dflmd = REM_MODE_LSB;
06807       if(d > 30000)
06808          return -1;
06809    }
06810    else if(m == 14){ /* 20 meters */
06811       dflmd = REM_MODE_USB;
06812       if(d > 35000)
06813          return -1;
06814    }
06815    else if(m == 18){ /* 17 meters */
06816       dflmd = REM_MODE_USB;
06817       if((d < 6800) || (d > 16800))
06818          return -1;
06819    }
06820    else if(m == 21){ /* 15 meters */
06821       dflmd = REM_MODE_USB;
06822       if((d < 20000) || (d > 45000))
06823          return -1;
06824    }
06825    else if(m == 24){ /* 12 meters */
06826       dflmd = REM_MODE_USB;
06827       if((d < 89000) || (d > 99000))
06828          return -1;
06829    }
06830    else if(m == 28){ /* 10 meters */
06831       dflmd = REM_MODE_USB;
06832    }
06833    else if(m == 29){ 
06834       if(d >= 51000)
06835          dflmd = REM_MODE_FM;
06836       else
06837          dflmd = REM_MODE_USB;
06838       if(d > 70000)
06839          return -1;
06840    }
06841    else if(m == 50){ /* 6 meters */
06842       if(d >= 30000)
06843          dflmd = REM_MODE_FM;
06844       else
06845          dflmd = REM_MODE_USB;
06846 
06847    }
06848    else if((m >= 51) && ( m < 54)){
06849       dflmd = REM_MODE_FM;
06850    }
06851    else if(m == 144){ /* 2 meters */
06852       if(d >= 30000)
06853          dflmd = REM_MODE_FM;
06854       else
06855          dflmd = REM_MODE_USB;
06856    }
06857    else if((m >= 145) && (m < 148)){
06858       dflmd = REM_MODE_FM;
06859    }
06860    else if((m >= 430) && (m < 450)){ /* 70 centimeters */
06861       if(m  < 438)
06862          dflmd = REM_MODE_USB;
06863       else
06864          dflmd = REM_MODE_FM;
06865       ;
06866    }
06867    else
06868       return -1;
06869 
06870    if(defmode)
06871       *defmode = dflmd;
06872 
06873    return 0;
06874 }
06875 
06876 /* take a PL frequency and turn it into a code */
06877 static int ic706_pltocode(char *str)
06878 {
06879 int i;
06880 char *s;
06881 
06882    s = strchr(str,'.');
06883    i = 0;
06884    if (s) i = atoi(s + 1);
06885    i += atoi(str) * 10;
06886    switch(i)
06887    {
06888        case 670:
06889       return 0;
06890        case 693:
06891       return 1;
06892        case 719:
06893       return 2;
06894        case 744:
06895       return 3;
06896        case 770:
06897       return 4;
06898        case 797:
06899       return 5;
06900        case 825:
06901       return 6;
06902        case 854:
06903       return 7;
06904        case 885:
06905       return 8;
06906        case 915:
06907       return 9;
06908        case 948:
06909       return 10;
06910        case 974:
06911       return 11;
06912        case 1000:
06913       return 12;
06914        case 1035:
06915       return 13;
06916        case 1072:
06917       return 14;
06918        case 1109:
06919       return 15;
06920        case 1148:
06921       return 16;
06922        case 1188:
06923       return 17;
06924        case 1230:
06925       return 18;
06926        case 1273:
06927       return 19;
06928        case 1318:
06929       return 20;
06930        case 1365:
06931       return 21;
06932        case 1413:
06933       return 22;
06934        case 1462:
06935       return 23;
06936        case 1514:
06937       return 24;
06938        case 1567:
06939       return 25;
06940        case 1598:
06941       return 26;
06942        case 1622:
06943       return 27;
06944        case 1655:
06945       return 28;     
06946        case 1679:
06947       return 29;
06948        case 1713:
06949       return 30;
06950        case 1738:
06951       return 31;
06952        case 1773:
06953       return 32;
06954        case 1799:
06955       return 33;
06956             case 1835:
06957       return 34;
06958        case 1862:
06959       return 35;
06960        case 1899:
06961       return 36;
06962        case 1928:
06963       return 37;
06964        case 1966:
06965       return 38;
06966        case 1995:
06967       return 39;
06968        case 2035:
06969       return 40;
06970        case 2065:
06971       return 41;
06972        case 2107:
06973       return 42;
06974        case 2181:
06975       return 43;
06976        case 2257:
06977       return 44;
06978        case 2291:
06979       return 45;
06980        case 2336:
06981       return 46;
06982        case 2418:
06983       return 47;
06984        case 2503:
06985       return 48;
06986        case 2541:
06987       return 49;
06988    }
06989    return -1;
06990 }
06991 
06992 /* ic-706 simple commands */
06993 
06994 static int simple_command_ic706(struct rpt *myrpt, char command, char subcommand)
06995 {
06996    unsigned char cmdstr[10];
06997    
06998    cmdstr[0] = cmdstr[1] = 0xfe;
06999    cmdstr[2] = myrpt->p.civaddr;
07000    cmdstr[3] = 0xe0;
07001    cmdstr[4] = command;
07002    cmdstr[5] = subcommand;
07003    cmdstr[6] = 0xfd;
07004 
07005    return(civ_cmd(myrpt,cmdstr,7));
07006 }
07007 
07008 /*
07009 * Set a new frequency for the ic706
07010 */
07011 
07012 static int set_freq_ic706(struct rpt *myrpt, char *newfreq)
07013 {
07014    unsigned char cmdstr[20];
07015    char mhz[MAXREMSTR], decimals[MAXREMSTR];
07016    int fd,m,d;
07017 
07018    fd = 0;
07019    if(debug) 
07020       printf("New frequency: %s\n",newfreq);
07021 
07022    if(split_freq(mhz, decimals, newfreq))
07023       return -1; 
07024 
07025    m = atoi(mhz);
07026    d = atoi(decimals);
07027 
07028    /* The ic-706 likes packed BCD frequencies */
07029 
07030    cmdstr[0] = cmdstr[1] = 0xfe;
07031    cmdstr[2] = myrpt->p.civaddr;
07032    cmdstr[3] = 0xe0;
07033    cmdstr[4] = 5;
07034    cmdstr[5] = ((d % 10) << 4);
07035    cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
07036    cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
07037    cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
07038    cmdstr[9] = (m / 100);
07039    cmdstr[10] = 0xfd;
07040 
07041    return(civ_cmd(myrpt,cmdstr,11));
07042 }
07043 
07044 /* ic-706 offset */
07045 
07046 static int set_offset_ic706(struct rpt *myrpt, char offset)
07047 {
07048    unsigned char c;
07049 
07050    switch(offset){
07051       case  REM_SIMPLEX:
07052          c = 0x10;
07053          break;
07054 
07055       case  REM_MINUS:
07056          c = 0x11;
07057          break;
07058       
07059       case  REM_PLUS:
07060          c = 0x12;
07061          break;   
07062 
07063       default:
07064          return -1;
07065    }
07066 
07067    return simple_command_ic706(myrpt,0x0f,c);
07068 
07069 }
07070 
07071 /* ic-706 mode */
07072 
07073 static int set_mode_ic706(struct rpt *myrpt, char newmode)
07074 {
07075    unsigned char c;
07076    
07077    switch(newmode){
07078       case  REM_MODE_FM:
07079          c = 5;
07080          break;
07081 
07082       case  REM_MODE_USB:
07083          c = 1;
07084          break;
07085 
07086       case  REM_MODE_LSB:
07087          c = 0;
07088          break;
07089 
07090       case  REM_MODE_AM:
07091          c = 2;
07092          break;
07093       
07094       default:
07095          return -1;
07096    }
07097    return simple_command_ic706(myrpt,6,c);
07098 }
07099 
07100 /* Set tone encode and decode modes */
07101 
07102 static int set_ctcss_mode_ic706(struct rpt *myrpt, char txplon, char rxplon)
07103 {
07104    unsigned char cmdstr[10];
07105    int rv;
07106 
07107    cmdstr[0] = cmdstr[1] = 0xfe;
07108    cmdstr[2] = myrpt->p.civaddr;
07109    cmdstr[3] = 0xe0;
07110    cmdstr[4] = 0x16;
07111    cmdstr[5] = 0x42;
07112    cmdstr[6] = (txplon != 0);
07113    cmdstr[7] = 0xfd;
07114 
07115    rv = civ_cmd(myrpt,cmdstr,8);
07116    if (rv) return(-1);
07117 
07118    cmdstr[0] = cmdstr[1] = 0xfe;
07119    cmdstr[2] = myrpt->p.civaddr;
07120    cmdstr[3] = 0xe0;
07121    cmdstr[4] = 0x16;
07122    cmdstr[5] = 0x43;
07123    cmdstr[6] = (rxplon != 0);
07124    cmdstr[7] = 0xfd;
07125 
07126    return(civ_cmd(myrpt,cmdstr,8));
07127 }
07128 
07129 #if 0
07130 /* Set transmit and receive ctcss tone frequencies */
07131 
07132 static int set_ctcss_freq_ic706(struct rpt *myrpt, char *txtone, char *rxtone)
07133 {
07134    unsigned char cmdstr[10];
07135    char hertz[MAXREMSTR],decimal[MAXREMSTR];
07136    int h,d,rv;
07137 
07138    memset(cmdstr, 0, 5);
07139 
07140    if(split_ctcss_freq(hertz, decimal, txtone))
07141       return -1; 
07142 
07143    h = atoi(hertz);
07144    d = atoi(decimal);
07145    
07146    cmdstr[0] = cmdstr[1] = 0xfe;
07147    cmdstr[2] = myrpt->p.civaddr;
07148    cmdstr[3] = 0xe0;
07149    cmdstr[4] = 0x1b;
07150    cmdstr[5] = 0;
07151    cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
07152    cmdstr[7] = ((h % 10) << 4) + (d % 10);
07153    cmdstr[8] = 0xfd;
07154 
07155    rv = civ_cmd(myrpt,cmdstr,9);
07156    if (rv) return(-1);
07157 
07158    if (!rxtone) return(0);
07159 
07160    if(split_ctcss_freq(hertz, decimal, rxtone))
07161       return -1; 
07162 
07163    h = atoi(hertz);
07164    d = atoi(decimal);
07165 
07166    cmdstr[0] = cmdstr[1] = 0xfe;
07167    cmdstr[2] = myrpt->p.civaddr;
07168    cmdstr[3] = 0xe0;
07169    cmdstr[4] = 0x1b;
07170    cmdstr[5] = 1;
07171    cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
07172    cmdstr[7] = ((h % 10) << 4) + (d % 10);
07173    cmdstr[8] = 0xfd;
07174    return(civ_cmd(myrpt,cmdstr,9));
07175 }  
07176 #endif
07177 
07178 static int vfo_ic706(struct rpt *myrpt)
07179 {
07180    unsigned char cmdstr[10];
07181    
07182    cmdstr[0] = cmdstr[1] = 0xfe;
07183    cmdstr[2] = myrpt->p.civaddr;
07184    cmdstr[3] = 0xe0;
07185    cmdstr[4] = 7;
07186    cmdstr[5] = 0xfd;
07187 
07188    return(civ_cmd(myrpt,cmdstr,6));
07189 }
07190 
07191 static int mem2vfo_ic706(struct rpt *myrpt)
07192 {
07193    unsigned char cmdstr[10];
07194    
07195    cmdstr[0] = cmdstr[1] = 0xfe;
07196    cmdstr[2] = myrpt->p.civaddr;
07197    cmdstr[3] = 0xe0;
07198    cmdstr[4] = 0x0a;
07199    cmdstr[5] = 0xfd;
07200 
07201    return(civ_cmd(myrpt,cmdstr,6));
07202 }
07203 
07204 static int select_mem_ic706(struct rpt *myrpt, int slot)
07205 {
07206    unsigned char cmdstr[10];
07207    
07208    cmdstr[0] = cmdstr[1] = 0xfe;
07209    cmdstr[2] = myrpt->p.civaddr;
07210    cmdstr[3] = 0xe0;
07211    cmdstr[4] = 8;
07212    cmdstr[5] = 0;
07213    cmdstr[6] = ((slot / 10) << 4) + (slot % 10);
07214    cmdstr[7] = 0xfd;
07215 
07216    return(civ_cmd(myrpt,cmdstr,8));
07217 }
07218 
07219 static int set_ic706(struct rpt *myrpt)
07220 {
07221    int res = 0,i;
07222    
07223    if(debug)
07224       printf("Set to VFO A\n");
07225 
07226    if (!res)
07227       res = simple_command_ic706(myrpt,7,0);
07228 
07229 
07230    if((myrpt->remmode == REM_MODE_FM))
07231    {
07232       i = ic706_pltocode(myrpt->rxpl);
07233       if (i == -1) return -1;
07234       if(debug)
07235          printf("Select memory number\n");
07236       if (!res)
07237          res = select_mem_ic706(myrpt,i + IC706_PL_MEMORY_OFFSET);
07238       if(debug)
07239          printf("Transfer memory to VFO\n");
07240       if (!res)
07241          res = mem2vfo_ic706(myrpt);
07242    }
07243       
07244    if(debug)
07245       printf("Set to VFO\n");
07246 
07247    if (!res)
07248       res = vfo_ic706(myrpt);
07249 
07250    if(debug)
07251       printf("Modulation mode\n");
07252 
07253    if (!res)
07254       res = set_mode_ic706(myrpt, myrpt->remmode);    /* Modulation mode */
07255 
07256    if(debug)
07257       printf("Split off\n");
07258 
07259    if(!res)
07260       simple_command_ic706(myrpt, 0x82,0);         /* Split off */
07261 
07262    if(debug)
07263       printf("Frequency\n");
07264 
07265    if(!res)
07266       res = set_freq_ic706(myrpt, myrpt->freq);    /* Frequency */
07267    if((myrpt->remmode == REM_MODE_FM)){
07268       if(debug)
07269          printf("Offset\n");
07270       if(!res)
07271          res = set_offset_ic706(myrpt, myrpt->offset);   /* Offset if FM */
07272       if(!res){
07273          if(debug)
07274             printf("CTCSS mode\n");
07275          res = set_ctcss_mode_ic706(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
07276       }
07277    }
07278    return res;
07279 }
07280 
07281 /*
07282 * Bump frequency up or down by a small amount 
07283 * Return 0 if the new frequnecy is valid, or -1 if invalid
07284 * Interval is in Hz, resolution is 10Hz 
07285 */
07286 
07287 static int multimode_bump_freq_ic706(struct rpt *myrpt, int interval)
07288 {
07289    int m,d;
07290    char mhz[MAXREMSTR], decimals[MAXREMSTR];
07291    unsigned char cmdstr[20];
07292 
07293    if(debug)
07294       printf("Before bump: %s\n", myrpt->freq);
07295 
07296    if(split_freq(mhz, decimals, myrpt->freq))
07297       return -1;
07298    
07299    m = atoi(mhz);
07300    d = atoi(decimals);
07301 
07302    d += (interval / 10); /* 10Hz resolution */
07303    if(d < 0){
07304       m--;
07305       d += 100000;
07306    }
07307    else if(d >= 100000){
07308       m++;
07309       d -= 100000;
07310    }
07311 
07312    if(check_freq_ic706(m, d, NULL)){
07313       if(debug)
07314          printf("Bump freq invalid\n");
07315       return -1;
07316    }
07317 
07318    snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
07319 
07320    if(debug)
07321       printf("After bump: %s\n", myrpt->freq);
07322 
07323    /* The ic-706 likes packed BCD frequencies */
07324 
07325    cmdstr[0] = cmdstr[1] = 0xfe;
07326    cmdstr[2] = myrpt->p.civaddr;
07327    cmdstr[3] = 0xe0;
07328    cmdstr[4] = 0;
07329    cmdstr[5] = ((d % 10) << 4);
07330    cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
07331    cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
07332    cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
07333    cmdstr[9] = (m / 100);
07334    cmdstr[10] = 0xfd;
07335 
07336    return(serial_remote_io(myrpt,cmdstr,11,NULL,0,0));
07337 }
07338 
07339 
07340 
07341 /*
07342 * Dispatch to correct I/O handler 
07343 */
07344 
07345 static int setrem(struct rpt *myrpt)
07346 {
07347 char  str[300];
07348 char  *offsets[] = {"MINUS","SIMPLEX","PLUS"};
07349 char  *powerlevels[] = {"LOW","MEDIUM","HIGH"};
07350 char  *modes[] = {"FM","USB","LSB","AM"};
07351 int   res = -1;
07352 
07353    if (myrpt->p.archivedir)
07354    {
07355       sprintf(str,"FREQ,%s,%s,%s,%s,%s,%s,%d,%d",myrpt->freq,
07356          modes[(int)myrpt->remmode],
07357          myrpt->txpl,myrpt->rxpl,offsets[(int)myrpt->offset],
07358          powerlevels[(int)myrpt->powerlevel],myrpt->txplon,
07359          myrpt->rxplon);
07360       donodelog(myrpt,str);
07361    }
07362    if(!strcmp(myrpt->remote, remote_rig_ft897))
07363    {
07364       rpt_telemetry(myrpt,SETREMOTE,NULL);
07365       res = 0;
07366    }
07367    if(!strcmp(myrpt->remote, remote_rig_ic706))
07368    {
07369       rpt_telemetry(myrpt,SETREMOTE,NULL);
07370       res = 0;
07371    }
07372    else if(!strcmp(myrpt->remote, remote_rig_rbi))
07373    {
07374       res = setrbi_check(myrpt);
07375       if (!res)
07376       {
07377          rpt_telemetry(myrpt,SETREMOTE,NULL);
07378          res = 0;
07379       }
07380    }
07381    else if(!strcmp(myrpt->remote, remote_rig_kenwood)) {
07382       rpt_telemetry(myrpt,SETREMOTE,NULL);
07383       res = 0;
07384    }
07385    else
07386       res = 0;
07387 
07388    if (res < 0) ast_log(LOG_ERROR,"Unable to send remote command on node %s\n",myrpt->name);
07389 
07390    return res;
07391 }
07392 
07393 static int closerem(struct rpt *myrpt)
07394 {
07395    if(!strcmp(myrpt->remote, remote_rig_ft897))
07396       return closerem_ft897(myrpt);
07397    else
07398       return 0;
07399 }
07400 
07401 /*
07402 * Dispatch to correct RX frequency checker
07403 */
07404 
07405 static int check_freq(struct rpt *myrpt, int m, int d, int *defmode)
07406 {
07407    if(!strcmp(myrpt->remote, remote_rig_ft897))
07408       return check_freq_ft897(m, d, defmode);
07409    else if(!strcmp(myrpt->remote, remote_rig_ic706))
07410       return check_freq_ic706(m, d, defmode);
07411    else if(!strcmp(myrpt->remote, remote_rig_rbi))
07412       return check_freq_rbi(m, d, defmode);
07413    else if(!strcmp(myrpt->remote, remote_rig_kenwood))
07414       return check_freq_kenwood(m, d, defmode);
07415    else
07416       return -1;
07417 }
07418 
07419 /*
07420  * Check TX frequency before transmitting
07421  */
07422 
07423 static char check_tx_freq(struct rpt *myrpt)
07424 {
07425    int i;
07426    int radio_mhz, radio_decimals, ulimit_mhz, ulimit_decimals, llimit_mhz, llimit_decimals;
07427    char radio_mhz_char[MAXREMSTR];
07428    char radio_decimals_char[MAXREMSTR];
07429    char limit_mhz_char[MAXREMSTR];
07430    char limit_decimals_char[MAXREMSTR];
07431    char limits[256];
07432    char *limit_ranges[40];
07433    struct ast_variable *limitlist;
07434    
07435 
07436    /* Must have user logged in and tx_limits defined */
07437 
07438    if(!myrpt->p.txlimitsstanzaname || !myrpt->loginuser[0] || !myrpt->loginlevel[0]){
07439       if(debug > 3){
07440          ast_log(LOG_NOTICE, "No tx band table defined, or no user logged in\n");
07441       }
07442       return 1; /* Assume it's ok otherwise */
07443    }
07444 
07445    /* Retrieve the band table for the loginlevel */
07446    limitlist = ast_variable_browse(myrpt->cfg, myrpt->p.txlimitsstanzaname);
07447 
07448    if(!limitlist){
07449       ast_log(LOG_WARNING, "No entries in %s band table stanza\n", myrpt->p.txlimitsstanzaname);
07450       return 0;
07451    }
07452 
07453    split_freq(radio_mhz_char, radio_decimals_char, myrpt->freq);
07454    radio_mhz = atoi(radio_mhz_char);
07455    radio_decimals = decimals2int(radio_decimals_char);
07456 
07457 
07458    if(debug > 3){
07459       ast_log(LOG_NOTICE, "Login User = %s, login level = %s\n", myrpt->loginuser, myrpt->loginlevel);
07460    }
07461 
07462    /* Find our entry */
07463 
07464    for(;limitlist; limitlist=limitlist->next){
07465       if(!strcmp(limitlist->name, myrpt->loginlevel))
07466          break;
07467    }
07468 
07469    if(!limitlist){
07470       ast_log(LOG_WARNING, "Can't find %s entry in band table stanza %s\n", myrpt->loginlevel, myrpt->p.txlimitsstanzaname);
07471       return 0;
07472    }
07473    
07474    if(debug > 3){
07475       ast_log(LOG_NOTICE, "Auth %s = %s\n", limitlist->name, limitlist->value);
07476    }
07477 
07478    /* Parse the limits */
07479 
07480    strncpy(limits, limitlist->value, 256);
07481    limits[255] = 0;
07482    finddelim(limits, limit_ranges, 40);
07483    for(i = 0; i < 40 && limit_ranges[i] ; i++){
07484       char range[40];
07485       char *r,*s;
07486       strncpy(range, limit_ranges[i], 40);
07487       range[39] = 0;
07488                 if(debug > 3){
07489          ast_log(LOG_NOTICE, "Checking to see if %s is within limits of %s\n", myrpt->freq, range);
07490                 }        
07491    
07492       r = strchr(range, '-');
07493       if(!r){
07494          ast_log(LOG_WARNING, "Malformed range in %s tx band table entry\n", limitlist->name);
07495          return 0;
07496       }
07497       *r++ = 0;
07498       s = eatwhite(range);
07499       r = eatwhite(r);
07500       split_freq(limit_mhz_char, limit_decimals_char, s);
07501       llimit_mhz = atoi(limit_mhz_char);
07502       llimit_decimals = decimals2int(limit_decimals_char);
07503       split_freq(limit_mhz_char, limit_decimals_char, r);
07504       ulimit_mhz = atoi(limit_mhz_char);
07505       ulimit_decimals = decimals2int(limit_decimals_char);
07506          
07507       if((radio_mhz >= llimit_mhz) && (radio_mhz <= ulimit_mhz)){
07508          if(radio_mhz == llimit_mhz){ /* CASE 1: TX freq is in llimit mhz portion of band */
07509             if(radio_decimals >= llimit_decimals){ /* Cannot be below llimit decimals */
07510                if(llimit_mhz == ulimit_mhz){ /* If bandwidth < 1Mhz, check ulimit decimals */
07511                   if(radio_decimals <= ulimit_decimals){
07512                      return 1;
07513                   }
07514                   else{
07515                      if(debug > 3)
07516                         ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 1\n");
07517                      return 0;
07518                   }
07519                }
07520                else{
07521                   return 1;
07522                }
07523             }
07524             else{ /* Is below llimit decimals */
07525                if(debug > 3)
07526                   ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 2\n");
07527                return 0;
07528             }
07529          }
07530          else if(radio_mhz == ulimit_mhz){ /* CASE 2: TX freq not in llimit mhz portion of band */
07531             if(radio_decimals <= ulimit_decimals){
07532                return 1;
07533             }
07534             else{ /* Is above ulimit decimals */
07535                if(debug > 3)
07536                   ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 3\n");
07537                return 0;
07538             }
07539          }
07540          else /* CASE 3: TX freq within a multi-Mhz band and ok */
07541             return 1; 
07542       }
07543    }
07544    if(debug > 3) /* No match found in TX band table */
07545       ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 4\n");
07546    return 0;
07547 }
07548 
07549 
07550 /*
07551 * Dispatch to correct frequency bumping function
07552 */
07553 
07554 static int multimode_bump_freq(struct rpt *myrpt, int interval)
07555 {
07556    if(!strcmp(myrpt->remote, remote_rig_ft897))
07557       return multimode_bump_freq_ft897(myrpt, interval);
07558    else if(!strcmp(myrpt->remote, remote_rig_ic706))
07559       return multimode_bump_freq_ic706(myrpt, interval);
07560    else
07561       return -1;
07562 }
07563 
07564 
07565 /*
07566 * Queue announcment that scan has been stopped 
07567 */
07568 
07569 static void stop_scan(struct rpt *myrpt)
07570 {
07571    myrpt->hfscanstop = 1;
07572    rpt_telemetry(myrpt,SCAN,0);
07573 }
07574 
07575 /*
07576 * This is called periodically when in scan mode
07577 */
07578 
07579 
07580 static int service_scan(struct rpt *myrpt)
07581 {
07582    int res, interval;
07583    char mhz[MAXREMSTR], decimals[MAXREMSTR], k10=0i, k100=0;
07584 
07585    switch(myrpt->hfscanmode){
07586 
07587       case HF_SCAN_DOWN_SLOW:
07588          interval = -10; /* 100Hz /sec */
07589          break;
07590 
07591       case HF_SCAN_DOWN_QUICK:
07592          interval = -50; /* 500Hz /sec */
07593          break;
07594 
07595       case HF_SCAN_DOWN_FAST:
07596          interval = -200; /* 2KHz /sec */
07597          break;
07598 
07599       case HF_SCAN_UP_SLOW:
07600          interval = 10; /* 100Hz /sec */
07601          break;
07602 
07603       case HF_SCAN_UP_QUICK:
07604          interval = 50; /* 500 Hz/sec */
07605          break;
07606 
07607       case HF_SCAN_UP_FAST:
07608          interval = 200; /* 2KHz /sec */
07609          break;
07610 
07611       default:
07612          myrpt->hfscanmode = 0; /* Huh? */
07613          return -1;
07614    }
07615 
07616    res = split_freq(mhz, decimals, myrpt->freq);
07617       
07618    if(!res){
07619       k100 =decimals[0];
07620       k10 = decimals[1];
07621       res = multimode_bump_freq(myrpt, interval);
07622    }
07623 
07624    if(!res)
07625       res = split_freq(mhz, decimals, myrpt->freq);
07626 
07627 
07628    if(res){
07629       myrpt->hfscanmode = 0;
07630       myrpt->hfscanstatus = -2;
07631       return -1;
07632    }
07633 
07634    /* Announce 10KHz boundaries */
07635    if(k10 != decimals[1]){
07636       int myhund = (interval < 0) ? k100 : decimals[0];
07637       int myten = (interval < 0) ? k10 : decimals[1];
07638       myrpt->hfscanstatus = (myten == '0') ? (myhund - '0') * 100 : (myten - '0') * 10;
07639    } else myrpt->hfscanstatus = 0;
07640    return res;
07641 
07642 }
07643 
07644 /*
07645  * Retrieve a memory channel
07646  * Return 0 if sucessful,
07647  * -1 if channel not found,
07648  *  1 if parse error
07649  */
07650 
07651 static int retreive_memory(struct rpt *myrpt, char *memory)
07652 {
07653    char tmp[30], *s, *s1, *val;
07654 
07655    val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.memory, memory);
07656    if (!val){
07657       return -1;
07658    }        
07659    strncpy(tmp,val,sizeof(tmp) - 1);
07660    tmp[sizeof(tmp)-1] = 0;
07661 
07662    s = strchr(tmp,',');
07663    if (!s)
07664       return 1; 
07665    *s++ = 0;
07666    s1 = strchr(s,',');
07667    if (!s1)
07668       return 1;
07669    *s1++ = 0;
07670    strncpy(myrpt->freq, tmp, sizeof(myrpt->freq) - 1);
07671    strncpy(myrpt->rxpl, s, sizeof(myrpt->rxpl) - 1);
07672    strncpy(myrpt->txpl, s, sizeof(myrpt->rxpl) - 1);
07673    myrpt->remmode = REM_MODE_FM;
07674    myrpt->offset = REM_SIMPLEX;
07675    myrpt->powerlevel = REM_MEDPWR;
07676    myrpt->txplon = myrpt->rxplon = 0;
07677    while(*s1){
07678       switch(*s1++){
07679          case 'A':
07680          case 'a':
07681             strcpy(myrpt->rxpl, "100.0");
07682             strcpy(myrpt->txpl, "100.0");
07683             myrpt->remmode = REM_MODE_AM; 
07684             break;
07685          case 'B':
07686          case 'b':
07687             strcpy(myrpt->rxpl, "100.0");
07688             strcpy(myrpt->txpl, "100.0");
07689             myrpt->remmode = REM_MODE_LSB;
07690             break;
07691          case 'F':
07692             myrpt->remmode = REM_MODE_FM;
07693             break;
07694          case 'L':
07695          case 'l':
07696             myrpt->powerlevel = REM_LOWPWR;
07697             break;               
07698          case 'H':
07699          case 'h':
07700             myrpt->powerlevel = REM_HIPWR;
07701             break;
07702                
07703          case 'M':
07704          case 'm':
07705             myrpt->powerlevel = REM_MEDPWR;
07706             break;
07707                   
07708          case '-':
07709             myrpt->offset = REM_MINUS;
07710             break;
07711                   
07712          case '+':
07713             myrpt->offset = REM_PLUS;
07714             break;
07715                   
07716          case 'S':
07717          case 's':
07718             myrpt->offset = REM_SIMPLEX;
07719             break;
07720                   
07721          case 'T':
07722          case 't':
07723             myrpt->txplon = 1;
07724             break;
07725                   
07726          case 'R':
07727          case 'r':
07728             myrpt->rxplon = 1;
07729             break;
07730 
07731          case 'U':
07732          case 'u':
07733             strcpy(myrpt->rxpl, "100.0");
07734             strcpy(myrpt->txpl, "100.0");
07735             myrpt->remmode = REM_MODE_USB;
07736             break;
07737          default:
07738             return 1;
07739       }
07740    }
07741    return 0;
07742 }
07743 
07744 
07745 
07746 /*
07747 * Remote base function
07748 */
07749 
07750 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
07751 {
07752    char *s,*s1,*s2;
07753    int i,j,r,ht,k,l,ls2,m,d,offset,offsave, modesave, defmode=0;
07754    intptr_t p;
07755    char multimode = 0;
07756    char oc,*cp,*cp1,*cp2;
07757    char tmp[20], freq[20] = "", savestr[20] = "";
07758    char mhz[MAXREMSTR], decimals[MAXREMSTR];
07759 
07760    if((!param) || (command_source == SOURCE_RPT) || (command_source == SOURCE_LNK))
07761       return DC_ERROR;
07762       
07763    p = myatoi(param);
07764 
07765    if ((p != 99) && (p != 5) && (p != 140) && myrpt->p.authlevel && 
07766       (!myrpt->loginlevel[0])) return DC_ERROR;
07767    multimode = multimode_capable(myrpt);
07768 
07769    switch(p){
07770 
07771       case 1:  /* retrieve memory */
07772          if(strlen(digitbuf) < 2) /* needs 2 digits */
07773             break;
07774          
07775          for(i = 0 ; i < 2 ; i++){
07776             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
07777                return DC_ERROR;
07778          }
07779        
07780          r = retreive_memory(myrpt, digitbuf);
07781          if (r < 0){
07782             rpt_telemetry(myrpt,MEMNOTFOUND,NULL);
07783             return DC_COMPLETE;
07784          }
07785          if (r > 0){
07786             return DC_ERROR;
07787          }
07788          if (setrem(myrpt) == -1) return DC_ERROR;
07789          return DC_COMPLETE;  
07790          
07791       case 2:  /* set freq and offset */
07792       
07793          
07794             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for M+*K+*O or M+*H+* depending on mode */
07795             if(digitbuf[i] == '*'){
07796                j++;
07797                continue;
07798             }
07799             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
07800                goto invalid_freq;
07801             else{
07802                if(j == 0)
07803                   l++; /* # of digits before first * */
07804                if(j == 1)
07805                   k++; /* # of digits after first * */
07806             }
07807          }
07808       
07809          i = strlen(digitbuf) - 1;
07810          if(multimode){
07811             if((j > 2) || (l > 3) || (k > 6))
07812                goto invalid_freq; /* &^@#! */
07813          }
07814          else{
07815             if((j > 2) || (l > 4) || (k > 3))
07816                goto invalid_freq; /* &^@#! */
07817          }
07818 
07819          /* Wait for M+*K+* */
07820 
07821          if(j < 2)
07822             break; /* Not yet */
07823 
07824          /* We have a frequency */
07825 
07826          strncpy(tmp, digitbuf ,sizeof(tmp) - 1);
07827          
07828          s = tmp;
07829          s1 = strsep(&s, "*"); /* Pick off MHz */
07830          s2 = strsep(&s,"*"); /* Pick off KHz and Hz */
07831          ls2 = strlen(s2); 
07832          
07833          switch(ls2){ /* Allow partial entry of khz and hz digits for laziness support */
07834             case 1:
07835                ht = 0;
07836                k = 100 * atoi(s2);
07837                break;
07838             
07839             case 2:
07840                ht = 0;
07841                k = 10 * atoi(s2);
07842                break;
07843                
07844             case 3:
07845                if(!multimode){
07846                   if((s2[2] != '0')&&(s2[2] != '5'))
07847                      goto invalid_freq;
07848                }
07849                ht = 0;
07850                k = atoi(s2);
07851                   break;
07852             case 4:
07853                k = atoi(s2)/10;
07854                ht = 10 * (atoi(s2+(ls2-1)));
07855                break;
07856 
07857             case 5:
07858                k = atoi(s2)/100;
07859                ht = (atoi(s2+(ls2-2)));
07860                break;
07861                
07862             default:
07863                goto invalid_freq;
07864          }
07865 
07866          /* Check frequency for validity and establish a default mode */
07867          
07868          snprintf(freq, sizeof(freq), "%s.%03d%02d",s1, k, ht);
07869 
07870          if(debug)
07871             printf("New frequency: %s\n", freq);      
07872    
07873          split_freq(mhz, decimals, freq);
07874          m = atoi(mhz);
07875          d = atoi(decimals);
07876 
07877                         if(check_freq(myrpt, m, d, &defmode)) /* Check to see if frequency entered is legit */
07878                                 goto invalid_freq;
07879 
07880 
07881          if((defmode == REM_MODE_FM) && (digitbuf[i] == '*')) /* If FM, user must enter and additional offset digit */
07882             break; /* Not yet */
07883 
07884 
07885          offset = REM_SIMPLEX; /* Assume simplex */
07886 
07887          if(defmode == REM_MODE_FM){
07888             oc = *s; /* Pick off offset */
07889          
07890             if (oc){
07891                switch(oc){
07892                   case '1':
07893                      offset = REM_MINUS;
07894                      break;
07895                   
07896                   case '2':
07897                      offset = REM_SIMPLEX;
07898                   break;
07899                   
07900                   case '3':
07901                      offset = REM_PLUS;
07902                      break;
07903                   
07904                   default:
07905                      goto invalid_freq;
07906                } 
07907             } 
07908          }  
07909          offsave = myrpt->offset;
07910          modesave = myrpt->remmode;
07911          strncpy(savestr, myrpt->freq, sizeof(savestr) - 1);
07912          strncpy(myrpt->freq, freq, sizeof(myrpt->freq) - 1);
07913          myrpt->offset = offset;
07914          myrpt->remmode = defmode;
07915 
07916          if (setrem(myrpt) == -1){
07917             myrpt->offset = offsave;
07918             myrpt->remmode = modesave;
07919             strncpy(myrpt->freq, savestr, sizeof(myrpt->freq) - 1);
07920             goto invalid_freq;
07921          }
07922 
07923          return DC_COMPLETE;
07924 
07925 invalid_freq:
07926          rpt_telemetry(myrpt,INVFREQ,NULL);
07927          return DC_ERROR; 
07928       
07929       case 3: /* set rx PL tone */
07930             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
07931             if(digitbuf[i] == '*'){
07932                j++;
07933                continue;
07934             }
07935             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
07936                return DC_ERROR;
07937             else{
07938                if(j)
07939                   l++;
07940                else
07941                   k++;
07942             }
07943          }
07944          if((j > 1) || (k > 3) || (l > 1))
07945             return DC_ERROR; /* &$@^! */
07946          i = strlen(digitbuf) - 1;
07947          if((j != 1) || (k < 2)|| (l != 1))
07948             break; /* Not yet */
07949          if(debug)
07950             printf("PL digits entered %s\n", digitbuf);
07951             
07952          strncpy(tmp, digitbuf, sizeof(tmp) - 1);
07953          /* see if we have at least 1 */
07954          s = strchr(tmp,'*');
07955          if(s)
07956             *s = '.';
07957          strncpy(savestr, myrpt->rxpl, sizeof(savestr) - 1);
07958          strncpy(myrpt->rxpl, tmp, sizeof(myrpt->rxpl) - 1);
07959          if(!strcmp(myrpt->remote, remote_rig_rbi))
07960          {
07961             strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
07962          }
07963          if (setrem(myrpt) == -1){
07964             strncpy(myrpt->rxpl, savestr, sizeof(myrpt->rxpl) - 1);
07965             return DC_ERROR;
07966          }
07967       
07968       
07969          return DC_COMPLETE;
07970       
07971       case 4: /* set tx PL tone */
07972          /* cant set tx tone on RBI (rx tone does both) */
07973          if(!strcmp(myrpt->remote, remote_rig_rbi))
07974             return DC_ERROR;
07975          if(!strcmp(myrpt->remote, remote_rig_ic706))
07976             return DC_ERROR;
07977             for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
07978             if(digitbuf[i] == '*'){
07979                j++;
07980                continue;
07981             }
07982             if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
07983                return DC_ERROR;
07984             else{
07985                if(j)
07986                   l++;
07987                else
07988                   k++;
07989             }
07990          }
07991          if((j > 1) || (k > 3) || (l > 1))
07992             return DC_ERROR; /* &$@^! */
07993          i = strlen(digitbuf) - 1;
07994          if((j != 1) || (k < 2)|| (l != 1))
07995             break; /* Not yet */
07996          if(debug)
07997             printf("PL digits entered %s\n", digitbuf);
07998             
07999          strncpy(tmp, digitbuf, sizeof(tmp) - 1);
08000          /* see if we have at least 1 */
08001          s = strchr(tmp,'*');
08002          if(s)
08003             *s = '.';
08004          strncpy(savestr, myrpt->txpl, sizeof(savestr) - 1);
08005          strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
08006          
08007          if (setrem(myrpt) == -1){
08008             strncpy(myrpt->txpl, savestr, sizeof(myrpt->txpl) - 1);
08009             return DC_ERROR;
08010          }
08011       
08012       
08013          return DC_COMPLETE;
08014       
08015 
08016       case 6: /* MODE (FM,USB,LSB,AM) */
08017          if(strlen(digitbuf) < 1)
08018             break;
08019 
08020          if(!multimode)
08021             return DC_ERROR; /* Multimode radios only */
08022 
08023          switch(*digitbuf){
08024             case '1':
08025                split_freq(mhz, decimals, myrpt->freq); 
08026                m=atoi(mhz);
08027                if(m < 29) /* No FM allowed below 29MHz! */
08028                   return DC_ERROR;
08029                myrpt->remmode = REM_MODE_FM;
08030                
08031                rpt_telemetry(myrpt,REMMODE,NULL);
08032                break;
08033 
08034             case '2':
08035                myrpt->remmode = REM_MODE_USB;
08036                rpt_telemetry(myrpt,REMMODE,NULL);
08037                break;   
08038 
08039             case '3':
08040                myrpt->remmode = REM_MODE_LSB;
08041                rpt_telemetry(myrpt,REMMODE,NULL);
08042                break;
08043             
08044             case '4':
08045                myrpt->remmode = REM_MODE_AM;
08046                rpt_telemetry(myrpt,REMMODE,NULL);
08047                break;
08048       
08049             default:
08050                return DC_ERROR;
08051          }
08052 
08053          if(setrem(myrpt))
08054             return DC_ERROR;
08055          return DC_COMPLETEQUIET;
08056       case 99:
08057          /* cant log in when logged in */
08058          if (myrpt->loginlevel[0]) 
08059             return DC_ERROR;
08060          *myrpt->loginuser = 0;
08061          myrpt->loginlevel[0] = 0;
08062          cp = strdup(param);
08063          cp1 = strchr(cp,',');
08064          ast_mutex_lock(&myrpt->lock);
08065          if (cp1) 
08066          {
08067             *cp1 = 0;
08068             cp2 = strchr(cp1 + 1,',');
08069             if (cp2) 
08070             {
08071                *cp2 = 0;
08072                strncpy(myrpt->loginlevel,cp2 + 1,
08073                   sizeof(myrpt->loginlevel) - 1);
08074             }
08075             strncpy(myrpt->loginuser,cp1 + 1,sizeof(myrpt->loginuser));
08076             ast_mutex_unlock(&myrpt->lock);
08077             if (myrpt->p.archivedir)
08078             {
08079                char str[100];
08080 
08081                sprintf(str,"LOGIN,%s,%s",
08082                    myrpt->loginuser,myrpt->loginlevel);
08083                donodelog(myrpt,str);
08084             }
08085             if (debug) 
08086                printf("loginuser %s level %s\n",myrpt->loginuser,myrpt->loginlevel);
08087             rpt_telemetry(myrpt,REMLOGIN,NULL);
08088          }
08089          free(cp);
08090          return DC_COMPLETEQUIET;
08091       case 100: /* RX PL Off */
08092          myrpt->rxplon = 0;
08093          setrem(myrpt);
08094          rpt_telemetry(myrpt,REMXXX,(void *)p);
08095          return DC_COMPLETEQUIET;
08096       case 101: /* RX PL On */
08097          myrpt->rxplon = 1;
08098          setrem(myrpt);
08099          rpt_telemetry(myrpt,REMXXX,(void *)p);
08100          return DC_COMPLETEQUIET;
08101       case 102: /* TX PL Off */
08102          myrpt->txplon = 0;
08103          setrem(myrpt);
08104          rpt_telemetry(myrpt,REMXXX,(void *)p);
08105          return DC_COMPLETEQUIET;
08106       case 103: /* TX PL On */
08107          myrpt->txplon = 1;
08108          setrem(myrpt);
08109          rpt_telemetry(myrpt,REMXXX,(void *)p);
08110          return DC_COMPLETEQUIET;
08111       case 104: /* Low Power */
08112          if(!strcmp(myrpt->remote, remote_rig_ic706))
08113             return DC_ERROR;
08114          myrpt->powerlevel = REM_LOWPWR;
08115          setrem(myrpt);
08116          rpt_telemetry(myrpt,REMXXX,(void *)p);
08117          return DC_COMPLETEQUIET;
08118       case 105: /* Medium Power */
08119          if(!strcmp(myrpt->remote, remote_rig_ic706))
08120             return DC_ERROR;
08121          myrpt->powerlevel = REM_MEDPWR;
08122          setrem(myrpt);
08123          rpt_telemetry(myrpt,REMXXX,(void *)p);
08124          return DC_COMPLETEQUIET;
08125       case 106: /* Hi Power */
08126          if(!strcmp(myrpt->remote, remote_rig_ic706))
08127             return DC_ERROR;
08128          myrpt->powerlevel = REM_HIPWR;
08129          setrem(myrpt);
08130          rpt_telemetry(myrpt,REMXXX,(void *)p);
08131          return DC_COMPLETEQUIET;
08132       case 107: /* Bump down 20Hz */
08133          multimode_bump_freq(myrpt, -20);
08134          return DC_COMPLETE;
08135       case 108: /* Bump down 100Hz */
08136          multimode_bump_freq(myrpt, -100);
08137          return DC_COMPLETE;
08138       case 109: /* Bump down 500Hz */
08139          multimode_bump_freq(myrpt, -500);
08140          return DC_COMPLETE;
08141       case 110: /* Bump up 20Hz */
08142          multimode_bump_freq(myrpt, 20);
08143          return DC_COMPLETE;
08144       case 111: /* Bump up 100Hz */
08145          multimode_bump_freq(myrpt, 100);
08146          return DC_COMPLETE;
08147       case 112: /* Bump up 500Hz */
08148          multimode_bump_freq(myrpt, 500);
08149          return DC_COMPLETE;
08150       case 113: /* Scan down slow */
08151          myrpt->scantimer = REM_SCANTIME;
08152          myrpt->hfscanmode = HF_SCAN_DOWN_SLOW;
08153          rpt_telemetry(myrpt,REMXXX,(void *)p);
08154          return DC_COMPLETEQUIET;
08155       case 114: /* Scan down quick */
08156          myrpt->scantimer = REM_SCANTIME;
08157          myrpt->hfscanmode = HF_SCAN_DOWN_QUICK;
08158          rpt_telemetry(myrpt,REMXXX,(void *)p);
08159          return DC_COMPLETEQUIET;
08160       case 115: /* Scan down fast */
08161          myrpt->scantimer = REM_SCANTIME;
08162          myrpt->hfscanmode = HF_SCAN_DOWN_FAST;
08163          rpt_telemetry(myrpt,REMXXX,(void *)p);
08164          return DC_COMPLETEQUIET;
08165       case 116: /* Scan up slow */
08166          myrpt->scantimer = REM_SCANTIME;
08167          myrpt->hfscanmode = HF_SCAN_UP_SLOW;
08168          rpt_telemetry(myrpt,REMXXX,(void *)p);
08169          return DC_COMPLETEQUIET;
08170       case 117: /* Scan up quick */
08171          myrpt->scantimer = REM_SCANTIME;
08172          myrpt->hfscanmode = HF_SCAN_UP_QUICK;
08173          rpt_telemetry(myrpt,REMXXX,(void *)p);
08174          return DC_COMPLETEQUIET;
08175       case 118: /* Scan up fast */
08176          myrpt->scantimer = REM_SCANTIME;
08177          myrpt->hfscanmode = HF_SCAN_UP_FAST;
08178          rpt_telemetry(myrpt,REMXXX,(void *)p);
08179          return DC_COMPLETEQUIET;
08180       case 119: /* Tune Request */
08181          /* if not currently going, and valid to do */
08182          if((!myrpt->tunerequest) && 
08183              ((!strcmp(myrpt->remote, remote_rig_ft897) || 
08184             !strcmp(myrpt->remote, remote_rig_ic706)) )) { 
08185             myrpt->remotetx = 0;
08186             ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
08187             myrpt->tunerequest = 1;
08188             rpt_telemetry(myrpt,TUNE,NULL);
08189             return DC_COMPLETEQUIET;
08190          }
08191          return DC_ERROR;        
08192       case 5: /* Long Status */
08193          rpt_telemetry(myrpt,REMLONGSTATUS,NULL);
08194          return DC_COMPLETEQUIET;
08195       case 140: /* Short Status */
08196          rpt_telemetry(myrpt,REMSHORTSTATUS,NULL);
08197          return DC_COMPLETEQUIET;
08198       case 200:
08199       case 201:
08200       case 202:
08201       case 203:
08202       case 204:
08203       case 205:
08204       case 206:
08205       case 207:
08206       case 208:
08207       case 209:
08208       case 210:
08209       case 211:
08210       case 212:
08211       case 213:
08212       case 214:
08213       case 215:
08214          do_dtmf_local(myrpt,remdtmfstr[p - 200]);
08215          return DC_COMPLETEQUIET;
08216       default:
08217          break;
08218    }
08219    return DC_INDETERMINATE;
08220 }
08221 
08222 
08223 static int handle_remote_dtmf_digit(struct rpt *myrpt,char c, char *keyed, int phonemode)
08224 {
08225 time_t   now;
08226 int   ret,res = 0,src;
08227 
08228    time(&myrpt->last_activity_time);
08229    /* Stop scan mode if in scan mode */
08230    if(myrpt->hfscanmode){
08231       stop_scan(myrpt);
08232       return 0;
08233    }
08234 
08235    time(&now);
08236    /* if timed-out */
08237    if ((myrpt->dtmf_time_rem + DTMF_TIMEOUT) < now)
08238    {
08239       myrpt->dtmfidx = -1;
08240       myrpt->dtmfbuf[0] = 0;
08241       myrpt->dtmf_time_rem = 0;
08242    }
08243    /* if decode not active */
08244    if (myrpt->dtmfidx == -1)
08245    {
08246       /* if not lead-in digit, dont worry */
08247       if (c != myrpt->p.funcchar)
08248       {
08249          if (!myrpt->p.propagate_dtmf)
08250          {
08251             rpt_mutex_lock(&myrpt->lock);
08252             do_dtmf_local(myrpt,c);
08253             rpt_mutex_unlock(&myrpt->lock);
08254          }
08255          return 0;
08256       }
08257       myrpt->dtmfidx = 0;
08258       myrpt->dtmfbuf[0] = 0;
08259       myrpt->dtmf_time_rem = now;
08260       return 0;
08261    }
08262    /* if too many in buffer, start over */
08263    if (myrpt->dtmfidx >= MAXDTMF)
08264    {
08265       myrpt->dtmfidx = 0;
08266       myrpt->dtmfbuf[0] = 0;
08267       myrpt->dtmf_time_rem = now;
08268    }
08269    if (c == myrpt->p.funcchar)
08270    {
08271       /* if star at beginning, or 2 together, erase buffer */
08272       if ((myrpt->dtmfidx < 1) || 
08273          (myrpt->dtmfbuf[myrpt->dtmfidx - 1] == myrpt->p.funcchar))
08274       {
08275          myrpt->dtmfidx = 0;
08276          myrpt->dtmfbuf[0] = 0;
08277          myrpt->dtmf_time_rem = now;
08278          return 0;
08279       }
08280    }
08281    myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
08282    myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
08283    myrpt->dtmf_time_rem = now;
08284    
08285    
08286    src = SOURCE_RMT;
08287    if (phonemode > 1) src = SOURCE_DPHONE;
08288    else if (phonemode) src = SOURCE_PHONE;
08289    ret = collect_function_digits(myrpt, myrpt->dtmfbuf, src, NULL);
08290    
08291    switch(ret){
08292    
08293       case DC_INDETERMINATE:
08294          res = 0;
08295          break;
08296             
08297       case DC_DOKEY:
08298          if (keyed) *keyed = 1;
08299          res = 0;
08300          break;
08301             
08302       case DC_REQ_FLUSH:
08303          myrpt->dtmfidx = 0;
08304          myrpt->dtmfbuf[0] = 0;
08305          res = 0;
08306          break;
08307             
08308             
08309       case DC_COMPLETE:
08310          res = 1;
08311       case DC_COMPLETEQUIET:
08312          myrpt->totalexecdcommands++;
08313          myrpt->dailyexecdcommands++;
08314          strncpy(myrpt->lastdtmfcommand, myrpt->dtmfbuf, MAXDTMF-1);
08315          myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
08316          myrpt->dtmfbuf[0] = 0;
08317          myrpt->dtmfidx = -1;
08318          myrpt->dtmf_time_rem = 0;
08319          break;
08320             
08321       case DC_ERROR:
08322       default:
08323          myrpt->dtmfbuf[0] = 0;
08324          myrpt->dtmfidx = -1;
08325          myrpt->dtmf_time_rem = 0;
08326          res = 0;
08327          break;
08328    }
08329 
08330    return res;
08331 }
08332 
08333 static int handle_remote_data(struct rpt *myrpt, char *str)
08334 {
08335 char  tmp[300],cmd[300],dest[300],src[300],c;
08336 int   seq,res;
08337 
08338    /* put string in our buffer */
08339    strncpy(tmp,str,sizeof(tmp) - 1);
08340    if (!strcmp(tmp,discstr)) return 0;
08341 
08342 #ifndef  DO_NOT_NOTIFY_MDC1200_ON_REMOTE_BASES
08343    if (tmp[0] == 'I')
08344    {
08345       if (sscanf(tmp,"%s %s %x",cmd,src,&seq) != 3)
08346       {
08347          ast_log(LOG_WARNING, "Unable to parse ident string %s\n",str);
08348          return 0;
08349       }
08350       mdc1200_notify(myrpt,src,seq);
08351       return 0;
08352    }
08353 #endif
08354    if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
08355    {
08356       ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
08357       return 0;
08358    }
08359    if (strcmp(cmd,"D"))
08360    {
08361       ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
08362       return 0;
08363    }
08364    /* if not for me, ignore */
08365    if (strcmp(dest,myrpt->name)) return 0;
08366    if (myrpt->p.archivedir)
08367    {
08368       char str[100];
08369 
08370       sprintf(str,"DTMF,%c",c);
08371       donodelog(myrpt,str);
08372    }
08373    c = func_xlat(myrpt,c,&myrpt->p.outxlat);
08374    if (!c) return(0);
08375    res = handle_remote_dtmf_digit(myrpt,c, NULL, 0);
08376    if (res != 1)
08377       return res;
08378    rpt_telemetry(myrpt,COMPLETE,NULL);
08379    return 0;
08380 }
08381 
08382 static int handle_remote_phone_dtmf(struct rpt *myrpt, char c, char *keyed, int phonemode)
08383 {
08384 int   res;
08385 
08386 
08387    if (keyed && *keyed && (c == myrpt->p.endchar))
08388    {
08389       *keyed = 0;
08390       return DC_INDETERMINATE;
08391    }
08392 
08393    if (myrpt->p.archivedir)
08394    {
08395       char str[100];
08396 
08397       sprintf(str,"DTMF(P),%c",c);
08398       donodelog(myrpt,str);
08399    }
08400    res = handle_remote_dtmf_digit(myrpt,c,keyed, phonemode);
08401    if (res != 1)
08402       return res;
08403    rpt_telemetry(myrpt,COMPLETE,NULL);
08404    return 0;
08405 }
08406 
08407 static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l)
08408 {
08409    char *val, *s, *s1, *s2, *tele;
08410    char tmp[300], deststr[300] = "";
08411 
08412    val = node_lookup(myrpt,l->name);
08413    if (!val)
08414    {
08415       fprintf(stderr,"attempt_reconnect: cannot find node %s\n",l->name);
08416       return -1;
08417    }
08418 
08419    rpt_mutex_lock(&myrpt->lock);
08420    /* remove from queue */
08421    remque((struct qelem *) l);
08422    rpt_mutex_unlock(&myrpt->lock);
08423    strncpy(tmp,val,sizeof(tmp) - 1);
08424    s = tmp;
08425    s1 = strsep(&s,",");
08426    s2 = strsep(&s,",");
08427    snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
08428    tele = strchr(deststr, '/');
08429    if (!tele) {
08430       fprintf(stderr,"attempt_reconnect:Dial number (%s) must be in format tech/number\n",deststr);
08431       return -1;
08432    }
08433    *tele++ = 0;
08434    l->elaptime = 0;
08435    l->connecttime = 0;
08436    l->thisconnected = 0;
08437    l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
08438    if (l->chan){
08439       ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
08440       ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
08441       l->chan->whentohangup = 0;
08442       l->chan->appl = "Apprpt";
08443       l->chan->data = "(Remote Rx)";
08444       if (option_verbose > 2)
08445          ast_verbose(VERBOSE_PREFIX_3 "rpt (attempt_reconnect) initiating call to %s/%s on %s\n",
08446             deststr, tele, l->chan->name);
08447       if(l->chan->cid.cid_num)
08448          free(l->chan->cid.cid_num);
08449       l->chan->cid.cid_num = strdup(myrpt->name);
08450                 ast_call(l->chan,tele,999); 
08451 
08452    }
08453    else 
08454    {
08455       if (option_verbose > 2)
08456          ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
08457             deststr,tele,l->chan->name);
08458       return -1;
08459    }
08460    rpt_mutex_lock(&myrpt->lock);
08461    /* put back in queue */
08462    insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
08463    rpt_mutex_unlock(&myrpt->lock);
08464    ast_log(LOG_NOTICE,"Reconnect Attempt to %s in process\n",l->name);
08465    return 0;
08466 }
08467 
08468 /* 0 return=continue, 1 return = break, -1 return = error */
08469 static void local_dtmf_helper(struct rpt *myrpt,char c)
08470 {
08471 int   res;
08472 pthread_attr_t attr;
08473 char  cmd[MAXDTMF+1] = "";
08474 
08475    if (myrpt->p.archivedir)
08476    {
08477       char str[100];
08478 
08479       sprintf(str,"DTMF,MAIN,%c",c);
08480       donodelog(myrpt,str);
08481    }
08482    if (c == myrpt->p.endchar)
08483    {
08484    /* if in simple mode, kill autopatch */
08485       if (myrpt->p.simple && myrpt->callmode)
08486       {
08487          rpt_mutex_lock(&myrpt->lock);
08488          myrpt->callmode = 0;
08489          rpt_mutex_unlock(&myrpt->lock);
08490          rpt_telemetry(myrpt,TERM,NULL);
08491          return;
08492       }
08493       rpt_mutex_lock(&myrpt->lock);
08494       myrpt->stopgen = 1;
08495       if (myrpt->cmdnode[0])
08496       {
08497          myrpt->cmdnode[0] = 0;
08498          myrpt->dtmfidx = -1;
08499          myrpt->dtmfbuf[0] = 0;
08500          rpt_mutex_unlock(&myrpt->lock);
08501          rpt_telemetry(myrpt,COMPLETE,NULL);
08502       } 
08503       else
08504                 {
08505                         rpt_mutex_unlock(&myrpt->lock);
08506                         if (myrpt->p.propagate_phonedtmf)
08507                                do_dtmf_phone(myrpt,NULL,c);
08508                 }
08509       return;
08510    }
08511    rpt_mutex_lock(&myrpt->lock);
08512    if (myrpt->cmdnode[0])
08513    {
08514       rpt_mutex_unlock(&myrpt->lock);
08515       send_link_dtmf(myrpt,c);
08516       return;
08517    }
08518    if (!myrpt->p.simple)
08519    {
08520       if (c == myrpt->p.funcchar)
08521       {
08522          myrpt->dtmfidx = 0;
08523          myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
08524          rpt_mutex_unlock(&myrpt->lock);
08525          time(&myrpt->dtmf_time);
08526          return;
08527       } 
08528       else if ((c != myrpt->p.endchar) && (myrpt->dtmfidx >= 0))
08529       {
08530          time(&myrpt->dtmf_time);
08531          
08532          if (myrpt->dtmfidx < MAXDTMF)
08533          {
08534             myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
08535             myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
08536             
08537             strncpy(cmd, myrpt->dtmfbuf, sizeof(cmd) - 1);
08538             
08539             rpt_mutex_unlock(&myrpt->lock);
08540             res = collect_function_digits(myrpt, cmd, SOURCE_RPT, NULL);
08541             rpt_mutex_lock(&myrpt->lock);
08542             switch(res){
08543                 case DC_INDETERMINATE:
08544                break;
08545                 case DC_REQ_FLUSH:
08546                myrpt->dtmfidx = 0;
08547                myrpt->dtmfbuf[0] = 0;
08548                break;
08549                 case DC_COMPLETE:
08550                 case DC_COMPLETEQUIET:
08551                myrpt->totalexecdcommands++;
08552                myrpt->dailyexecdcommands++;
08553                strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
08554                myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
08555                myrpt->dtmfbuf[0] = 0;
08556                myrpt->dtmfidx = -1;
08557                myrpt->dtmf_time = 0;
08558                break;
08559 
08560                 case DC_ERROR:
08561                 default:
08562                myrpt->dtmfbuf[0] = 0;
08563                myrpt->dtmfidx = -1;
08564                myrpt->dtmf_time = 0;
08565                break;
08566             }
08567             if(res != DC_INDETERMINATE) {
08568                rpt_mutex_unlock(&myrpt->lock);
08569                return;
08570             }
08571          } 
08572       }
08573    }
08574    else /* if simple */
08575    {
08576       if ((!myrpt->callmode) && (c == myrpt->p.funcchar))
08577       {
08578          myrpt->callmode = 1;
08579          myrpt->patchnoct = 0;
08580          myrpt->patchquiet = 0;
08581          myrpt->patchfarenddisconnect = 0;
08582          myrpt->patchdialtime = 0;
08583          strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
08584          myrpt->cidx = 0;
08585          myrpt->exten[myrpt->cidx] = 0;
08586          rpt_mutex_unlock(&myrpt->lock);
08587               pthread_attr_init(&attr);
08588               pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
08589          ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *)myrpt);
08590          return;
08591       }
08592    }
08593    if (myrpt->callmode == 1)
08594    {
08595       myrpt->exten[myrpt->cidx++] = c;
08596       myrpt->exten[myrpt->cidx] = 0;
08597       /* if this exists */
08598       if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
08599       {
08600          myrpt->callmode = 2;
08601          rpt_mutex_unlock(&myrpt->lock);
08602          if(!myrpt->patchquiet)
08603             rpt_telemetry(myrpt,PROC,NULL); 
08604          return;
08605       }
08606       /* if can continue, do so */
08607       if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
08608       {
08609          /* call has failed, inform user */
08610          myrpt->callmode = 4;
08611       }
08612       rpt_mutex_unlock(&myrpt->lock);
08613       return;
08614    }
08615    if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
08616    {
08617       myrpt->mydtmf = c;
08618    }
08619    rpt_mutex_unlock(&myrpt->lock);
08620    if ((myrpt->dtmfidx < 0) && myrpt->p.propagate_phonedtmf)
08621       do_dtmf_phone(myrpt,NULL,c);
08622    return;
08623 }
08624 
08625 
08626 /* place an ID event in the telemetry queue */
08627 
08628 static void queue_id(struct rpt *myrpt)
08629 {
08630    if(myrpt->p.idtime){ /* ID time must be non-zero */
08631       myrpt->mustid = myrpt->tailid = 0;
08632       myrpt->idtimer = myrpt->p.idtime; /* Reset our ID timer */
08633       rpt_mutex_unlock(&myrpt->lock);
08634       rpt_telemetry(myrpt,ID,NULL);
08635       rpt_mutex_lock(&myrpt->lock);
08636    }
08637 }
08638 
08639 /* Scheduler */
08640 /* must be called locked */
08641 
08642 static void do_scheduler(struct rpt *myrpt)
08643 {
08644    int i,res;
08645    struct tm tmnow;
08646    struct ast_variable *skedlist;
08647    char *strs[5],*vp,*val,value[100];
08648 
08649    memcpy(&myrpt->lasttv, &myrpt->curtv, sizeof(struct timeval));
08650    
08651    if( (res = gettimeofday(&myrpt->curtv, NULL)) < 0)
08652       ast_log(LOG_NOTICE, "Scheduler gettime of day returned: %s\n", strerror(res));
08653 
08654    /* Try to get close to a 1 second resolution */
08655    
08656    if(myrpt->lasttv.tv_sec == myrpt->curtv.tv_sec)
08657       return;
08658 
08659    rpt_localtime(&myrpt->curtv.tv_sec, &tmnow);
08660 
08661    /* If midnight, then reset all daily statistics */
08662    
08663    if((tmnow.tm_hour == 0)&&(tmnow.tm_min == 0)&&(tmnow.tm_sec == 0)){
08664       myrpt->dailykeyups = 0;
08665       myrpt->dailytxtime = 0;
08666       myrpt->dailykerchunks = 0;
08667       myrpt->dailyexecdcommands = 0;
08668    }
08669 
08670    if(tmnow.tm_sec != 0)
08671       return;
08672 
08673    /* Code below only executes once per minute */
08674 
08675 
08676    /* Don't schedule if remote */
08677 
08678         if (myrpt->remote)
08679                 return;
08680 
08681    /* Don't schedule if disabled */
08682 
08683         if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable){
08684       if(debug > 6)
08685          ast_log(LOG_NOTICE, "Scheduler disabled\n");
08686       return;
08687    }
08688 
08689    if(!myrpt->p.skedstanzaname){ /* No stanza means we do nothing */
08690       if(debug > 6)
08691          ast_log(LOG_NOTICE,"No stanza for scheduler in rpt.conf\n");
08692       return;
08693    }
08694 
08695         /* get pointer to linked list of scheduler entries */
08696         skedlist = ast_variable_browse(myrpt->cfg, myrpt->p.skedstanzaname);
08697 
08698    if(debug > 6){
08699       ast_log(LOG_NOTICE, "Time now: %02d:%02d %02d %02d %02d\n",
08700          tmnow.tm_hour,tmnow.tm_min,tmnow.tm_mday,tmnow.tm_mon + 1, tmnow.tm_wday); 
08701    }
08702    /* walk the list */
08703    for(; skedlist; skedlist = skedlist->next){
08704       if(debug > 6)
08705          ast_log(LOG_NOTICE, "Scheduler entry %s = %s being considered\n",skedlist->name, skedlist->value);
08706       strncpy(value,skedlist->value,99);
08707       value[99] = 0;
08708       /* point to the substrings for minute, hour, dom, month, and dow */
08709       for( i = 0, vp = value ; i < 5; i++){
08710          if(!*vp)
08711             break;
08712          while((*vp == ' ') || (*vp == 0x09)) /* get rid of any leading white space */
08713             vp++;
08714          strs[i] = vp; /* save pointer to beginning of substring */
08715          while((*vp != ' ') && (*vp != 0x09) && (*vp != 0)) /* skip over substring */
08716             vp++;
08717          if(*vp)
08718             *vp++ = 0; /* mark end of substring */
08719       }
08720       if(debug > 6)
08721          ast_log(LOG_NOTICE, "i = %d, min = %s, hour = %s, mday=%s, mon=%s, wday=%s\n",i,
08722             strs[0], strs[1], strs[2], strs[3], strs[4]); 
08723       if(i == 5){
08724          if((*strs[0] != '*')&&(atoi(strs[0]) != tmnow.tm_min))
08725             continue;
08726          if((*strs[1] != '*')&&(atoi(strs[1]) != tmnow.tm_hour))
08727             continue;
08728          if((*strs[2] != '*')&&(atoi(strs[2]) != tmnow.tm_mday))
08729             continue;
08730          if((*strs[3] != '*')&&(atoi(strs[3]) != tmnow.tm_mon + 1))
08731             continue;
08732          if(atoi(strs[4]) == 7)
08733             strs[4] = "0";
08734          if((*strs[4] != '*')&&(atoi(strs[4]) != tmnow.tm_wday))
08735             continue;
08736          if(debug)
08737             ast_log(LOG_NOTICE, "Executing scheduler entry %s = %s\n", skedlist->name, skedlist->value);
08738          if(atoi(skedlist->name) == 0)
08739             return; /* Zero is reserved for the startup macro */
08740          val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, skedlist->name);
08741          if (!val){
08742             ast_log(LOG_WARNING,"Scheduler could not find macro %s\n",skedlist->name);
08743             return; /* Macro not found */
08744          }
08745          if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val)){
08746             ast_log(LOG_WARNING, "Scheduler could not execute macro %s: Macro buffer full\n",
08747                skedlist->name);
08748             return; /* Macro buffer full */
08749          }
08750          myrpt->macrotimer = MACROTIME;
08751          strncat(myrpt->macrobuf,val,MAXMACRO - strlen(myrpt->macrobuf) - 1);
08752       }
08753       else{
08754          ast_log(LOG_WARNING,"Malformed scheduler entry in rpt.conf: %s = %s\n",
08755             skedlist->name, skedlist->value);
08756       }
08757    }
08758 
08759 }
08760 
08761 /* single thread with one file (request) to dial */
08762 static void *rpt(void *this)
08763 {
08764 struct   rpt *myrpt = (struct rpt *)this;
08765 char *tele,*idtalkover,c;
08766 int ms = MSWAIT,i,lasttx=0,val,remrx=0,identqueued,othertelemqueued;
08767 int tailmessagequeued,ctqueued,dtmfed;
08768 struct ast_channel *who;
08769 struct dahdi_confinfo ci;  /* conference info */
08770 time_t   t;
08771 struct rpt_link *l,*m;
08772 struct rpt_tele *telem;
08773 char tmpstr[300],lstr[MAXLINKLIST];
08774 
08775 
08776    if (myrpt->p.archivedir) mkdir(myrpt->p.archivedir,0600);
08777    sprintf(tmpstr,"%s/%s",myrpt->p.archivedir,myrpt->name);
08778    mkdir(tmpstr,0600);
08779    rpt_mutex_lock(&myrpt->lock);
08780 
08781    telem = myrpt->tele.next;
08782    while(telem != &myrpt->tele)
08783    {
08784       ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
08785       telem = telem->next;
08786    }
08787    rpt_mutex_unlock(&myrpt->lock);
08788    /* find our index, and load the vars initially */
08789    for(i = 0; i < nrpts; i++)
08790    {
08791       if (&rpt_vars[i] == myrpt)
08792       {
08793          load_rpt_vars(i,0);
08794          break;
08795       }
08796    }
08797    rpt_mutex_lock(&myrpt->lock);
08798    strncpy(tmpstr,myrpt->rxchanname,sizeof(tmpstr) - 1);
08799    tele = strchr(tmpstr,'/');
08800    if (!tele)
08801    {
08802       fprintf(stderr,"rpt:Rxchannel Dial number (%s) must be in format tech/number\n",myrpt->rxchanname);
08803       rpt_mutex_unlock(&myrpt->lock);
08804       myrpt->rpt_thread = AST_PTHREADT_STOP;
08805       pthread_exit(NULL);
08806    }
08807    *tele++ = 0;
08808    myrpt->rxchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
08809    myrpt->zaprxchannel = NULL;
08810    if (!strcasecmp(tmpstr,"Zap"))
08811       myrpt->zaprxchannel = myrpt->rxchannel;
08812    if (myrpt->rxchannel)
08813    {
08814       if (myrpt->rxchannel->_state == AST_STATE_BUSY)
08815       {
08816          fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
08817          rpt_mutex_unlock(&myrpt->lock);
08818          ast_hangup(myrpt->rxchannel);
08819          myrpt->rpt_thread = AST_PTHREADT_STOP;
08820          pthread_exit(NULL);
08821       }
08822       ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
08823       ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
08824 #ifdef   AST_CDR_FLAG_POST_DISABLED
08825       ast_set_flag(myrpt->rxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
08826 #endif
08827       myrpt->rxchannel->whentohangup = 0;
08828       myrpt->rxchannel->appl = "Apprpt";
08829       myrpt->rxchannel->data = "(Repeater Rx)";
08830       if (option_verbose > 2)
08831          ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
08832             tmpstr,tele,myrpt->rxchannel->name);
08833       ast_call(myrpt->rxchannel,tele,999);
08834       if (myrpt->rxchannel->_state != AST_STATE_UP)
08835       {
08836          rpt_mutex_unlock(&myrpt->lock);
08837          ast_hangup(myrpt->rxchannel);
08838          myrpt->rpt_thread = AST_PTHREADT_STOP;
08839          pthread_exit(NULL);
08840       }
08841    }
08842    else
08843    {
08844       fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
08845       rpt_mutex_unlock(&myrpt->lock);
08846       myrpt->rpt_thread = AST_PTHREADT_STOP;
08847       pthread_exit(NULL);
08848    }
08849    myrpt->zaptxchannel = NULL;
08850    if (myrpt->txchanname)
08851    {
08852       strncpy(tmpstr,myrpt->txchanname,sizeof(tmpstr) - 1);
08853       tele = strchr(tmpstr,'/');
08854       if (!tele)
08855       {
08856          fprintf(stderr,"rpt:Txchannel Dial number (%s) must be in format tech/number\n",myrpt->txchanname);
08857          rpt_mutex_unlock(&myrpt->lock);
08858          ast_hangup(myrpt->rxchannel);
08859          myrpt->rpt_thread = AST_PTHREADT_STOP;
08860          pthread_exit(NULL);
08861       }
08862       *tele++ = 0;
08863       myrpt->txchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
08864       if (!strcasecmp(tmpstr,"Zap"))
08865          myrpt->zaptxchannel = myrpt->txchannel;
08866       if (myrpt->txchannel)
08867       {
08868          if (myrpt->txchannel->_state == AST_STATE_BUSY)
08869          {
08870             fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
08871             rpt_mutex_unlock(&myrpt->lock);
08872             ast_hangup(myrpt->txchannel);
08873             ast_hangup(myrpt->rxchannel);
08874             myrpt->rpt_thread = AST_PTHREADT_STOP;
08875             pthread_exit(NULL);
08876          }        
08877          ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
08878          ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
08879 #ifdef   AST_CDR_FLAG_POST_DISABLED
08880          ast_set_flag(myrpt->txchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
08881 #endif
08882          myrpt->txchannel->whentohangup = 0;
08883          myrpt->txchannel->appl = "Apprpt";
08884          myrpt->txchannel->data = "(Repeater Tx)";
08885          if (option_verbose > 2)
08886             ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
08887                tmpstr,tele,myrpt->txchannel->name);
08888          ast_call(myrpt->txchannel,tele,999);
08889          if (myrpt->rxchannel->_state != AST_STATE_UP)
08890          {
08891             rpt_mutex_unlock(&myrpt->lock);
08892             ast_hangup(myrpt->rxchannel);
08893             ast_hangup(myrpt->txchannel);
08894             myrpt->rpt_thread = AST_PTHREADT_STOP;
08895             pthread_exit(NULL);
08896          }
08897       }
08898       else
08899       {
08900          fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
08901          rpt_mutex_unlock(&myrpt->lock);
08902          ast_hangup(myrpt->rxchannel);
08903          myrpt->rpt_thread = AST_PTHREADT_STOP;
08904          pthread_exit(NULL);
08905       }
08906    }
08907    else
08908    {
08909       myrpt->txchannel = myrpt->rxchannel;
08910    }
08911    ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
08912    ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
08913    /* allocate a pseudo-channel thru asterisk */
08914    myrpt->pchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
08915    if (!myrpt->pchannel)
08916    {
08917       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
08918       rpt_mutex_unlock(&myrpt->lock);
08919       if (myrpt->txchannel != myrpt->rxchannel) 
08920          ast_hangup(myrpt->txchannel);
08921       ast_hangup(myrpt->rxchannel);
08922       myrpt->rpt_thread = AST_PTHREADT_STOP;
08923       pthread_exit(NULL);
08924    }
08925 #ifdef   AST_CDR_FLAG_POST_DISABLED
08926    ast_set_flag(myrpt->pchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
08927 #endif
08928    if (!myrpt->zaprxchannel) myrpt->zaprxchannel = myrpt->pchannel;
08929    if (!myrpt->zaptxchannel)
08930    {
08931       /* allocate a pseudo-channel thru asterisk */
08932       myrpt->zaptxchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
08933       if (!myrpt->zaptxchannel)
08934       {
08935          fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
08936          rpt_mutex_unlock(&myrpt->lock);
08937          if (myrpt->txchannel != myrpt->rxchannel) 
08938             ast_hangup(myrpt->txchannel);
08939          ast_hangup(myrpt->rxchannel);
08940          myrpt->rpt_thread = AST_PTHREADT_STOP;
08941          pthread_exit(NULL);
08942       }
08943       ast_set_read_format(myrpt->zaptxchannel,AST_FORMAT_SLINEAR);
08944       ast_set_write_format(myrpt->zaptxchannel,AST_FORMAT_SLINEAR);
08945 #ifdef   AST_CDR_FLAG_POST_DISABLED
08946       ast_set_flag(myrpt->zaptxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
08947 #endif
08948    }
08949    /* allocate a pseudo-channel thru asterisk */
08950    myrpt->monchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
08951    if (!myrpt->monchannel)
08952    {
08953       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
08954       rpt_mutex_unlock(&myrpt->lock);
08955       if (myrpt->txchannel != myrpt->rxchannel) 
08956          ast_hangup(myrpt->txchannel);
08957       ast_hangup(myrpt->rxchannel);
08958       myrpt->rpt_thread = AST_PTHREADT_STOP;
08959       pthread_exit(NULL);
08960    }
08961    ast_set_read_format(myrpt->monchannel,AST_FORMAT_SLINEAR);
08962    ast_set_write_format(myrpt->monchannel,AST_FORMAT_SLINEAR);
08963 #ifdef   AST_CDR_FLAG_POST_DISABLED
08964    ast_set_flag(myrpt->monchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
08965 #endif
08966    /* make a conference for the tx */
08967    ci.chan = 0;
08968    ci.confno = -1; /* make a new conf */
08969    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER;
08970    /* first put the channel on the conference in proper mode */
08971    if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
08972    {
08973       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
08974       rpt_mutex_unlock(&myrpt->lock);
08975       ast_hangup(myrpt->pchannel);
08976       ast_hangup(myrpt->monchannel);
08977       if (myrpt->txchannel != myrpt->rxchannel) 
08978          ast_hangup(myrpt->txchannel);
08979       ast_hangup(myrpt->rxchannel);
08980       myrpt->rpt_thread = AST_PTHREADT_STOP;
08981       pthread_exit(NULL);
08982    }
08983    /* save tx conference number */
08984    myrpt->txconf = ci.confno;
08985    /* make a conference for the pseudo */
08986    ci.chan = 0;
08987    ci.confno = -1; /* make a new conf */
08988    ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
08989       (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
08990    /* first put the channel on the conference in announce mode */
08991    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
08992    {
08993       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
08994       rpt_mutex_unlock(&myrpt->lock);
08995       ast_hangup(myrpt->pchannel);
08996       ast_hangup(myrpt->monchannel);
08997       if (myrpt->txchannel != myrpt->rxchannel) 
08998          ast_hangup(myrpt->txchannel);
08999       ast_hangup(myrpt->rxchannel);
09000       myrpt->rpt_thread = AST_PTHREADT_STOP;
09001       pthread_exit(NULL);
09002    }
09003    /* save pseudo channel conference number */
09004    myrpt->conf = ci.confno;
09005    /* make a conference for the pseudo */
09006    ci.chan = 0;
09007    if ((strstr(myrpt->txchannel->name,"pseudo") == NULL) &&
09008       (myrpt->zaptxchannel == myrpt->txchannel))
09009    {
09010       /* get tx channel's port number */
09011       if (ioctl(myrpt->txchannel->fds[0],DAHDI_CHANNO,&ci.confno) == -1)
09012       {
09013          ast_log(LOG_WARNING, "Unable to set tx channel's chan number\n");
09014          rpt_mutex_unlock(&myrpt->lock);
09015          ast_hangup(myrpt->pchannel);
09016          ast_hangup(myrpt->monchannel);
09017          if (myrpt->txchannel != myrpt->rxchannel) 
09018             ast_hangup(myrpt->txchannel);
09019          ast_hangup(myrpt->rxchannel);
09020          myrpt->rpt_thread = AST_PTHREADT_STOP;
09021          pthread_exit(NULL);
09022       }
09023       ci.confmode = DAHDI_CONF_MONITORTX;
09024    }
09025    else
09026    {
09027       ci.confno = myrpt->txconf;
09028       ci.confmode = DAHDI_CONF_CONFANNMON;
09029    }
09030    /* first put the channel on the conference in announce mode */
09031    if (ioctl(myrpt->monchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
09032    {
09033       ast_log(LOG_WARNING, "Unable to set conference mode for monitor\n");
09034       rpt_mutex_unlock(&myrpt->lock);
09035       ast_hangup(myrpt->pchannel);
09036       ast_hangup(myrpt->monchannel);
09037       if (myrpt->txchannel != myrpt->rxchannel) 
09038          ast_hangup(myrpt->txchannel);
09039       ast_hangup(myrpt->rxchannel);
09040       myrpt->rpt_thread = AST_PTHREADT_STOP;
09041       pthread_exit(NULL);
09042    }
09043    /* allocate a pseudo-channel thru asterisk */
09044    myrpt->txpchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
09045    if (!myrpt->txpchannel)
09046    {
09047       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
09048       rpt_mutex_unlock(&myrpt->lock);
09049       ast_hangup(myrpt->pchannel);
09050       ast_hangup(myrpt->monchannel);
09051       if (myrpt->txchannel != myrpt->rxchannel) 
09052          ast_hangup(myrpt->txchannel);
09053       ast_hangup(myrpt->rxchannel);
09054       myrpt->rpt_thread = AST_PTHREADT_STOP;
09055       pthread_exit(NULL);
09056    }
09057 #ifdef   AST_CDR_FLAG_POST_DISABLED
09058    ast_set_flag(myrpt->txpchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
09059 #endif
09060    /* make a conference for the tx */
09061    ci.chan = 0;
09062    ci.confno = myrpt->txconf;
09063    ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER ;
09064    /* first put the channel on the conference in proper mode */
09065    if (ioctl(myrpt->txpchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
09066    {
09067       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
09068       rpt_mutex_unlock(&myrpt->lock);
09069       ast_hangup(myrpt->txpchannel);
09070       ast_hangup(myrpt->monchannel);
09071       if (myrpt->txchannel != myrpt->rxchannel) 
09072          ast_hangup(myrpt->txchannel);
09073       ast_hangup(myrpt->rxchannel);
09074       myrpt->rpt_thread = AST_PTHREADT_STOP;
09075       pthread_exit(NULL);
09076    }
09077    /* Now, the idea here is to copy from the physical rx channel buffer
09078       into the pseudo tx buffer, and from the pseudo rx buffer into the 
09079       tx channel buffer */
09080    myrpt->links.next = &myrpt->links;
09081    myrpt->links.prev = &myrpt->links;
09082    myrpt->tailtimer = 0;
09083    myrpt->totimer = 0;
09084    myrpt->tmsgtimer = myrpt->p.tailmessagetime;
09085    myrpt->idtimer = myrpt->p.politeid;
09086    myrpt->mustid = myrpt->tailid = 0;
09087    myrpt->callmode = 0;
09088    myrpt->tounkeyed = 0;
09089    myrpt->tonotify = 0;
09090    myrpt->retxtimer = 0;
09091    myrpt->rerxtimer = 0;
09092    myrpt->skedtimer = 0;
09093    myrpt->tailevent = 0;
09094    lasttx = 0;
09095    myrpt->keyed = 0;
09096    idtalkover = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover");
09097    myrpt->dtmfidx = -1;
09098    myrpt->dtmfbuf[0] = 0;
09099    myrpt->rem_dtmfidx = -1;
09100    myrpt->rem_dtmfbuf[0] = 0;
09101    myrpt->dtmf_time = 0;
09102    myrpt->rem_dtmf_time = 0;
09103    myrpt->disgorgetime = 0;
09104    myrpt->lastnodewhichkeyedusup[0] = '\0';
09105    myrpt->dailytxtime = 0;
09106    myrpt->totaltxtime = 0;
09107    myrpt->dailykeyups = 0;
09108    myrpt->totalkeyups = 0;
09109    myrpt->dailykerchunks = 0;
09110    myrpt->totalkerchunks = 0;
09111    myrpt->dailyexecdcommands = 0;
09112    myrpt->totalexecdcommands = 0;
09113    myrpt->timeouts = 0;
09114    myrpt->exten[0] = '\0';
09115    myrpt->lastdtmfcommand[0] = '\0';
09116    if (myrpt->p.startupmacro)
09117    {
09118       snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
09119    }
09120    rpt_mutex_unlock(&myrpt->lock);
09121    val = 1;
09122    ast_channel_setoption(myrpt->rxchannel,AST_OPTION_RELAXDTMF,&val,sizeof(char),0);
09123    val = 1;
09124    ast_channel_setoption(myrpt->rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
09125    if (myrpt->p.archivedir) donodelog(myrpt,"STARTUP");
09126    dtmfed = 0;
09127    while (ms >= 0)
09128    {
09129       struct ast_frame *f,*f1,*f2;
09130       struct ast_channel *cs[300],*cs1[300];
09131       int totx=0,elap=0,n,x,toexit=0;
09132 
09133       /* DEBUG Dump */
09134       if((myrpt->disgorgetime) && (time(NULL) >= myrpt->disgorgetime)){
09135          struct rpt_link *zl;
09136          struct rpt_tele *zt;
09137 
09138          myrpt->disgorgetime = 0;
09139          ast_log(LOG_NOTICE,"********** Variable Dump Start (app_rpt) **********\n");
09140          ast_log(LOG_NOTICE,"totx = %d\n",totx);
09141          ast_log(LOG_NOTICE,"remrx = %d\n",remrx);
09142          ast_log(LOG_NOTICE,"lasttx = %d\n",lasttx);
09143          ast_log(LOG_NOTICE,"elap = %d\n",elap);
09144          ast_log(LOG_NOTICE,"toexit = %d\n",toexit);
09145 
09146          ast_log(LOG_NOTICE,"myrpt->keyed = %d\n",myrpt->keyed);
09147          ast_log(LOG_NOTICE,"myrpt->localtx = %d\n",myrpt->localtx);
09148          ast_log(LOG_NOTICE,"myrpt->callmode = %d\n",myrpt->callmode);
09149          ast_log(LOG_NOTICE,"myrpt->mustid = %d\n",myrpt->mustid);
09150          ast_log(LOG_NOTICE,"myrpt->tounkeyed = %d\n",myrpt->tounkeyed);
09151          ast_log(LOG_NOTICE,"myrpt->tonotify = %d\n",myrpt->tonotify);
09152          ast_log(LOG_NOTICE,"myrpt->retxtimer = %ld\n",myrpt->retxtimer);
09153          ast_log(LOG_NOTICE,"myrpt->totimer = %d\n",myrpt->totimer);
09154          ast_log(LOG_NOTICE,"myrpt->tailtimer = %d\n",myrpt->tailtimer);
09155          ast_log(LOG_NOTICE,"myrpt->tailevent = %d\n",myrpt->tailevent);
09156 
09157          zl = myrpt->links.next;
09158                   while(zl != &myrpt->links){
09159             ast_log(LOG_NOTICE,"*** Link Name: %s ***\n",zl->name);
09160             ast_log(LOG_NOTICE,"        link->lasttx %d\n",zl->lasttx);
09161             ast_log(LOG_NOTICE,"        link->lastrx %d\n",zl->lastrx);
09162             ast_log(LOG_NOTICE,"        link->connected %d\n",zl->connected);
09163             ast_log(LOG_NOTICE,"        link->hasconnected %d\n",zl->hasconnected);
09164             ast_log(LOG_NOTICE,"        link->outbound %d\n",zl->outbound);
09165             ast_log(LOG_NOTICE,"        link->disced %d\n",zl->disced);
09166             ast_log(LOG_NOTICE,"        link->killme %d\n",zl->killme);
09167             ast_log(LOG_NOTICE,"        link->disctime %ld\n",zl->disctime);
09168             ast_log(LOG_NOTICE,"        link->retrytimer %ld\n",zl->retrytimer);
09169             ast_log(LOG_NOTICE,"        link->retries = %d\n",zl->retries);
09170             ast_log(LOG_NOTICE,"        link->reconnects = %d\n",zl->reconnects);
09171                            zl = zl->next;
09172                   }
09173                                                                                                                                
09174          zt = myrpt->tele.next;
09175          if(zt != &myrpt->tele)
09176             ast_log(LOG_NOTICE,"*** Telemetry Queue ***\n");
09177                   while(zt != &myrpt->tele){
09178             ast_log(LOG_NOTICE,"        Telemetry mode: %d\n",zt->mode);
09179                            zt = zt->next;
09180                   }
09181          ast_log(LOG_NOTICE,"******* Variable Dump End (app_rpt) *******\n");
09182 
09183       }  
09184 
09185 
09186       if (myrpt->reload)
09187       {
09188          struct rpt_tele *telem;
09189 
09190          rpt_mutex_lock(&myrpt->lock);
09191          telem = myrpt->tele.next;
09192          while(telem != &myrpt->tele)
09193          {
09194             ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
09195             telem = telem->next;
09196          }
09197          myrpt->reload = 0;
09198          rpt_mutex_unlock(&myrpt->lock);
09199          usleep(10000);
09200          /* find our index, and load the vars */
09201          for(i = 0; i < nrpts; i++)
09202          {
09203             if (&rpt_vars[i] == myrpt)
09204             {
09205                load_rpt_vars(i,0);
09206                break;
09207             }
09208          }
09209       }
09210 
09211       rpt_mutex_lock(&myrpt->lock);
09212       if (ast_check_hangup(myrpt->rxchannel)) break;
09213       if (ast_check_hangup(myrpt->txchannel)) break;
09214       if (ast_check_hangup(myrpt->pchannel)) break;
09215       if (ast_check_hangup(myrpt->monchannel)) break;
09216       if (ast_check_hangup(myrpt->txpchannel)) break;
09217       if (myrpt->zaptxchannel && ast_check_hangup(myrpt->zaptxchannel)) break;
09218 
09219       /* Set local tx with keyed */
09220       myrpt->localtx = myrpt->keyed;
09221       /* If someone's connected, and they're transmitting from their end to us, set remrx true */
09222       l = myrpt->links.next;
09223       remrx = 0;
09224       while(l != &myrpt->links)
09225       {
09226          if (l->lastrx){
09227             remrx = 1;
09228             if(l->name[0] != '0') /* Ignore '0' nodes */
09229                strcpy(myrpt->lastnodewhichkeyedusup, l->name); /* Note the node which is doing the key up */
09230          }
09231          l = l->next;
09232       }
09233       /* Create a "must_id" flag for the cleanup ID */      
09234       if(myrpt->p.idtime) /* ID time must be non-zero */
09235          myrpt->mustid |= (myrpt->idtimer) && (myrpt->keyed || remrx) ;
09236       /* Build a fresh totx from myrpt->keyed and autopatch activated */
09237       totx = myrpt->callmode;
09238       /* If full duplex, add local tx to totx */
09239       if (myrpt->p.duplex > 1) 
09240       {
09241          totx = totx || myrpt->localtx;
09242       }
09243       /* Traverse the telemetry list to see what's queued */
09244       identqueued = 0;
09245       othertelemqueued = 0;
09246       tailmessagequeued = 0;
09247       ctqueued = 0;
09248       telem = myrpt->tele.next;
09249       while(telem != &myrpt->tele)
09250       {
09251          if((telem->mode == ID) || (telem->mode == IDTALKOVER)){
09252             identqueued = 1; /* Identification telemetry */
09253          }
09254          else if(telem->mode == TAILMSG)
09255          {
09256             tailmessagequeued = 1; /* Tail message telemetry */
09257          }
09258          else
09259          {
09260             if ((telem->mode != UNKEY) && (telem->mode != LINKUNKEY))
09261                othertelemqueued = 1;  /* Other telemetry */
09262             else
09263                ctqueued = 1; /* Courtesy tone telemetry */
09264          }
09265          telem = telem->next;
09266       }
09267    
09268       /* Add in any "other" telemetry, unless specified otherwise */
09269       if (!myrpt->p.notelemtx) totx = totx || othertelemqueued;
09270       /* Update external (to links) transmitter PTT state with everything but ID, CT, and tailmessage telemetry */
09271       myrpt->exttx = totx;
09272       totx = totx || myrpt->dtmf_local_timer;
09273       /* If half or 3/4 duplex, add localtx to external link tx */
09274       if (myrpt->p.duplex < 2) myrpt->exttx = myrpt->exttx || myrpt->localtx;
09275       /* Add in ID telemetry to local transmitter */
09276       totx = totx || remrx;
09277       /* If 3/4 or full duplex, add in ident and CT telemetry */
09278       if (myrpt->p.duplex > 0)
09279          totx = totx || identqueued || ctqueued;
09280       /* If full duplex, add local dtmf stuff active */
09281       if (myrpt->p.duplex > 1) 
09282       {
09283          totx = totx || (myrpt->dtmfidx > -1) ||
09284             myrpt->cmdnode[0];
09285       }
09286       /* Reset time out timer variables if there is no activity */
09287       if (!totx) 
09288       {
09289          myrpt->totimer = myrpt->p.totime;
09290          myrpt->tounkeyed = 0;
09291          myrpt->tonotify = 0;
09292       }
09293       else{
09294          myrpt->tailtimer = myrpt->p.s[myrpt->p.sysstate_cur].alternatetail ?
09295             myrpt->p.althangtime : /* Initialize tail timer */
09296             myrpt->p.hangtime;
09297       }
09298       /* Disable the local transmitter if we are timed out */
09299       totx = totx && myrpt->totimer;
09300       /* if timed-out and not said already, say it */
09301       if ((!myrpt->totimer) && (!myrpt->tonotify))
09302       {
09303          myrpt->tonotify = 1;
09304          myrpt->timeouts++;
09305          rpt_mutex_unlock(&myrpt->lock);
09306          rpt_telemetry(myrpt,TIMEOUT,NULL);
09307          rpt_mutex_lock(&myrpt->lock);
09308       }
09309 
09310       /* If unkey and re-key, reset time out timer */
09311       if ((!totx) && (!myrpt->totimer) && (!myrpt->tounkeyed) && (!myrpt->keyed))
09312       {
09313          myrpt->tounkeyed = 1;
09314       }
09315       if ((!totx) && (!myrpt->totimer) && myrpt->tounkeyed && myrpt->keyed)
09316       {
09317          myrpt->totimer = myrpt->p.totime;
09318          myrpt->tounkeyed = 0;
09319          myrpt->tonotify = 0;
09320          rpt_mutex_unlock(&myrpt->lock);
09321          continue;
09322       }
09323       /* if timed-out and in circuit busy after call */
09324       if ((!totx) && (!myrpt->totimer) && (myrpt->callmode == 4))
09325       {
09326          myrpt->callmode = 0;
09327       }
09328       /* get rid of tail if timed out */
09329       if (!myrpt->totimer) myrpt->tailtimer = 0;
09330       /* if not timed-out, add in tail */
09331       if (myrpt->totimer) totx = totx || myrpt->tailtimer;
09332       /* If user or links key up or are keyed up over standard ID, switch to talkover ID, if one is defined */
09333       /* If tail message, kill the message if someone keys up over it */ 
09334       if ((myrpt->keyed || remrx) && ((identqueued && idtalkover) || (tailmessagequeued))) {
09335          int hasid = 0,hastalkover = 0;
09336 
09337          telem = myrpt->tele.next;
09338          while(telem != &myrpt->tele){
09339             if(telem->mode == ID){
09340                if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
09341                hasid = 1;
09342             }
09343             if(telem->mode == TAILMSG){
09344                                         if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
09345                                 }
09346             if (telem->mode == IDTALKOVER) hastalkover = 1;
09347             telem = telem->next;
09348          }
09349          rpt_mutex_unlock(&myrpt->lock);
09350          if (hasid && (!hastalkover)) rpt_telemetry(myrpt, IDTALKOVER, NULL); /* Start Talkover ID */
09351          rpt_mutex_lock(&myrpt->lock);
09352       }
09353       /* Try to be polite */
09354       /* If the repeater has been inactive for longer than the ID time, do an initial ID in the tail*/
09355       /* If within 30 seconds of the time to ID, try do it in the tail */
09356       /* else if at ID time limit, do it right over the top of them */
09357       /* Lastly, if the repeater has been keyed, and the ID timer is expired, do a clean up ID */
09358       if(myrpt->mustid && (!myrpt->idtimer))
09359          queue_id(myrpt);
09360 
09361       if ((myrpt->p.idtime && totx && (!myrpt->exttx) &&
09362           (myrpt->idtimer <= myrpt->p.politeid) && myrpt->tailtimer)) /* ID time must be non-zero */ 
09363          {
09364             myrpt->tailid = 1;
09365          }
09366 
09367       /* If tail timer expires, then check for tail messages */
09368 
09369       if(myrpt->tailevent){
09370          myrpt->tailevent = 0;
09371          if(myrpt->tailid){
09372             totx = 1;
09373             queue_id(myrpt);
09374          }
09375          else if ((myrpt->p.tailmessages[0]) &&
09376             (myrpt->p.tailmessagetime) && (myrpt->tmsgtimer == 0)){
09377                totx = 1;
09378                myrpt->tmsgtimer = myrpt->p.tailmessagetime; 
09379                rpt_mutex_unlock(&myrpt->lock);
09380                rpt_telemetry(myrpt, TAILMSG, NULL);
09381                rpt_mutex_lock(&myrpt->lock);
09382          }  
09383       }
09384 
09385       /* Main TX control */
09386 
09387       /* let telemetry transmit anyway (regardless of timeout) */
09388       if (myrpt->p.duplex > 0) totx = totx || (myrpt->tele.next != &myrpt->tele);
09389       if (totx && (!lasttx))
09390       {
09391          char mydate[100],myfname[100];
09392          time_t myt;
09393 
09394          if (myrpt->monstream) ast_closestream(myrpt->monstream);
09395          if (myrpt->p.archivedir)
09396          {
09397             long blocksleft;
09398 
09399             time(&myt);
09400             strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
09401                localtime(&myt));
09402             sprintf(myfname,"%s/%s/%s",myrpt->p.archivedir,
09403                myrpt->name,mydate);
09404             myrpt->monstream = ast_writefile(myfname,"wav49",
09405                "app_rpt Air Archive",O_CREAT | O_APPEND,0,0600);
09406             if (myrpt->p.monminblocks)
09407             {
09408                blocksleft = diskavail(myrpt);
09409                if (blocksleft >= myrpt->p.monminblocks)
09410                   donodelog(myrpt,"TXKEY,MAIN");
09411             } else donodelog(myrpt,"TXKEY,MAIN");
09412          }
09413          lasttx = 1;
09414          myrpt->dailykeyups++;
09415          myrpt->totalkeyups++;
09416          rpt_mutex_unlock(&myrpt->lock);
09417          ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
09418          rpt_mutex_lock(&myrpt->lock);
09419       }
09420       totx = totx && !myrpt->p.s[myrpt->p.sysstate_cur].txdisable;
09421       if ((!totx) && lasttx)
09422       {
09423          if (myrpt->monstream) ast_closestream(myrpt->monstream);
09424          myrpt->monstream = NULL;
09425 
09426          lasttx = 0;
09427          rpt_mutex_unlock(&myrpt->lock);
09428          ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
09429          rpt_mutex_lock(&myrpt->lock);
09430          donodelog(myrpt,"TXUNKEY,MAIN");
09431       }
09432       time(&t);
09433       /* if DTMF timeout */
09434       if ((!myrpt->cmdnode[0]) && (myrpt->dtmfidx >= 0) && ((myrpt->dtmf_time + DTMF_TIMEOUT) < t))
09435       {
09436          myrpt->dtmfidx = -1;
09437          myrpt->dtmfbuf[0] = 0;
09438       }        
09439       /* if remote DTMF timeout */
09440       if ((myrpt->rem_dtmfidx >= 0) && ((myrpt->rem_dtmf_time + DTMF_TIMEOUT) < t))
09441       {
09442          myrpt->rem_dtmfidx = -1;
09443          myrpt->rem_dtmfbuf[0] = 0;
09444       }  
09445 
09446       /* Reconnect */
09447    
09448       l = myrpt->links.next;
09449       while(l != &myrpt->links)
09450       {
09451          if (l->killme)
09452          {
09453             /* remove from queue */
09454             remque((struct qelem *) l);
09455             if (!strcmp(myrpt->cmdnode,l->name))
09456                myrpt->cmdnode[0] = 0;
09457             rpt_mutex_unlock(&myrpt->lock);
09458             /* hang-up on call to device */
09459             if (l->chan) ast_hangup(l->chan);
09460             ast_hangup(l->pchan);
09461             free(l);
09462             rpt_mutex_lock(&myrpt->lock);
09463             /* re-start link traversal */
09464             l = myrpt->links.next;
09465             continue;
09466          }
09467          l = l->next;
09468       }
09469       n = 0;
09470       cs[n++] = myrpt->rxchannel;
09471       cs[n++] = myrpt->pchannel;
09472       cs[n++] = myrpt->monchannel;
09473       cs[n++] = myrpt->txpchannel;
09474       if (myrpt->txchannel != myrpt->rxchannel) cs[n++] = myrpt->txchannel;
09475       if (myrpt->zaptxchannel != myrpt->txchannel)
09476          cs[n++] = myrpt->zaptxchannel;
09477       l = myrpt->links.next;
09478       while(l != &myrpt->links)
09479       {
09480          if ((!l->killme) && (!l->disctime) && l->chan)
09481          {
09482             cs[n++] = l->chan;
09483             cs[n++] = l->pchan;
09484          }
09485          l = l->next;
09486       }
09487       rpt_mutex_unlock(&myrpt->lock);
09488       ms = MSWAIT;
09489       for(x = 0; x < n; x++)
09490       {
09491          int s = -(-x - myrpt->scram - 1) % n;
09492          cs1[x] = cs[s];
09493       }
09494       myrpt->scram++;
09495       who = ast_waitfor_n(cs1,n,&ms);
09496       if (who == NULL) ms = 0;
09497       elap = MSWAIT - ms;
09498       rpt_mutex_lock(&myrpt->lock);
09499       l = myrpt->links.next;
09500       while(l != &myrpt->links)
09501       {
09502          if (l->linklisttimer)
09503          {
09504             l->linklisttimer -= elap;
09505             if (l->linklisttimer < 0) l->linklisttimer = 0;
09506          }
09507          if ((!l->linklisttimer) && (l->name[0] != '0') && (!l->isremote))
09508          {
09509             struct   ast_frame lf;
09510 
09511             memset(&lf,0,sizeof(lf));
09512             lf.frametype = AST_FRAME_TEXT;
09513             lf.subclass = 0;
09514             lf.offset = 0;
09515             lf.mallocd = 0;
09516             lf.samples = 0;
09517             l->linklisttimer = LINKLISTTIME;
09518             strcpy(lstr,"L ");
09519             __mklinklist(myrpt,l,lstr + 2);
09520             if (l->chan)
09521             {
09522                lf.datalen = strlen(lstr) + 1;
09523                lf.data = lstr;
09524                ast_write(l->chan,&lf);
09525                if (debug > 6) ast_log(LOG_NOTICE,
09526                   "@@@@ node %s sent node string %s to node %s\n",
09527                      myrpt->name,lstr,l->name);
09528             }
09529          }
09530 #ifndef  OLDKEY
09531          if ((l->retxtimer += elap) >= REDUNDANT_TX_TIME)
09532          {
09533             l->retxtimer = 0;
09534             if (l->chan && l->phonemode == 0) 
09535             {
09536                if (l->lasttx)
09537                   ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
09538                else
09539                   ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
09540             }
09541          }
09542          if ((l->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 5))
09543          {
09544             if (debug == 7) printf("@@@@ rx un-key\n");
09545             l->lastrx = 0;
09546             l->rerxtimer = 0;
09547             if(myrpt->p.duplex) 
09548                rpt_telemetry(myrpt,LINKUNKEY,l);
09549             if (myrpt->p.archivedir)
09550             {
09551                char str[100];
09552 
09553                l->lastrx1 = 0;
09554                sprintf(str,"RXUNKEY(T),%s",l->name);
09555                donodelog(myrpt,str);
09556             }
09557          }
09558 #endif
09559          if (l->disctime) /* Disconnect timer active on a channel ? */
09560          {
09561             l->disctime -= elap;
09562             if (l->disctime <= 0) /* Disconnect timer expired on inbound channel ? */
09563                l->disctime = 0; /* Yep */
09564          }
09565 
09566          if (l->retrytimer)
09567          {
09568             l->retrytimer -= elap;
09569             if (l->retrytimer < 0) l->retrytimer = 0;
09570          }
09571 
09572          /* Tally connect time */
09573          l->connecttime += elap;
09574 
09575          /* ignore non-timing channels */
09576          if (l->elaptime < 0)
09577          {
09578             l = l->next;
09579             continue;
09580          }
09581          l->elaptime += elap;
09582          /* if connection has taken too long */
09583          if ((l->elaptime > MAXCONNECTTIME) && 
09584             ((!l->chan) || (l->chan->_state != AST_STATE_UP)))
09585          {
09586             l->elaptime = 0;
09587             rpt_mutex_unlock(&myrpt->lock);
09588             if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
09589             rpt_mutex_lock(&myrpt->lock);
09590             break;
09591          }
09592          if ((!l->chan) && (!l->retrytimer) && l->outbound && 
09593             (l->retries++ < l->max_retries) && (l->hasconnected))
09594          {
09595             if (l->chan) ast_hangup(l->chan);
09596             l->chan = 0;
09597             rpt_mutex_unlock(&myrpt->lock);
09598             if ((l->name[0] != '0') && (!l->isremote))
09599             {
09600                if (attempt_reconnect(myrpt,l) == -1)
09601                {
09602                   l->retrytimer = RETRY_TIMER_MS;
09603                } 
09604             }
09605             else 
09606             {
09607                l->retrytimer = l->max_retries + 1;
09608             }
09609 
09610             rpt_mutex_lock(&myrpt->lock);
09611             break;
09612          }
09613          if ((!l->chan) && (!l->retrytimer) && l->outbound &&
09614             (l->retries >= l->max_retries))
09615          {
09616             /* remove from queue */
09617             remque((struct qelem *) l);
09618             if (!strcmp(myrpt->cmdnode,l->name))
09619                myrpt->cmdnode[0] = 0;
09620             rpt_mutex_unlock(&myrpt->lock);
09621             if (l->name[0] != '0')
09622             {
09623                if (!l->hasconnected)
09624                   rpt_telemetry(myrpt,CONNFAIL,l);
09625                else rpt_telemetry(myrpt,REMDISC,l);
09626             }
09627             if (myrpt->p.archivedir)
09628             {
09629                char str[100];
09630 
09631                if (!l->hasconnected)
09632                   sprintf(str,"LINKFAIL,%s",l->name);
09633                else
09634                   sprintf(str,"LINKDISC,%s",l->name);
09635                donodelog(myrpt,str);
09636             }
09637             /* hang-up on call to device */
09638             ast_hangup(l->pchan);
09639             free(l);
09640                                 rpt_mutex_lock(&myrpt->lock);
09641             break;
09642          }
09643                         if ((!l->chan) && (!l->disctime) && (!l->outbound))
09644                         {
09645                                 /* remove from queue */
09646                                 remque((struct qelem *) l);
09647                                 if (!strcmp(myrpt->cmdnode,l->name))
09648                                         myrpt->cmdnode[0] = 0;
09649                                 rpt_mutex_unlock(&myrpt->lock);
09650             if (l->name[0] != '0') 
09651             {
09652                                    rpt_telemetry(myrpt,REMDISC,l);
09653             }
09654             if (myrpt->p.archivedir)
09655             {
09656                char str[100];
09657 
09658                sprintf(str,"LINKDISC,%s",l->name);
09659                donodelog(myrpt,str);
09660             }
09661                                 /* hang-up on call to device */
09662                                 ast_hangup(l->pchan);
09663                                 free(l);
09664                                 rpt_mutex_lock(&myrpt->lock);
09665                                 break;
09666                         }
09667          l = l->next;
09668       }
09669       if(totx){
09670          myrpt->dailytxtime += elap;
09671          myrpt->totaltxtime += elap;
09672       }
09673       i = myrpt->tailtimer;
09674       if (myrpt->tailtimer) myrpt->tailtimer -= elap;
09675       if (myrpt->tailtimer < 0) myrpt->tailtimer = 0;
09676       if((i) && (myrpt->tailtimer == 0))
09677          myrpt->tailevent = 1;
09678       if ((!myrpt->p.s[myrpt->p.sysstate_cur].totdisable) && myrpt->totimer) myrpt->totimer -= elap;
09679       if (myrpt->totimer < 0) myrpt->totimer = 0;
09680       if (myrpt->idtimer) myrpt->idtimer -= elap;
09681       if (myrpt->idtimer < 0) myrpt->idtimer = 0;
09682       if (myrpt->tmsgtimer) myrpt->tmsgtimer -= elap;
09683       if (myrpt->tmsgtimer < 0) myrpt->tmsgtimer = 0;
09684       /* do macro timers */
09685       if (myrpt->macrotimer) myrpt->macrotimer -= elap;
09686       if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
09687       /* do local dtmf timer */
09688       if (myrpt->dtmf_local_timer)
09689       {
09690          if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
09691          if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
09692       }
09693       do_dtmf_local(myrpt,0);
09694       /* Execute scheduler appx. every 2 tenths of a second */
09695       if (myrpt->skedtimer <= 0){
09696          myrpt->skedtimer = 200;
09697          do_scheduler(myrpt);
09698       }
09699       else
09700          myrpt->skedtimer -=elap;
09701       if (!ms) 
09702       {
09703          rpt_mutex_unlock(&myrpt->lock);
09704          continue;
09705       }
09706       c = myrpt->macrobuf[0];
09707       time(&t);
09708       if (c && (!myrpt->macrotimer) && 
09709          starttime && (t > (starttime + START_DELAY)))
09710       {
09711          myrpt->macrotimer = MACROTIME;
09712          memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
09713          if ((c == 'p') || (c == 'P'))
09714             myrpt->macrotimer = MACROPTIME;
09715          rpt_mutex_unlock(&myrpt->lock);
09716          if (myrpt->p.archivedir)
09717          {
09718             char str[100];
09719 
09720             sprintf(str,"DTMF(M),MAIN,%c",c);
09721             donodelog(myrpt,str);
09722          }
09723          local_dtmf_helper(myrpt,c);
09724       } else rpt_mutex_unlock(&myrpt->lock);
09725       if (who == myrpt->rxchannel) /* if it was a read from rx */
09726       {
09727          int ismuted;
09728 
09729          f = ast_read(myrpt->rxchannel);
09730          if (!f)
09731          {
09732             if (debug) printf("@@@@ rpt:Hung Up\n");
09733             break;
09734          }
09735          if (f->frametype == AST_FRAME_VOICE)
09736          {
09737 #ifdef   _MDC_DECODE_H_
09738             unsigned char ubuf[2560];
09739             short *sp;
09740             int n;
09741 #endif
09742 
09743             if ((!myrpt->localtx) && (!myrpt->p.linktolink)) {
09744                memset(f->data,0,f->datalen);
09745             }
09746 
09747 #ifdef   _MDC_DECODE_H_
09748             sp = (short *) f->data;
09749             /* convert block to unsigned char */
09750             for(n = 0; n < f->datalen / 2; n++)
09751             {
09752                ubuf[n] = (*sp++ >> 8) + 128;
09753             }
09754             n = mdc_decoder_process_samples(myrpt->mdc,ubuf,f->datalen / 2);
09755             if (n == 1)
09756             {
09757                   unsigned char op,arg;
09758                   unsigned short unitID;
09759 
09760                   mdc_decoder_get_packet(myrpt->mdc,&op,&arg,&unitID);
09761                   if (debug > 2)
09762                   {
09763                      ast_log(LOG_NOTICE,"Got (single-length) packet:\n");
09764                      ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
09765                         op & 255,arg & 255,unitID);
09766                   }
09767                   if ((op == 1) && (arg == 0))
09768                   {
09769                      myrpt->lastunit = unitID;
09770                      mdc1200_notify(myrpt,NULL,myrpt->lastunit);
09771                      mdc1200_send(myrpt,myrpt->lastunit);
09772                   }
09773             }
09774             if ((debug > 2) && (i == 2))
09775             {
09776                unsigned char op,arg,ex1,ex2,ex3,ex4;
09777                unsigned short unitID;
09778 
09779                mdc_decoder_get_double_packet(myrpt->mdc,&op,&arg,&unitID,
09780                   &ex1,&ex2,&ex3,&ex4);
09781                ast_log(LOG_NOTICE,"Got (double-length) packet:\n");
09782                ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
09783                   op & 255,arg & 255,unitID);
09784                ast_log(LOG_NOTICE,"ex1: %02x, ex2: %02x, ex3: %02x, ex4: %02x\n",
09785                   ex1 & 255, ex2 & 255, ex3 & 255, ex4 & 255);
09786             }
09787 #endif
09788 #ifdef   __RPT_NOTCH
09789             /* apply inbound filters, if any */
09790             rpt_filter(myrpt,f->data,f->datalen / 2);
09791 #endif
09792             if (ioctl(myrpt->zaprxchannel->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
09793             {
09794                ismuted = 0;
09795             }
09796             if (dtmfed) ismuted = 1;
09797             dtmfed = 0;
09798             if (ismuted)
09799             {
09800                memset(f->data,0,f->datalen);
09801                if (myrpt->lastf1)
09802                   memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
09803                if (myrpt->lastf2)
09804                   memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
09805             } 
09806             if (f) f2 = ast_frdup(f);
09807             else f2 = NULL;
09808             f1 = myrpt->lastf2;
09809             myrpt->lastf2 = myrpt->lastf1;
09810             myrpt->lastf1 = f2;
09811             if (ismuted)
09812             {
09813                if (myrpt->lastf1)
09814                   memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
09815                if (myrpt->lastf2)
09816                   memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
09817             }
09818             if (f1)
09819             {
09820                ast_write(myrpt->pchannel,f1);
09821                ast_frfree(f1);
09822             }
09823          }
09824 #ifndef  OLD_ASTERISK
09825          else if (f->frametype == AST_FRAME_DTMF_BEGIN)
09826          {
09827             if (myrpt->lastf1)
09828                memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
09829             if (myrpt->lastf2)
09830                memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
09831             dtmfed = 1;
09832          }
09833 #endif
09834          else if (f->frametype == AST_FRAME_DTMF)
09835          {
09836             c = (char) f->subclass; /* get DTMF char */
09837             ast_frfree(f);
09838             if (myrpt->lastf1)
09839                memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
09840             if (myrpt->lastf2)
09841                memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
09842             dtmfed = 1;
09843             if (!myrpt->keyed) continue;
09844             c = func_xlat(myrpt,c,&myrpt->p.inxlat);
09845             if (c) local_dtmf_helper(myrpt,c);
09846             continue;
09847          }                 
09848          else if (f->frametype == AST_FRAME_CONTROL)
09849          {
09850             if (f->subclass == AST_CONTROL_HANGUP)
09851             {
09852                if (debug) printf("@@@@ rpt:Hung Up\n");
09853                ast_frfree(f);
09854                break;
09855             }
09856             /* if RX key */
09857             if (f->subclass == AST_CONTROL_RADIO_KEY)
09858             {
09859                if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink)) 
09860                {
09861                   if (debug == 7) printf("@@@@ rx key\n");
09862                   myrpt->keyed = 1;
09863                }
09864                if (myrpt->p.archivedir)
09865                {
09866                   donodelog(myrpt,"RXKEY,MAIN");
09867                }
09868             }
09869             /* if RX un-key */
09870             if (f->subclass == AST_CONTROL_RADIO_UNKEY)
09871             {
09872                if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink))
09873                {
09874                   if (debug == 7) printf("@@@@ rx un-key\n");
09875                   if(myrpt->p.duplex && myrpt->keyed) {
09876                      rpt_telemetry(myrpt,UNKEY,NULL);
09877                   }
09878                }
09879                myrpt->keyed = 0;
09880                if (myrpt->p.archivedir)
09881                {
09882                   donodelog(myrpt,"RXUNKEY,MAIN");
09883                }
09884             }
09885          }
09886          ast_frfree(f);
09887          continue;
09888       }
09889       if (who == myrpt->pchannel) /* if it was a read from pseudo */
09890       {
09891          f = ast_read(myrpt->pchannel);
09892          if (!f)
09893          {
09894             if (debug) printf("@@@@ rpt:Hung Up\n");
09895             break;
09896          }
09897          if (f->frametype == AST_FRAME_VOICE)
09898          {
09899             ast_write(myrpt->txpchannel,f);
09900          }
09901          if (f->frametype == AST_FRAME_CONTROL)
09902          {
09903             if (f->subclass == AST_CONTROL_HANGUP)
09904             {
09905                if (debug) printf("@@@@ rpt:Hung Up\n");
09906                ast_frfree(f);
09907                break;
09908             }
09909          }
09910          ast_frfree(f);
09911          continue;
09912       }
09913       if (who == myrpt->txchannel) /* if it was a read from tx */
09914       {
09915          f = ast_read(myrpt->txchannel);
09916          if (!f)
09917          {
09918             if (debug) printf("@@@@ rpt:Hung Up\n");
09919             break;
09920          }
09921          if (f->frametype == AST_FRAME_CONTROL)
09922          {
09923             if (f->subclass == AST_CONTROL_HANGUP)
09924             {
09925                if (debug) printf("@@@@ rpt:Hung Up\n");
09926                ast_frfree(f);
09927                break;
09928             }
09929          }
09930          ast_frfree(f);
09931          continue;
09932       }
09933       if (who == myrpt->zaptxchannel) /* if it was a read from pseudo-tx */
09934       {
09935          f = ast_read(myrpt->zaptxchannel);
09936          if (!f)
09937          {
09938             if (debug) printf("@@@@ rpt:Hung Up\n");
09939             break;
09940          }
09941          if (f->frametype == AST_FRAME_VOICE)
09942          {
09943             ast_write(myrpt->txchannel,f);
09944          }
09945          if (f->frametype == AST_FRAME_CONTROL)
09946          {
09947             if (f->subclass == AST_CONTROL_HANGUP)
09948             {
09949                if (debug) printf("@@@@ rpt:Hung Up\n");
09950                ast_frfree(f);
09951                break;
09952             }
09953          }
09954          ast_frfree(f);
09955          continue;
09956       }
09957       toexit = 0;
09958       rpt_mutex_lock(&myrpt->lock);
09959       l = myrpt->links.next;
09960       while(l != &myrpt->links)
09961       {
09962          if (l->disctime)
09963          {
09964             l = l->next;
09965             continue;
09966          }
09967          if (who == l->chan) /* if it was a read from rx */
09968          {
09969             int remnomute;
09970 
09971             remrx = 0;
09972             /* see if any other links are receiving */
09973             m = myrpt->links.next;
09974             while(m != &myrpt->links)
09975             {
09976                /* if not us, count it */
09977                if ((m != l) && (m->lastrx)) remrx = 1;
09978                m = m->next;
09979             }
09980             rpt_mutex_unlock(&myrpt->lock);
09981             remnomute = myrpt->localtx && 
09982                 (!(myrpt->cmdnode[0] || 
09983                (myrpt->dtmfidx > -1)));
09984             totx = (((l->isremote) ? (remnomute) : 
09985                myrpt->exttx) || remrx) && l->mode;
09986             if (l->phonemode == 0 && l->chan && (l->lasttx != totx))
09987             {
09988                if (totx)
09989                {
09990                   ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
09991                }
09992                else
09993                {
09994                   ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
09995                }
09996                if (myrpt->p.archivedir)
09997                {
09998                   char str[100];
09999 
10000                   if (totx)
10001                      sprintf(str,"TXKEY,%s",l->name);
10002                   else
10003                      sprintf(str,"TXUNKEY,%s",l->name);
10004                   donodelog(myrpt,str);
10005                }
10006             }
10007             l->lasttx = totx;
10008             f = ast_read(l->chan);
10009             if (!f)
10010             {
10011                rpt_mutex_lock(&myrpt->lock);
10012                __kickshort(myrpt);
10013                rpt_mutex_unlock(&myrpt->lock);
10014                if ((!l->disced) && (!l->outbound))
10015                {
10016                   if ((l->name[0] == '0') || l->isremote)
10017                      l->disctime = 1;
10018                   else
10019                      l->disctime = DISC_TIME;
10020                   rpt_mutex_lock(&myrpt->lock);
10021                   ast_hangup(l->chan);
10022                   l->chan = 0;
10023                   break;
10024                }
10025 
10026                if (l->retrytimer) 
10027                {
10028                   ast_hangup(l->chan);
10029                   l->chan = 0;
10030                   rpt_mutex_lock(&myrpt->lock);
10031                   break; 
10032                }
10033                if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
10034                {
10035                   rpt_mutex_lock(&myrpt->lock);
10036                   if (l->chan) ast_hangup(l->chan);
10037                   l->chan = 0;
10038                   l->hasconnected = 1;
10039                   l->retrytimer = RETRY_TIMER_MS;
10040                   l->elaptime = 0;
10041                   l->connecttime = 0;
10042                   l->thisconnected = 0;
10043                   break;
10044                }
10045                rpt_mutex_lock(&myrpt->lock);
10046                /* remove from queue */
10047                remque((struct qelem *) l);
10048                if (!strcmp(myrpt->cmdnode,l->name))
10049                   myrpt->cmdnode[0] = 0;
10050                __kickshort(myrpt);
10051                rpt_mutex_unlock(&myrpt->lock);
10052                if (!l->hasconnected)
10053                   rpt_telemetry(myrpt,CONNFAIL,l);
10054                else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
10055                if (myrpt->p.archivedir)
10056                {
10057                   char str[100];
10058 
10059                   if (!l->hasconnected)
10060                      sprintf(str,"LINKFAIL,%s",l->name);
10061                   else
10062                      sprintf(str,"LINKDISC,%s",l->name);
10063                   donodelog(myrpt,str);
10064                }
10065                if (l->lastf1) ast_frfree(l->lastf1);
10066                l->lastf1 = NULL;
10067                if (l->lastf2) ast_frfree(l->lastf2);
10068                l->lastf2 = NULL;
10069                /* hang-up on call to device */
10070                ast_hangup(l->chan);
10071                ast_hangup(l->pchan);
10072                free(l);
10073                rpt_mutex_lock(&myrpt->lock);
10074                break;
10075             }
10076             if (f->frametype == AST_FRAME_VOICE)
10077             {
10078                int ismuted;
10079 
10080                if (l->phonemode)
10081                {
10082                   if (ioctl(l->chan->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
10083                   {
10084                      ismuted = 0;
10085                   }
10086                   /* if not receiving, zero-out audio */
10087                   ismuted |= (!l->lastrx);
10088                   if (l->dtmfed && l->phonemode) ismuted = 1;
10089                   l->dtmfed = 0;
10090                   if (ismuted)
10091                   {
10092                      memset(f->data,0,f->datalen);
10093                      if (l->lastf1)
10094                         memset(l->lastf1->data,0,l->lastf1->datalen);
10095                      if (l->lastf2)
10096                         memset(l->lastf2->data,0,l->lastf2->datalen);
10097                   } 
10098                   if (f) f2 = ast_frdup(f);
10099                   else f2 = NULL;
10100                   f1 = l->lastf2;
10101                   l->lastf2 = l->lastf1;
10102                   l->lastf1 = f2;
10103                   if (ismuted)
10104                   {
10105                      if (l->lastf1)
10106                         memset(l->lastf1->data,0,l->lastf1->datalen);
10107                      if (l->lastf2)
10108                         memset(l->lastf2->data,0,l->lastf2->datalen);
10109                   }
10110                   if (f1)
10111                   {
10112                      ast_write(l->pchan,f1);
10113                      ast_frfree(f1);
10114                   }
10115                }
10116                else
10117                {
10118                   if (!l->lastrx)
10119                      memset(f->data,0,f->datalen);
10120                   ast_write(l->pchan,f);
10121                }
10122             }
10123 #ifndef  OLD_ASTERISK
10124             else if (f->frametype == AST_FRAME_DTMF_BEGIN)
10125             {
10126                if (l->lastf1)
10127                   memset(l->lastf1->data,0,l->lastf1->datalen);
10128                if (l->lastf2)
10129                   memset(l->lastf2->data,0,l->lastf2->datalen);
10130                l->dtmfed = 1;
10131             }
10132 #endif
10133 
10134             if (f->frametype == AST_FRAME_TEXT)
10135             {
10136                handle_link_data(myrpt,l,f->data);
10137             }
10138             if (f->frametype == AST_FRAME_DTMF)
10139             {
10140                if (l->lastf1)
10141                   memset(l->lastf1->data,0,l->lastf1->datalen);
10142                if (l->lastf2)
10143                   memset(l->lastf2->data,0,l->lastf2->datalen);
10144                l->dtmfed = 1;
10145                handle_link_phone_dtmf(myrpt,l,f->subclass);
10146             }
10147             if (f->frametype == AST_FRAME_CONTROL)
10148             {
10149                if (f->subclass == AST_CONTROL_ANSWER)
10150                {
10151                   char lconnected = l->connected;
10152 
10153                   __kickshort(myrpt);
10154                   l->connected = 1;
10155                   l->hasconnected = 1;
10156                   l->thisconnected = 1;
10157                   l->elaptime = -1;
10158                   if (!l->isremote) l->retries = 0;
10159                   if (!lconnected) 
10160                   {
10161                      rpt_telemetry(myrpt,CONNECTED,l);
10162                      if (myrpt->p.archivedir)
10163                      {
10164                         char str[100];
10165 
10166                         if (l->mode)
10167                            sprintf(str,"LINKTRX,%s",l->name);
10168                         else
10169                            sprintf(str,"LINKMONITOR,%s",l->name);
10170                         donodelog(myrpt,str);
10171                      }
10172                   }     
10173                   else
10174                      l->reconnects++;
10175                }
10176                /* if RX key */
10177                if (f->subclass == AST_CONTROL_RADIO_KEY)
10178                {
10179                   if (debug == 7 ) printf("@@@@ rx key\n");
10180                   l->lastrx = 1;
10181                   l->rerxtimer = 0;
10182                   if (myrpt->p.archivedir && (!l->lastrx1))
10183                   {
10184                      char str[100];
10185 
10186                      l->lastrx1 = 1;
10187                      sprintf(str,"RXKEY,%s",l->name);
10188                      donodelog(myrpt,str);
10189                   }
10190                }
10191                /* if RX un-key */
10192                if (f->subclass == AST_CONTROL_RADIO_UNKEY)
10193                {
10194                   if (debug == 7) printf("@@@@ rx un-key\n");
10195                   l->lastrx = 0;
10196                   l->rerxtimer = 0;
10197                   if(myrpt->p.duplex) 
10198                      rpt_telemetry(myrpt,LINKUNKEY,l);
10199                   if (myrpt->p.archivedir && (l->lastrx1))
10200                   {
10201                      char str[100];
10202 
10203                      l->lastrx1 = 0;
10204                      sprintf(str,"RXUNKEY,%s",l->name);
10205                      donodelog(myrpt,str);
10206                   }
10207                }
10208                if (f->subclass == AST_CONTROL_HANGUP)
10209                {
10210                   ast_frfree(f);
10211                   rpt_mutex_lock(&myrpt->lock);
10212                   __kickshort(myrpt);
10213                   rpt_mutex_unlock(&myrpt->lock);
10214                   if ((!l->outbound) && (!l->disced))
10215                   {
10216                      if ((l->name[0] == '0') || l->isremote)
10217                         l->disctime = 1;
10218                      else
10219                         l->disctime = DISC_TIME;
10220                      rpt_mutex_lock(&myrpt->lock);
10221                      ast_hangup(l->chan);
10222                      l->chan = 0;
10223                      break;
10224                   }
10225                   if (l->retrytimer) 
10226                   {
10227                      if (l->chan) ast_hangup(l->chan);
10228                      l->chan = 0;
10229                      rpt_mutex_lock(&myrpt->lock);
10230                      break;
10231                   }
10232                   if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
10233                   {
10234                      rpt_mutex_lock(&myrpt->lock);
10235                      if (l->chan) ast_hangup(l->chan);
10236                      l->chan = 0;
10237                      l->hasconnected = 1;
10238                      l->elaptime = 0;
10239                      l->retrytimer = RETRY_TIMER_MS;
10240                      l->connecttime = 0;
10241                      l->thisconnected = 0;
10242                      break;
10243                   }
10244                   rpt_mutex_lock(&myrpt->lock);
10245                   /* remove from queue */
10246                   remque((struct qelem *) l);
10247                   if (!strcmp(myrpt->cmdnode,l->name))
10248                      myrpt->cmdnode[0] = 0;
10249                   __kickshort(myrpt);
10250                   rpt_mutex_unlock(&myrpt->lock);
10251                   if (!l->hasconnected)
10252                      rpt_telemetry(myrpt,CONNFAIL,l);
10253                   else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
10254                   if (myrpt->p.archivedir)
10255                   {
10256                      char str[100];
10257 
10258                      if (!l->hasconnected)
10259                         sprintf(str,"LINKFAIL,%s",l->name);
10260                      else
10261                         sprintf(str,"LINKDISC,%s",l->name);
10262                      donodelog(myrpt,str);
10263                   }
10264                   if (l->lastf1) ast_frfree(l->lastf1);
10265                   l->lastf1 = NULL;
10266                   if (l->lastf2) ast_frfree(l->lastf2);
10267                   l->lastf2 = NULL;
10268                   /* hang-up on call to device */
10269                   ast_hangup(l->chan);
10270                   ast_hangup(l->pchan);
10271                   free(l);
10272                   rpt_mutex_lock(&myrpt->lock);
10273                   break;
10274                }
10275             }
10276             ast_frfree(f);
10277             rpt_mutex_lock(&myrpt->lock);
10278             break;
10279          }
10280          if (who == l->pchan) 
10281          {
10282             rpt_mutex_unlock(&myrpt->lock);
10283             f = ast_read(l->pchan);
10284             if (!f)
10285             {
10286                if (debug) printf("@@@@ rpt:Hung Up\n");
10287                toexit = 1;
10288                rpt_mutex_lock(&myrpt->lock);
10289                break;
10290             }
10291             if (f->frametype == AST_FRAME_VOICE)
10292             {
10293                if (l->chan) ast_write(l->chan,f);
10294             }
10295             if (f->frametype == AST_FRAME_CONTROL)
10296             {
10297                if (f->subclass == AST_CONTROL_HANGUP)
10298                {
10299                   if (debug) printf("@@@@ rpt:Hung Up\n");
10300                   ast_frfree(f);
10301                   toexit = 1;
10302                   rpt_mutex_lock(&myrpt->lock);
10303                   break;
10304                }
10305             }
10306             ast_frfree(f);
10307             rpt_mutex_lock(&myrpt->lock);
10308             break;
10309          }
10310          l = l->next;
10311       }
10312       rpt_mutex_unlock(&myrpt->lock);
10313       if (toexit) break;
10314       if (who == myrpt->monchannel) 
10315       {
10316          f = ast_read(myrpt->monchannel);
10317          if (!f)
10318          {
10319             if (debug) printf("@@@@ rpt:Hung Up\n");
10320             break;
10321          }
10322          if (f->frametype == AST_FRAME_VOICE)
10323          {
10324             if (myrpt->monstream) 
10325                ast_writestream(myrpt->monstream,f);
10326          }
10327          if (f->frametype == AST_FRAME_CONTROL)
10328          {
10329             if (f->subclass == AST_CONTROL_HANGUP)
10330             {
10331                if (debug) printf("@@@@ rpt:Hung Up\n");
10332                ast_frfree(f);
10333                break;
10334             }
10335          }
10336          ast_frfree(f);
10337          continue;
10338       }
10339       if (who == myrpt->txpchannel) /* if it was a read from remote tx */
10340       {
10341          f = ast_read(myrpt->txpchannel);
10342          if (!f)
10343          {
10344             if (debug) printf("@@@@ rpt:Hung Up\n");
10345             break;
10346          }
10347          if (f->frametype == AST_FRAME_CONTROL)
10348          {
10349             if (f->subclass == AST_CONTROL_HANGUP)
10350             {
10351                if (debug) printf("@@@@ rpt:Hung Up\n");
10352                ast_frfree(f);
10353                break;
10354             }
10355          }
10356          ast_frfree(f);
10357          continue;
10358       }
10359    }
10360    usleep(100000);
10361    ast_hangup(myrpt->pchannel);
10362    ast_hangup(myrpt->monchannel);
10363    ast_hangup(myrpt->txpchannel);
10364    if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel);
10365    if (myrpt->zaptxchannel != myrpt->txchannel) ast_hangup(myrpt->zaptxchannel);
10366    if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
10367    myrpt->lastf1 = NULL;
10368    if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
10369    myrpt->lastf2 = NULL;
10370    ast_hangup(myrpt->rxchannel);
10371    rpt_mutex_lock(&myrpt->lock);
10372    l = myrpt->links.next;
10373    while(l != &myrpt->links)
10374    {
10375       struct rpt_link *ll = l;
10376       /* remove from queue */
10377       remque((struct qelem *) l);
10378       /* hang-up on call to device */
10379       if (l->chan) ast_hangup(l->chan);
10380       ast_hangup(l->pchan);
10381       l = l->next;
10382       free(ll);
10383    }
10384    rpt_mutex_unlock(&myrpt->lock);
10385    if (debug) printf("@@@@ rpt:Hung up channel\n");
10386    myrpt->rpt_thread = AST_PTHREADT_STOP;
10387    pthread_exit(NULL); 
10388    return NULL;
10389 }
10390 
10391    
10392 static void *rpt_master(void *ignore)
10393 {
10394 int   i,n;
10395 pthread_attr_t attr;
10396 struct ast_config *cfg;
10397 char *this,*val;
10398 
10399    /* init nodelog queue */
10400    nodelog.next = nodelog.prev = &nodelog;
10401    /* go thru all the specified repeaters */
10402    this = NULL;
10403    n = 0;
10404    /* wait until asterisk starts */
10405         while(!ast_test_flag(&ast_options,AST_OPT_FLAG_FULLY_BOOTED))
10406                 usleep(250000);
10407    rpt_vars[n].cfg = ast_config_load("rpt.conf");
10408    cfg = rpt_vars[n].cfg;
10409    if (!cfg) {
10410       ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
10411       pthread_exit(NULL);
10412    }
10413    while((this = ast_category_browse(cfg,this)) != NULL)
10414    {
10415       for(i = 0 ; i < strlen(this) ; i++){
10416          if((this[i] < '0') || (this[i] > '9'))
10417             break;
10418       }
10419       if(i != strlen(this)) continue; /* Not a node defn */
10420       memset(&rpt_vars[n],0,sizeof(rpt_vars[n]));
10421       rpt_vars[n].name = strdup(this);
10422       val = (char *) ast_variable_retrieve(cfg,this,"rxchannel");
10423       if (val) rpt_vars[n].rxchanname = strdup(val);
10424       val = (char *) ast_variable_retrieve(cfg,this,"txchannel");
10425       if (val) rpt_vars[n].txchanname = strdup(val);
10426       val = (char *) ast_variable_retrieve(cfg,this,"remote");
10427       if (val) rpt_vars[n].remote = strdup(val);
10428       ast_mutex_init(&rpt_vars[n].lock);
10429       ast_mutex_init(&rpt_vars[n].remlock);
10430       rpt_vars[n].tele.next = &rpt_vars[n].tele;
10431       rpt_vars[n].tele.prev = &rpt_vars[n].tele;
10432       rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
10433       rpt_vars[n].tailmessagen = 0;
10434 #ifdef   _MDC_DECODE_H_
10435       rpt_vars[n].mdc = mdc_decoder_new(8000);
10436 #endif
10437       n++;
10438    }
10439    nrpts = n;
10440    ast_config_destroy(cfg);
10441 
10442    /* start em all */
10443    for(i = 0; i < n; i++)
10444    {
10445       load_rpt_vars(i,1);
10446 
10447       /* if is a remote, dont start one for it */
10448       if (rpt_vars[i].remote)
10449       {
10450          if(retreive_memory(&rpt_vars[i],"init")){ /* Try to retreive initial memory channel */
10451             strncpy(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq) - 1);
10452             strncpy(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl) - 1);
10453 
10454             strncpy(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl) - 1);
10455             rpt_vars[i].remmode = REM_MODE_FM;
10456             rpt_vars[i].offset = REM_SIMPLEX;
10457             rpt_vars[i].powerlevel = REM_MEDPWR;
10458          }
10459          continue;
10460       }
10461       if (!rpt_vars[i].p.ident)
10462       {
10463          ast_log(LOG_WARNING,"Did not specify ident for node %s\n",rpt_vars[i].name);
10464          ast_config_destroy(cfg);
10465          pthread_exit(NULL);
10466       }
10467            pthread_attr_init(&attr);
10468            pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
10469       ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
10470    }
10471    usleep(500000);
10472    time(&starttime);
10473    for(;;)
10474    {
10475       /* Now monitor each thread, and restart it if necessary */
10476       for(i = 0; i < n; i++)
10477       { 
10478          int rv;
10479          if (rpt_vars[i].remote) continue;
10480          if (rpt_vars[i].rpt_thread == AST_PTHREADT_STOP) 
10481             rv = -1;
10482          else
10483             rv = pthread_kill(rpt_vars[i].rpt_thread,0);
10484          if (rv)
10485          {
10486             if(time(NULL) - rpt_vars[i].lastthreadrestarttime <= 15)
10487             {
10488                if(rpt_vars[i].threadrestarts >= 5)
10489                {
10490                   ast_log(LOG_ERROR,"Continual RPT thread restarts, killing Asterisk\n");
10491                   exit(1); /* Stuck in a restart loop, kill Asterisk and start over */
10492                }
10493                else
10494                {
10495                   ast_log(LOG_NOTICE,"RPT thread restarted on %s\n",rpt_vars[i].name);
10496                   rpt_vars[i].threadrestarts++;
10497                }
10498             }
10499             else
10500                rpt_vars[i].threadrestarts = 0;
10501 
10502             rpt_vars[i].lastthreadrestarttime = time(NULL);
10503                  pthread_attr_init(&attr);
10504                  pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
10505             ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
10506             ast_log(LOG_WARNING, "rpt_thread restarted on node %s\n", rpt_vars[i].name);
10507          }
10508 
10509       }
10510       for(;;)
10511       {
10512          struct nodelog *nodep;
10513          char *space,datestr[100],fname[300];
10514          int fd;
10515 
10516          ast_mutex_lock(&nodeloglock);
10517          nodep = nodelog.next;
10518          if(nodep == &nodelog) /* if nothing in queue */
10519          {
10520             ast_mutex_unlock(&nodeloglock);
10521             break;
10522          }
10523          remque((struct qelem *)nodep);
10524          ast_mutex_unlock(&nodeloglock);
10525          space = strchr(nodep->str,' ');
10526          if (!space) 
10527          {
10528             free(nodep);
10529             continue;
10530          }
10531          *space = 0;
10532          strftime(datestr,sizeof(datestr) - 1,"%Y%m%d",
10533             localtime(&nodep->timestamp));
10534          sprintf(fname,"%s/%s/%s.txt",nodep->archivedir,
10535             nodep->str,datestr);
10536          fd = open(fname,O_WRONLY | O_CREAT | O_APPEND,0600);
10537          if (fd == -1)
10538          {
10539             ast_log(LOG_ERROR,"Cannot open node log file %s for write",space + 1);
10540             free(nodep);
10541             continue;
10542          }
10543          if (write(fd,space + 1,strlen(space + 1)) !=
10544             strlen(space + 1))
10545          {
10546             ast_log(LOG_ERROR,"Cannot write node log file %s for write",space + 1);
10547             free(nodep);
10548             continue;
10549          }
10550          close(fd);
10551          free(nodep);
10552       }
10553       sleep(2);
10554    }
10555    ast_config_destroy(cfg);
10556    pthread_exit(NULL);
10557 }
10558 
10559 static int rpt_exec(struct ast_channel *chan, void *data)
10560 {
10561    int res=-1,i,rem_totx,rem_rx,remkeyed,n,phone_mode = 0;
10562    int iskenwood_pci4,authtold,authreq,setting,notremming,reming;
10563    int ismuted,dtmfed;
10564 #ifdef   OLD_ASTERISK
10565    struct localuser *u;
10566 #endif
10567    char tmp[256], keyed = 0,keyed1 = 0;
10568    char *options,*stringp,*tele,c;
10569    struct   rpt *myrpt;
10570    struct ast_frame *f,*f1,*f2;
10571    struct ast_channel *who;
10572    struct ast_channel *cs[20];
10573    struct   rpt_link *l;
10574    struct dahdi_confinfo ci;  /* conference info */
10575    struct dahdi_params par;
10576    int ms,elap,nullfd;
10577    time_t t,last_timeout_warning;
10578    struct   dahdi_radio_param z;
10579    struct rpt_tele *telem;
10580 
10581    nullfd = open("/dev/null",O_RDWR);
10582    if (ast_strlen_zero(data)) {
10583       ast_log(LOG_WARNING, "Rpt requires an argument (system node)\n");
10584       return -1;
10585    }
10586 
10587    strncpy(tmp, (char *)data, sizeof(tmp)-1);
10588    time(&t);
10589    /* if time has externally shifted negative, screw it */
10590    if (t < starttime) t = starttime + START_DELAY;
10591    if ((!starttime) || (t < (starttime + START_DELAY)))
10592    {
10593       ast_log(LOG_NOTICE,"Node %s rejecting call: too soon!\n",tmp);
10594       ast_safe_sleep(chan,3000);
10595       return -1;
10596    }
10597    stringp=tmp;
10598    strsep(&stringp, "|");
10599    options = stringp;
10600    myrpt = NULL;
10601    /* see if we can find our specified one */
10602    for(i = 0; i < nrpts; i++)
10603    {
10604       /* if name matches, assign it and exit loop */
10605       if (!strcmp(tmp,rpt_vars[i].name))
10606       {
10607          myrpt = &rpt_vars[i];
10608          break;
10609       }
10610    }
10611    if (myrpt == NULL)
10612    {
10613       ast_log(LOG_WARNING, "Cannot find specified system node %s\n",tmp);
10614       return -1;
10615    }
10616    
10617    if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable){ /* Do not allow incoming connections if disabled */
10618       ast_log(LOG_NOTICE, "Connect attempt to node %s  with tx disabled", myrpt->name);
10619       return -1;
10620    }
10621 
10622    /* if not phone access, must be an IAX connection */
10623    if (options && ((*options == 'P') || (*options == 'D') || (*options == 'R')))
10624    {
10625       int val;
10626 
10627       phone_mode = 1;
10628       if (*options == 'D') phone_mode = 2;
10629       ast_set_callerid(chan,"0","app_rpt user","0");
10630       val = 1;
10631       ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
10632    }
10633    else
10634    {
10635 #ifdef ALLOW_LOCAL_CHANNELS
10636            /* Check to insure the connection is IAX2 or Local*/
10637            if ( (strncmp(chan->name,"IAX2",4)) && (strncmp(chan->name,"Local",5)) ) {
10638                ast_log(LOG_WARNING, "We only accept links via IAX2 or Local!!\n");
10639                return -1;
10640            }
10641 #else
10642       if (strncmp(chan->name,"IAX2",4))
10643       {
10644          ast_log(LOG_WARNING, "We only accept links via IAX2!!\n");
10645          return -1;
10646       }
10647 #endif
10648    }
10649    if (options && (*options == 'R'))
10650    {
10651 
10652       /* Parts of this section taken from app_parkandannounce */
10653       char *return_context;
10654       int l, m, lot, timeout = 0;
10655       char tmp[256],*template;
10656       char *working, *context, *exten, *priority;
10657       char *s,*orig_s;
10658 
10659 
10660       rpt_mutex_lock(&myrpt->lock);
10661       m = myrpt->callmode;
10662       rpt_mutex_unlock(&myrpt->lock);
10663 
10664       if ((!myrpt->p.nobusyout) && m)
10665       {
10666          if (chan->_state != AST_STATE_UP)
10667          {
10668             ast_indicate(chan,AST_CONTROL_BUSY);
10669          }
10670          while(ast_safe_sleep(chan,10000) != -1);
10671          return -1;
10672       }
10673 
10674       if (chan->_state != AST_STATE_UP)
10675       {
10676          ast_answer(chan);
10677       }
10678 
10679       l=strlen(options)+2;
10680       orig_s=malloc(l);
10681       if(!orig_s) {
10682          ast_log(LOG_WARNING, "Out of memory\n");
10683          return -1;
10684       }
10685       s=orig_s;
10686       strncpy(s,options,l);
10687 
10688       template=strsep(&s,"|");
10689       if(!template) {
10690          ast_log(LOG_WARNING, "An announce template must be defined\n");
10691          free(orig_s);
10692          return -1;
10693       } 
10694   
10695       if(s) {
10696          timeout = atoi(strsep(&s, "|"));
10697          timeout *= 1000;
10698       }
10699    
10700       return_context = s;
10701   
10702       if(return_context != NULL) {
10703          /* set the return context. Code borrowed from the Goto builtin */
10704     
10705          working = return_context;
10706          context = strsep(&working, "|");
10707          exten = strsep(&working, "|");
10708          if(!exten) {
10709             /* Only a priority in this one */
10710             priority = context;
10711             exten = NULL;
10712             context = NULL;
10713          } else {
10714             priority = strsep(&working, "|");
10715             if(!priority) {
10716                /* Only an extension and priority in this one */
10717                priority = exten;
10718                exten = context;
10719                context = NULL;
10720          }
10721       }
10722       if(atoi(priority) < 0) {
10723          ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", priority);
10724          free(orig_s);
10725          return -1;
10726       }
10727       /* At this point we have a priority and maybe an extension and a context */
10728       chan->priority = atoi(priority);
10729 #ifdef OLD_ASTERISK
10730       if(exten && strcasecmp(exten, "BYEXTENSION"))
10731 #else
10732       if(exten)
10733 #endif
10734          strncpy(chan->exten, exten, sizeof(chan->exten)-1);
10735       if(context)
10736          strncpy(chan->context, context, sizeof(chan->context)-1);
10737       } else {  /* increment the priority by default*/
10738          chan->priority++;
10739       }
10740 
10741       if(option_verbose > 2) {
10742          ast_verbose( VERBOSE_PREFIX_3 "Return Context: (%s,%s,%d) ID: %s\n", chan->context,chan->exten, chan->priority, chan->cid.cid_num);
10743          if(!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
10744             ast_verbose( VERBOSE_PREFIX_3 "Warning: Return Context Invalid, call will return to default|s\n");
10745          }
10746       }
10747   
10748       /* we are using masq_park here to protect * from touching the channel once we park it.  If the channel comes out of timeout
10749       before we are done announcing and the channel is messed with, Kablooeee.  So we use Masq to prevent this.  */
10750 
10751       ast_masq_park_call(chan, NULL, timeout, &lot);
10752 
10753       if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, return_context);
10754 
10755       snprintf(tmp,sizeof(tmp) - 1,"%d,%s",lot,template + 1);
10756 
10757       rpt_telemetry(myrpt,REV_PATCH,tmp);
10758 
10759       free(orig_s);
10760 
10761       return 0;
10762 
10763    }
10764 
10765    if (!options)
10766    {
10767                 struct ast_hostent ahp;
10768                 struct hostent *hp;
10769       struct in_addr ia;
10770       char hisip[100],nodeip[100],*val, *s, *s1, *s2, *b,*b1;
10771 
10772       /* look at callerid to see what node this comes from */
10773       if (!chan->cid.cid_num) /* if doesn't have caller id */
10774       {
10775          ast_log(LOG_WARNING, "Doesnt have callerid on %s\n",tmp);
10776          return -1;
10777       }
10778 
10779       /* get his IP from IAX2 module */
10780       memset(hisip,0,sizeof(hisip));
10781 #ifdef ALLOW_LOCAL_CHANNELS
10782            /* set IP address if this is a local connection*/
10783            if (strncmp(chan->name,"Local",5)==0) {
10784                strcpy(hisip,"127.0.0.1");
10785            } else {
10786          pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
10787       }
10788 #else
10789       pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
10790 #endif
10791 
10792       if (!hisip[0])
10793       {
10794          ast_log(LOG_WARNING, "Link IP address cannot be determined!!\n");
10795          return -1;
10796       }
10797       
10798       ast_callerid_parse(chan->cid.cid_num,&b,&b1);
10799       ast_shrink_phone_number(b1);
10800       if (!strcmp(myrpt->name,b1))
10801       {
10802          ast_log(LOG_WARNING, "Trying to link to self!!\n");
10803          return -1;
10804       }
10805 
10806       if (*b1 < '1')
10807       {
10808          ast_log(LOG_WARNING, "Node %s Invalid for connection here!!\n",b1);
10809          return -1;
10810       }
10811 
10812 
10813       /* look for his reported node string */
10814       val = node_lookup(myrpt,b1);
10815       if (!val)
10816       {
10817          ast_log(LOG_WARNING, "Reported node %s cannot be found!!\n",b1);
10818          return -1;
10819       }
10820       strncpy(tmp,val,sizeof(tmp) - 1);
10821       s = tmp;
10822       s1 = strsep(&s,",");
10823       s2 = strsep(&s,",");
10824       if (!s2)
10825       {
10826          ast_log(LOG_WARNING, "Reported node %s not in correct format!!\n",b1);
10827          return -1;
10828       }
10829                 if (strcmp(s2,"NONE")) {
10830          hp = ast_gethostbyname(s2, &ahp);
10831          if (!hp)
10832          {
10833             ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s2);
10834             return -1;
10835          }
10836          memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
10837 #ifdef   OLD_ASTERISK
10838          ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
10839 #else
10840          strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
10841 #endif
10842          if (strcmp(hisip,nodeip))
10843          {
10844             char *s3 = strchr(s1,'@');
10845             if (s3) s1 = s3 + 1;
10846             s3 = strchr(s1,'/');
10847             if (s3) *s3 = 0;
10848             hp = ast_gethostbyname(s1, &ahp);
10849             if (!hp)
10850             {
10851                ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s1);
10852                return -1;
10853             }
10854             memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
10855 #ifdef   OLD_ASTERISK
10856             ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
10857 #else
10858             strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
10859 #endif
10860             if (strcmp(hisip,nodeip))
10861             {
10862                ast_log(LOG_WARNING, "Node %s IP %s does not match link IP %s!!\n",b1,nodeip,hisip);
10863                return -1;
10864             }
10865          }
10866       }
10867    }
10868 
10869    /* if is not a remote */
10870    if (!myrpt->remote)
10871    {
10872 
10873       char *b,*b1;
10874       int reconnects = 0;
10875 
10876       /* look at callerid to see what node this comes from */
10877       if (!chan->cid.cid_num) /* if doesn't have caller id */
10878       {
10879          ast_log(LOG_WARNING, "Doesnt have callerid on %s\n",tmp);
10880          return -1;
10881       }
10882 
10883       ast_callerid_parse(chan->cid.cid_num,&b,&b1);
10884       ast_shrink_phone_number(b1);
10885       if (!strcmp(myrpt->name,b1))
10886       {
10887          ast_log(LOG_WARNING, "Trying to link to self!!\n");
10888          return -1;
10889       }
10890       rpt_mutex_lock(&myrpt->lock);
10891       l = myrpt->links.next;
10892       /* try to find this one in queue */
10893       while(l != &myrpt->links)
10894       {
10895          if (l->name[0] == '0') 
10896          {
10897             l = l->next;
10898             continue;
10899          }
10900          /* if found matching string */
10901          if (!strcmp(l->name,b1)) break;
10902          l = l->next;
10903       }
10904       /* if found */
10905       if (l != &myrpt->links) 
10906       {
10907          l->killme = 1;
10908          l->retries = l->max_retries + 1;
10909          l->disced = 2;
10910          reconnects = l->reconnects;
10911          reconnects++;
10912                         rpt_mutex_unlock(&myrpt->lock);
10913          usleep(500000);   
10914       } else 
10915          rpt_mutex_unlock(&myrpt->lock);
10916       /* establish call in tranceive mode */
10917       l = malloc(sizeof(struct rpt_link));
10918       if (!l)
10919       {
10920          ast_log(LOG_WARNING, "Unable to malloc\n");
10921          pthread_exit(NULL);
10922       }
10923       /* zero the silly thing */
10924       memset((char *)l,0,sizeof(struct rpt_link));
10925       l->mode = 1;
10926       strncpy(l->name,b1,MAXNODESTR - 1);
10927       l->isremote = 0;
10928       l->chan = chan;
10929       l->connected = 1;
10930       l->thisconnected = 1;
10931       l->hasconnected = 1;
10932       l->reconnects = reconnects;
10933       l->phonemode = phone_mode;
10934       l->lastf1 = NULL;
10935       l->lastf2 = NULL;
10936       l->dtmfed = 0;
10937       ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
10938       ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
10939       /* allocate a pseudo-channel thru asterisk */
10940       l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
10941       if (!l->pchan)
10942       {
10943          fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10944          pthread_exit(NULL);
10945       }
10946       ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
10947       ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
10948 #ifdef   AST_CDR_FLAG_POST_DISABLED
10949       ast_set_flag(l->pchan->cdr,AST_CDR_FLAG_POST_DISABLED);
10950 #endif
10951       /* make a conference for the tx */
10952       ci.chan = 0;
10953       ci.confno = myrpt->conf;
10954       ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
10955       /* first put the channel on the conference in proper mode */
10956       if (ioctl(l->pchan->fds[0],DAHDI_SETCONF,&ci) == -1)
10957       {
10958          ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
10959          pthread_exit(NULL);
10960       }
10961       rpt_mutex_lock(&myrpt->lock);
10962       if (phone_mode > 1) l->lastrx = 1;
10963       l->max_retries = MAX_RETRIES;
10964       /* insert at end of queue */
10965       insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
10966       __kickshort(myrpt);
10967       rpt_mutex_unlock(&myrpt->lock);
10968       if (chan->_state != AST_STATE_UP) {
10969          ast_answer(chan);
10970       }
10971       if (myrpt->p.archivedir)
10972       {
10973          char str[100];
10974 
10975          if (l->phonemode)
10976             sprintf(str,"LINK(P),%s",l->name);
10977          else
10978             sprintf(str,"LINK,%s",l->name);
10979          donodelog(myrpt,str);
10980       }
10981       return AST_PBX_KEEPALIVE;
10982    }
10983    /* well, then it is a remote */
10984    rpt_mutex_lock(&myrpt->lock);
10985    /* if remote, error if anyone else already linked */
10986    if (myrpt->remoteon)
10987    {
10988       rpt_mutex_unlock(&myrpt->lock);
10989       usleep(500000);
10990       if (myrpt->remoteon)
10991       {
10992          ast_log(LOG_WARNING, "Trying to use busy link on %s\n",tmp);
10993          return -1;
10994       }     
10995       rpt_mutex_lock(&myrpt->lock);
10996    }
10997 #ifdef HAVE_IOPERM
10998    if ((!strcmp(myrpt->remote, remote_rig_rbi)) &&
10999      (ioperm(myrpt->p.iobase,1,1) == -1))
11000    {
11001       rpt_mutex_unlock(&myrpt->lock);
11002       ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
11003       return -1;
11004    }
11005 #endif
11006    myrpt->remoteon = 1;
11007 #ifdef   OLD_ASTERISK
11008    LOCAL_USER_ADD(u);
11009 #endif
11010    rpt_mutex_unlock(&myrpt->lock);
11011    /* find our index, and load the vars initially */
11012    for(i = 0; i < nrpts; i++)
11013    {
11014       if (&rpt_vars[i] == myrpt)
11015       {
11016          load_rpt_vars(i,0);
11017          break;
11018       }
11019    }
11020    rpt_mutex_lock(&myrpt->lock);
11021    tele = strchr(myrpt->rxchanname,'/');
11022    if (!tele)
11023    {
11024       fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
11025       rpt_mutex_unlock(&myrpt->lock);
11026       pthread_exit(NULL);
11027    }
11028    *tele++ = 0;
11029    myrpt->rxchannel = ast_request(myrpt->rxchanname,AST_FORMAT_SLINEAR,tele,NULL);
11030    myrpt->zaprxchannel = NULL;
11031    if (!strcasecmp(myrpt->rxchanname,"Zap"))
11032       myrpt->zaprxchannel = myrpt->rxchannel;
11033    if (myrpt->rxchannel)
11034    {
11035       ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
11036       ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
11037 #ifdef   AST_CDR_FLAG_POST_DISABLED
11038       ast_set_flag(myrpt->rxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11039 #endif
11040       myrpt->rxchannel->whentohangup = 0;
11041       myrpt->rxchannel->appl = "Apprpt";
11042       myrpt->rxchannel->data = "(Link Rx)";
11043       if (option_verbose > 2)
11044          ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
11045             myrpt->rxchanname,tele,myrpt->rxchannel->name);
11046       rpt_mutex_unlock(&myrpt->lock);
11047       ast_call(myrpt->rxchannel,tele,999);
11048       rpt_mutex_lock(&myrpt->lock);
11049    }
11050    else
11051    {
11052       fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
11053       rpt_mutex_unlock(&myrpt->lock);
11054       pthread_exit(NULL);
11055    }
11056    *--tele = '/';
11057    myrpt->zaptxchannel = NULL;
11058    if (myrpt->txchanname)
11059    {
11060       tele = strchr(myrpt->txchanname,'/');
11061       if (!tele)
11062       {
11063          fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
11064          rpt_mutex_unlock(&myrpt->lock);
11065          ast_hangup(myrpt->rxchannel);
11066          pthread_exit(NULL);
11067       }
11068       *tele++ = 0;
11069       myrpt->txchannel = ast_request(myrpt->txchanname,AST_FORMAT_SLINEAR,tele,NULL);
11070       if (!strcasecmp(myrpt->txchanname,"Zap"))
11071          myrpt->zaptxchannel = myrpt->txchannel;
11072       if (myrpt->txchannel)
11073       {
11074          ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
11075          ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
11076 #ifdef   AST_CDR_FLAG_POST_DISABLED
11077          ast_set_flag(myrpt->txchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11078 #endif
11079          myrpt->txchannel->whentohangup = 0;
11080          myrpt->txchannel->appl = "Apprpt";
11081          myrpt->txchannel->data = "(Link Tx)";
11082          if (option_verbose > 2)
11083             ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
11084                myrpt->txchanname,tele,myrpt->txchannel->name);
11085          rpt_mutex_unlock(&myrpt->lock);
11086          ast_call(myrpt->txchannel,tele,999);
11087          rpt_mutex_lock(&myrpt->lock);
11088       }
11089       else
11090       {
11091          fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
11092          rpt_mutex_unlock(&myrpt->lock);
11093          ast_hangup(myrpt->rxchannel);
11094          pthread_exit(NULL);
11095       }
11096       *--tele = '/';
11097    }
11098    else
11099    {
11100       myrpt->txchannel = myrpt->rxchannel;
11101    }
11102    /* allocate a pseudo-channel thru asterisk */
11103    myrpt->pchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
11104    if (!myrpt->pchannel)
11105    {
11106       fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11107       rpt_mutex_unlock(&myrpt->lock);
11108       if (myrpt->txchannel != myrpt->rxchannel) 
11109          ast_hangup(myrpt->txchannel);
11110       ast_hangup(myrpt->rxchannel);
11111       pthread_exit(NULL);
11112    }
11113    ast_set_read_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
11114    ast_set_write_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
11115 #ifdef   AST_CDR_FLAG_POST_DISABLED
11116    ast_set_flag(myrpt->pchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11117 #endif
11118    if (!myrpt->zaprxchannel) myrpt->zaprxchannel = myrpt->pchannel;
11119    if (!myrpt->zaptxchannel) myrpt->zaptxchannel = myrpt->pchannel;
11120    /* make a conference for the pseudo */
11121    ci.chan = 0;
11122    ci.confno = -1; /* make a new conf */
11123    ci.confmode = DAHDI_CONF_CONFANNMON ;
11124    /* first put the channel on the conference in announce/monitor mode */
11125    if (ioctl(myrpt->pchannel->fds[0],DAHDI_SETCONF,&ci) == -1)
11126    {
11127       ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
11128       rpt_mutex_unlock(&myrpt->lock);
11129       ast_hangup(myrpt->pchannel);
11130       if (myrpt->txchannel != myrpt->rxchannel) 
11131          ast_hangup(myrpt->txchannel);
11132       ast_hangup(myrpt->rxchannel);
11133       pthread_exit(NULL);
11134    }
11135    /* save pseudo channel conference number */
11136    myrpt->conf = myrpt->txconf = ci.confno;
11137    /* if serial io port, open it */
11138    myrpt->iofd = -1;
11139    if (myrpt->p.ioport && ((myrpt->iofd = openserial(myrpt->p.ioport)) == -1))
11140    {
11141       rpt_mutex_unlock(&myrpt->lock);
11142       ast_hangup(myrpt->pchannel);
11143       if (myrpt->txchannel != myrpt->rxchannel) 
11144          ast_hangup(myrpt->txchannel);
11145       ast_hangup(myrpt->rxchannel);
11146       pthread_exit(NULL);
11147    }
11148    iskenwood_pci4 = 0;
11149    memset(&z,0,sizeof(z));
11150    if ((myrpt->iofd < 1) && (myrpt->txchannel == myrpt->zaptxchannel))
11151    {
11152       z.radpar = DAHDI_RADPAR_REMMODE;
11153       z.data = DAHDI_RADPAR_REM_NONE;
11154       res = ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z);
11155       /* if PCIRADIO and kenwood selected */
11156       if ((!res) && (!strcmp(myrpt->remote,remote_rig_kenwood)))
11157       {
11158          z.radpar = DAHDI_RADPAR_UIOMODE;
11159          z.data = 1;
11160          if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11161          {
11162             ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
11163             return -1;
11164          }
11165          z.radpar = DAHDI_RADPAR_UIODATA;
11166          z.data = 3;
11167          if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11168          {
11169             ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11170             return -1;
11171          }
11172          i = DAHDI_OFFHOOK;
11173          if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_HOOK,&i) == -1)
11174          {
11175             ast_log(LOG_ERROR,"Cannot set hook\n");
11176             return -1;
11177          }
11178          iskenwood_pci4 = 1;
11179       }
11180    }
11181    if (myrpt->txchannel == myrpt->zaptxchannel)
11182    {
11183       i = DAHDI_ONHOOK;
11184       ioctl(myrpt->zaptxchannel->fds[0],DAHDI_HOOK,&i);
11185       /* if PCIRADIO and Yaesu ft897/ICOM IC-706 selected */
11186       if ((myrpt->iofd < 1) && (!res) &&
11187          (!strcmp(myrpt->remote,remote_rig_ft897) ||
11188             (!strcmp(myrpt->remote,remote_rig_ic706))))
11189       {
11190          z.radpar = DAHDI_RADPAR_UIOMODE;
11191          z.data = 1;
11192          if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11193          {
11194             ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
11195             return -1;
11196          }
11197          z.radpar = DAHDI_RADPAR_UIODATA;
11198          z.data = 3;
11199          if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11200          {
11201             ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11202             return -1;
11203          }
11204       }
11205    }
11206    myrpt->remoterx = 0;
11207    myrpt->remotetx = 0;
11208    myrpt->retxtimer = 0;
11209    myrpt->rerxtimer = 0;
11210    myrpt->remoteon = 1;
11211    myrpt->dtmfidx = -1;
11212    myrpt->dtmfbuf[0] = 0;
11213    myrpt->dtmf_time_rem = 0;
11214    myrpt->hfscanmode = 0;
11215    myrpt->hfscanstatus = 0;
11216    if (myrpt->p.startupmacro)
11217    {
11218       snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
11219    }
11220    time(&myrpt->start_time);
11221    myrpt->last_activity_time = myrpt->start_time;
11222    last_timeout_warning = 0;
11223    myrpt->reload = 0;
11224    myrpt->tele.next = &myrpt->tele;
11225    myrpt->tele.prev = &myrpt->tele;
11226    rpt_mutex_unlock(&myrpt->lock);
11227    ast_set_write_format(chan, AST_FORMAT_SLINEAR);
11228    ast_set_read_format(chan, AST_FORMAT_SLINEAR);
11229    rem_rx = 0;
11230    remkeyed = 0;
11231    /* if we are on 2w loop and are a remote, turn EC on */
11232    if (myrpt->remote && (myrpt->rxchannel == myrpt->txchannel))
11233    {
11234       i = 128;
11235       ioctl(myrpt->zaprxchannel->fds[0],DAHDI_ECHOCANCEL,&i);
11236    }
11237    if (chan->_state != AST_STATE_UP) {
11238       ast_answer(chan);
11239    }
11240 
11241    if (myrpt->rxchannel == myrpt->zaprxchannel)
11242    {
11243       if (ioctl(myrpt->zaprxchannel->fds[0],DAHDI_GET_PARAMS,&par) != -1)
11244       {
11245          if (par.rxisoffhook)
11246          {
11247             ast_indicate(chan,AST_CONTROL_RADIO_KEY);
11248             myrpt->remoterx = 1;
11249             remkeyed = 1;
11250          }
11251       }
11252    }
11253    if (myrpt->p.archivedir)
11254    {
11255       char mycmd[100],mydate[100],*b,*b1;
11256       time_t myt;
11257       long blocksleft;
11258 
11259 
11260       mkdir(myrpt->p.archivedir,0600);
11261       sprintf(mycmd,"%s/%s",myrpt->p.archivedir,myrpt->name);
11262       mkdir(mycmd,0600);
11263       time(&myt);
11264       strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
11265          localtime(&myt));
11266       sprintf(mycmd,"mixmonitor start %s %s/%s/%s.wav49 a",chan->name,
11267          myrpt->p.archivedir,myrpt->name,mydate);
11268       if (myrpt->p.monminblocks)
11269       {
11270          blocksleft = diskavail(myrpt);
11271          if (myrpt->p.remotetimeout)
11272          {
11273             blocksleft -= (myrpt->p.remotetimeout *
11274                MONITOR_DISK_BLOCKS_PER_MINUTE) / 60;
11275          }
11276          if (blocksleft >= myrpt->p.monminblocks)
11277             ast_cli_command(nullfd,mycmd);
11278       } else ast_cli_command(nullfd,mycmd);
11279       /* look at callerid to see what node this comes from */
11280       if (!chan->cid.cid_num) /* if doesn't have caller id */
11281       {
11282          b1 = "0";
11283       } else {
11284          ast_callerid_parse(chan->cid.cid_num,&b,&b1);
11285          ast_shrink_phone_number(b1);
11286       }
11287       sprintf(mycmd,"CONNECT,%s",b1);
11288       donodelog(myrpt,mycmd);
11289    }
11290    myrpt->loginuser[0] = 0;
11291    myrpt->loginlevel[0] = 0;
11292    myrpt->authtelltimer = 0;
11293    myrpt->authtimer = 0;
11294    authtold = 0;
11295    authreq = 0;
11296    if (myrpt->p.authlevel > 1) authreq = 1;
11297    setrem(myrpt); 
11298    n = 0;
11299    dtmfed = 0;
11300    cs[n++] = chan;
11301    cs[n++] = myrpt->rxchannel;
11302    cs[n++] = myrpt->pchannel;
11303    if (myrpt->rxchannel != myrpt->txchannel)
11304       cs[n++] = myrpt->txchannel;
11305    /* start un-locked */
11306    for(;;) 
11307    {
11308       if (ast_check_hangup(chan)) break;
11309       if (ast_check_hangup(myrpt->rxchannel)) break;
11310       notremming = 0;
11311       setting = 0;
11312       reming = 0;
11313       telem = myrpt->tele.next;
11314       while(telem != &myrpt->tele)
11315       {
11316          if (telem->mode == SETREMOTE) setting = 1;
11317          if ((telem->mode == SETREMOTE) ||
11318              (telem->mode == SCAN) ||
11319             (telem->mode == TUNE))  reming = 1;
11320          else notremming = 1;
11321          telem = telem->next;
11322       }
11323       if (myrpt->reload)
11324       {
11325          myrpt->reload = 0;
11326          /* find our index, and load the vars */
11327          for(i = 0; i < nrpts; i++)
11328          {
11329             if (&rpt_vars[i] == myrpt)
11330             {
11331                load_rpt_vars(i,0);
11332                break;
11333             }
11334          }
11335       }
11336       time(&t);
11337       if (myrpt->p.remotetimeout)
11338       { 
11339          time_t r;
11340 
11341          r = (t - myrpt->start_time);
11342          if (r >= myrpt->p.remotetimeout)
11343          {
11344             sayfile(chan,"rpt/node");
11345             ast_say_character_str(chan,myrpt->name,NULL,chan->language);
11346             sayfile(chan,"rpt/timeout");
11347             ast_safe_sleep(chan,1000);
11348             break;
11349          }
11350          if ((myrpt->p.remotetimeoutwarning) && 
11351              (r >= (myrpt->p.remotetimeout -
11352             myrpt->p.remotetimeoutwarning)) &&
11353                 (r <= (myrpt->p.remotetimeout - 
11354                   myrpt->p.remotetimeoutwarningfreq)))
11355          {
11356             if (myrpt->p.remotetimeoutwarningfreq)
11357             {
11358                 if ((t - last_timeout_warning) >=
11359                myrpt->p.remotetimeoutwarningfreq)
11360                 {
11361                time(&last_timeout_warning);
11362                rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
11363                 }
11364             }
11365             else
11366             {
11367                 if (!last_timeout_warning)
11368                 {
11369                time(&last_timeout_warning);
11370                rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
11371                 }
11372             }
11373          }
11374       }
11375       if (myrpt->p.remoteinacttimeout && myrpt->last_activity_time)
11376       { 
11377          time_t r;
11378 
11379          r = (t - myrpt->last_activity_time);
11380          if (r >= myrpt->p.remoteinacttimeout)
11381          {
11382             sayfile(chan,"rpt/node");
11383             ast_say_character_str(chan,myrpt->name,NULL,chan->language);
11384             sayfile(chan,"rpt/timeout");
11385             ast_safe_sleep(chan,1000);
11386             break;
11387          }
11388          if ((myrpt->p.remotetimeoutwarning) && 
11389              (r >= (myrpt->p.remoteinacttimeout -
11390             myrpt->p.remotetimeoutwarning)) &&
11391                 (r <= (myrpt->p.remoteinacttimeout - 
11392                   myrpt->p.remotetimeoutwarningfreq)))
11393          {
11394             if (myrpt->p.remotetimeoutwarningfreq)
11395             {
11396                 if ((t - last_timeout_warning) >=
11397                myrpt->p.remotetimeoutwarningfreq)
11398                 {
11399                time(&last_timeout_warning);
11400                rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
11401                 }
11402             }
11403             else
11404             {
11405                 if (!last_timeout_warning)
11406                 {
11407                time(&last_timeout_warning);
11408                rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
11409                 }
11410             }
11411          }
11412       }
11413       ms = MSWAIT;
11414       who = ast_waitfor_n(cs,n,&ms);
11415       if (who == NULL) ms = 0;
11416       elap = MSWAIT - ms;
11417       if (myrpt->macrotimer) myrpt->macrotimer -= elap;
11418       if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
11419       if (!ms) continue;
11420       /* do local dtmf timer */
11421       if (myrpt->dtmf_local_timer)
11422       {
11423          if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
11424          if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
11425       }
11426       rpt_mutex_lock(&myrpt->lock);
11427       do_dtmf_local(myrpt,0);
11428       rpt_mutex_unlock(&myrpt->lock);
11429       rem_totx =  myrpt->dtmf_local_timer && (!phone_mode);
11430       rem_totx |= keyed && (!myrpt->tunerequest);
11431       rem_rx = (remkeyed && (!setting)) || (myrpt->tele.next != &myrpt->tele);
11432       if(!strcmp(myrpt->remote, remote_rig_ic706))
11433          rem_totx |= myrpt->tunerequest;
11434       if (keyed && (!keyed1))
11435       {
11436          keyed1 = 1;
11437       }
11438 
11439       if (!keyed && (keyed1))
11440       {
11441          time_t myt;
11442 
11443          keyed1 = 0;
11444          time(&myt);
11445          /* if login necessary, and not too soon */
11446          if ((myrpt->p.authlevel) && 
11447              (!myrpt->loginlevel[0]) &&
11448             (myt > (t + 3)))
11449          {
11450             authreq = 1;
11451             authtold = 0;
11452             myrpt->authtelltimer = AUTHTELLTIME - AUTHTXTIME;
11453          }
11454       }
11455 
11456 
11457       if (rem_rx && (!myrpt->remoterx))
11458       {
11459          myrpt->remoterx = 1;
11460          ast_indicate(chan,AST_CONTROL_RADIO_KEY);
11461       }
11462       if ((!rem_rx) && (myrpt->remoterx))
11463       {
11464          myrpt->remoterx = 0;
11465          ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
11466       }
11467       /* if auth requested, and not authed yet */
11468       if (authreq && (!myrpt->loginlevel[0]))
11469       {
11470          if ((!authtold) && ((myrpt->authtelltimer += elap)
11471              >= AUTHTELLTIME))
11472          {
11473             authtold = 1;
11474             rpt_telemetry(myrpt,LOGINREQ,NULL);
11475          }
11476          if ((myrpt->authtimer += elap) >= AUTHLOGOUTTIME)
11477          {
11478             break; /* if not logged in, hang up after a time */
11479          }
11480       }
11481 #ifndef  OLDKEY
11482       if ((myrpt->retxtimer += elap) >= REDUNDANT_TX_TIME)
11483       {
11484          myrpt->retxtimer = 0;
11485          if ((myrpt->remoterx) && (!myrpt->remotetx))
11486             ast_indicate(chan,AST_CONTROL_RADIO_KEY);
11487          else
11488             ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
11489       }
11490 
11491       if ((myrpt->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 2))
11492       {
11493          keyed = 0;
11494          myrpt->rerxtimer = 0;
11495       }
11496 #endif
11497       if (rem_totx && (!myrpt->remotetx))
11498       {
11499          /* if not authed, and needed, dont transmit */
11500          if ((!myrpt->p.authlevel) || myrpt->loginlevel[0])
11501          {
11502             myrpt->remotetx = 1;
11503             if((myrpt->remtxfreqok = check_tx_freq(myrpt)))
11504             {
11505                time(&myrpt->last_activity_time);
11506                if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->zaptxchannel))
11507                {
11508                   z.radpar = DAHDI_RADPAR_UIODATA;
11509                   z.data = 1;
11510                   if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11511                   {
11512                      ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11513                      return -1;
11514                   }
11515                }
11516                else
11517                {
11518                   ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
11519                }
11520                if (myrpt->p.archivedir) donodelog(myrpt,"TXKEY");
11521             }
11522          }
11523       }
11524       if ((!rem_totx) && myrpt->remotetx) /* Remote base radio TX unkey */
11525       {
11526          myrpt->remotetx = 0;
11527          if(!myrpt->remtxfreqok){
11528             rpt_telemetry(myrpt,UNAUTHTX,NULL);
11529          }
11530          if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->zaptxchannel))
11531          {
11532             z.radpar = DAHDI_RADPAR_UIODATA;
11533             z.data = 3;
11534             if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11535             {
11536                ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11537                return -1;
11538             }
11539          }
11540          else
11541          {
11542             ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
11543          }
11544          if (myrpt->p.archivedir) donodelog(myrpt,"TXUNKEY");
11545       }
11546       if (myrpt->hfscanmode){
11547          myrpt->scantimer -= elap;
11548          if(myrpt->scantimer <= 0){
11549             if (!reming)
11550             {
11551                myrpt->scantimer = REM_SCANTIME;
11552                rpt_telemetry(myrpt,SCAN,0);
11553             } else myrpt->scantimer = 1;
11554          }
11555       }
11556       rpt_mutex_lock(&myrpt->lock);
11557       c = myrpt->macrobuf[0];
11558       if (c && (!myrpt->macrotimer))
11559       {
11560          myrpt->macrotimer = MACROTIME;
11561          memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
11562          if ((c == 'p') || (c == 'P'))
11563             myrpt->macrotimer = MACROPTIME;
11564          rpt_mutex_unlock(&myrpt->lock);
11565          if (myrpt->p.archivedir)
11566          {
11567             char str[100];
11568                sprintf(str,"DTMF(M),%c",c);
11569             donodelog(myrpt,str);
11570          }
11571          if (handle_remote_dtmf_digit(myrpt,c,&keyed,0) == -1) break;
11572          continue;
11573       } else rpt_mutex_unlock(&myrpt->lock);
11574       if (who == chan) /* if it was a read from incomming */
11575       {
11576          f = ast_read(chan);
11577          if (!f)
11578          {
11579             if (debug) printf("@@@@ link:Hung Up\n");
11580             break;
11581          }
11582          if (f->frametype == AST_FRAME_VOICE)
11583          {
11584             if (ioctl(chan->fds[0], DAHDI_GETCONFMUTE, &ismuted) == -1)
11585             {
11586                ismuted = 0;
11587             }
11588             /* if not transmitting, zero-out audio */
11589             ismuted |= (!myrpt->remotetx);
11590             if (dtmfed && phone_mode) ismuted = 1;
11591             dtmfed = 0;
11592             if (ismuted)
11593             {
11594                memset(f->data,0,f->datalen);
11595                if (myrpt->lastf1)
11596                   memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11597                if (myrpt->lastf2)
11598                   memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11599             } 
11600             if (f) f2 = ast_frdup(f);
11601             else f2 = NULL;
11602             f1 = myrpt->lastf2;
11603             myrpt->lastf2 = myrpt->lastf1;
11604             myrpt->lastf1 = f2;
11605             if (ismuted)
11606             {
11607                if (myrpt->lastf1)
11608                   memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11609                if (myrpt->lastf2)
11610                   memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11611             }
11612             if (f1)
11613             {
11614                if (phone_mode)
11615                   ast_write(myrpt->txchannel,f1);
11616                else
11617                   ast_write(myrpt->txchannel,f);
11618                ast_frfree(f1);
11619             }
11620          }
11621 #ifndef  OLD_ASTERISK
11622          else if (f->frametype == AST_FRAME_DTMF_BEGIN)
11623          {
11624             if (myrpt->lastf1)
11625                memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11626             if (myrpt->lastf2)
11627                memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11628             dtmfed = 1;
11629          }
11630 #endif
11631          if (f->frametype == AST_FRAME_DTMF)
11632          {
11633             if (myrpt->lastf1)
11634                memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11635             if (myrpt->lastf2)
11636                memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11637             dtmfed = 1;
11638             if (handle_remote_phone_dtmf(myrpt,f->subclass,&keyed,phone_mode) == -1)
11639             {
11640                if (debug) printf("@@@@ rpt:Hung Up\n");
11641                ast_frfree(f);
11642                break;
11643             }
11644          }
11645          if (f->frametype == AST_FRAME_TEXT)
11646          {
11647             if (handle_remote_data(myrpt,f->data) == -1)
11648             {
11649                if (debug) printf("@@@@ rpt:Hung Up\n");
11650                ast_frfree(f);
11651                break;
11652             }
11653          }
11654          if (f->frametype == AST_FRAME_CONTROL)
11655          {
11656             if (f->subclass == AST_CONTROL_HANGUP)
11657             {
11658                if (debug) printf("@@@@ rpt:Hung Up\n");
11659                ast_frfree(f);
11660                break;
11661             }
11662             /* if RX key */
11663             if (f->subclass == AST_CONTROL_RADIO_KEY)
11664             {
11665                if (debug == 7) printf("@@@@ rx key\n");
11666                keyed = 1;
11667                myrpt->rerxtimer = 0;
11668             }
11669             /* if RX un-key */
11670             if (f->subclass == AST_CONTROL_RADIO_UNKEY)
11671             {
11672                myrpt->rerxtimer = 0;
11673                if (debug == 7) printf("@@@@ rx un-key\n");
11674                keyed = 0;
11675             }
11676          }
11677          ast_frfree(f);
11678          continue;
11679       }
11680       if (who == myrpt->rxchannel) /* if it was a read from radio */
11681       {
11682          f = ast_read(myrpt->rxchannel);
11683          if (!f)
11684          {
11685             if (debug) printf("@@@@ link:Hung Up\n");
11686             break;
11687          }
11688          if (f->frametype == AST_FRAME_VOICE)
11689          {
11690             int myreming = 0;
11691 
11692             if(!strcmp(myrpt->remote, remote_rig_kenwood))
11693                myreming = reming;
11694 
11695             if (myreming || (!remkeyed) ||
11696             ((myrpt->remote) && (myrpt->remotetx)) ||
11697               ((myrpt->remmode != REM_MODE_FM) &&
11698                 notremming))
11699                memset(f->data,0,f->datalen); 
11700              ast_write(myrpt->pchannel,f);
11701          }
11702          else if (f->frametype == AST_FRAME_CONTROL)
11703          {
11704             if (f->subclass == AST_CONTROL_HANGUP)
11705             {
11706                if (debug) printf("@@@@ rpt:Hung Up\n");
11707                ast_frfree(f);
11708                break;
11709             }
11710             /* if RX key */
11711             if (f->subclass == AST_CONTROL_RADIO_KEY)
11712             {
11713                if (debug == 7) printf("@@@@ remote rx key\n");
11714                if (!myrpt->remotetx)
11715                {
11716                   remkeyed = 1;
11717                }
11718             }
11719             /* if RX un-key */
11720             if (f->subclass == AST_CONTROL_RADIO_UNKEY)
11721             {
11722                if (debug == 7) printf("@@@@ remote rx un-key\n");
11723                if (!myrpt->remotetx) 
11724                {
11725                   remkeyed = 0;
11726                }
11727             }
11728          }
11729          ast_frfree(f);
11730          continue;
11731       }
11732       if (who == myrpt->pchannel) /* if is remote mix output */
11733       {
11734          f = ast_read(myrpt->pchannel);
11735          if (!f)
11736          {
11737             if (debug) printf("@@@@ link:Hung Up\n");
11738             break;
11739          }
11740          if (f->frametype == AST_FRAME_VOICE)
11741          {
11742             ast_write(chan,f);
11743          }
11744          if (f->frametype == AST_FRAME_CONTROL)
11745          {
11746             if (f->subclass == AST_CONTROL_HANGUP)
11747             {
11748                if (debug) printf("@@@@ rpt:Hung Up\n");
11749                ast_frfree(f);
11750                break;
11751             }
11752          }
11753          ast_frfree(f);
11754          continue;
11755       }
11756       if ((myrpt->rxchannel != myrpt->txchannel) && 
11757          (who == myrpt->txchannel)) /* do this cuz you have to */
11758       {
11759          f = ast_read(myrpt->txchannel);
11760          if (!f)
11761          {
11762             if (debug) printf("@@@@ link:Hung Up\n");
11763             break;
11764          }
11765          if (f->frametype == AST_FRAME_CONTROL)
11766          {
11767             if (f->subclass == AST_CONTROL_HANGUP)
11768             {
11769                if (debug) printf("@@@@ rpt:Hung Up\n");
11770                ast_frfree(f);
11771                break;
11772             }
11773          }
11774          ast_frfree(f);
11775          continue;
11776       }
11777    }
11778    if (myrpt->p.archivedir)
11779    {
11780       char mycmd[100],*b,*b1;
11781 
11782       /* look at callerid to see what node this comes from */
11783       if (!chan->cid.cid_num) /* if doesn't have caller id */
11784       {
11785          b1 = "0";
11786       } else {
11787          ast_callerid_parse(chan->cid.cid_num,&b,&b1);
11788          ast_shrink_phone_number(b1);
11789       }
11790       sprintf(mycmd,"DISCONNECT,%s",b1);
11791       donodelog(myrpt,mycmd);
11792    }
11793    /* wait for telem to be done */
11794    while(myrpt->tele.next != &myrpt->tele) usleep(100000);
11795    sprintf(tmp,"mixmonitor stop %s",chan->name);
11796    ast_cli_command(nullfd,tmp);
11797    close(nullfd);
11798    rpt_mutex_lock(&myrpt->lock);
11799    myrpt->hfscanmode = 0;
11800    myrpt->hfscanstatus = 0;
11801    myrpt->remoteon = 0;
11802    rpt_mutex_unlock(&myrpt->lock);
11803    if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
11804    myrpt->lastf1 = NULL;
11805    if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
11806    myrpt->lastf2 = NULL;
11807    if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->zaptxchannel))
11808    {
11809       z.radpar = DAHDI_RADPAR_UIOMODE;
11810       z.data = 3;
11811       if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11812       {
11813          ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
11814          return -1;
11815       }
11816       z.radpar = DAHDI_RADPAR_UIODATA;
11817       z.data = 3;
11818       if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_RADIO_SETPARAM,&z) == -1)
11819       {
11820          ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11821          return -1;
11822       }
11823       i = DAHDI_OFFHOOK;
11824       if (ioctl(myrpt->zaptxchannel->fds[0],DAHDI_HOOK,&i) == -1)
11825       {
11826          ast_log(LOG_ERROR,"Cannot set hook\n");
11827          return -1;
11828       }
11829    }
11830    if (myrpt->iofd) close(myrpt->iofd);
11831    myrpt->iofd = -1;
11832    ast_hangup(myrpt->pchannel);
11833    if (myrpt->rxchannel != myrpt->txchannel) ast_hangup(myrpt->txchannel);
11834    ast_hangup(myrpt->rxchannel);
11835    closerem(myrpt);
11836 #ifdef   OLD_ASTERISK
11837    LOCAL_USER_REMOVE(u);
11838 #endif
11839    return res;
11840 }
11841 
11842 #ifdef   OLD_ASTERISK
11843 int unload_module()
11844 #else
11845 static int unload_module(void)
11846 #endif
11847 {
11848    int i;
11849 
11850 #ifdef   OLD_ASTERISK
11851    STANDARD_HANGUP_LOCALUSERS;
11852 #endif
11853    for(i = 0; i < nrpts; i++) {
11854       if (!strcmp(rpt_vars[i].name,rpt_vars[i].p.nodes)) continue;
11855                 ast_mutex_destroy(&rpt_vars[i].lock);
11856                 ast_mutex_destroy(&rpt_vars[i].remlock);
11857    }
11858    i = ast_unregister_application(app);
11859 
11860    /* Unregister cli extensions */
11861    ast_cli_unregister(&cli_debug);
11862    ast_cli_unregister(&cli_dump);
11863    ast_cli_unregister(&cli_stats);
11864    ast_cli_unregister(&cli_lstats);
11865    ast_cli_unregister(&cli_nodes);
11866    ast_cli_unregister(&cli_reload);
11867    ast_cli_unregister(&cli_restart);
11868    ast_cli_unregister(&cli_fun);
11869 
11870    return i;
11871 }
11872 
11873 #ifdef   OLD_ASTERISK
11874 int load_module()
11875 #else
11876 static int load_module(void)
11877 #endif
11878 {
11879    ast_pthread_create(&rpt_master_thread,NULL,rpt_master,NULL);
11880 
11881    /* Register cli extensions */
11882    ast_cli_register(&cli_debug);
11883    ast_cli_register(&cli_dump);
11884    ast_cli_register(&cli_stats);
11885    ast_cli_register(&cli_lstats);
11886    ast_cli_register(&cli_nodes);
11887    ast_cli_register(&cli_reload);
11888    ast_cli_register(&cli_restart);
11889    ast_cli_register(&cli_fun);
11890 
11891    return ast_register_application(app, rpt_exec, synopsis, descrip);
11892 }
11893 
11894 #ifdef   OLD_ASTERISK
11895 char *description()
11896 {
11897    return tdesc;
11898 }
11899 int usecount(void)
11900 {
11901    int res;
11902    STANDARD_USECOUNT(res);
11903    return res;
11904 }
11905 
11906 char *key()
11907 {
11908    return ASTERISK_GPL_KEY;
11909 }
11910 #endif
11911 
11912 #ifdef   OLD_ASTERISK
11913 int reload()
11914 #else
11915 static int reload(void)
11916 #endif
11917 {
11918 int   n;
11919 
11920    for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
11921    return(0);
11922 }
11923 
11924 #ifndef  OLD_ASTERISK
11925 /* STD_MOD(MOD_1, reload, NULL, NULL); */
11926 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Radio Repeater/Remote Base Application",
11927       .load = load_module,
11928       .unload = unload_module,
11929       .reload = reload,
11930           );
11931 
11932 #endif
11933 

Generated on Thu May 14 14:48:47 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7