Merged revisions 317427 via svnmerge from
[asterisk/asterisk.git] / apps / app_rpt.c
1 #define NEW_ASTERISK
2 /* #define OLD_ASTERISK */
3 /*
4  * Asterisk -- An open source telephony toolkit.
5  *
6  * Copyright (C) 2002-2008, Jim Dixon, WB6NIL
7  *
8  * Jim Dixon, WB6NIL <jim@lambdatel.com>
9  * Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
10  *
11  * See http://www.asterisk.org for more information about
12  * the Asterisk project. Please do not directly contact
13  * any of the maintainers of this project for assistance;
14  * the project provides a web site, mailing lists and IRC
15  * channels for your use.
16  *
17  * This program is free software, distributed under the terms of
18  * the GNU General Public License Version 2. See the LICENSE file
19  * at the top of the source tree.
20  */
21 /*! \file
22  *
23  * \brief Radio Repeater / Remote Base program 
24  *  version 0.115 5/12/08 2055 EDT
25  * 
26  * \author Jim Dixon, WB6NIL <jim@lambdatel.com>
27  *
28  * \note Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
29  * \note Steven Henke, W9SH, <w9sh@arrl.net> added a few features here and there.
30  *
31  * See http://www.zapatatelephony.org/app_rpt.html
32  *
33  *
34  * Repeater / Remote Functions:
35  * "Simple" Mode:  * - autopatch access, # - autopatch hangup
36  * Normal mode:
37  * See the function list in rpt.conf (autopatchup, autopatchdn)
38  * autopatchup can optionally take comma delimited setting=value pairs:
39  *  
40  *
41  * context=string               :       Override default context with "string"
42  * dialtime=ms                  :       Specify the max number of milliseconds between phone number digits (1000 milliseconds = 1 second)
43  * farenddisconnect=1           :       Automatically disconnect when called party hangs up
44  * noct=1                       :       Don't send repeater courtesy tone during autopatch calls
45  * quiet=1                      :       Don't send dial tone, or connect messages. Do not send patch down message when called party hangs up
46  *
47  *
48  * Example: 123=autopatchup,dialtime=20000,noct=1,farenddisconnect=1
49  *
50  *  To send an asterisk (*) while dialing or talking on phone,
51  *  use the autopatch acess code.
52  *
53  *
54  * status cmds:
55  *
56  *  1 - Force ID (global)
57  *  2 - Give Time of Day (global)
58  *  3 - Give software Version (global)
59  *  11 - Force ID (local only)
60  *  12 - Give Time of Day (local only)
61  *
62  * cop (control operator) cmds:
63  *
64  *  1 - System warm boot
65  *  2 - System enable
66  *  3 - System disable
67  *  4 - Test Tone On/Off
68  *  5 - Dump System Variables on Console (debug)
69  *  6 - PTT (phone mode only)
70  *  7 - Time out timer enable
71  *  8 - Time out timer disable
72  *  9 - Autopatch enable
73  *  10 - Autopatch disable
74  *  11 - Link enable
75  *  12 - Link disable
76  *  13 - Query System State
77  *  14 - Change System State
78  *  15 - Scheduler Enable
79  *  16 - Scheduler Disable
80  *  17 - User functions (time, id, etc) enable
81  *  18 - User functions (time, id, etc) disable
82  *  19 - Select alternate hang timer
83  *  20 - Select standard hang timer 
84  *  21 - Enable Parrot Mode
85  *  22 - Disable Parrot Mode
86  *  23 - Birdbath (Current Parrot Cleanup/Flush)
87  *  24 - Flush all telemetry
88  *  25 - Query last node un-keyed
89  *  26 - Query all nodes keyed/unkeyed
90  *  30 - Recall Memory Setting in Attached Xcvr
91  *  31 - Channel Selector for Parallel Programmed Xcvr
92  *  32 - Touchtone pad test: command + Digit string + # to playback all digits pressed
93  *
94  * ilink cmds:
95  *
96  *  1 - Disconnect specified link
97  *  2 - Connect specified link -- monitor only
98  *  3 - Connect specified link -- tranceive
99  *  4 - Enter command mode on specified link
100  *  5 - System status
101  *  6 - Disconnect all links
102  *  11 - Disconnect a previously permanently connected link
103  *  12 - Permanently connect specified link -- monitor only
104  *  13 - Permanently connect specified link -- tranceive
105  *  15 - Full system status (all nodes)
106  *  16 - Reconnect links disconnected with "disconnect all links"
107  *  200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
108  *
109  * remote cmds:
110  *
111  *  1 - Recall Memory MM  (*000-*099) (Gets memory from rpt.conf)
112  *  2 - Set VFO MMMMM*KKK*O   (Mhz digits, Khz digits, Offset)
113  *  3 - Set Rx PL Tone HHH*D*
114  *  4 - Set Tx PL Tone HHH*D* (Not currently implemented with DHE RBI-1)
115  *  5 - Link Status (long)
116  *  6 - Set operating mode M (FM, USB, LSB, AM, etc)
117  *  100 - RX PL off (Default)
118  *  101 - RX PL On
119  *  102 - TX PL Off (Default)
120  *  103 - TX PL On
121  *  104 - Low Power
122  *  105 - Med Power
123  *  106 - Hi Power
124  *  107 - Bump Down 20 Hz
125  *  108 - Bump Down 100 Hz
126  *  109 - Bump Down 500 Hz
127  *  110 - Bump Up 20 Hz
128  *  111 - Bump Up 100 Hz
129  *  112 - Bump Up 500 Hz
130  *  113 - Scan Down Slow
131  *  114 - Scan Down Medium
132  *  115 - Scan Down Fast
133  *  116 - Scan Up Slow
134  *  117 - Scan Up Medium
135  *  118 - Scan Up Fast
136  *  119 - Transmit allowing auto-tune
137  *  140 - Link Status (brief)
138  *  200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
139  *
140  * playback cmds:
141  *  specify the name of the file to be played (for example, 25=rpt/foo)
142  *
143  *
144  * 'duplex' modes:  (defaults to duplex=2)
145  *
146  * 0 - Only remote links key Tx and no main repeat audio.
147  * 1 - Everything other then main Rx keys Tx, no main repeat audio.
148  * 2 - Normal mode
149  * 3 - Normal except no main repeat audio.
150  * 4 - Normal except no main repeat audio during autopatch only
151  *
152 */
153
154 /*** MODULEINFO
155         <depend>dahdi</depend>
156         <depend>tonezone</depend>
157         <defaultenabled>no</defaultenabled>
158  ***/
159
160 /* Un-comment the following to include support for MDC-1200 digital tone
161    signalling protocol (using KA6SQG's GPL'ed implementation) */
162 /* #include "mdc_decode.c" */
163
164 /* Un-comment the following to include support for notch filters in the
165    rx audio stream (using Tony Fisher's mknotch (mkfilter) implementation) */
166 /* #include "rpt_notch.c" */
167
168 /* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
169
170 #ifdef OLD_ASTERISK
171 #define ast_free free
172 #define ast_malloc malloc
173 #define ast_strdup strdup
174 #endif
175
176
177 #define MAXDTMF 32
178 #define MAXMACRO 2048
179 #define MAXLINKLIST 512
180 #define LINKLISTTIME 10000
181 #define LINKLISTSHORTTIME 200
182 #define LINKPOSTTIME 30000
183 #define LINKPOSTSHORTTIME 200
184 #define KEYPOSTTIME 30000
185 #define KEYPOSTSHORTTIME 200
186 #define MACROTIME 100
187 #define MACROPTIME 500
188 #define DTMF_TIMEOUT 3
189 #define KENWOOD_RETRIES 5
190 #define TOPKEYN 32
191 #define TOPKEYWAIT 3
192 #define TOPKEYMAXSTR 30
193
194 #define AUTHTELLTIME 7000
195 #define AUTHTXTIME 1000
196 #define AUTHLOGOUTTIME 25000
197
198 #ifdef  __RPT_NOTCH
199 #define MAXFILTERS 10
200 #endif
201
202 #define DISC_TIME 10000  /* report disc after 10 seconds of no connect */
203 #define MAX_RETRIES 5
204 #define MAX_RETRIES_PERM 1000000000
205
206 #define REDUNDANT_TX_TIME 2000
207
208 #define RETRY_TIMER_MS 5000
209
210 #define PATCH_DIALPLAN_TIMEOUT 1500
211
212 #ifdef OLD_ASTERISK
213 #define START_DELAY 10
214 #else
215 #define START_DELAY 2
216 #endif
217
218 #define RPT_LOCKOUT_SECS 10
219
220 #define MAXPEERSTR 31
221 #define MAXREMSTR 15
222
223 #define DELIMCHR ','
224 #define QUOTECHR 34
225
226 #define MONITOR_DISK_BLOCKS_PER_MINUTE 38
227
228 #define DEFAULT_MONITOR_MIN_DISK_BLOCKS 10000
229 #define DEFAULT_REMOTE_INACT_TIMEOUT (15 * 60)
230 #define DEFAULT_REMOTE_TIMEOUT (60 * 60)
231 #define DEFAULT_REMOTE_TIMEOUT_WARNING (3 * 60)
232 #define DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ 30
233
234 #define NODES "nodes"
235 #define EXTNODES "extnodes"
236 #define MEMORY "memory"
237 #define MACRO "macro"
238 #define FUNCTIONS "functions"
239 #define TELEMETRY "telemetry"
240 #define MORSE "morse"
241 #define TONEMACRO "tonemacro"
242 #define FUNCCHAR '*'
243 #define ENDCHAR '#'
244 #define EXTNODEFILE "/var/lib/asterisk/rpt_extnodes"
245 #define NODENAMES "rpt/nodenames"
246 #define PARROTFILE "/tmp/parrot_%s_%u"
247
248 #define PARROTTIME 1000
249
250 #define DEFAULT_IOBASE 0x378
251
252 #define DEFAULT_CIV_ADDR 0x58
253
254 #define MAXCONNECTTIME 5000
255
256 #define MAXNODESTR 300
257
258 #define MAXNODELEN 16
259
260 #define MAXIDENTLEN 32
261
262 #define MAXPATCHCONTEXT 100
263
264 #define ACTIONSIZE 32
265
266 #define TELEPARAMSIZE 256
267
268 #define REM_SCANTIME 100
269
270 #define DTMF_LOCAL_TIME 250
271 #define DTMF_LOCAL_STARTTIME 500
272
273 #define IC706_PL_MEMORY_OFFSET 50
274
275 #define VOX_ON_DEBOUNCE_COUNT 3
276 #define VOX_OFF_DEBOUNCE_COUNT 20
277 #define VOX_MAX_THRESHOLD 10000.0
278 #define VOX_MIN_THRESHOLD 3000.0
279 #define VOX_TIMEOUT_MS 5000
280 #define VOX_RECOVER_MS 500
281 #define SIMPLEX_PATCH_DELAY 25
282 #define SIMPLEX_PHONE_DELAY 25
283
284 #define STATPOST_PROGRAM "/usr/bin/wget,-q,--output-document=/dev/null,--no-check-certificate"
285
286 #define ALLOW_LOCAL_CHANNELS
287
288 enum {REM_OFF,REM_MONITOR,REM_TX};
289
290 enum{ID,PROC,TERM,COMPLETE,UNKEY,REMDISC,REMALREADY,REMNOTFOUND,REMGO,
291         CONNECTED,CONNFAIL,STATUS,TIMEOUT,ID1, STATS_TIME, PLAYBACK,
292         STATS_VERSION, IDTALKOVER, ARB_ALPHA, TEST_TONE, REV_PATCH,
293         TAILMSG, MACRO_NOTFOUND, MACRO_BUSY, LASTNODEKEY, FULLSTATUS,
294         MEMNOTFOUND, INVFREQ, REMMODE, REMLOGIN, REMXXX, REMSHORTSTATUS,
295         REMLONGSTATUS, LOGINREQ, SCAN, SCANSTAT, TUNE, SETREMOTE, TOPKEY,
296         TIMEOUT_WARNING, ACT_TIMEOUT_WARNING, LINKUNKEY, UNAUTHTX, PARROT,
297         STATS_TIME_LOCAL};
298
299
300 enum {REM_SIMPLEX,REM_MINUS,REM_PLUS};
301
302 enum {REM_LOWPWR,REM_MEDPWR,REM_HIPWR};
303
304 enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_COMPLETEQUIET, DC_DOKEY};
305
306 enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT, SOURCE_PHONE, SOURCE_DPHONE, SOURCE_ALT};
307
308 enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM, DLY_COMP, DLY_LINKUNKEY, DLY_PARROT};
309
310 enum {REM_MODE_FM,REM_MODE_USB,REM_MODE_LSB,REM_MODE_AM};
311
312 enum {HF_SCAN_OFF,HF_SCAN_DOWN_SLOW,HF_SCAN_DOWN_QUICK,
313       HF_SCAN_DOWN_FAST,HF_SCAN_UP_SLOW,HF_SCAN_UP_QUICK,HF_SCAN_UP_FAST};
314
315 #include "asterisk.h"
316
317 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
318
319 #include <signal.h>
320 #include <stdio.h>
321 #include <stdint.h>
322 #include <unistd.h>
323 #include <string.h>
324 #include <stdlib.h>
325 #include <search.h>
326 #include <sys/types.h>
327 #include <sys/stat.h>
328 #include <errno.h>
329 #include <dirent.h>
330 #include <ctype.h>
331 #include <sys/stat.h>
332 #include <sys/time.h>
333 #include <sys/file.h>
334 #include <sys/ioctl.h>
335 #ifdef HAVE_SYS_IO_H
336 #include <sys/io.h>
337 #endif
338 #include <sys/vfs.h>
339 #include <math.h>
340 #include <dahdi/user.h>
341 #include <dahdi/tonezone.h>
342 #include <netinet/in.h>
343 #include <arpa/inet.h>
344
345 #include "asterisk/utils.h"
346 #include "asterisk/lock.h"
347 #include "asterisk/file.h"
348 #include "asterisk/logger.h"
349 #include "asterisk/channel.h"
350 #include "asterisk/callerid.h"
351 #include "asterisk/pbx.h"
352 #include "asterisk/module.h"
353 #include "asterisk/translate.h"
354 #include "asterisk/features.h"
355 #include "asterisk/options.h"
356 #include "asterisk/cli.h"
357 #include "asterisk/config.h"
358 #include "asterisk/say.h"
359 #include "asterisk/localtime.h"
360 #include "asterisk/cdr.h"
361 #include "asterisk/options.h"
362 #include "asterisk/manager.h"
363 #include "asterisk/app.h"
364
365 #include <termios.h>
366
367 #ifdef  NEW_ASTERISK
368 struct ast_flags config_flags = { CONFIG_FLAG_WITHCOMMENTS };
369 #endif
370
371
372 /* Start a tone-list going */
373 int ast_playtones_start(struct ast_channel *chan, int vol, const char* tonelist, int interruptible);
374 /*! Stop the tones from playing */
375 void ast_playtones_stop(struct ast_channel *chan);
376
377 static  char *tdesc = "Radio Repeater / Remote Base  version 0.115  5/12/2008";
378
379 static char *app = "Rpt";
380
381 static char *synopsis = "Radio Repeater/Remote Base Control System";
382
383 static char *descrip = 
384 "  Rpt(nodename[|options][|M][|*]):  \n"
385 "    Radio Remote Link or Remote Base Link Endpoint Process.\n"
386 "\n"
387 "    Not specifying an option puts it in normal endpoint mode (where source\n"
388 "    IP and nodename are verified).\n"
389 "\n"
390 "    Options are as follows:\n"
391 "\n"
392 "        X - Normal endpoint mode WITHOUT security check. Only specify\n"
393 "            this if you have checked security already (like with an IAX2\n"
394 "            user/password or something).\n"
395 "\n"
396 "        Rannounce-string[|timeout[|timeout-destination]] - Amateur Radio\n"
397 "            Reverse Autopatch. Caller is put on hold, and announcement (as\n"
398 "            specified by the 'announce-string') is played on radio system.\n"
399 "            Users of radio system can access autopatch, dial specified\n"
400 "            code, and pick up call. Announce-string is list of names of\n"
401 "            recordings, or \"PARKED\" to substitute code for un-parking,\n"
402 "            or \"NODE\" to substitute node number.\n"
403 "\n"
404 "        P - Phone Control mode. This allows a regular phone user to have\n"
405 "            full control and audio access to the radio system. For the\n"
406 "            user to have DTMF control, the 'phone_functions' parameter\n"
407 "            must be specified for the node in 'rpt.conf'. An additional\n"
408 "            function (cop,6) must be listed so that PTT control is available.\n"
409 "\n"
410 "        D - Dumb Phone Control mode. This allows a regular phone user to\n"
411 "            have full control and audio access to the radio system. In this\n"
412 "            mode, the PTT is activated for the entire length of the call.\n"
413 "            For the user to have DTMF control (not generally recomended in\n"
414 "            this mode), the 'dphone_functions' parameter must be specified\n"
415 "            for the node in 'rpt.conf'. Otherwise no DTMF control will be\n"
416 "            available to the phone user.\n"
417 "\n"
418 "        S - Simplex Dumb Phone Control mode. This allows a regular phone user\n"
419 "            audio-only access to the radio system. In this mode, the\n"
420 "            transmitter is toggled on and off when the phone user presses the\n"
421 "            funcchar (*) key on the telephone set. In addition, the transmitter\n"
422 "            will turn off if the endchar (#) key is pressed. When a user first\n"
423 "            calls in, the transmitter will be off, and the user can listen for\n"
424 "            radio traffic. When the user wants to transmit, they press the *\n" 
425 "            key, start talking, then press the * key again or the # key to turn\n"
426 "            the transmitter off.  No other functions can be executed by the\n"
427 "            user on the phone when this mode is selected. Note: If your\n"
428 "            radio system is full-duplex, we recommend using either P or D\n"
429 "            modes as they provide more flexibility.\n"
430 "\n"
431 "        q - Query Status. Sets channel variables and returns + 101 in plan.\n"
432 "\n"
433 "        M - Memory Channel Steer as MXX where XX is the memory channel number.\n"
434 "\n"
435 "        * - Alt Macro to execute (e.g. *7 for status)\n"
436 "\n";
437 ;
438
439 static int debug = 0;  /* Set this >0 for extra debug output */
440 static int nrpts = 0;
441
442 static const char remdtmfstr[] = "0123456789*#ABCD";
443
444 enum {TOP_TOP,TOP_WON,WON_BEFREAD,BEFREAD_AFTERREAD};
445
446 int max_chan_stat [] = {22000,1000,22000,100,22000,2000,22000};
447
448 #define NRPTSTAT 7
449
450 struct rpt_chan_stat
451 {
452         struct timeval last;
453         long long total;
454         unsigned long count;
455         unsigned long largest;
456         struct timeval largest_time;
457 };
458
459 char *discstr = "!!DISCONNECT!!";
460 char *newkeystr = "!NEWKEY!";
461 static char *remote_rig_ft897="ft897";
462 static char *remote_rig_rbi="rbi";
463 static char *remote_rig_kenwood="kenwood";
464 static char *remote_rig_tm271="tm271";
465 static char *remote_rig_ic706="ic706";
466 static char *remote_rig_rtx150="rtx150";
467 static char *remote_rig_rtx450="rtx450";
468 static char *remote_rig_ppp16="ppp16";                  // parallel port programmable 16 channels
469
470 #define ISRIG_RTX(x) ((!strcmp(x,remote_rig_rtx150)) || (!strcmp(x,remote_rig_rtx450)))
471 #define IS_XPMR(x) (!strncasecmp(x->rxchanname,"rad",3))
472
473 #ifdef  OLD_ASTERISK
474 STANDARD_LOCAL_USER;
475 LOCAL_USER_DECL;
476 #endif
477
478 #define MSWAIT 200
479 #define HANGTIME 5000
480 #define TOTIME 180000
481 #define IDTIME 300000
482 #define MAXRPTS 20
483 #define MAX_STAT_LINKS 32
484 #define POLITEID 30000
485 #define FUNCTDELAY 1500
486
487 #define MAXXLAT 20
488 #define MAXXLATTIME 3
489
490 #define MAX_SYSSTATES 10
491
492 struct vox {
493         float   speech_energy;
494         float   noise_energy;
495         int     enacount;
496         char    voxena;
497         char    lastvox;
498         int     offdebcnt;
499         int     ondebcnt;
500 } ;
501
502 #define mymax(x,y) ((x > y) ? x : y)
503 #define mymin(x,y) ((x < y) ? x : y)
504
505 struct rpt_topkey
506 {
507 char    node[TOPKEYMAXSTR];
508 int     timesince;
509 int     keyed;
510 } ;
511
512 struct rpt_xlat
513 {
514 char    funccharseq[MAXXLAT];
515 char    endcharseq[MAXXLAT];
516 char    passchars[MAXXLAT];
517 int     funcindex;
518 int     endindex;
519 time_t  lastone;
520 } ;
521
522 static time_t   starttime = 0;
523
524 static  pthread_t rpt_master_thread;
525
526 struct rpt;
527
528 struct rpt_link
529 {
530         struct rpt_link *next;
531         struct rpt_link *prev;
532         char    mode;                   /* 1 if in tx mode */
533         char    isremote;
534         char    phonemode;
535         char    phonevox;               /* vox the phone */
536         char    name[MAXNODESTR];       /* identifier (routing) string */
537         char    lasttx;
538         char    lasttx1;
539         char    lastrx;
540         char    lastrealrx;
541         char    lastrx1;
542         char    connected;
543         char    hasconnected;
544         char    perma;
545         char    thisconnected;
546         char    outbound;
547         char    disced;
548         char    killme;
549         long    elaptime;
550         long    disctime;
551         long    retrytimer;
552         long    retxtimer;
553         long    rerxtimer;
554         int     retries;
555         int     max_retries;
556         int     reconnects;
557         long long connecttime;
558         struct ast_channel *chan;       
559         struct ast_channel *pchan;      
560         char    linklist[MAXLINKLIST];
561         time_t  linklistreceived;
562         long    linklisttimer;
563         int     dtmfed;
564         int linkunkeytocttimer;
565         struct timeval lastlinktv;
566         struct  ast_frame *lastf1,*lastf2;
567         struct  rpt_chan_stat chan_stat[NRPTSTAT];
568         struct vox vox;
569         char wasvox;
570         int voxtotimer;
571         char voxtostate;
572         char newkey;
573 #ifdef OLD_ASTERISK
574         AST_LIST_HEAD(, ast_frame) rxq;
575 #else
576         AST_LIST_HEAD_NOLOCK(, ast_frame) rxq;
577 #endif
578 } ;
579
580 struct rpt_lstat
581 {
582         struct  rpt_lstat *next;
583         struct  rpt_lstat *prev;
584         char    peer[MAXPEERSTR];
585         char    name[MAXNODESTR];
586         char    mode;
587         char    outbound;
588         char    reconnects;
589         char    thisconnected;
590         long long       connecttime;
591         struct  rpt_chan_stat chan_stat[NRPTSTAT];
592 } ;
593
594 struct rpt_tele
595 {
596         struct rpt_tele *next;
597         struct rpt_tele *prev;
598         struct rpt *rpt;
599         struct ast_channel *chan;
600         int     mode;
601         struct rpt_link mylink;
602         char param[TELEPARAMSIZE];
603         intptr_t submode;
604         uintptr_t  parrot;
605         pthread_t threadid;
606 } ;
607
608 struct function_table_tag
609 {
610         char action[ACTIONSIZE];
611         int (*function)(struct rpt *myrpt, char *param, char *digitbuf, 
612                 int command_source, struct rpt_link *mylink);
613 } ;
614
615 /* Used to store the morse code patterns */
616
617 struct morse_bits
618 {                 
619         int len;
620         int ddcomb;
621 } ;
622
623 struct telem_defaults
624 {
625         char name[20];
626         char value[80];
627 } ;
628
629
630 struct sysstate
631 {
632         char txdisable;
633         char totdisable;
634         char linkfundisable;
635         char autopatchdisable;
636         char schedulerdisable;
637         char userfundisable;
638         char alternatetail;
639 };
640
641 /* rpt cmd support */
642 #define CMD_DEPTH 1
643 #define CMD_STATE_IDLE 0
644 #define CMD_STATE_BUSY 1
645 #define CMD_STATE_READY 2
646 #define CMD_STATE_EXECUTING 3
647
648 struct rpt_cmd_struct
649 {
650     int state;
651     int functionNumber;
652     char param[MAXDTMF];
653     char digits[MAXDTMF];
654     int command_source;
655 };
656
657 static struct rpt
658 {
659         ast_mutex_t lock;
660         ast_mutex_t remlock;
661         ast_mutex_t statpost_lock;
662         struct ast_config *cfg;
663         char reload;
664         char xlink;                                                                     // cross link state of a share repeater/remote radio
665         unsigned int statpost_seqno;
666
667         char *name;
668         char *rxchanname;
669         char *txchanname;
670         char remote;
671         char *remoterig;
672         struct  rpt_chan_stat chan_stat[NRPTSTAT];
673         unsigned int scram;
674
675         struct {
676                 char *ourcontext;
677                 char *ourcallerid;
678                 char *acctcode;
679                 char *ident;
680                 char *tonezone;
681                 char simple;
682                 char *functions;
683                 char *link_functions;
684                 char *phone_functions;
685                 char *dphone_functions;
686                 char *alt_functions;
687                 char *nodes;
688                 char *extnodes;
689                 char *extnodefile;
690                 int hangtime;
691                 int althangtime;
692                 int totime;
693                 int idtime;
694                 int tailmessagetime;
695                 int tailsquashedtime;
696                 int duplex;
697                 int politeid;
698                 char *tailmessages[500];
699                 int tailmessagemax;
700                 char    *memory;
701                 char    *macro;
702                 char    *tonemacro;
703                 char    *startupmacro;
704                 int iobase;
705                 char *ioport;
706                 char funcchar;
707                 char endchar;
708                 char nobusyout;
709                 char notelemtx;
710                 char propagate_dtmf;
711                 char propagate_phonedtmf;
712                 char linktolink;
713                 unsigned char civaddr;
714                 struct rpt_xlat inxlat;
715                 struct rpt_xlat outxlat;
716                 char *archivedir;
717                 int authlevel;
718                 char *csstanzaname;
719                 char *skedstanzaname;
720                 char *txlimitsstanzaname;
721                 long monminblocks;
722                 int remoteinacttimeout;
723                 int remotetimeout;
724                 int remotetimeoutwarning;
725                 int remotetimeoutwarningfreq;
726                 int sysstate_cur;
727                 struct sysstate s[MAX_SYSSTATES];
728                 char parrotmode;
729                 int parrottime;
730                 char *rptnode;
731                 char remote_mars;
732                 int voxtimeout_ms;
733                 int voxrecover_ms;
734                 int simplexpatchdelay;
735                 int simplexphonedelay;
736                 char *statpost_program;
737                 char *statpost_url;
738         } p;
739         struct rpt_link links;
740         int unkeytocttimer;
741         time_t lastkeyedtime;
742         time_t lasttxkeyedtime;
743         char keyed;
744         char txkeyed;
745         char exttx;
746         char localtx;
747         char remoterx;
748         char remotetx;
749         char remoteon;
750         char remtxfreqok;
751         char tounkeyed;
752         char tonotify;
753         char dtmfbuf[MAXDTMF];
754         char macrobuf[MAXMACRO];
755         char rem_dtmfbuf[MAXDTMF];
756         char lastdtmfcommand[MAXDTMF];
757         char cmdnode[50];
758         char nowchan;                                           // channel now
759         char waschan;                                           // channel selected initially or by command
760         char bargechan;                                         // barge in channel
761         char macropatch;                                        // autopatch via tonemacro state
762         char parrotstate;
763         int  parrottimer;
764         unsigned int parrotcnt;
765         struct ast_channel *rxchannel,*txchannel, *monchannel, *parrotchannel;
766         struct ast_channel *pchannel,*txpchannel, *dahdirxchannel, *dahditxchannel;
767         struct ast_channel *voxchannel;
768         struct ast_frame *lastf1,*lastf2;
769         struct rpt_tele tele;
770         struct timeval lasttv,curtv;
771         pthread_t rpt_call_thread,rpt_thread;
772         time_t dtmf_time,rem_dtmf_time,dtmf_time_rem;
773         int calldigittimer;
774         int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx,scantimer,tmsgtimer,skedtimer;
775         int mustid,tailid;
776         int tailevent;
777         int telemrefcount;
778         int dtmfidx,rem_dtmfidx;
779         int dailytxtime,dailykerchunks,totalkerchunks,dailykeyups,totalkeyups,timeouts;
780         int totalexecdcommands, dailyexecdcommands;
781         long    retxtimer;
782         long    rerxtimer;
783         long long totaltxtime;
784         char mydtmf;
785         char exten[AST_MAX_EXTENSION];
786         char freq[MAXREMSTR],rxpl[MAXREMSTR],txpl[MAXREMSTR];
787         char offset;
788         char powerlevel;
789         char txplon;
790         char rxplon;
791         char remmode;
792         char tunerequest;
793         char hfscanmode;
794         int hfscanstatus;
795         char hfscanstop;
796         char lastlinknode[MAXNODESTR];
797         char savednodes[MAXNODESTR];
798         int stopgen;
799         char patchfarenddisconnect;
800         char patchnoct;
801         char patchquiet;
802         char patchcontext[MAXPATCHCONTEXT];
803         int patchdialtime;
804         int macro_longest;
805         int phone_longestfunc;
806         int alt_longestfunc;
807         int dphone_longestfunc;
808         int link_longestfunc;
809         int longestfunc;
810         int longestnode;
811         int threadrestarts;             
812         int tailmessagen;
813         time_t disgorgetime;
814         time_t lastthreadrestarttime;
815         long    macrotimer;
816         char    lastnodewhichkeyedusup[MAXNODESTR];
817         int     dtmf_local_timer;
818         char    dtmf_local_str[100];
819         struct ast_filestream *monstream,*parrotstream;
820         char    loginuser[50];
821         char    loginlevel[10];
822         long    authtelltimer;
823         long    authtimer;
824         int iofd;
825         time_t start_time,last_activity_time;
826         char    lasttone[32];
827         struct rpt_tele *active_telem;
828         struct  rpt_topkey topkey[TOPKEYN];
829         int topkeystate;
830         time_t topkeytime;
831         int topkeylong;
832         struct vox vox;
833         char wasvox;
834         int voxtotimer;
835         char voxtostate;
836         int linkposttimer;                      
837         int keyposttimer;                       
838         char newkey;
839         char inpadtest;
840 #ifdef OLD_ASTERISK
841         AST_LIST_HEAD(, ast_frame) txq;
842 #else
843         AST_LIST_HEAD_NOLOCK(, ast_frame) txq;
844 #endif
845         char txrealkeyed;
846 #ifdef  __RPT_NOTCH
847         struct rptfilter
848         {
849                 char    desc[100];
850                 float   x0;
851                 float   x1;
852                 float   x2;
853                 float   y0;
854                 float   y1;
855                 float   y2;
856                 float   gain;
857                 float   const0;
858                 float   const1;
859                 float   const2;
860         } filters[MAXFILTERS];
861 #endif
862 #ifdef  _MDC_DECODE_H_
863         mdc_decoder_t *mdc;
864         unsigned short lastunit;
865 #endif
866         struct rpt_cmd_struct cmdAction;
867 } rpt_vars[MAXRPTS];    
868
869 struct nodelog {
870 struct nodelog *next;
871 struct nodelog *prev;
872 time_t  timestamp;
873 char archivedir[MAXNODESTR];
874 char str[MAXNODESTR * 2];
875 } nodelog;
876
877 static int service_scan(struct rpt *myrpt);
878 static int set_mode_ft897(struct rpt *myrpt, char newmode);
879 static int set_mode_ic706(struct rpt *myrpt, char newmode);
880 static int simple_command_ft897(struct rpt *myrpt, char command);
881 static int setrem(struct rpt *myrpt);
882 static int setrtx_check(struct rpt *myrpt);
883 static int channel_revert(struct rpt *myrpt);
884 static int channel_steer(struct rpt *myrpt, char *data);
885 static struct ast_format_cap *get_slin_cap(struct ast_format_cap *cap);
886
887 AST_MUTEX_DEFINE_STATIC(nodeloglock);
888
889 AST_MUTEX_DEFINE_STATIC(nodelookuplock);
890
891 #ifdef  APP_RPT_LOCK_DEBUG
892
893 #warning COMPILING WITH LOCK-DEBUGGING ENABLED!!
894
895 #define MAXLOCKTHREAD 100
896
897 #define rpt_mutex_lock(x) _rpt_mutex_lock(x,myrpt,__LINE__)
898 #define rpt_mutex_unlock(x) _rpt_mutex_unlock(x,myrpt,__LINE__)
899
900 struct lockthread
901 {
902         pthread_t id;
903         int lockcount;
904         int lastlock;
905         int lastunlock;
906 } lockthreads[MAXLOCKTHREAD];
907
908
909 struct by_lightning
910 {
911         int line;
912         struct timeval tv;
913         struct rpt *rpt;
914         struct lockthread lockthread;
915 } lock_ring[32];
916
917 int lock_ring_index = 0;
918
919 AST_MUTEX_DEFINE_STATIC(locklock);
920
921 static struct lockthread *get_lockthread(pthread_t id)
922 {
923 int     i;
924
925         for(i = 0; i < MAXLOCKTHREAD; i++)
926         {
927                 if (lockthreads[i].id == id) return(&lockthreads[i]);
928         }
929         return(NULL);
930 }
931
932 static struct lockthread *put_lockthread(pthread_t id)
933 {
934 int     i;
935
936         for(i = 0; i < MAXLOCKTHREAD; i++)
937         {
938                 if (lockthreads[i].id == id)
939                         return(&lockthreads[i]);
940         }
941         for(i = 0; i < MAXLOCKTHREAD; i++)
942         {
943                 if (!lockthreads[i].id)
944                 {
945                         lockthreads[i].lockcount = 0;
946                         lockthreads[i].lastlock = 0;
947                         lockthreads[i].lastunlock = 0;
948                         lockthreads[i].id = id;
949                         return(&lockthreads[i]);
950                 }
951         }
952         return(NULL);
953 }
954
955 static void rpt_mutex_spew(void)
956 {
957         struct by_lightning lock_ring_copy[32];
958         int lock_ring_index_copy;
959         int i,j;
960         long long diff;
961         char a[100];
962         struct timeval lasttv;
963
964         ast_mutex_lock(&locklock);
965         memcpy(&lock_ring_copy, &lock_ring, sizeof(lock_ring_copy));
966         lock_ring_index_copy = lock_ring_index;
967         ast_mutex_unlock(&locklock);
968
969         lasttv.tv_sec = lasttv.tv_usec = 0;
970         for(i = 0 ; i < 32 ; i++)
971         {
972                 j = (i + lock_ring_index_copy) % 32;
973                 strftime(a,sizeof(a) - 1,"%m/%d/%Y %H:%M:%S",
974                         localtime(&lock_ring_copy[j].tv.tv_sec));
975                 diff = 0;
976                 if(lasttv.tv_sec)
977                 {
978                         diff = (lock_ring_copy[j].tv.tv_sec - lasttv.tv_sec)
979                                 * 1000000;
980                         diff += (lock_ring_copy[j].tv.tv_usec - lasttv.tv_usec);
981                 }
982                 lasttv.tv_sec = lock_ring_copy[j].tv.tv_sec;
983                 lasttv.tv_usec = lock_ring_copy[j].tv.tv_usec;
984                 if (!lock_ring_copy[j].tv.tv_sec) continue;
985                 if (lock_ring_copy[j].line < 0)
986                 {
987                         ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] UNLOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
988                                 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);
989                 }
990                 else
991                 {
992                         ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] LOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
993                                 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);
994                 }
995         }
996 }
997
998
999 static void _rpt_mutex_lock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
1000 {
1001 struct lockthread *t;
1002 pthread_t id;
1003
1004         id = pthread_self();
1005         ast_mutex_lock(&locklock);
1006         t = put_lockthread(id);
1007         if (!t)
1008         {
1009                 ast_mutex_unlock(&locklock);
1010                 return;
1011         }
1012         if (t->lockcount)
1013         {
1014                 int lastline = t->lastlock;
1015                 ast_mutex_unlock(&locklock);
1016                 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);
1017                 rpt_mutex_spew();
1018                 return;
1019         }
1020         t->lastlock = line;
1021         t->lockcount = 1;
1022         gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
1023         lock_ring[lock_ring_index].rpt = myrpt;
1024         memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
1025         lock_ring[lock_ring_index++].line = line;
1026         if(lock_ring_index == 32)
1027                 lock_ring_index = 0;
1028         ast_mutex_unlock(&locklock);
1029         ast_mutex_lock(lockp);
1030 }
1031
1032
1033 static void _rpt_mutex_unlock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
1034 {
1035 struct lockthread *t;
1036 pthread_t id;
1037
1038         id = pthread_self();
1039         ast_mutex_lock(&locklock);
1040         t = put_lockthread(id);
1041         if (!t)
1042         {
1043                 ast_mutex_unlock(&locklock);
1044                 return;
1045         }
1046         if (!t->lockcount)
1047         {
1048                 int lastline = t->lastunlock;
1049                 ast_mutex_unlock(&locklock);
1050                 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);
1051                 rpt_mutex_spew();
1052                 return;
1053         }
1054         t->lastunlock = line;
1055         t->lockcount = 0;
1056         gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
1057         lock_ring[lock_ring_index].rpt = myrpt;
1058         memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
1059         lock_ring[lock_ring_index++].line = -line;
1060         if(lock_ring_index == 32)
1061                 lock_ring_index = 0;
1062         ast_mutex_unlock(&locklock);
1063         ast_mutex_unlock(lockp);
1064 }
1065
1066 #else  /* APP_RPT_LOCK_DEBUG */
1067
1068 #define rpt_mutex_lock(x) ast_mutex_lock(x)
1069 #define rpt_mutex_unlock(x) ast_mutex_unlock(x)
1070
1071 #endif  /* APP_RPT_LOCK_DEBUG */
1072
1073 static struct ast_format_cap *get_slin_cap(struct ast_format_cap *cap)
1074 {
1075         struct ast_format tmp;
1076         cap = ast_format_cap_alloc_nolock();
1077         if (!cap) {
1078                 return NULL;
1079         }
1080         ast_format_cap_add(cap, ast_format_set(&tmp, AST_FORMAT_SLINEAR, 0));
1081
1082         return cap;
1083 }
1084
1085 /*
1086 * Return 1 if rig is multimode capable
1087 */
1088
1089 static int multimode_capable(struct rpt *myrpt)
1090 {
1091         if(!strcmp(myrpt->remoterig, remote_rig_ft897))
1092                 return 1;
1093         if(!strcmp(myrpt->remoterig, remote_rig_ic706))
1094                 return 1;
1095         return 0;
1096 }       
1097
1098 static void voxinit_rpt(struct rpt *myrpt,char enable)
1099 {
1100
1101         myrpt->vox.speech_energy = 0.0;
1102         myrpt->vox.noise_energy = 0.0;
1103         myrpt->vox.enacount = 0;
1104         myrpt->vox.voxena = 0;
1105         if (!enable) myrpt->vox.voxena = -1;
1106         myrpt->vox.lastvox = 0;
1107         myrpt->vox.ondebcnt = VOX_ON_DEBOUNCE_COUNT;
1108         myrpt->vox.offdebcnt = VOX_OFF_DEBOUNCE_COUNT;
1109         myrpt->wasvox = 0;
1110         myrpt->voxtotimer = 0;
1111         myrpt->voxtostate = 0;
1112 }
1113
1114 static void voxinit_link(struct rpt_link *mylink,char enable)
1115 {
1116
1117         mylink->vox.speech_energy = 0.0;
1118         mylink->vox.noise_energy = 0.0;
1119         mylink->vox.enacount = 0;
1120         mylink->vox.voxena = 0;
1121         if (!enable) mylink->vox.voxena = -1;
1122         mylink->vox.lastvox = 0;
1123         mylink->vox.ondebcnt = VOX_ON_DEBOUNCE_COUNT;
1124         mylink->vox.offdebcnt = VOX_OFF_DEBOUNCE_COUNT;
1125         mylink->wasvox = 0;
1126         mylink->voxtotimer = 0;
1127         mylink->voxtostate = 0;
1128 }
1129
1130 static int dovox(struct vox *v,short *buf,int bs)
1131 {
1132
1133         int i;
1134         float   esquare = 0.0;
1135         float   energy = 0.0;
1136         float   threshold = 0.0;
1137         
1138         if (v->voxena < 0) return(v->lastvox);
1139         for(i = 0; i < bs; i++)
1140         {
1141                 esquare += (float) buf[i] * (float) buf[i];
1142         }
1143         energy = sqrt(esquare);
1144
1145         if (energy >= v->speech_energy)
1146                 v->speech_energy += (energy - v->speech_energy) / 4;
1147         else
1148                 v->speech_energy += (energy - v->speech_energy) / 64;
1149
1150         if (energy >= v->noise_energy)
1151                 v->noise_energy += (energy - v->noise_energy) / 64;
1152         else
1153                 v->noise_energy += (energy - v->noise_energy) / 4;
1154         
1155         if (v->voxena) threshold = v->speech_energy / 8;
1156         else
1157         {
1158                 threshold = mymax(v->speech_energy / 16,v->noise_energy * 2);
1159                 threshold = mymin(threshold,VOX_MAX_THRESHOLD);
1160         }
1161         threshold = mymax(threshold,VOX_MIN_THRESHOLD);
1162         if (energy > threshold)
1163         {
1164                 if (v->voxena) v->noise_energy *= 0.75;
1165                 v->voxena = 1;
1166         } else  v->voxena = 0;
1167         if (v->lastvox != v->voxena)
1168         {
1169                 if (v->enacount++ >= ((v->lastvox) ? v->offdebcnt : v->ondebcnt))
1170                 {
1171                         v->lastvox = v->voxena;
1172                         v->enacount = 0;
1173                 }
1174         } else v->enacount = 0;
1175         return(v->lastvox);
1176 }
1177
1178
1179
1180
1181 /*
1182 * CLI extensions
1183 */
1184
1185 /* Debug mode */
1186 static int rpt_do_debug(int fd, int argc, const char * const *argv);
1187 static int rpt_do_dump(int fd, int argc, const char * const *argv);
1188 static int rpt_do_stats(int fd, int argc, const char * const *argv);
1189 static int rpt_do_lstats(int fd, int argc, const char * const *argv);
1190 static int rpt_do_nodes(int fd, int argc, const char * const *argv);
1191 static int rpt_do_local_nodes(int fd, int argc, const char * const *argv);
1192 static int rpt_do_reload(int fd, int argc, const char * const *argv);
1193 static int rpt_do_restart(int fd, int argc, const char * const *argv);
1194 static int rpt_do_fun(int fd, int argc, const char * const *argv);
1195 static int rpt_do_fun1(int fd, int argc, const char * const *argv);
1196 static int rpt_do_cmd(int fd, int argc, const char * const *argv);
1197
1198 static char debug_usage[] =
1199 "Usage: rpt debug level {0-7}\n"
1200 "       Enables debug messages in app_rpt\n";
1201
1202 static char dump_usage[] =
1203 "Usage: rpt dump <nodename>\n"
1204 "       Dumps struct debug info to log\n";
1205
1206 static char dump_stats[] =
1207 "Usage: rpt stats <nodename>\n"
1208 "       Dumps node statistics to console\n";
1209
1210 static char dump_lstats[] =
1211 "Usage: rpt lstats <nodename>\n"
1212 "       Dumps link statistics to console\n";
1213
1214 static char dump_nodes[] =
1215 "Usage: rpt nodes <nodename>\n"
1216 "       Dumps a list of directly and indirectly connected nodes to the console\n";
1217
1218 static char usage_local_nodes[] =
1219 "Usage: rpt localnodes\n"
1220 "       Dumps a list of the locally configured node numbers to the console.\n";
1221
1222 static char reload_usage[] =
1223 "Usage: rpt reload\n"
1224 "       Reloads app_rpt running config parameters\n";
1225
1226 static char restart_usage[] =
1227 "Usage: rpt restart\n"
1228 "       Restarts app_rpt\n";
1229
1230 static char fun_usage[] =
1231 "Usage: rpt fun <nodename> <command>\n"
1232 "       Send a DTMF function to a node\n";
1233
1234 static char cmd_usage[] =
1235 "Usage: rpt cmd <nodename> <cmd-name> <cmd-index> <cmd-args.\n"
1236 "       Send a command to a node.\n        i.e. rpt cmd 2000 ilink 3 2001\n";
1237
1238 #ifndef NEW_ASTERISK
1239
1240 static struct ast_cli_entry  cli_debug =
1241         { { "rpt", "debug", "level" }, rpt_do_debug, 
1242                 "Enable app_rpt debugging", debug_usage };
1243
1244 static struct ast_cli_entry  cli_dump =
1245         { { "rpt", "dump" }, rpt_do_dump,
1246                 "Dump app_rpt structs for debugging", dump_usage };
1247
1248 static struct ast_cli_entry  cli_stats =
1249         { { "rpt", "stats" }, rpt_do_stats,
1250                 "Dump node statistics", dump_stats };
1251
1252 static struct ast_cli_entry  cli_nodes =
1253         { { "rpt", "nodes" }, rpt_do_nodes,
1254                 "Dump node list", dump_nodes };
1255
1256 static struct ast_cli_entry  cli_local_nodes =
1257         { { "rpt", "localnodes" }, rpt_do_local_nodes,
1258                 "Dump list of local node numbers", usage_local_nodes };
1259
1260 static struct ast_cli_entry  cli_lstats =
1261         { { "rpt", "lstats" }, rpt_do_lstats,
1262                 "Dump link statistics", dump_lstats };
1263
1264 static struct ast_cli_entry  cli_reload =
1265         { { "rpt", "reload" }, rpt_do_reload,
1266                 "Reload app_rpt config", reload_usage };
1267
1268 static struct ast_cli_entry  cli_restart =
1269         { { "rpt", "restart" }, rpt_do_restart,
1270                 "Restart app_rpt", restart_usage };
1271
1272 static struct ast_cli_entry  cli_fun =
1273         { { "rpt", "fun" }, rpt_do_fun,
1274                 "Execute a DTMF function", fun_usage };
1275
1276 static struct ast_cli_entry  cli_fun1 =
1277         { { "rpt", "fun1" }, rpt_do_fun1,
1278                 "Execute a DTMF function", fun_usage };
1279
1280 static struct ast_cli_entry  cli_cmd =
1281         { { "rpt", "cmd" }, rpt_do_cmd,
1282                 "Execute a DTMF function", cmd_usage };
1283
1284 #endif
1285
1286 /*
1287 * Telemetry defaults
1288 */
1289
1290
1291 static struct telem_defaults tele_defs[] = {
1292         {"ct1","|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
1293         {"ct2","|t(660,880,150,3072)"},
1294         {"ct3","|t(440,0,150,3072)"},
1295         {"ct4","|t(550,0,150,3072)"},
1296         {"ct5","|t(660,0,150,3072)"},
1297         {"ct6","|t(880,0,150,3072)"},
1298         {"ct7","|t(660,440,150,3072)"},
1299         {"ct8","|t(700,1100,150,3072)"},
1300         {"remotemon","|t(1600,0,75,2048)"},
1301         {"remotetx","|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
1302         {"cmdmode","|t(900,904,200,2048)"},
1303         {"functcomplete","|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
1304 } ;
1305
1306 /*
1307 * Forward decl's - these suppress compiler warnings when funcs coded further down the file than thier invokation
1308 */
1309
1310 static int setrbi(struct rpt *myrpt);
1311 static int set_ft897(struct rpt *myrpt);
1312 static int set_ic706(struct rpt *myrpt);
1313 static int setkenwood(struct rpt *myrpt);
1314 static int set_tm271(struct rpt *myrpt);
1315 static int setrbi_check(struct rpt *myrpt);
1316
1317
1318
1319 /*
1320 * Define function protos for function table here
1321 */
1322
1323 static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1324 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1325 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1326 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1327 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1328 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1329 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1330 static int function_playback(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1331 /*
1332 * Function table
1333 */
1334
1335 static struct function_table_tag function_table[] = {
1336         {"cop", function_cop},
1337         {"autopatchup", function_autopatchup},
1338         {"autopatchdn", function_autopatchdn},
1339         {"ilink", function_ilink},
1340         {"status", function_status},
1341         {"remote", function_remote},
1342         {"macro", function_macro},
1343         {"playback", function_playback}
1344 } ;
1345
1346 static long diskavail(struct rpt *myrpt)
1347 {
1348 struct  statfs statfsbuf;
1349
1350         if (!myrpt->p.archivedir) return(0);
1351         if (statfs(myrpt->p.archivedir,&statfsbuf) == -1)
1352         {
1353                 ast_log(LOG_WARNING,"Cannot get filesystem size for %s node %s\n",
1354                         myrpt->p.archivedir,myrpt->name);
1355                 return(-1);
1356         }
1357         return(statfsbuf.f_bavail);
1358 }
1359
1360 static void flush_telem(struct rpt *myrpt)
1361 {
1362         struct rpt_tele *telem;
1363         if(debug > 2)
1364                 ast_log(LOG_NOTICE, "flush_telem()!!");
1365         rpt_mutex_lock(&myrpt->lock);
1366         telem = myrpt->tele.next;
1367         while(telem != &myrpt->tele)
1368         {
1369                 if (telem->mode != SETREMOTE) ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
1370                 telem = telem->next;
1371         }
1372         rpt_mutex_unlock(&myrpt->lock);
1373 }
1374 /*
1375         return via error priority
1376 */
1377 static int priority_jump(struct rpt *myrpt, struct ast_channel *chan)
1378 {
1379         int res=0;
1380
1381         // if (ast_test_flag(&flags,OPT_JUMP) && ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101) == 0){
1382         if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101) == 0){
1383                 res = 0;
1384         } else {
1385                 res = -1;
1386         }
1387         return res;
1388 }
1389 /*
1390 */
1391 static int linkcount(struct rpt *myrpt)
1392 {
1393         struct  rpt_link *l;
1394         char *reverse_patch_state;
1395         int numoflinks;
1396
1397         reverse_patch_state = "DOWN";
1398         numoflinks = 0;
1399         l = myrpt->links.next;
1400         while(l && (l != &myrpt->links)){
1401                 if(numoflinks >= MAX_STAT_LINKS){
1402                         ast_log(LOG_WARNING,
1403                         "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
1404                         break;
1405                 }
1406                 //if (l->name[0] == '0'){ /* Skip '0' nodes */
1407                 //      reverse_patch_state = "UP";
1408                 //      l = l->next;
1409                 //      continue;
1410                 //}
1411                 numoflinks++;
1412          
1413                 l = l->next;
1414         }
1415         ast_log(LOG_NOTICE, "numoflinks=%i\n",numoflinks);
1416         return numoflinks;
1417 }
1418 /*
1419  * Retrieve a memory channel
1420  * Return 0 if sucessful,
1421  * -1 if channel not found,
1422  *  1 if parse error
1423  */
1424 static int retreive_memory(struct rpt *myrpt, char *memory)
1425 {
1426         char tmp[30], *s, *s1, *val;
1427
1428         if (debug)ast_log(LOG_NOTICE, "memory=%s block=%s\n",memory,myrpt->p.memory);
1429
1430         val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.memory, memory);
1431         if (!val){
1432                 return -1;
1433         }                       
1434         strncpy(tmp,val,sizeof(tmp) - 1);
1435         tmp[sizeof(tmp)-1] = 0;
1436
1437         s = strchr(tmp,',');
1438         if (!s)
1439                 return 1; 
1440         *s++ = 0;
1441         s1 = strchr(s,',');
1442         if (!s1)
1443                 return 1;
1444         *s1++ = 0;
1445         strncpy(myrpt->freq, tmp, sizeof(myrpt->freq) - 1);
1446         strncpy(myrpt->rxpl, s, sizeof(myrpt->rxpl) - 1);
1447         strncpy(myrpt->txpl, s, sizeof(myrpt->rxpl) - 1);
1448         myrpt->remmode = REM_MODE_FM;
1449         myrpt->offset = REM_SIMPLEX;
1450         myrpt->powerlevel = REM_MEDPWR;
1451         myrpt->txplon = myrpt->rxplon = 0;
1452         while(*s1){
1453                 switch(*s1++){
1454                         case 'A':
1455                         case 'a':
1456                                 strcpy(myrpt->rxpl, "100.0");
1457                                 strcpy(myrpt->txpl, "100.0");
1458                                 myrpt->remmode = REM_MODE_AM;   
1459                                 break;
1460                         case 'B':
1461                         case 'b':
1462                                 strcpy(myrpt->rxpl, "100.0");
1463                                 strcpy(myrpt->txpl, "100.0");
1464                                 myrpt->remmode = REM_MODE_LSB;
1465                                 break;
1466                         case 'F':
1467                                 myrpt->remmode = REM_MODE_FM;
1468                                 break;
1469                         case 'L':
1470                         case 'l':
1471                                 myrpt->powerlevel = REM_LOWPWR;
1472                                 break;                                  
1473                         case 'H':
1474                         case 'h':
1475                                 myrpt->powerlevel = REM_HIPWR;
1476                                 break;
1477                                         
1478                         case 'M':
1479                         case 'm':
1480                                 myrpt->powerlevel = REM_MEDPWR;
1481                                 break;
1482                                                 
1483                         case '-':
1484                                 myrpt->offset = REM_MINUS;
1485                                 break;
1486                                                 
1487                         case '+':
1488                                 myrpt->offset = REM_PLUS;
1489                                 break;
1490                                                 
1491                         case 'S':
1492                         case 's':
1493                                 myrpt->offset = REM_SIMPLEX;
1494                                 break;
1495                                                 
1496                         case 'T':
1497                         case 't':
1498                                 myrpt->txplon = 1;
1499                                 break;
1500                                                 
1501                         case 'R':
1502                         case 'r':
1503                                 myrpt->rxplon = 1;
1504                                 break;
1505
1506                         case 'U':
1507                         case 'u':
1508                                 strcpy(myrpt->rxpl, "100.0");
1509                                 strcpy(myrpt->txpl, "100.0");
1510                                 myrpt->remmode = REM_MODE_USB;
1511                                 break;
1512                         default:
1513                                 return 1;
1514                 }
1515         }
1516         return 0;
1517 }
1518 /*
1519
1520 */
1521 static void birdbath(struct rpt *myrpt)
1522 {
1523         struct rpt_tele *telem;
1524         if(debug > 2)
1525                 ast_log(LOG_NOTICE, "birdbath!!");
1526         rpt_mutex_lock(&myrpt->lock);
1527         telem = myrpt->tele.next;
1528         while(telem != &myrpt->tele)
1529         {
1530                 if (telem->mode == PARROT) ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
1531                 telem = telem->next;
1532         }
1533         rpt_mutex_unlock(&myrpt->lock);
1534 }
1535
1536 static void do_dtmf_phone(struct rpt *myrpt, struct rpt_link *mylink, char c)
1537 {
1538 struct        rpt_link *l;
1539
1540        l = myrpt->links.next;
1541        /* go thru all the links */
1542        while(l != &myrpt->links)
1543        {
1544                if (!l->phonemode)
1545                {
1546                        l = l->next;
1547                        continue;
1548                }
1549                /* don't send to self */
1550                if (mylink && (l == mylink))
1551                {
1552                        l = l->next;
1553                        continue;
1554                }
1555 #ifdef  NEW_ASTERISK
1556                if (l->chan) ast_senddigit(l->chan,c,0);
1557 #else
1558                if (l->chan) ast_senddigit(l->chan,c);
1559 #endif
1560                l = l->next;
1561        }
1562        return;
1563 }
1564
1565 /* node logging function */
1566 static void donodelog(struct rpt *myrpt,char *str)
1567 {
1568 struct nodelog *nodep;
1569 char    datestr[100];
1570
1571         if (!myrpt->p.archivedir) return;
1572         nodep = (struct nodelog *)ast_malloc(sizeof(struct nodelog));
1573         if (nodep == NULL)
1574         {
1575                 ast_log(LOG_ERROR,"Cannot get memory for node log");
1576                 return;
1577         }
1578         time(&nodep->timestamp);
1579         strncpy(nodep->archivedir,myrpt->p.archivedir,
1580                 sizeof(nodep->archivedir) - 1);
1581         strftime(datestr,sizeof(datestr) - 1,"%Y%m%d%H%M%S",
1582                 localtime(&nodep->timestamp));
1583         snprintf(nodep->str,sizeof(nodep->str) - 1,"%s %s,%s\n",
1584                 myrpt->name,datestr,str);
1585         ast_mutex_lock(&nodeloglock);
1586         insque((struct qelem *) nodep, (struct qelem *) nodelog.prev);
1587         ast_mutex_unlock(&nodeloglock);
1588 }
1589
1590 /* must be called locked */
1591 static void do_dtmf_local(struct rpt *myrpt, char c)
1592 {
1593 int     i;
1594 char    digit;
1595 static const char* dtmf_tones[] = {
1596         "!941+1336/200,!0/200", /* 0 */
1597         "!697+1209/200,!0/200", /* 1 */
1598         "!697+1336/200,!0/200", /* 2 */
1599         "!697+1477/200,!0/200", /* 3 */
1600         "!770+1209/200,!0/200", /* 4 */
1601         "!770+1336/200,!0/200", /* 5 */
1602         "!770+1477/200,!0/200", /* 6 */
1603         "!852+1209/200,!0/200", /* 7 */
1604         "!852+1336/200,!0/200", /* 8 */
1605         "!852+1477/200,!0/200", /* 9 */
1606         "!697+1633/200,!0/200", /* A */
1607         "!770+1633/200,!0/200", /* B */
1608         "!852+1633/200,!0/200", /* C */
1609         "!941+1633/200,!0/200", /* D */
1610         "!941+1209/200,!0/200", /* * */
1611         "!941+1477/200,!0/200" };       /* # */
1612
1613
1614         if (c)
1615         {
1616                 snprintf(myrpt->dtmf_local_str + strlen(myrpt->dtmf_local_str),sizeof(myrpt->dtmf_local_str) - 1,"%c",c);
1617                 if (!myrpt->dtmf_local_timer) 
1618                          myrpt->dtmf_local_timer = DTMF_LOCAL_STARTTIME;
1619         }
1620         /* if at timeout */
1621         if (myrpt->dtmf_local_timer == 1)
1622         {
1623                 if(debug > 6)
1624                         ast_log(LOG_NOTICE,"time out dtmf_local_timer=%i\n",myrpt->dtmf_local_timer);
1625
1626                 /* if anything in the string */
1627                 if (myrpt->dtmf_local_str[0])
1628                 {
1629                         digit = myrpt->dtmf_local_str[0];
1630                         myrpt->dtmf_local_str[0] = 0;
1631                         for(i = 1; myrpt->dtmf_local_str[i]; i++)
1632                         {
1633                                 myrpt->dtmf_local_str[i - 1] =
1634                                         myrpt->dtmf_local_str[i];
1635                         }
1636                         myrpt->dtmf_local_str[i - 1] = 0;
1637                         myrpt->dtmf_local_timer = DTMF_LOCAL_TIME;
1638                         rpt_mutex_unlock(&myrpt->lock);
1639                         if (digit >= '0' && digit <='9')
1640                                 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'0'], 0);
1641                         else if (digit >= 'A' && digit <= 'D')
1642                                 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'A'+10], 0);
1643                         else if (digit == '*')
1644                                 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[14], 0);
1645                         else if (digit == '#')
1646                                 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[15], 0);
1647                         else {
1648                                 /* not handled */
1649                                 ast_debug(1, "Unable to generate DTMF tone '%c' for '%s'\n", digit, myrpt->txchannel->name);
1650                         }
1651                         rpt_mutex_lock(&myrpt->lock);
1652                 }
1653                 else
1654                 {
1655                         myrpt->dtmf_local_timer = 0;
1656                 }
1657         }
1658 }
1659
1660 static int setdtr(int fd, int enable)
1661 {
1662 struct termios mode;
1663
1664         if (fd < 0) return -1;
1665         if (tcgetattr(fd, &mode)) {
1666                 ast_log(LOG_WARNING, "Unable to get serial parameters for dtr: %s\n", strerror(errno));
1667                 return -1;
1668         }
1669         if (enable)
1670         {
1671                 cfsetspeed(&mode, B9600);
1672         }
1673         else
1674         {
1675                 cfsetspeed(&mode, B0);
1676                 usleep(100000);
1677         }
1678         if (tcsetattr(fd, TCSADRAIN, &mode)) {
1679                 ast_log(LOG_WARNING, "Unable to set serial parameters for dtr: %s\n", strerror(errno));
1680                 return -1;
1681         }
1682         if (enable) usleep(100000);
1683         return 0;
1684 }
1685
1686 static int openserial(struct rpt *myrpt,char *fname)
1687 {
1688         struct termios mode;
1689         int fd;
1690
1691         fd = open(fname,O_RDWR);
1692         if (fd == -1)
1693         {
1694                 ast_log(LOG_WARNING,"Cannot open serial port %s\n",fname);
1695                 return -1;
1696         }
1697         memset(&mode, 0, sizeof(mode));
1698         if (tcgetattr(fd, &mode)) {
1699                 ast_log(LOG_WARNING, "Unable to get serial parameters on %s: %s\n", fname, strerror(errno));
1700                 return -1;
1701         }
1702 #ifndef SOLARIS
1703         cfmakeraw(&mode);
1704 #else
1705         mode.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
1706                         |INLCR|IGNCR|ICRNL|IXON);
1707         mode.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
1708         mode.c_cflag &= ~(CSIZE|PARENB|CRTSCTS);
1709         mode.c_cflag |= CS8;
1710         mode.c_cc[VTIME] = 3;
1711         mode.c_cc[VMIN] = 1; 
1712 #endif
1713
1714         cfsetispeed(&mode, B9600);
1715         cfsetospeed(&mode, B9600);
1716         if (tcsetattr(fd, TCSANOW, &mode)) 
1717                 ast_log(LOG_WARNING, "Unable to set serial parameters on %s: %s\n", fname, strerror(errno));
1718         if(!strcmp(myrpt->remoterig, remote_rig_kenwood)) setdtr(fd,0); 
1719         usleep(100000);
1720         if (debug)ast_log(LOG_NOTICE,"Opened serial port %s\n",fname);
1721         return(fd);     
1722 }
1723
1724 static void mdc1200_notify(struct rpt *myrpt,char *fromnode, unsigned int unit)
1725 {
1726         if (!fromnode)
1727         {
1728                 ast_verbose("Got MDC-1200 ID %04X from local system (%s)\n",
1729                         unit,myrpt->name);
1730         }
1731         else
1732         {
1733                 ast_verbose("Got MDC-1200 ID %04X from node %s (%s)\n",
1734                         unit,fromnode,myrpt->name);
1735         }
1736 }
1737
1738 #ifdef  _MDC_DECODE_H_
1739
1740 static void mdc1200_send(struct rpt *myrpt, unsigned int unit)
1741 {
1742 struct rpt_link *l;
1743 struct  ast_frame wf;
1744 char    str[200];
1745
1746
1747         sprintf(str,"I %s %04X",myrpt->name,unit);
1748
1749         wf.frametype = AST_FRAME_TEXT;
1750         wf.subclass.integer = 0;
1751         wf.offset = 0;
1752         wf.mallocd = 0;
1753         wf.datalen = strlen(str) + 1;
1754         wf.samples = 0;
1755
1756
1757         l = myrpt->links.next;
1758         /* otherwise, send it to all of em */
1759         while(l != &myrpt->links)
1760         {
1761                 if (l->name[0] == '0') 
1762                 {
1763                         l = l->next;
1764                         continue;
1765                 }
1766                 wf.data = str;
1767                 if (l->chan) ast_write(l->chan,&wf); 
1768                 l = l->next;
1769         }
1770         return;
1771 }
1772
1773 #endif
1774
1775 static char func_xlat(struct rpt *myrpt,char c,struct rpt_xlat *xlat)
1776 {
1777 time_t  now;
1778 int     gotone;
1779
1780         time(&now);
1781         gotone = 0;
1782         /* if too much time, reset the skate machine */
1783         if ((now - xlat->lastone) > MAXXLATTIME)
1784         {
1785                 xlat->funcindex = xlat->endindex = 0;
1786         }
1787         if (xlat->funccharseq[0] && (c == xlat->funccharseq[xlat->funcindex++]))
1788         {
1789                 time(&xlat->lastone);
1790                 gotone = 1;
1791                 if (!xlat->funccharseq[xlat->funcindex])
1792                 {
1793                         xlat->funcindex = xlat->endindex = 0;
1794                         return(myrpt->p.funcchar);
1795                 }
1796         } else xlat->funcindex = 0;
1797         if (xlat->endcharseq[0] && (c == xlat->endcharseq[xlat->endindex++]))
1798         {
1799                 time(&xlat->lastone);
1800                 gotone = 1;
1801                 if (!xlat->endcharseq[xlat->endindex])
1802                 {
1803                         xlat->funcindex = xlat->endindex = 0;
1804                         return(myrpt->p.endchar);
1805                 }
1806         } else xlat->endindex = 0;
1807         /* if in middle of decode seq, send nothing back */
1808         if (gotone) return(0);
1809         /* if no pass chars specified, return em all */
1810         if (!xlat->passchars[0]) return(c);
1811         /* if a "pass char", pass it */
1812         if (strchr(xlat->passchars,c)) return(c);
1813         return(0);
1814 }
1815
1816 /*
1817  * Return a pointer to the first non-whitespace character
1818  */
1819
1820 static char *eatwhite(char *s)
1821 {
1822         while((*s == ' ') || (*s == 0x09)){ /* get rid of any leading white space */
1823                 if(!*s)
1824                         break;
1825                 s++;
1826         }
1827         return s;
1828 }
1829
1830 /*
1831 * Break up a delimited string into a table of substrings
1832 *
1833 * str - delimited string ( will be modified )
1834 * strp- list of pointers to substrings (this is built by this function), NULL will be placed at end of list
1835 * limit- maximum number of substrings to process
1836 */
1837         
1838
1839
1840 static int finddelim(char *str, char *strp[], int limit)
1841 {
1842 int     i,l,inquo;
1843
1844         inquo = 0;
1845         i = 0;
1846         strp[i++] = str;
1847         if (!*str)
1848            {
1849                 strp[0] = 0;
1850                 return(0);
1851            }
1852         for(l = 0; *str && (l < limit) ; str++)
1853            {
1854                 if (*str == QUOTECHR)
1855                    {
1856                         if (inquo)
1857                            {
1858                                 *str = 0;
1859                                 inquo = 0;
1860                            }
1861                         else
1862                            {
1863                                 strp[i - 1] = str + 1;
1864                                 inquo = 1;
1865                            }
1866                 }
1867                 if ((*str == DELIMCHR) && (!inquo))
1868                 {
1869                         *str = 0;
1870                         l++;
1871                         strp[i++] = str + 1;
1872                 }
1873            }
1874         strp[i] = 0;
1875         return(i);
1876
1877 }
1878 /*
1879         send asterisk frame text message on the current tx channel
1880 */
1881 static int send_usb_txt(struct rpt *myrpt, char *txt) 
1882 {
1883         struct ast_frame wf;
1884  
1885         if (debug)ast_log(LOG_NOTICE, "send_usb_txt %s\n",txt);
1886         wf.frametype = AST_FRAME_TEXT;
1887         wf.subclass.integer = 0;
1888         wf.offset = 0;
1889         wf.mallocd = 0;
1890         wf.datalen = strlen(txt) + 1;
1891         wf.data.ptr = txt;
1892         wf.samples = 0;
1893         ast_write(myrpt->txchannel,&wf); 
1894         return 0;
1895 }
1896 /* must be called locked */
1897 static void __mklinklist(struct rpt *myrpt, struct rpt_link *mylink, char *buf)
1898 {
1899 struct rpt_link *l;
1900 char mode;
1901 int     i,spos;
1902
1903         buf[0] = 0; /* clear output buffer */
1904         if (myrpt->remote) return;
1905         /* go thru all links */
1906         for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
1907         {
1908                 /* if is not a real link, ignore it */
1909                 if (l->name[0] == '0') continue;
1910                 /* don't count our stuff */
1911                 if (l == mylink) continue;
1912                 if (mylink && (!strcmp(l->name,mylink->name))) continue;
1913                 /* figure out mode to report */
1914                 mode = 'T'; /* use Tranceive by default */
1915                 if (!l->mode) mode = 'R'; /* indicate RX for our mode */
1916                 if (!l->thisconnected)  mode = 'C'; /* indicate connecting */
1917                 spos = strlen(buf); /* current buf size (b4 we add our stuff) */
1918                 if (spos)
1919                 {
1920                         strcat(buf,",");
1921                         spos++;
1922                 }
1923                 /* add nodes into buffer */
1924                 if (l->linklist[0])
1925                 {
1926                         snprintf(buf + spos,MAXLINKLIST - spos,
1927                                 "%c%s,%s",mode,l->name,l->linklist);
1928                 }
1929                 else /* if no nodes, add this node into buffer */
1930                 {
1931                         snprintf(buf + spos,MAXLINKLIST - spos,
1932                                 "%c%s",mode,l->name);
1933                 }
1934                 /* if we are in tranceive mode, let all modes stand */
1935                 if (mode == 'T') continue;
1936                 /* downgrade everyone on this node if appropriate */
1937                 for(i = spos; buf[i]; i++)
1938                 {
1939                         if (buf[i] == 'T') buf[i] = mode;
1940                         if ((buf[i] == 'R') && (mode == 'C')) buf[i] = mode;
1941                 }
1942         }
1943         return;
1944 }
1945
1946 /* must be called locked */
1947 static void __kickshort(struct rpt *myrpt)
1948 {
1949 struct rpt_link *l;
1950
1951         for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
1952         {
1953                 /* if is not a real link, ignore it */
1954                 if (l->name[0] == '0') continue;
1955                 l->linklisttimer = LINKLISTSHORTTIME;
1956         }
1957         myrpt->linkposttimer = LINKPOSTSHORTTIME;
1958         return;
1959 }
1960
1961 static void statpost(struct rpt *myrpt,char *pairs)
1962 {
1963 char *str,*astr;
1964 char *astrs[100];
1965 int     n,pid;
1966 time_t  now;
1967 unsigned int seq;
1968
1969         if (!myrpt->p.statpost_url) return;
1970         str = ast_malloc(strlen(pairs) + strlen(myrpt->p.statpost_url) + 200);
1971         astr = ast_strdup(myrpt->p.statpost_program);
1972         if ((!str) || (!astr)) {
1973                 ast_free(str);
1974                 ast_free(astr);
1975                 return;
1976         }
1977         n = finddelim(astr,astrs,100);
1978         if (n < 1) {
1979                 ast_free(str);
1980                 ast_free(astr);
1981                 return;
1982         }
1983         ast_mutex_lock(&myrpt->statpost_lock);
1984         seq = ++myrpt->statpost_seqno;
1985         ast_mutex_unlock(&myrpt->statpost_lock);
1986         astrs[n++] = str;
1987         astrs[n] = NULL;
1988         time(&now);
1989         sprintf(str,"%s?node=%s&time=%u&seqno=%u",myrpt->p.statpost_url,
1990                 myrpt->name,(unsigned int) now,seq);
1991         if (pairs) sprintf(str + strlen(str),"&%s",pairs);
1992         if (!(pid = ast_safe_fork(0)))
1993         {
1994                 execv(astrs[0],astrs);
1995                 ast_log(LOG_ERROR, "exec of %s failed.\n", astrs[0]);
1996                 perror("asterisk");
1997                 exit(0);
1998         }
1999         ast_free(astr);
2000         ast_free(str);
2001         return;
2002 }
2003
2004 static char *node_lookup(struct rpt *myrpt,char *digitbuf)
2005 {
2006
2007 char *val;
2008 int longestnode,j;
2009 struct stat mystat;
2010 static time_t last = 0;
2011 static struct ast_config *ourcfg = NULL;
2012 struct ast_variable *vp;
2013
2014         /* try to look it up locally first */
2015         val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
2016         if (val) return(val);
2017         ast_mutex_lock(&nodelookuplock);
2018         /* if file does not exist */
2019         if (stat(myrpt->p.extnodefile,&mystat) == -1)
2020         {
2021                 if (ourcfg) ast_config_destroy(ourcfg);
2022                 ourcfg = NULL;
2023                 ast_mutex_unlock(&nodelookuplock);
2024                 return(NULL);
2025         }
2026         /* if we need to reload */
2027         if (mystat.st_mtime > last)
2028         {
2029                 if (ourcfg) ast_config_destroy(ourcfg);
2030 #ifdef  NEW_ASTERISK
2031                 ourcfg = ast_config_load(myrpt->p.extnodefile,config_flags);
2032 #else
2033                 ourcfg = ast_config_load(myrpt->p.extnodefile);
2034 #endif
2035                 /* if file not there, just bail */
2036                 if (!ourcfg || ourcfg == CONFIG_STATUS_FILEINVALID)
2037                 {
2038                         ast_mutex_unlock(&nodelookuplock);
2039                         return(NULL);
2040                 }
2041                 /* reset "last" time */
2042                 last = mystat.st_mtime;
2043
2044                 /* determine longest node length again */               
2045                 longestnode = 0;
2046                 vp = ast_variable_browse(myrpt->cfg, myrpt->p.nodes);
2047                 while(vp){
2048                         j = strlen(vp->name);
2049                         if (j > longestnode)
2050                                 longestnode = j;
2051                         vp = vp->next;
2052                 }
2053
2054                 vp = ast_variable_browse(ourcfg, myrpt->p.extnodes);
2055                 while(vp){
2056                         j = strlen(vp->name);
2057                         if (j > longestnode)
2058                                 longestnode = j;
2059                         vp = vp->next;
2060                 }
2061
2062                 myrpt->longestnode = longestnode;
2063         }
2064         val = NULL;
2065         if (ourcfg)
2066                 val = (char *) ast_variable_retrieve(ourcfg, myrpt->p.extnodes, digitbuf);
2067         ast_mutex_unlock(&nodelookuplock);
2068         return(val);
2069 }
2070
2071 /*
2072 * Match a keyword in a list, and return index of string plus 1 if there was a match,* else return 0.
2073 * If param is passed in non-null, then it will be set to the first character past the match
2074 */
2075
2076 static int matchkeyword(char *string, char **param, char *keywords[])
2077 {
2078 int     i,ls;
2079         for( i = 0 ; keywords[i] ; i++){
2080                 ls = strlen(keywords[i]);
2081                 if(!ls){
2082                         *param = NULL;
2083                         return 0;
2084                 }
2085                 if(!strncmp(string, keywords[i], ls)){
2086                         if(param)
2087                                 *param = string + ls;
2088                         return i + 1; 
2089                 }
2090         }
2091         *param = NULL;
2092         return 0;
2093 }
2094
2095 /*
2096 * Skip characters in string which are in charlist, and return a pointer to the
2097 * first non-matching character
2098 */
2099
2100 static char *skipchars(char *string, char *charlist)
2101 {
2102 int i;  
2103         while(*string){
2104                 for(i = 0; charlist[i] ; i++){
2105                         if(*string == charlist[i]){
2106                                 string++;
2107                                 break;
2108                         }
2109                 }
2110                 if(!charlist[i])
2111                         return string;
2112         }
2113         return string;
2114 }
2115
2116 static int myatoi(const char *str)
2117 {
2118         int     ret;
2119
2120         if (!str) {
2121                 return -1;
2122         }
2123
2124         /* leave this %i alone, non-base-10 input is useful here */
2125         if (sscanf(str, "%30i", &ret) != 1) {
2126                 return -1;
2127         }
2128
2129         return ret;
2130 }
2131
2132 static int mycompar(const void *a, const void *b)
2133 {
2134 char    **x = (char **) a;
2135 char    **y = (char **) b;
2136 int     xoff,yoff;
2137
2138         if ((**x < '0') || (**x > '9')) xoff = 1; else xoff = 0;
2139         if ((**y < '0') || (**y > '9')) yoff = 1; else yoff = 0;
2140         return(strcmp((*x) + xoff,(*y) + yoff));
2141 }
2142
2143 static int topcompar(const void *a, const void *b)
2144 {
2145 struct rpt_topkey *x = (struct rpt_topkey *) a;
2146 struct rpt_topkey *y = (struct rpt_topkey *) b;
2147
2148         return(x->timesince - y->timesince);
2149 }
2150
2151 #ifdef  __RPT_NOTCH
2152
2153 /* rpt filter routine */
2154 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
2155 {
2156 int     i,j;
2157 struct  rptfilter *f;
2158
2159         for(i = 0; i < len; i++)
2160         {
2161                 for(j = 0; j < MAXFILTERS; j++)
2162                 {
2163                         f = &myrpt->filters[j];
2164                         if (!*f->desc) continue;
2165                         f->x0 = f->x1; f->x1 = f->x2;
2166                         f->x2 = ((float)buf[i]) / f->gain;
2167                         f->y0 = f->y1; f->y1 = f->y2;
2168                         f->y2 =   (f->x0 + f->x2) +   f->const0 * f->x1
2169                                      + (f->const1 * f->y0) + (f->const2 * f->y1);
2170                         buf[i] = (short)f->y2;
2171                 }
2172         }
2173 }
2174
2175 #endif
2176
2177
2178 /*
2179  Get the time for the machine's time zone
2180  Note: Asterisk requires a copy of localtime
2181  in the /etc directory for this to work properly.
2182  If /etc/localtime is not present, you will get
2183  GMT time! This is especially important on systems
2184  running embedded linux distributions as they don't usually
2185  have support for locales. 
2186
2187  If OLD_ASTERISK is defined, then the older localtime_r
2188  function will be used. The /etc/localtime file is not
2189  required in this case. This provides backward compatibility
2190  with Asterisk 1.2 systems.
2191
2192 */
2193
2194 #ifdef  NEW_ASTERISK
2195 static void rpt_localtime( time_t * t, struct ast_tm *lt)
2196 {
2197         struct timeval when;
2198
2199         when.tv_sec = *t;
2200         when.tv_usec = 0;
2201         ast_localtime(&when, lt, NULL);
2202 }
2203
2204 #else
2205 static void rpt_localtime( time_t * t, struct tm *lt)
2206 {
2207 #ifdef OLD_ASTERISK
2208         localtime_r(t, lt);
2209 #else
2210         ast_localtime(t, lt, NULL);
2211 #endif
2212 }
2213 #endif
2214
2215
2216 /* Retrieve an int from a config file */
2217                                                                                 
2218 static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl)
2219 {
2220         char *var;
2221         int ret;
2222         char include_zero = 0;
2223
2224         if(min < 0){ /* If min is negative, this means include 0 as a valid entry */
2225                 min = -min;
2226                 include_zero = 1;
2227         }           
2228                                                                      
2229         var = (char *) ast_variable_retrieve(myrpt->cfg, category, name);
2230         if(var){
2231                 ret = myatoi(var);
2232                 if(include_zero && !ret)
2233                         return 0;
2234                 if(ret < min)
2235                         ret = min;
2236                 if(ret > max)
2237                         ret = max;
2238         }
2239         else
2240                 ret = defl;
2241         return ret;
2242 }
2243
2244
2245 static void load_rpt_vars(int n,int init)
2246 {
2247 char *this,*val;
2248 int     i,j,longestnode;
2249 struct ast_variable *vp;
2250 struct ast_config *cfg;
2251 char *strs[100];
2252 char s1[256];
2253 static char *cs_keywords[] = {"rptena","rptdis","apena","apdis","lnkena","lnkdis","totena","totdis","skena","skdis",
2254                                 "ufena","ufdis","atena","atdis",NULL};
2255
2256         if (option_verbose > 2)
2257                 ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n",
2258                         (init) ? "Loading initial" : "Re-Loading",rpt_vars[n].name);
2259         ast_mutex_lock(&rpt_vars[n].lock);
2260         if (rpt_vars[n].cfg) ast_config_destroy(rpt_vars[n].cfg);
2261 #ifdef  NEW_ASTERISK
2262         cfg = ast_config_load("rpt.conf",config_flags);
2263 #else
2264         cfg = ast_config_load("rpt.conf");
2265 #endif
2266         if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
2267                 ast_mutex_unlock(&rpt_vars[n].lock);
2268                 ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
2269                 pthread_exit(NULL);
2270         }
2271         rpt_vars[n].cfg = cfg; 
2272         this = rpt_vars[n].name;
2273         memset(&rpt_vars[n].p,0,sizeof(rpt_vars[n].p));
2274         if (init)
2275         {
2276                 char *cp;
2277                 int savearea = (char *)&rpt_vars[n].p - (char *)&rpt_vars[n];
2278
2279                 cp = (char *) &rpt_vars[n].p;
2280                 memset(cp + sizeof(rpt_vars[n].p),0,
2281                         sizeof(rpt_vars[n]) - (sizeof(rpt_vars[n].p) + savearea));
2282                 rpt_vars[n].tele.next = &rpt_vars[n].tele;
2283                 rpt_vars[n].tele.prev = &rpt_vars[n].tele;
2284                 rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
2285                 rpt_vars[n].tailmessagen = 0;
2286         }
2287 #ifdef  __RPT_NOTCH
2288         /* zot out filters stuff */
2289         memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
2290 #endif
2291         val = (char *) ast_variable_retrieve(cfg,this,"context");
2292         if (val) rpt_vars[n].p.ourcontext = val;
2293         else rpt_vars[n].p.ourcontext = this;
2294         val = (char *) ast_variable_retrieve(cfg,this,"callerid");
2295         if (val) rpt_vars[n].p.ourcallerid = val;
2296         val = (char *) ast_variable_retrieve(cfg,this,"accountcode");
2297         if (val) rpt_vars[n].p.acctcode = val;
2298         val = (char *) ast_variable_retrieve(cfg,this,"idrecording");
2299         if (val) rpt_vars[n].p.ident = val;
2300         val = (char *) ast_variable_retrieve(cfg,this,"hangtime");
2301         if (val) rpt_vars[n].p.hangtime = atoi(val);
2302                 else rpt_vars[n].p.hangtime = HANGTIME;
2303         val = (char *) ast_variable_retrieve(cfg,this,"althangtime");
2304         if (val) rpt_vars[n].p.althangtime = atoi(val);
2305                 else rpt_vars[n].p.althangtime = HANGTIME;
2306         val = (char *) ast_variable_retrieve(cfg,this,"totime");
2307         if (val) rpt_vars[n].p.totime = atoi(val);
2308                 else rpt_vars[n].p.totime = TOTIME;
2309         val = (char *) ast_variable_retrieve(cfg,this,"voxtimeout");
2310         if (val) rpt_vars[n].p.voxtimeout_ms = atoi(val);
2311                 else rpt_vars[n].p.voxtimeout_ms = VOX_TIMEOUT_MS;
2312         val = (char *) ast_variable_retrieve(cfg,this,"voxrecover");
2313         if (val) rpt_vars[n].p.voxrecover_ms = atoi(val);
2314                 else rpt_vars[n].p.voxrecover_ms = VOX_RECOVER_MS;
2315         val = (char *) ast_variable_retrieve(cfg,this,"simplexpatchdelay");
2316         if (val) rpt_vars[n].p.simplexpatchdelay = atoi(val);
2317                 else rpt_vars[n].p.simplexpatchdelay = SIMPLEX_PATCH_DELAY;
2318         val = (char *) ast_variable_retrieve(cfg,this,"simplexphonedelay");
2319         if (val) rpt_vars[n].p.simplexphonedelay = atoi(val);
2320                 else rpt_vars[n].p.simplexphonedelay = SIMPLEX_PHONE_DELAY;
2321         val = (char *) ast_variable_retrieve(cfg,this,"statpost_program");
2322         if (val) rpt_vars[n].p.statpost_program = val;
2323                 else rpt_vars[n].p.statpost_program = STATPOST_PROGRAM;
2324         rpt_vars[n].p.statpost_url = 
2325                 (char *) ast_variable_retrieve(cfg,this,"statpost_url");
2326         rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0);                
2327         rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0);              
2328         rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2);
2329         rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", -60000, 2400000, IDTIME);        /* Enforce a min max including zero */
2330         rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
2331         val = (char *) ast_variable_retrieve(cfg,this,"tonezone");
2332         if (val) rpt_vars[n].p.tonezone = val;
2333         rpt_vars[n].p.tailmessages[0] = 0;
2334         rpt_vars[n].p.tailmessagemax = 0;
2335         val = (char *) ast_variable_retrieve(cfg,this,"tailmessagelist");
2336         if (val) rpt_vars[n].p.tailmessagemax = finddelim(val, rpt_vars[n].p.tailmessages, 500);
2337         val = (char *) ast_variable_retrieve(cfg,this,"memory");
2338         if (!val) val = MEMORY;
2339         rpt_vars[n].p.memory = val;
2340         val = (char *) ast_variable_retrieve(cfg,this,"macro");
2341         if (!val) val = MACRO;
2342         rpt_vars[n].p.macro = val;
2343         val = (char *) ast_variable_retrieve(cfg,this,"tonemacro");
2344         if (!val) val = TONEMACRO;
2345         rpt_vars[n].p.tonemacro = val;
2346         val = (char *) ast_variable_retrieve(cfg,this,"startup_macro");
2347         if (val) rpt_vars[n].p.startupmacro = val;
2348         val = (char *) ast_variable_retrieve(cfg,this,"iobase");
2349         /* do not use atoi() here, we need to be able to have
2350                 the input specified in hex or decimal so we use
2351                 sscanf with a %i */
2352         if ((!val) || (sscanf(val,"%30i",&rpt_vars[n].p.iobase) != 1))
2353                 rpt_vars[n].p.iobase = DEFAULT_IOBASE;
2354         val = (char *) ast_variable_retrieve(cfg,this,"ioport");
2355         rpt_vars[n].p.ioport = val;
2356         val = (char *) ast_variable_retrieve(cfg,this,"functions");
2357         if (!val)
2358                 {
2359                         val = FUNCTIONS;
2360                         rpt_vars[n].p.simple = 1;
2361                 } 
2362         rpt_vars[n].p.functions = val;
2363         val =  (char *) ast_variable_retrieve(cfg,this,"link_functions");
2364         if (val) rpt_vars[n].p.link_functions = val;
2365         else 
2366                 rpt_vars[n].p.link_functions = rpt_vars[n].p.functions;
2367         val = (char *) ast_variable_retrieve(cfg,this,"phone_functions");
2368         if (val) rpt_vars[n].p.phone_functions = val;
2369         val = (char *) ast_variable_retrieve(cfg,this,"dphone_functions");
2370         if (val) rpt_vars[n].p.dphone_functions = val;
2371         val = (char *) ast_variable_retrieve(cfg,this,"alt_functions");
2372         if (val) rpt_vars[n].p.alt_functions = val;
2373         val = (char *) ast_variable_retrieve(cfg,this,"funcchar");
2374         if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else 
2375                 rpt_vars[n].p.funcchar = *val;          
2376         val = (char *) ast_variable_retrieve(cfg,this,"endchar");
2377         if (!val) rpt_vars[n].p.endchar = ENDCHAR; else 
2378                 rpt_vars[n].p.endchar = *val;           
2379         val = (char *) ast_variable_retrieve(cfg,this,"nobusyout");
2380         if (val) rpt_vars[n].p.nobusyout = ast_true(val);
2381         val = (char *) ast_variable_retrieve(cfg,this,"notelemtx");
2382         if (val) rpt_vars[n].p.notelemtx = ast_true(val);
2383         val = (char *) ast_variable_retrieve(cfg,this,"propagate_dtmf");
2384         if (val) rpt_vars[n].p.propagate_dtmf = ast_true(val);
2385         val = (char *) ast_variable_retrieve(cfg,this,"propagate_phonedtmf");
2386         if (val) rpt_vars[n].p.propagate_phonedtmf = ast_true(val);
2387         val = (char *) ast_variable_retrieve(cfg,this,"linktolink");
2388         if (val) rpt_vars[n].p.linktolink = ast_true(val);
2389         val = (char *) ast_variable_retrieve(cfg,this,"nodes");
2390         if (!val) val = NODES;
2391         rpt_vars[n].p.nodes = val;
2392         val = (char *) ast_variable_retrieve(cfg,this,"extnodes");
2393         if (!val) val = EXTNODES;
2394         rpt_vars[n].p.extnodes = val;
2395         val = (char *) ast_variable_retrieve(cfg,this,"extnodefile");
2396         if (!val) val = EXTNODEFILE;
2397         rpt_vars[n].p.extnodefile = val;
2398         val = (char *) ast_variable_retrieve(cfg,this,"archivedir");
2399         if (val) rpt_vars[n].p.archivedir = val;
2400         val = (char *) ast_variable_retrieve(cfg,this,"authlevel");
2401         if (val) rpt_vars[n].p.authlevel = atoi(val); 
2402         else rpt_vars[n].p.authlevel = 0;
2403         val = (char *) ast_variable_retrieve(cfg,this,"parrot");
2404         if (val) rpt_vars[n].p.parrotmode = ast_true(val) * 2;
2405         else rpt_vars[n].p.parrotmode = 0;
2406         val = (char *) ast_variable_retrieve(cfg,this,"parrottime");
2407         if (val) rpt_vars[n].p.parrottime = atoi(val); 
2408         else rpt_vars[n].p.parrottime = PARROTTIME;
2409         val = (char *) ast_variable_retrieve(cfg,this,"rptnode");
2410         rpt_vars[n].p.rptnode = val;
2411         val = (char *) ast_variable_retrieve(cfg,this,"mars");
2412         if (val) rpt_vars[n].p.remote_mars = atoi(val); 
2413         else rpt_vars[n].p.remote_mars = 0;
2414         val = (char *) ast_variable_retrieve(cfg,this,"monminblocks");
2415         if (val) rpt_vars[n].p.monminblocks = atol(val); 
2416         else rpt_vars[n].p.monminblocks = DEFAULT_MONITOR_MIN_DISK_BLOCKS;
2417         val = (char *) ast_variable_retrieve(cfg,this,"remote_inact_timeout");
2418         if (val) rpt_vars[n].p.remoteinacttimeout = atoi(val); 
2419         else rpt_vars[n].p.remoteinacttimeout = DEFAULT_REMOTE_INACT_TIMEOUT;
2420         val = (char *) ast_variable_retrieve(cfg,this,"civaddr");
2421         if (val) rpt_vars[n].p.civaddr = atoi(val); 
2422         else rpt_vars[n].p.civaddr = DEFAULT_CIV_ADDR;
2423         val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout");
2424         if (val) rpt_vars[n].p.remotetimeout = atoi(val); 
2425         else rpt_vars[n].p.remotetimeout = DEFAULT_REMOTE_TIMEOUT;
2426         val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning");
2427         if (val) rpt_vars[n].p.remotetimeoutwarning = atoi(val); 
2428         else rpt_vars[n].p.remotetimeoutwarning = DEFAULT_REMOTE_TIMEOUT_WARNING;
2429         val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning_freq");
2430         if (val) rpt_vars[n].p.remotetimeoutwarningfreq = atoi(val); 
2431         else rpt_vars[n].p.remotetimeoutwarningfreq = DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ;
2432 #ifdef  __RPT_NOTCH
2433         val = (char *) ast_variable_retrieve(cfg,this,"rxnotch");
2434         if (val) {
2435                 i = finddelim(val,strs,MAXFILTERS * 2);
2436                 i &= ~1; /* force an even number, rounded down */
2437                 if (i >= 2) for(j = 0; j < i; j += 2)
2438                 {
2439                         rpt_mknotch(atof(strs[j]),atof(strs[j + 1]),
2440                           &rpt_vars[n].filters[j >> 1].gain,
2441                             &rpt_vars[n].filters[j >> 1].const0,
2442                                 &rpt_vars[n].filters[j >> 1].const1,
2443                                     &rpt_vars[n].filters[j >> 1].const2);
2444                         sprintf(rpt_vars[n].filters[j >> 1].desc,"%s Hz, BW = %s",
2445                                 strs[j],strs[j + 1]);
2446                 }
2447
2448         }
2449 #endif
2450         val = (char *) ast_variable_retrieve(cfg,this,"inxlat");
2451         if (val) {
2452                 memset(&rpt_vars[n].p.inxlat,0,sizeof(struct rpt_xlat));
2453                 i = finddelim(val,strs,3);
2454                 if (i) strncpy(rpt_vars[n].p.inxlat.funccharseq,strs[0],MAXXLAT - 1);
2455                 if (i > 1) strncpy(rpt_vars[n].p.inxlat.endcharseq,strs[1],MAXXLAT - 1);
2456                 if (i > 2) strncpy(rpt_vars[n].p.inxlat.passchars,strs[2],MAXXLAT - 1);
2457         }
2458         val = (char *) ast_variable_retrieve(cfg,this,"outxlat");
2459         if (val) {
2460                 memset(&rpt_vars[n].p.outxlat,0,sizeof(struct rpt_xlat));
2461                 i = finddelim(val,strs,3);
2462                 if (i) strncpy(rpt_vars[n].p.outxlat.funccharseq,strs[0],MAXXLAT - 1);
2463                 if (i > 1) strncpy(rpt_vars[n].p.outxlat.endcharseq,strs[1],MAXXLAT - 1);
2464                 if (i > 2) strncpy(rpt_vars[n].p.outxlat.passchars,strs[2],MAXXLAT - 1);
2465         }
2466         /* retreive the stanza name for the control states if there is one */
2467         val = (char *) ast_variable_retrieve(cfg,this,"controlstates");
2468         rpt_vars[n].p.csstanzaname = val;
2469                 
2470         /* retreive the stanza name for the scheduler if there is one */
2471         val = (char *) ast_variable_retrieve(cfg,this,"scheduler");
2472         rpt_vars[n].p.skedstanzaname = val;
2473
2474         /* retreive the stanza name for the txlimits */
2475         val = (char *) ast_variable_retrieve(cfg,this,"txlimits");
2476         rpt_vars[n].p.txlimitsstanzaname = val;
2477
2478         longestnode = 0;
2479
2480         vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
2481                 
2482         while(vp){
2483                 j = strlen(vp->name);
2484                 if (j > longestnode)
2485                         longestnode = j;
2486                 vp = vp->next;
2487         }
2488
2489         rpt_vars[n].longestnode = longestnode;
2490                 
2491         /*
2492         * For this repeater, Determine the length of the longest function 
2493         */
2494         rpt_vars[n].longestfunc = 0;
2495         vp = ast_variable_browse(cfg, rpt_vars[n].p.functions);
2496         while(vp){
2497                 j = strlen(vp->name);
2498                 if (j > rpt_vars[n].longestfunc)
2499                         rpt_vars[n].longestfunc = j;
2500                 vp = vp->next;
2501         }
2502         /*
2503         * For this repeater, Determine the length of the longest function 
2504         */
2505         rpt_vars[n].link_longestfunc = 0;
2506         vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions);
2507         while(vp){
2508                 j = strlen(vp->name);
2509                 if (j > rpt_vars[n].link_longestfunc)
2510                         rpt_vars[n].link_longestfunc = j;
2511                 vp = vp->next;
2512         }
2513         rpt_vars[n].phone_longestfunc = 0;
2514         if (rpt_vars[n].p.phone_functions)
2515         {
2516                 vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions);
2517                 while(vp){
2518                         j = strlen(vp->name);
2519                         if (j > rpt_vars[n].phone_longestfunc)
2520                                 rpt_vars[n].phone_longestfunc = j;
2521                         vp = vp->next;
2522                 }
2523         }
2524         rpt_vars[n].dphone_longestfunc = 0;
2525         if (rpt_vars[n].p.dphone_functions)
2526         {
2527                 vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions);
2528                 while(vp){
2529                         j = strlen(vp->name);
2530                         if (j > rpt_vars[n].dphone_longestfunc)
2531                                 rpt_vars[n].dphone_longestfunc = j;
2532                         vp = vp->next;
2533                 }
2534         }
2535         rpt_vars[n].alt_longestfunc = 0;
2536         if (rpt_vars[n].p.alt_functions)
2537         {
2538                 vp = ast_variable_browse(cfg, rpt_vars[n].p.alt_functions);
2539                 while(vp){
2540                         j = strlen(vp->name);
2541                         if (j > rpt_vars[n].alt_longestfunc)
2542                                 rpt_vars[n].alt_longestfunc = j;
2543                         vp = vp->next;
2544                 }
2545         }
2546         rpt_vars[n].macro_longest = 1;
2547         vp = ast_variable_browse(cfg, rpt_vars[n].p.macro);
2548         while(vp){
2549                 j = strlen(vp->name);
2550                 if (j > rpt_vars[n].macro_longest)
2551                         rpt_vars[n].macro_longest = j;
2552                 vp = vp->next;
2553         }
2554         
2555         /* Browse for control states */
2556         if(rpt_vars[n].p.csstanzaname)
2557                 vp = ast_variable_browse(cfg, rpt_vars[n].p.csstanzaname);
2558         else
2559                 vp = NULL;
2560         for( i = 0 ; vp && (i < MAX_SYSSTATES) ; i++){ /* Iterate over the number of control state lines in the stanza */
2561                 int k,nukw,statenum;
2562                 statenum=atoi(vp->name);
2563                 strncpy(s1, vp->value, 255);
2564                 s1[255] = 0;
2565                 nukw  = finddelim(s1,strs,32);
2566                 
2567                 for (k = 0 ; k < nukw ; k++){ /* for each user specified keyword */     
2568                         for(j = 0 ; cs_keywords[j] != NULL ; j++){ /* try to match to one in our internal table */
2569                                 if(!strcmp(strs[k],cs_keywords[j])){
2570                                         switch(j){
2571                                                 case 0: /* rptena */
2572                                                         rpt_vars[n].p.s[statenum].txdisable = 0;
2573                                                         break;
2574                                                 case 1: /* rptdis */
2575                                                         rpt_vars[n].p.s[statenum].txdisable = 1;
2576                                                         break;
2577                         
2578                                                 case 2: /* apena */
2579                                                         rpt_vars[n].p.s[statenum].autopatchdisable = 0;
2580                                                         break;
2581
2582                                                 case 3: /* apdis */
2583                                                         rpt_vars[n].p.s[statenum].autopatchdisable = 1;
2584                                                         break;
2585
2586                                                 case 4: /* lnkena */
2587                                                         rpt_vars[n].p.s[statenum].linkfundisable = 0;
2588                                                         break;
2589         
2590                                                 case 5: /* lnkdis */
2591                                                         rpt_vars[n].p.s[statenum].linkfundisable = 1;
2592                                                         break;
2593
2594                                                 case 6: /* totena */
2595                                                         rpt_vars[n].p.s[statenum].totdisable = 0;
2596                                                         break;
2597                                         
2598                                                 case 7: /* totdis */
2599                                                         rpt_vars[n].p.s[statenum].totdisable = 1;
2600                                                         break;
2601
2602                                                 case 8: /* skena */
2603                                                         rpt_vars[n].p.s[statenum].schedulerdisable = 0;
2604                                                         break;
2605
2606                                                 case 9: /* skdis */
2607                                                         rpt_vars[n].p.s[statenum].schedulerdisable = 1;
2608                                                         break;
2609
2610                                                 case 10: /* ufena */
2611                                                         rpt_vars[n].p.s[statenum].userfundisable = 0;
2612                                                         break;
2613
2614                                                 case 11: /* ufdis */
2615                                                         rpt_vars[n].p.s[statenum].userfundisable = 1;
2616                                                         break;
2617
2618                                                 case 12: /* atena */
2619                                                         rpt_vars[n].p.s[statenum].alternatetail = 1;
2620                                                         break;
2621
2622                                                 case 13: /* atdis */
2623                                                         rpt_vars[n].p.s[statenum].alternatetail = 0;
2624                                                         break;
2625                         
2626                                                 default:
2627                                                         ast_log(LOG_WARNING,
2628                                                                 "Unhandled control state keyword %s", cs_keywords[i]);
2629                                                         break;
2630                                         }
2631                                 }
2632                         }
2633                 }
2634                 vp = vp->next;
2635         }
2636         ast_mutex_unlock(&rpt_vars[n].lock);
2637 }
2638
2639 /*
2640 * Enable or disable debug output at a given level at the console
2641 */
2642 static int rpt_do_debug(int fd, int argc, const char * const *argv)
2643 {
2644         int newlevel;
2645
2646         if (argc != 4) {
2647                 return RESULT_SHOWUSAGE;
2648         }
2649
2650         newlevel = myatoi(argv[3]);
2651
2652         if (newlevel < 0 || newlevel > 7) {
2653                 return RESULT_SHOWUSAGE;
2654         }
2655
2656         if (newlevel) {
2657                 ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
2658         } else {
2659                 ast_cli(fd, "app_rpt Debugging disabled\n");
2660         }
2661
2662         debug = newlevel;
2663
2664         return RESULT_SUCCESS;
2665 }
2666
2667 /*
2668 * Dump rpt struct debugging onto console
2669 */
2670                                                                                                                                  
2671 static int rpt_do_dump(int fd, int argc, const char * const *argv)
2672 {
2673         int i;
2674
2675         if (argc != 3)
2676                 return RESULT_SHOWUSAGE;
2677
2678         for(i = 0; i < nrpts; i++)
2679         {
2680                 if (!strcmp(argv[2],rpt_vars[i].name))
2681                 {
2682                         rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
2683                         ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
2684                         return RESULT_SUCCESS;
2685                 }
2686         }
2687         return RESULT_FAILURE;
2688 }
2689
2690 /*
2691 * Dump statistics onto console
2692 */
2693
2694 static int rpt_do_stats(int fd, int argc, const char * const *argv)
2695 {
2696         int i,j,numoflinks;
2697         int dailytxtime, dailykerchunks;
2698         time_t now;
2699         int totalkerchunks, dailykeyups, totalkeyups, timeouts;
2700         int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
2701         int uptime;
2702         long long totaltxtime;
2703         struct  rpt_link *l;
2704         char *listoflinks[MAX_STAT_LINKS];      
2705         char *lastdtmfcommand,*parrot_ena;
2706         char *tot_state, *ider_state, *patch_state;
2707         char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
2708         char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
2709         struct rpt *myrpt;
2710
2711         static char *not_applicable = "N/A";
2712
2713         if(argc != 3)
2714                 return RESULT_SHOWUSAGE;
2715
2716         tot_state = ider_state = 
2717         patch_state = reverse_patch_state = 
2718         input_signal = not_applicable;
2719         called_number = lastdtmfcommand = NULL;
2720
2721         time(&now);
2722         for(i = 0; i < nrpts; i++)
2723         {
2724                 if (!strcmp(argv[2],rpt_vars[i].name)){
2725                         /* Make a copy of all stat variables while locked */
2726                         myrpt = &rpt_vars[i];
2727                         rpt_mutex_lock(&myrpt->lock); /* LOCK */
2728                         uptime = (int)(now - starttime);
2729                         dailytxtime = myrpt->dailytxtime;
2730                         totaltxtime = myrpt->totaltxtime;
2731                         dailykeyups = myrpt->dailykeyups;
2732                         totalkeyups = myrpt->totalkeyups;
2733                         dailykerchunks = myrpt->dailykerchunks;
2734                         totalkerchunks = myrpt->totalkerchunks;
2735                         dailyexecdcommands = myrpt->dailyexecdcommands;
2736                         totalexecdcommands = myrpt->totalexecdcommands;
2737                         timeouts = myrpt->timeouts;
2738
2739                         /* Traverse the list of connected nodes */
2740                         reverse_patch_state = "DOWN";
2741                         numoflinks = 0;
2742                         l = myrpt->links.next;
2743                         while(l && (l != &myrpt->links)){
2744                                 if(numoflinks >= MAX_STAT_LINKS){
2745                                         ast_log(LOG_NOTICE,
2746                                         "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
2747                                         break;
2748                                 }
2749                                 if (l->name[0] == '0'){ /* Skip '0' nodes */
2750                                         reverse_patch_state = "UP";
2751                                         l = l->next;
2752                                         continue;
2753                                 }
2754                                 listoflinks[numoflinks] = ast_strdup(l->name);
2755                                 if(listoflinks[numoflinks] == NULL){
2756                                         break;
2757                                 }
2758                                 else{
2759                                         numoflinks++;
2760                                 }
2761                                 l = l->next;
2762                         }
2763
2764                         if(myrpt->keyed)
2765                                 input_signal = "YES";
2766                         else
2767                                 input_signal = "NO";
2768
2769                         if(myrpt->p.parrotmode)
2770                                 parrot_ena = "ENABLED";
2771                         else
2772                                 parrot_ena = "DISABLED";
2773
2774                         if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
2775                                 sys_ena = "DISABLED";
2776                         else
2777                                 sys_ena = "ENABLED";
2778
2779                         if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
2780                                 tot_ena = "DISABLED";
2781                         else
2782                                 tot_ena = "ENABLED";
2783
2784                         if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
2785                                 link_ena = "DISABLED";
2786                         else
2787                                 link_ena = "ENABLED";
2788
2789                         if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
2790                                 patch_ena = "DISABLED";
2791                         else
2792                                 patch_ena = "ENABLED";
2793
2794                         if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
2795                                 sch_ena = "DISABLED";
2796                         else
2797                                 sch_ena = "ENABLED";
2798
2799                         if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
2800                                 user_funs = "DISABLED";
2801                         else
2802                                 user_funs = "ENABLED";
2803
2804                         if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
2805                                 tail_type = "ALTERNATE";
2806                         else
2807                                 tail_type = "STANDARD";
2808
2809                         if(!myrpt->totimer)
2810                                 tot_state = "TIMED OUT!";
2811                         else if(myrpt->totimer != myrpt->p.totime)
2812                                 tot_state = "ARMED";
2813                         else
2814                                 tot_state = "RESET";
2815
2816                         if(myrpt->tailid)
2817                                 ider_state = "QUEUED IN TAIL";
2818                         else if(myrpt->mustid)
2819                                 ider_state = "QUEUED FOR CLEANUP";
2820                         else
2821                                 ider_state = "CLEAN";
2822
2823                         switch(myrpt->callmode){
2824                                 case 1:
2825                                         patch_state = "DIALING";
2826                                         break;
2827                                 case 2:
2828                                         patch_state = "CONNECTING";
2829                                         break;
2830                                 case 3:
2831                                         patch_state = "UP";
2832                                         break;
2833
2834                                 case 4:
2835                                         patch_state = "CALL FAILED";
2836                                         break;
2837
2838                                 default:
2839                                         patch_state = "DOWN";
2840                         }
2841
2842                         if(strlen(myrpt->exten)){
2843                                 called_number = ast_strdup(myrpt->exten);
2844                         }
2845
2846                         if(strlen(myrpt->lastdtmfcommand)){
2847                                 lastdtmfcommand = ast_strdup(myrpt->lastdtmfcommand);
2848                         }
2849                         rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2850
2851                         ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
2852                         ast_cli(fd, "Selected system state............................: %d\n", myrpt->p.sysstate_cur);
2853                         ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
2854                         ast_cli(fd, "System...........................................: %s\n", sys_ena);
2855                         ast_cli(fd, "Parrot Mode......................................: %s\n", parrot_ena);
2856                         ast_cli(fd, "Scheduler........................................: %s\n", sch_ena);
2857                         ast_cli(fd, "Tail Time........................................: %s\n", tail_type);
2858                         ast_cli(fd, "Time out timer...................................: %s\n", tot_ena);
2859                         ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
2860                         ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
2861                         ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
2862                         ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
2863                         ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
2864                         ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
2865                         ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
2866                         ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
2867                         ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
2868                         ast_cli(fd, "Last DTMF command executed.......................: %s\n", 
2869                         (lastdtmfcommand && strlen(lastdtmfcommand)) ? lastdtmfcommand : not_applicable);
2870                         hours = dailytxtime/3600000;
2871                         dailytxtime %= 3600000;
2872                         minutes = dailytxtime/60000;
2873                         dailytxtime %= 60000;
2874                         seconds = dailytxtime/1000;
2875                         dailytxtime %= 1000;
2876
2877                         ast_cli(fd, "TX time today....................................: %02d:%02d:%02d.%d\n",
2878                                 hours, minutes, seconds, dailytxtime);
2879
2880                         hours = (int) totaltxtime/3600000;
2881                         totaltxtime %= 3600000;
2882                         minutes = (int) totaltxtime/60000;
2883                         totaltxtime %= 60000;
2884                         seconds = (int)  totaltxtime/1000;
2885                         totaltxtime %= 1000;
2886
2887                         ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
2888                                  hours, minutes, seconds, (int) totaltxtime);
2889
2890                         hours = uptime/3600;
2891                         uptime %= 3600;
2892                         minutes = uptime/60;
2893                         uptime %= 60;
2894
2895                         ast_cli(fd, "Uptime...........................................: %02d:%02d:%02d\n",
2896                                 hours, minutes, uptime);
2897
2898                         ast_cli(fd, "Nodes currently connected to us..................: ");
2899                         if(!numoflinks){
2900                               ast_cli(fd,"<NONE>");
2901                         }
2902                         else{
2903                                 for(j = 0 ;j < numoflinks; j++){
2904                                         ast_cli(fd, "%s", listoflinks[j]);
2905                                         if(j % 4 == 3){
2906                                                 ast_cli(fd, "\n");
2907                                                 ast_cli(fd, "                                                 : ");
2908                                         }       
2909                                         else{
2910                                                 if((numoflinks - 1) - j  > 0)
2911                                                         ast_cli(fd, ", ");
2912                                         }
2913                                 }
2914                         }
2915                         ast_cli(fd,"\n");
2916
2917                         ast_cli(fd, "Autopatch........................................: %s\n", patch_ena);
2918                         ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
2919                         ast_cli(fd, "Autopatch called number..........................: %s\n",
2920                         (called_number && strlen(called_number)) ? called_number : not_applicable);
2921                         ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n", reverse_patch_state);
2922                         ast_cli(fd, "User linking commands............................: %s\n", link_ena);
2923                         ast_cli(fd, "User functions...................................: %s\n\n", user_funs);
2924
2925                         for(j = 0; j < numoflinks; j++){ /* ast_free() all link names */
2926                                 ast_free(listoflinks[j]);
2927                         }
2928                         ast_free(called_number);
2929                         ast_free(lastdtmfcommand);
2930                         return RESULT_SUCCESS;
2931                 }
2932         }
2933         return RESULT_FAILURE;
2934 }
2935
2936 /*
2937 * Link stats function
2938 */
2939
2940 static int rpt_do_lstats(int fd, int argc, const char * const *argv)
2941 {
2942         int i,j;
2943         char *connstate;
2944         struct rpt *myrpt;
2945         struct rpt_link *l;
2946         struct rpt_lstat *s,*t;
2947         struct rpt_lstat s_head;
2948         if(argc != 3)
2949                 return RESULT_SHOWUSAGE;
2950
2951         s = NULL;
2952         s_head.next = &s_head;
2953         s_head.prev = &s_head;
2954
2955         for(i = 0; i < nrpts; i++)
2956         {
2957                 if (!strcmp(argv[2],rpt_vars[i].name)){
2958                         /* Make a copy of all stat variables while locked */
2959                         myrpt = &rpt_vars[i];
2960                         rpt_mutex_lock(&myrpt->lock); /* LOCK */
2961                         /* Traverse the list of connected nodes */
2962                         j = 0;
2963                         l = myrpt->links.next;
2964                         while(l && (l != &myrpt->links)){
2965                                 if (l->name[0] == '0'){ /* Skip '0' nodes */
2966                                         l = l->next;
2967                                         continue;
2968                                 }
2969                                 if((s = (struct rpt_lstat *) ast_malloc(sizeof(struct rpt_lstat))) == NULL){
2970                                         ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
2971                                         rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2972                                         return RESULT_FAILURE;
2973                                 }
2974                                 memset(s, 0, sizeof(struct rpt_lstat));
2975                                 strncpy(s->name, l->name, MAXREMSTR - 1);
2976                                 if (l->chan) pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
2977                                 else strcpy(s->peer,"(none)");
2978                                 s->mode = l->mode;
2979                                 s->outbound = l->outbound;
2980                                 s->reconnects = l->reconnects;
2981                                 s->connecttime = l->connecttime;
2982                                 s->thisconnected = l->thisconnected;
2983                                 memcpy(s->chan_stat,l->chan_stat,NRPTSTAT * sizeof(struct rpt_chan_stat));
2984                                 insque((struct qelem *) s, (struct qelem *) s_head.next);
2985                                 memset(l->chan_stat,0,NRPTSTAT * sizeof(struct rpt_chan_stat));
2986                                 l = l->next;
2987                         }
2988                         rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2989                         ast_cli(fd, "NODE      PEER                RECONNECTS  DIRECTION  CONNECT TIME        CONNECT STATE\n");
2990                         ast_cli(fd, "----      ----                ----------  ---------  ------------        -------------\n");
2991
2992                         for(s = s_head.next; s != &s_head; s = s->next){
2993                                 int hours, minutes, seconds;
2994                                 long long connecttime = s->connecttime;
2995                                 char conntime[21];
2996                                 hours = (int) connecttime/3600000;
2997                                 connecttime %= 3600000;
2998                                 minutes = (int) connecttime/60000;
2999                                 connecttime %= 60000;
3000                                 seconds = (int)  connecttime/1000;
3001                                 connecttime %= 1000;
3002                                 snprintf(conntime, 20, "%02d:%02d:%02d.%d",
3003                                         hours, minutes, seconds, (int) connecttime);
3004                                 conntime[20] = 0;
3005                                 if(s->thisconnected)
3006                                         connstate  = "ESTABLISHED";
3007                                 else
3008                                         connstate = "CONNECTING";
3009                                 ast_cli(fd, "%-10s%-20s%-12d%-11s%-20s%-20s\n",
3010                                         s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime, connstate);
3011                         }       
3012                         /* destroy our local link queue */
3013                         s = s_head.next;
3014                         while(s != &s_head){
3015                                 t = s;
3016                                 s = s->next;
3017                                 remque((struct qelem *)t);
3018                                 ast_free(t);
3019                         }                       
3020                         return RESULT_SUCCESS;
3021                 }
3022         }
3023         return RESULT_FAILURE;
3024 }
3025
3026 /*
3027 * List all nodes connected, directly or indirectly
3028 */
3029
3030 static int rpt_do_nodes(int fd, int argc, const char * const *argv)
3031 {
3032         int i,j;
3033         char ns;
3034         char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
3035         struct rpt *myrpt;
3036         if(argc != 3)
3037                 return RESULT_SHOWUSAGE;
3038
3039         for(i = 0; i < nrpts; i++)
3040         {
3041                 if (!strcmp(argv[2],rpt_vars[i].name)){
3042                         /* Make a copy of all stat variables while locked */
3043                         myrpt = &rpt_vars[i];
3044                         rpt_mutex_lock(&myrpt->lock); /* LOCK */
3045                         __mklinklist(myrpt,NULL,lbuf);
3046                         rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
3047                         /* parse em */
3048                         ns = finddelim(lbuf,strs,MAXLINKLIST);
3049                         /* sort em */
3050                         if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
3051                         ast_cli(fd,"\n");
3052                         ast_cli(fd, "************************* CONNECTED NODES *************************\n\n");
3053                         for(j = 0 ;; j++){
3054                                 if(!strs[j]){
3055                                         if(!j){
3056                                                 ast_cli(fd,"<NONE>");
3057                                         }
3058                                         break;
3059                                 }
3060                                 ast_cli(fd, "%s", strs[j]);
3061                                 if(j % 8 == 7){
3062                                         ast_cli(fd, "\n");
3063                                 }
3064                                 else{
3065                                         if(strs[j + 1])
3066                                                 ast_cli(fd, ", ");
3067                                 }
3068                         }
3069                         ast_cli(fd,"\n\n");
3070                         return RESULT_SUCCESS;
3071                 }
3072         }
3073         return RESULT_FAILURE;
3074 }
3075
3076 /*
3077 * List all locally configured nodes
3078 */
3079
3080 static int rpt_do_local_nodes(int fd, int argc, const char * const *argv)
3081 {
3082
3083     int i;
3084     ast_cli(fd, "\nNode\n----\n");
3085     for (i=0; i< nrpts; i++)
3086     {
3087         ast_cli(fd, "%s\n", rpt_vars[i].name);        
3088     } /* for i */
3089     ast_cli(fd,"\n");
3090     return RESULT_SUCCESS;
3091
3092
3093
3094 /*
3095 * reload vars 
3096 */
3097
3098 static int rpt_do_reload(int fd, int argc, const char * const *argv)
3099 {
3100 int     n;
3101
3102         if (argc > 2) return RESULT_SHOWUSAGE;
3103
3104         for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
3105
3106         return RESULT_FAILURE;
3107 }
3108
3109 /*
3110 * restart app_rpt
3111 */
3112                                                                                                                                  
3113 static int rpt_do_restart(int fd, int argc, const char * const *argv)
3114 {
3115 int     i;
3116
3117         if (argc > 2) return RESULT_SHOWUSAGE;
3118         for(i = 0; i < nrpts; i++)
3119         {
3120                 if (rpt_vars[i].rxchannel) ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
3121         }
3122         return RESULT_FAILURE;
3123 }
3124
3125
3126 /*
3127 * send an app_rpt DTMF function from the CLI
3128 */
3129                                                                                                                                  
3130 static int rpt_do_fun(int fd, int argc, const char * const *argv)
3131 {
3132         int     i,busy=0;
3133
3134         if (argc != 4) return RESULT_SHOWUSAGE;
3135
3136         for(i = 0; i < nrpts; i++){
3137                 if(!strcmp(argv[2], rpt_vars[i].name)){
3138                         struct rpt *myrpt = &rpt_vars[i];
3139                         rpt_mutex_lock(&myrpt->lock);
3140                         if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(argv[3])){
3141                                 rpt_mutex_unlock(&myrpt->lock);
3142                                 busy=1;
3143                         }
3144                         if(!busy){
3145                                 myrpt->macrotimer = MACROTIME;
3146                                 strncat(myrpt->macrobuf,argv[3],MAXMACRO - 1);
3147                         }
3148                         rpt_mutex_unlock(&myrpt->lock);
3149                 }
3150         }
3151         if(busy){
3152                 ast_cli(fd, "Function decoder busy");
3153         }
3154         return RESULT_FAILURE;
3155 }
3156 /*
3157         the convention is that macros in the data from the rpt() application
3158         are all at the end of the data, separated by the | and start with a *
3159         when put into the macro buffer, the characters have their high bit
3160         set so the macro processor knows they came from the application data
3161         and to use the alt-functions table.
3162         sph:
3163 */
3164 static int rpt_push_alt_macro(struct rpt *myrpt, char *sptr)
3165 {
3166         int     busy=0;
3167
3168         rpt_mutex_lock(&myrpt->lock);
3169         if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(sptr)){
3170                 rpt_mutex_unlock(&myrpt->lock);
3171                 busy=1;
3172         }
3173         if(!busy){
3174                 int x;
3175                 if (debug)ast_log(LOG_NOTICE, "rpt_push_alt_macro %s\n",sptr);
3176                 myrpt->macrotimer = MACROTIME;
3177                 for(x = 0; *(sptr + x); x++)
3178                     myrpt->macrobuf[x] = *(sptr + x) | 0x80;
3179                 *(sptr + x) = 0;
3180         }
3181         rpt_mutex_unlock(&myrpt->lock);
3182
3183         if(busy)ast_log(LOG_WARNING, "Function decoder busy on app_rpt command macro.\n");
3184
3185         return busy;
3186 }
3187 /*
3188         allows us to test rpt() application data commands
3189 */
3190 static int rpt_do_fun1(int fd, int argc, const char * const *argv)
3191 {
3192         int     i;
3193
3194     if (argc != 4) return RESULT_SHOWUSAGE;
3195
3196         for(i = 0; i < nrpts; i++){
3197                 if(!strcmp(argv[2], rpt_vars[i].name)){
3198                         struct rpt *myrpt = &rpt_vars[i];
3199                         rpt_push_alt_macro(myrpt, (char *) argv[3]);
3200                 }
3201         }
3202         return RESULT_FAILURE;
3203 }
3204 /*
3205 * send an app_rpt **command** from the CLI
3206 */
3207
3208 static int rpt_do_cmd(int fd, int argc, const char * const *argv)
3209 {
3210         int i, l;
3211         int busy=0;
3212         int maxActions = sizeof(function_table)/sizeof(struct function_table_tag);
3213
3214         int thisRpt = -1;
3215         int thisAction = -1;
3216         struct rpt *myrpt = NULL;
3217         if (argc != 6) return RESULT_SHOWUSAGE;
3218         
3219         for(i = 0; i < nrpts; i++)
3220         {
3221                 if(!strcmp(argv[2], rpt_vars[i].name))
3222                 {
3223                         thisRpt = i;
3224                         myrpt = &rpt_vars[i];
3225                         break;
3226                 } /* if !strcmp... */
3227         } /* for i */
3228
3229         if (thisRpt < 0)
3230         {
3231                 ast_cli(fd, "Unknown node number %s.\n", argv[2]);
3232                 return RESULT_FAILURE;
3233         } /* if thisRpt < 0 */
3234         
3235         /* Look up the action */
3236         l = strlen(argv[3]);
3237         for(i = 0 ; i < maxActions; i++)
3238         {
3239                 if(!strncasecmp(argv[3], function_table[i].action, l))
3240                 {
3241                         thisAction = i;
3242                         break;
3243                 } /* if !strncasecmp... */
3244         } /* for i */
3245         
3246         if (thisAction < 0)
3247         {
3248                 ast_cli(fd, "Unknown action name %s.\n", argv[3]);
3249                 return RESULT_FAILURE;
3250         } /* if thisAction < 0 */
3251
3252         /* at this point, it looks like all the arguments make sense... */
3253
3254         rpt_mutex_lock(&myrpt->lock);
3255
3256         if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE)
3257         {
3258                 rpt_vars[thisRpt].cmdAction.state = CMD_STATE_BUSY;
3259                 rpt_vars[thisRpt].cmdAction.functionNumber = thisAction;
3260                 strncpy(rpt_vars[thisRpt].cmdAction.param, argv[4], MAXDTMF);
3261                 strncpy(rpt_vars[thisRpt].cmdAction.digits, argv[5], MAXDTMF);
3262                 rpt_vars[thisRpt].cmdAction.command_source = SOURCE_RPT;
3263                 rpt_vars[thisRpt].cmdAction.state = CMD_STATE_READY;
3264         } /* if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE */
3265         else
3266         {
3267                 busy = 1;
3268         } /* if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE */
3269         rpt_mutex_unlock(&myrpt->lock);
3270
3271         return (busy ? RESULT_FAILURE : RESULT_SUCCESS);
3272 } /* rpt_do_cmd() */
3273
3274 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)