Asterisk media architecture conversion - no more format bitfields
[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_log(LOG_DEBUG, "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) return;
1979         ast_mutex_lock(&myrpt->statpost_lock);
1980         seq = ++myrpt->statpost_seqno;
1981         ast_mutex_unlock(&myrpt->statpost_lock);
1982         astrs[n++] = str;
1983         astrs[n] = NULL;
1984         time(&now);
1985         sprintf(str,"%s?node=%s&time=%u&seqno=%u",myrpt->p.statpost_url,
1986                 myrpt->name,(unsigned int) now,seq);
1987         if (pairs) sprintf(str + strlen(str),"&%s",pairs);
1988         if (!(pid = ast_safe_fork(0)))
1989         {
1990                 execv(astrs[0],astrs);
1991                 ast_log(LOG_ERROR, "exec of %s failed.\n", astrs[0]);
1992                 perror("asterisk");
1993                 exit(0);
1994         }
1995         ast_free(astr);
1996         ast_free(str);
1997         return;
1998 }
1999
2000 static char *node_lookup(struct rpt *myrpt,char *digitbuf)
2001 {
2002
2003 char *val;
2004 int longestnode,j;
2005 struct stat mystat;
2006 static time_t last = 0;
2007 static struct ast_config *ourcfg = NULL;
2008 struct ast_variable *vp;
2009
2010         /* try to look it up locally first */
2011         val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
2012         if (val) return(val);
2013         ast_mutex_lock(&nodelookuplock);
2014         /* if file does not exist */
2015         if (stat(myrpt->p.extnodefile,&mystat) == -1)
2016         {
2017                 if (ourcfg) ast_config_destroy(ourcfg);
2018                 ourcfg = NULL;
2019                 ast_mutex_unlock(&nodelookuplock);
2020                 return(NULL);
2021         }
2022         /* if we need to reload */
2023         if (mystat.st_mtime > last)
2024         {
2025                 if (ourcfg) ast_config_destroy(ourcfg);
2026 #ifdef  NEW_ASTERISK
2027                 ourcfg = ast_config_load(myrpt->p.extnodefile,config_flags);
2028 #else
2029                 ourcfg = ast_config_load(myrpt->p.extnodefile);
2030 #endif
2031                 /* if file not there, just bail */
2032                 if (!ourcfg || ourcfg == CONFIG_STATUS_FILEINVALID)
2033                 {
2034                         ast_mutex_unlock(&nodelookuplock);
2035                         return(NULL);
2036                 }
2037                 /* reset "last" time */
2038                 last = mystat.st_mtime;
2039
2040                 /* determine longest node length again */               
2041                 longestnode = 0;
2042                 vp = ast_variable_browse(myrpt->cfg, myrpt->p.nodes);
2043                 while(vp){
2044                         j = strlen(vp->name);
2045                         if (j > longestnode)
2046                                 longestnode = j;
2047                         vp = vp->next;
2048                 }
2049
2050                 vp = ast_variable_browse(ourcfg, myrpt->p.extnodes);
2051                 while(vp){
2052                         j = strlen(vp->name);
2053                         if (j > longestnode)
2054                                 longestnode = j;
2055                         vp = vp->next;
2056                 }
2057
2058                 myrpt->longestnode = longestnode;
2059         }
2060         val = NULL;
2061         if (ourcfg)
2062                 val = (char *) ast_variable_retrieve(ourcfg, myrpt->p.extnodes, digitbuf);
2063         ast_mutex_unlock(&nodelookuplock);
2064         return(val);
2065 }
2066
2067 /*
2068 * Match a keyword in a list, and return index of string plus 1 if there was a match,* else return 0.
2069 * If param is passed in non-null, then it will be set to the first character past the match
2070 */
2071
2072 static int matchkeyword(char *string, char **param, char *keywords[])
2073 {
2074 int     i,ls;
2075         for( i = 0 ; keywords[i] ; i++){
2076                 ls = strlen(keywords[i]);
2077                 if(!ls){
2078                         *param = NULL;
2079                         return 0;
2080                 }
2081                 if(!strncmp(string, keywords[i], ls)){
2082                         if(param)
2083                                 *param = string + ls;
2084                         return i + 1; 
2085                 }
2086         }
2087         *param = NULL;
2088         return 0;
2089 }
2090
2091 /*
2092 * Skip characters in string which are in charlist, and return a pointer to the
2093 * first non-matching character
2094 */
2095
2096 static char *skipchars(char *string, char *charlist)
2097 {
2098 int i;  
2099         while(*string){
2100                 for(i = 0; charlist[i] ; i++){
2101                         if(*string == charlist[i]){
2102                                 string++;
2103                                 break;
2104                         }
2105                 }
2106                 if(!charlist[i])
2107                         return string;
2108         }
2109         return string;
2110 }
2111
2112 static int myatoi(const char *str)
2113 {
2114         int     ret;
2115
2116         if (!str) {
2117                 return -1;
2118         }
2119
2120         /* leave this %i alone, non-base-10 input is useful here */
2121         if (sscanf(str, "%30i", &ret) != 1) {
2122                 return -1;
2123         }
2124
2125         return ret;
2126 }
2127
2128 static int mycompar(const void *a, const void *b)
2129 {
2130 char    **x = (char **) a;
2131 char    **y = (char **) b;
2132 int     xoff,yoff;
2133
2134         if ((**x < '0') || (**x > '9')) xoff = 1; else xoff = 0;
2135         if ((**y < '0') || (**y > '9')) yoff = 1; else yoff = 0;
2136         return(strcmp((*x) + xoff,(*y) + yoff));
2137 }
2138
2139 static int topcompar(const void *a, const void *b)
2140 {
2141 struct rpt_topkey *x = (struct rpt_topkey *) a;
2142 struct rpt_topkey *y = (struct rpt_topkey *) b;
2143
2144         return(x->timesince - y->timesince);
2145 }
2146
2147 #ifdef  __RPT_NOTCH
2148
2149 /* rpt filter routine */
2150 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
2151 {
2152 int     i,j;
2153 struct  rptfilter *f;
2154
2155         for(i = 0; i < len; i++)
2156         {
2157                 for(j = 0; j < MAXFILTERS; j++)
2158                 {
2159                         f = &myrpt->filters[j];
2160                         if (!*f->desc) continue;
2161                         f->x0 = f->x1; f->x1 = f->x2;
2162                         f->x2 = ((float)buf[i]) / f->gain;
2163                         f->y0 = f->y1; f->y1 = f->y2;
2164                         f->y2 =   (f->x0 + f->x2) +   f->const0 * f->x1
2165                                      + (f->const1 * f->y0) + (f->const2 * f->y1);
2166                         buf[i] = (short)f->y2;
2167                 }
2168         }
2169 }
2170
2171 #endif
2172
2173
2174 /*
2175  Get the time for the machine's time zone
2176  Note: Asterisk requires a copy of localtime
2177  in the /etc directory for this to work properly.
2178  If /etc/localtime is not present, you will get
2179  GMT time! This is especially important on systems
2180  running embedded linux distributions as they don't usually
2181  have support for locales. 
2182
2183  If OLD_ASTERISK is defined, then the older localtime_r
2184  function will be used. The /etc/localtime file is not
2185  required in this case. This provides backward compatibility
2186  with Asterisk 1.2 systems.
2187
2188 */
2189
2190 #ifdef  NEW_ASTERISK
2191 static void rpt_localtime( time_t * t, struct ast_tm *lt)
2192 {
2193         struct timeval when;
2194
2195         when.tv_sec = *t;
2196         when.tv_usec = 0;
2197         ast_localtime(&when, lt, NULL);
2198 }
2199
2200 #else
2201 static void rpt_localtime( time_t * t, struct tm *lt)
2202 {
2203 #ifdef OLD_ASTERISK
2204         localtime_r(t, lt);
2205 #else
2206         ast_localtime(t, lt, NULL);
2207 #endif
2208 }
2209 #endif
2210
2211
2212 /* Retrieve an int from a config file */
2213                                                                                 
2214 static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl)
2215 {
2216         char *var;
2217         int ret;
2218         char include_zero = 0;
2219
2220         if(min < 0){ /* If min is negative, this means include 0 as a valid entry */
2221                 min = -min;
2222                 include_zero = 1;
2223         }           
2224                                                                      
2225         var = (char *) ast_variable_retrieve(myrpt->cfg, category, name);
2226         if(var){
2227                 ret = myatoi(var);
2228                 if(include_zero && !ret)
2229                         return 0;
2230                 if(ret < min)
2231                         ret = min;
2232                 if(ret > max)
2233                         ret = max;
2234         }
2235         else
2236                 ret = defl;
2237         return ret;
2238 }
2239
2240
2241 static void load_rpt_vars(int n,int init)
2242 {
2243 char *this,*val;
2244 int     i,j,longestnode;
2245 struct ast_variable *vp;
2246 struct ast_config *cfg;
2247 char *strs[100];
2248 char s1[256];
2249 static char *cs_keywords[] = {"rptena","rptdis","apena","apdis","lnkena","lnkdis","totena","totdis","skena","skdis",
2250                                 "ufena","ufdis","atena","atdis",NULL};
2251
2252         if (option_verbose > 2)
2253                 ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n",
2254                         (init) ? "Loading initial" : "Re-Loading",rpt_vars[n].name);
2255         ast_mutex_lock(&rpt_vars[n].lock);
2256         if (rpt_vars[n].cfg) ast_config_destroy(rpt_vars[n].cfg);
2257 #ifdef  NEW_ASTERISK
2258         cfg = ast_config_load("rpt.conf",config_flags);
2259 #else
2260         cfg = ast_config_load("rpt.conf");
2261 #endif
2262         if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
2263                 ast_mutex_unlock(&rpt_vars[n].lock);
2264                 ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
2265                 pthread_exit(NULL);
2266         }
2267         rpt_vars[n].cfg = cfg; 
2268         this = rpt_vars[n].name;
2269         memset(&rpt_vars[n].p,0,sizeof(rpt_vars[n].p));
2270         if (init)
2271         {
2272                 char *cp;
2273                 int savearea = (char *)&rpt_vars[n].p - (char *)&rpt_vars[n];
2274
2275                 cp = (char *) &rpt_vars[n].p;
2276                 memset(cp + sizeof(rpt_vars[n].p),0,
2277                         sizeof(rpt_vars[n]) - (sizeof(rpt_vars[n].p) + savearea));
2278                 rpt_vars[n].tele.next = &rpt_vars[n].tele;
2279                 rpt_vars[n].tele.prev = &rpt_vars[n].tele;
2280                 rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
2281                 rpt_vars[n].tailmessagen = 0;
2282         }
2283 #ifdef  __RPT_NOTCH
2284         /* zot out filters stuff */
2285         memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
2286 #endif
2287         val = (char *) ast_variable_retrieve(cfg,this,"context");
2288         if (val) rpt_vars[n].p.ourcontext = val;
2289         else rpt_vars[n].p.ourcontext = this;
2290         val = (char *) ast_variable_retrieve(cfg,this,"callerid");
2291         if (val) rpt_vars[n].p.ourcallerid = val;
2292         val = (char *) ast_variable_retrieve(cfg,this,"accountcode");
2293         if (val) rpt_vars[n].p.acctcode = val;
2294         val = (char *) ast_variable_retrieve(cfg,this,"idrecording");
2295         if (val) rpt_vars[n].p.ident = val;
2296         val = (char *) ast_variable_retrieve(cfg,this,"hangtime");
2297         if (val) rpt_vars[n].p.hangtime = atoi(val);
2298                 else rpt_vars[n].p.hangtime = HANGTIME;
2299         val = (char *) ast_variable_retrieve(cfg,this,"althangtime");
2300         if (val) rpt_vars[n].p.althangtime = atoi(val);
2301                 else rpt_vars[n].p.althangtime = HANGTIME;
2302         val = (char *) ast_variable_retrieve(cfg,this,"totime");
2303         if (val) rpt_vars[n].p.totime = atoi(val);
2304                 else rpt_vars[n].p.totime = TOTIME;
2305         val = (char *) ast_variable_retrieve(cfg,this,"voxtimeout");
2306         if (val) rpt_vars[n].p.voxtimeout_ms = atoi(val);
2307                 else rpt_vars[n].p.voxtimeout_ms = VOX_TIMEOUT_MS;
2308         val = (char *) ast_variable_retrieve(cfg,this,"voxrecover");
2309         if (val) rpt_vars[n].p.voxrecover_ms = atoi(val);
2310                 else rpt_vars[n].p.voxrecover_ms = VOX_RECOVER_MS;
2311         val = (char *) ast_variable_retrieve(cfg,this,"simplexpatchdelay");
2312         if (val) rpt_vars[n].p.simplexpatchdelay = atoi(val);
2313                 else rpt_vars[n].p.simplexpatchdelay = SIMPLEX_PATCH_DELAY;
2314         val = (char *) ast_variable_retrieve(cfg,this,"simplexphonedelay");
2315         if (val) rpt_vars[n].p.simplexphonedelay = atoi(val);
2316                 else rpt_vars[n].p.simplexphonedelay = SIMPLEX_PHONE_DELAY;
2317         val = (char *) ast_variable_retrieve(cfg,this,"statpost_program");
2318         if (val) rpt_vars[n].p.statpost_program = val;
2319                 else rpt_vars[n].p.statpost_program = STATPOST_PROGRAM;
2320         rpt_vars[n].p.statpost_url = 
2321                 (char *) ast_variable_retrieve(cfg,this,"statpost_url");
2322         rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0);                
2323         rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0);              
2324         rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2);
2325         rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", -60000, 2400000, IDTIME);        /* Enforce a min max including zero */
2326         rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
2327         val = (char *) ast_variable_retrieve(cfg,this,"tonezone");
2328         if (val) rpt_vars[n].p.tonezone = val;
2329         rpt_vars[n].p.tailmessages[0] = 0;
2330         rpt_vars[n].p.tailmessagemax = 0;
2331         val = (char *) ast_variable_retrieve(cfg,this,"tailmessagelist");
2332         if (val) rpt_vars[n].p.tailmessagemax = finddelim(val, rpt_vars[n].p.tailmessages, 500);
2333         val = (char *) ast_variable_retrieve(cfg,this,"memory");
2334         if (!val) val = MEMORY;
2335         rpt_vars[n].p.memory = val;
2336         val = (char *) ast_variable_retrieve(cfg,this,"macro");
2337         if (!val) val = MACRO;
2338         rpt_vars[n].p.macro = val;
2339         val = (char *) ast_variable_retrieve(cfg,this,"tonemacro");
2340         if (!val) val = TONEMACRO;
2341         rpt_vars[n].p.tonemacro = val;
2342         val = (char *) ast_variable_retrieve(cfg,this,"startup_macro");
2343         if (val) rpt_vars[n].p.startupmacro = val;
2344         val = (char *) ast_variable_retrieve(cfg,this,"iobase");
2345         /* do not use atoi() here, we need to be able to have
2346                 the input specified in hex or decimal so we use
2347                 sscanf with a %i */
2348         if ((!val) || (sscanf(val,"%30i",&rpt_vars[n].p.iobase) != 1))
2349                 rpt_vars[n].p.iobase = DEFAULT_IOBASE;
2350         val = (char *) ast_variable_retrieve(cfg,this,"ioport");
2351         rpt_vars[n].p.ioport = val;
2352         val = (char *) ast_variable_retrieve(cfg,this,"functions");
2353         if (!val)
2354                 {
2355                         val = FUNCTIONS;
2356                         rpt_vars[n].p.simple = 1;
2357                 } 
2358         rpt_vars[n].p.functions = val;
2359         val =  (char *) ast_variable_retrieve(cfg,this,"link_functions");
2360         if (val) rpt_vars[n].p.link_functions = val;
2361         else 
2362                 rpt_vars[n].p.link_functions = rpt_vars[n].p.functions;
2363         val = (char *) ast_variable_retrieve(cfg,this,"phone_functions");
2364         if (val) rpt_vars[n].p.phone_functions = val;
2365         val = (char *) ast_variable_retrieve(cfg,this,"dphone_functions");
2366         if (val) rpt_vars[n].p.dphone_functions = val;
2367         val = (char *) ast_variable_retrieve(cfg,this,"alt_functions");
2368         if (val) rpt_vars[n].p.alt_functions = val;
2369         val = (char *) ast_variable_retrieve(cfg,this,"funcchar");
2370         if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else 
2371                 rpt_vars[n].p.funcchar = *val;          
2372         val = (char *) ast_variable_retrieve(cfg,this,"endchar");
2373         if (!val) rpt_vars[n].p.endchar = ENDCHAR; else 
2374                 rpt_vars[n].p.endchar = *val;           
2375         val = (char *) ast_variable_retrieve(cfg,this,"nobusyout");
2376         if (val) rpt_vars[n].p.nobusyout = ast_true(val);
2377         val = (char *) ast_variable_retrieve(cfg,this,"notelemtx");
2378         if (val) rpt_vars[n].p.notelemtx = ast_true(val);
2379         val = (char *) ast_variable_retrieve(cfg,this,"propagate_dtmf");
2380         if (val) rpt_vars[n].p.propagate_dtmf = ast_true(val);
2381         val = (char *) ast_variable_retrieve(cfg,this,"propagate_phonedtmf");
2382         if (val) rpt_vars[n].p.propagate_phonedtmf = ast_true(val);
2383         val = (char *) ast_variable_retrieve(cfg,this,"linktolink");
2384         if (val) rpt_vars[n].p.linktolink = ast_true(val);
2385         val = (char *) ast_variable_retrieve(cfg,this,"nodes");
2386         if (!val) val = NODES;
2387         rpt_vars[n].p.nodes = val;
2388         val = (char *) ast_variable_retrieve(cfg,this,"extnodes");
2389         if (!val) val = EXTNODES;
2390         rpt_vars[n].p.extnodes = val;
2391         val = (char *) ast_variable_retrieve(cfg,this,"extnodefile");
2392         if (!val) val = EXTNODEFILE;
2393         rpt_vars[n].p.extnodefile = val;
2394         val = (char *) ast_variable_retrieve(cfg,this,"archivedir");
2395         if (val) rpt_vars[n].p.archivedir = val;
2396         val = (char *) ast_variable_retrieve(cfg,this,"authlevel");
2397         if (val) rpt_vars[n].p.authlevel = atoi(val); 
2398         else rpt_vars[n].p.authlevel = 0;
2399         val = (char *) ast_variable_retrieve(cfg,this,"parrot");
2400         if (val) rpt_vars[n].p.parrotmode = ast_true(val) * 2;
2401         else rpt_vars[n].p.parrotmode = 0;
2402         val = (char *) ast_variable_retrieve(cfg,this,"parrottime");
2403         if (val) rpt_vars[n].p.parrottime = atoi(val); 
2404         else rpt_vars[n].p.parrottime = PARROTTIME;
2405         val = (char *) ast_variable_retrieve(cfg,this,"rptnode");
2406         rpt_vars[n].p.rptnode = val;
2407         val = (char *) ast_variable_retrieve(cfg,this,"mars");
2408         if (val) rpt_vars[n].p.remote_mars = atoi(val); 
2409         else rpt_vars[n].p.remote_mars = 0;
2410         val = (char *) ast_variable_retrieve(cfg,this,"monminblocks");
2411         if (val) rpt_vars[n].p.monminblocks = atol(val); 
2412         else rpt_vars[n].p.monminblocks = DEFAULT_MONITOR_MIN_DISK_BLOCKS;
2413         val = (char *) ast_variable_retrieve(cfg,this,"remote_inact_timeout");
2414         if (val) rpt_vars[n].p.remoteinacttimeout = atoi(val); 
2415         else rpt_vars[n].p.remoteinacttimeout = DEFAULT_REMOTE_INACT_TIMEOUT;
2416         val = (char *) ast_variable_retrieve(cfg,this,"civaddr");
2417         if (val) rpt_vars[n].p.civaddr = atoi(val); 
2418         else rpt_vars[n].p.civaddr = DEFAULT_CIV_ADDR;
2419         val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout");
2420         if (val) rpt_vars[n].p.remotetimeout = atoi(val); 
2421         else rpt_vars[n].p.remotetimeout = DEFAULT_REMOTE_TIMEOUT;
2422         val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning");
2423         if (val) rpt_vars[n].p.remotetimeoutwarning = atoi(val); 
2424         else rpt_vars[n].p.remotetimeoutwarning = DEFAULT_REMOTE_TIMEOUT_WARNING;
2425         val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning_freq");
2426         if (val) rpt_vars[n].p.remotetimeoutwarningfreq = atoi(val); 
2427         else rpt_vars[n].p.remotetimeoutwarningfreq = DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ;
2428 #ifdef  __RPT_NOTCH
2429         val = (char *) ast_variable_retrieve(cfg,this,"rxnotch");
2430         if (val) {
2431                 i = finddelim(val,strs,MAXFILTERS * 2);
2432                 i &= ~1; /* force an even number, rounded down */
2433                 if (i >= 2) for(j = 0; j < i; j += 2)
2434                 {
2435                         rpt_mknotch(atof(strs[j]),atof(strs[j + 1]),
2436                           &rpt_vars[n].filters[j >> 1].gain,
2437                             &rpt_vars[n].filters[j >> 1].const0,
2438                                 &rpt_vars[n].filters[j >> 1].const1,
2439                                     &rpt_vars[n].filters[j >> 1].const2);
2440                         sprintf(rpt_vars[n].filters[j >> 1].desc,"%s Hz, BW = %s",
2441                                 strs[j],strs[j + 1]);
2442                 }
2443
2444         }
2445 #endif
2446         val = (char *) ast_variable_retrieve(cfg,this,"inxlat");
2447         if (val) {
2448                 memset(&rpt_vars[n].p.inxlat,0,sizeof(struct rpt_xlat));
2449                 i = finddelim(val,strs,3);
2450                 if (i) strncpy(rpt_vars[n].p.inxlat.funccharseq,strs[0],MAXXLAT - 1);
2451                 if (i > 1) strncpy(rpt_vars[n].p.inxlat.endcharseq,strs[1],MAXXLAT - 1);
2452                 if (i > 2) strncpy(rpt_vars[n].p.inxlat.passchars,strs[2],MAXXLAT - 1);
2453         }
2454         val = (char *) ast_variable_retrieve(cfg,this,"outxlat");
2455         if (val) {
2456                 memset(&rpt_vars[n].p.outxlat,0,sizeof(struct rpt_xlat));
2457                 i = finddelim(val,strs,3);
2458                 if (i) strncpy(rpt_vars[n].p.outxlat.funccharseq,strs[0],MAXXLAT - 1);
2459                 if (i > 1) strncpy(rpt_vars[n].p.outxlat.endcharseq,strs[1],MAXXLAT - 1);
2460                 if (i > 2) strncpy(rpt_vars[n].p.outxlat.passchars,strs[2],MAXXLAT - 1);
2461         }
2462         /* retreive the stanza name for the control states if there is one */
2463         val = (char *) ast_variable_retrieve(cfg,this,"controlstates");
2464         rpt_vars[n].p.csstanzaname = val;
2465                 
2466         /* retreive the stanza name for the scheduler if there is one */
2467         val = (char *) ast_variable_retrieve(cfg,this,"scheduler");
2468         rpt_vars[n].p.skedstanzaname = val;
2469
2470         /* retreive the stanza name for the txlimits */
2471         val = (char *) ast_variable_retrieve(cfg,this,"txlimits");
2472         rpt_vars[n].p.txlimitsstanzaname = val;
2473
2474         longestnode = 0;
2475
2476         vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
2477                 
2478         while(vp){
2479                 j = strlen(vp->name);
2480                 if (j > longestnode)
2481                         longestnode = j;
2482                 vp = vp->next;
2483         }
2484
2485         rpt_vars[n].longestnode = longestnode;
2486                 
2487         /*
2488         * For this repeater, Determine the length of the longest function 
2489         */
2490         rpt_vars[n].longestfunc = 0;
2491         vp = ast_variable_browse(cfg, rpt_vars[n].p.functions);
2492         while(vp){
2493                 j = strlen(vp->name);
2494                 if (j > rpt_vars[n].longestfunc)
2495                         rpt_vars[n].longestfunc = j;
2496                 vp = vp->next;
2497         }
2498         /*
2499         * For this repeater, Determine the length of the longest function 
2500         */
2501         rpt_vars[n].link_longestfunc = 0;
2502         vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions);
2503         while(vp){
2504                 j = strlen(vp->name);
2505                 if (j > rpt_vars[n].link_longestfunc)
2506                         rpt_vars[n].link_longestfunc = j;
2507                 vp = vp->next;
2508         }
2509         rpt_vars[n].phone_longestfunc = 0;
2510         if (rpt_vars[n].p.phone_functions)
2511         {
2512                 vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions);
2513                 while(vp){
2514                         j = strlen(vp->name);
2515                         if (j > rpt_vars[n].phone_longestfunc)
2516                                 rpt_vars[n].phone_longestfunc = j;
2517                         vp = vp->next;
2518                 }
2519         }
2520         rpt_vars[n].dphone_longestfunc = 0;
2521         if (rpt_vars[n].p.dphone_functions)
2522         {
2523                 vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions);
2524                 while(vp){
2525                         j = strlen(vp->name);
2526                         if (j > rpt_vars[n].dphone_longestfunc)
2527                                 rpt_vars[n].dphone_longestfunc = j;
2528                         vp = vp->next;
2529                 }
2530         }
2531         rpt_vars[n].alt_longestfunc = 0;
2532         if (rpt_vars[n].p.alt_functions)
2533         {
2534                 vp = ast_variable_browse(cfg, rpt_vars[n].p.alt_functions);
2535                 while(vp){
2536                         j = strlen(vp->name);
2537                         if (j > rpt_vars[n].alt_longestfunc)
2538                                 rpt_vars[n].alt_longestfunc = j;
2539                         vp = vp->next;
2540                 }
2541         }
2542         rpt_vars[n].macro_longest = 1;
2543         vp = ast_variable_browse(cfg, rpt_vars[n].p.macro);
2544         while(vp){
2545                 j = strlen(vp->name);
2546                 if (j > rpt_vars[n].macro_longest)
2547                         rpt_vars[n].macro_longest = j;
2548                 vp = vp->next;
2549         }
2550         
2551         /* Browse for control states */
2552         if(rpt_vars[n].p.csstanzaname)
2553                 vp = ast_variable_browse(cfg, rpt_vars[n].p.csstanzaname);
2554         else
2555                 vp = NULL;
2556         for( i = 0 ; vp && (i < MAX_SYSSTATES) ; i++){ /* Iterate over the number of control state lines in the stanza */
2557                 int k,nukw,statenum;
2558                 statenum=atoi(vp->name);
2559                 strncpy(s1, vp->value, 255);
2560                 s1[255] = 0;
2561                 nukw  = finddelim(s1,strs,32);
2562                 
2563                 for (k = 0 ; k < nukw ; k++){ /* for each user specified keyword */     
2564                         for(j = 0 ; cs_keywords[j] != NULL ; j++){ /* try to match to one in our internal table */
2565                                 if(!strcmp(strs[k],cs_keywords[j])){
2566                                         switch(j){
2567                                                 case 0: /* rptena */
2568                                                         rpt_vars[n].p.s[statenum].txdisable = 0;
2569                                                         break;
2570                                                 case 1: /* rptdis */
2571                                                         rpt_vars[n].p.s[statenum].txdisable = 1;
2572                                                         break;
2573                         
2574                                                 case 2: /* apena */
2575                                                         rpt_vars[n].p.s[statenum].autopatchdisable = 0;
2576                                                         break;
2577
2578                                                 case 3: /* apdis */
2579                                                         rpt_vars[n].p.s[statenum].autopatchdisable = 1;
2580                                                         break;
2581
2582                                                 case 4: /* lnkena */
2583                                                         rpt_vars[n].p.s[statenum].linkfundisable = 0;
2584                                                         break;
2585         
2586                                                 case 5: /* lnkdis */
2587                                                         rpt_vars[n].p.s[statenum].linkfundisable = 1;
2588                                                         break;
2589
2590                                                 case 6: /* totena */
2591                                                         rpt_vars[n].p.s[statenum].totdisable = 0;
2592                                                         break;
2593                                         
2594                                                 case 7: /* totdis */
2595                                                         rpt_vars[n].p.s[statenum].totdisable = 1;
2596                                                         break;
2597
2598                                                 case 8: /* skena */
2599                                                         rpt_vars[n].p.s[statenum].schedulerdisable = 0;
2600                                                         break;
2601
2602                                                 case 9: /* skdis */
2603                                                         rpt_vars[n].p.s[statenum].schedulerdisable = 1;
2604                                                         break;
2605
2606                                                 case 10: /* ufena */
2607                                                         rpt_vars[n].p.s[statenum].userfundisable = 0;
2608                                                         break;
2609
2610                                                 case 11: /* ufdis */
2611                                                         rpt_vars[n].p.s[statenum].userfundisable = 1;
2612                                                         break;
2613
2614                                                 case 12: /* atena */
2615                                                         rpt_vars[n].p.s[statenum].alternatetail = 1;
2616                                                         break;
2617
2618                                                 case 13: /* atdis */
2619                                                         rpt_vars[n].p.s[statenum].alternatetail = 0;
2620                                                         break;
2621                         
2622                                                 default:
2623                                                         ast_log(LOG_WARNING,
2624                                                                 "Unhandled control state keyword %s", cs_keywords[i]);
2625                                                         break;
2626                                         }
2627                                 }
2628                         }
2629                 }
2630                 vp = vp->next;
2631         }
2632         ast_mutex_unlock(&rpt_vars[n].lock);
2633 }
2634
2635 /*
2636 * Enable or disable debug output at a given level at the console
2637 */
2638 static int rpt_do_debug(int fd, int argc, const char * const *argv)
2639 {
2640         int newlevel;
2641
2642         if (argc != 4) {
2643                 return RESULT_SHOWUSAGE;
2644         }
2645
2646         newlevel = myatoi(argv[3]);
2647
2648         if (newlevel < 0 || newlevel > 7) {
2649                 return RESULT_SHOWUSAGE;
2650         }
2651
2652         if (newlevel) {
2653                 ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
2654         } else {
2655                 ast_cli(fd, "app_rpt Debugging disabled\n");
2656         }
2657
2658         debug = newlevel;
2659
2660         return RESULT_SUCCESS;
2661 }
2662
2663 /*
2664 * Dump rpt struct debugging onto console
2665 */
2666                                                                                                                                  
2667 static int rpt_do_dump(int fd, int argc, const char * const *argv)
2668 {
2669         int i;
2670
2671         if (argc != 3)
2672                 return RESULT_SHOWUSAGE;
2673
2674         for(i = 0; i < nrpts; i++)
2675         {
2676                 if (!strcmp(argv[2],rpt_vars[i].name))
2677                 {
2678                         rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
2679                         ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
2680                         return RESULT_SUCCESS;
2681                 }
2682         }
2683         return RESULT_FAILURE;
2684 }
2685
2686 /*
2687 * Dump statistics onto console
2688 */
2689
2690 static int rpt_do_stats(int fd, int argc, const char * const *argv)
2691 {
2692         int i,j,numoflinks;
2693         int dailytxtime, dailykerchunks;
2694         time_t now;
2695         int totalkerchunks, dailykeyups, totalkeyups, timeouts;
2696         int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
2697         int uptime;
2698         long long totaltxtime;
2699         struct  rpt_link *l;
2700         char *listoflinks[MAX_STAT_LINKS];      
2701         char *lastdtmfcommand,*parrot_ena;
2702         char *tot_state, *ider_state, *patch_state;
2703         char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
2704         char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
2705         struct rpt *myrpt;
2706
2707         static char *not_applicable = "N/A";
2708
2709         if(argc != 3)
2710                 return RESULT_SHOWUSAGE;
2711
2712         tot_state = ider_state = 
2713         patch_state = reverse_patch_state = 
2714         input_signal = not_applicable;
2715         called_number = lastdtmfcommand = NULL;
2716
2717         time(&now);
2718         for(i = 0; i < nrpts; i++)
2719         {
2720                 if (!strcmp(argv[2],rpt_vars[i].name)){
2721                         /* Make a copy of all stat variables while locked */
2722                         myrpt = &rpt_vars[i];
2723                         rpt_mutex_lock(&myrpt->lock); /* LOCK */
2724                         uptime = (int)(now - starttime);
2725                         dailytxtime = myrpt->dailytxtime;
2726                         totaltxtime = myrpt->totaltxtime;
2727                         dailykeyups = myrpt->dailykeyups;
2728                         totalkeyups = myrpt->totalkeyups;
2729                         dailykerchunks = myrpt->dailykerchunks;
2730                         totalkerchunks = myrpt->totalkerchunks;
2731                         dailyexecdcommands = myrpt->dailyexecdcommands;
2732                         totalexecdcommands = myrpt->totalexecdcommands;
2733                         timeouts = myrpt->timeouts;
2734
2735                         /* Traverse the list of connected nodes */
2736                         reverse_patch_state = "DOWN";
2737                         numoflinks = 0;
2738                         l = myrpt->links.next;
2739                         while(l && (l != &myrpt->links)){
2740                                 if(numoflinks >= MAX_STAT_LINKS){
2741                                         ast_log(LOG_NOTICE,
2742                                         "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
2743                                         break;
2744                                 }
2745                                 if (l->name[0] == '0'){ /* Skip '0' nodes */
2746                                         reverse_patch_state = "UP";
2747                                         l = l->next;
2748                                         continue;
2749                                 }
2750                                 listoflinks[numoflinks] = ast_strdup(l->name);
2751                                 if(listoflinks[numoflinks] == NULL){
2752                                         break;
2753                                 }
2754                                 else{
2755                                         numoflinks++;
2756                                 }
2757                                 l = l->next;
2758                         }
2759
2760                         if(myrpt->keyed)
2761                                 input_signal = "YES";
2762                         else
2763                                 input_signal = "NO";
2764
2765                         if(myrpt->p.parrotmode)
2766                                 parrot_ena = "ENABLED";
2767                         else
2768                                 parrot_ena = "DISABLED";
2769
2770                         if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
2771                                 sys_ena = "DISABLED";
2772                         else
2773                                 sys_ena = "ENABLED";
2774
2775                         if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
2776                                 tot_ena = "DISABLED";
2777                         else
2778                                 tot_ena = "ENABLED";
2779
2780                         if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
2781                                 link_ena = "DISABLED";
2782                         else
2783                                 link_ena = "ENABLED";
2784
2785                         if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
2786                                 patch_ena = "DISABLED";
2787                         else
2788                                 patch_ena = "ENABLED";
2789
2790                         if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
2791                                 sch_ena = "DISABLED";
2792                         else
2793                                 sch_ena = "ENABLED";
2794
2795                         if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
2796                                 user_funs = "DISABLED";
2797                         else
2798                                 user_funs = "ENABLED";
2799
2800                         if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
2801                                 tail_type = "ALTERNATE";
2802                         else
2803                                 tail_type = "STANDARD";
2804
2805                         if(!myrpt->totimer)
2806                                 tot_state = "TIMED OUT!";
2807                         else if(myrpt->totimer != myrpt->p.totime)
2808                                 tot_state = "ARMED";
2809                         else
2810                                 tot_state = "RESET";
2811
2812                         if(myrpt->tailid)
2813                                 ider_state = "QUEUED IN TAIL";
2814                         else if(myrpt->mustid)
2815                                 ider_state = "QUEUED FOR CLEANUP";
2816                         else
2817                                 ider_state = "CLEAN";
2818
2819                         switch(myrpt->callmode){
2820                                 case 1:
2821                                         patch_state = "DIALING";
2822                                         break;
2823                                 case 2:
2824                                         patch_state = "CONNECTING";
2825                                         break;
2826                                 case 3:
2827                                         patch_state = "UP";
2828                                         break;
2829
2830                                 case 4:
2831                                         patch_state = "CALL FAILED";
2832                                         break;
2833
2834                                 default:
2835                                         patch_state = "DOWN";
2836                         }
2837
2838                         if(strlen(myrpt->exten)){
2839                                 called_number = ast_strdup(myrpt->exten);
2840                         }
2841
2842                         if(strlen(myrpt->lastdtmfcommand)){
2843                                 lastdtmfcommand = ast_strdup(myrpt->lastdtmfcommand);
2844                         }
2845                         rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2846
2847                         ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
2848                         ast_cli(fd, "Selected system state............................: %d\n", myrpt->p.sysstate_cur);
2849                         ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
2850                         ast_cli(fd, "System...........................................: %s\n", sys_ena);
2851                         ast_cli(fd, "Parrot Mode......................................: %s\n", parrot_ena);
2852                         ast_cli(fd, "Scheduler........................................: %s\n", sch_ena);
2853                         ast_cli(fd, "Tail Time........................................: %s\n", tail_type);
2854                         ast_cli(fd, "Time out timer...................................: %s\n", tot_ena);
2855                         ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
2856                         ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
2857                         ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
2858                         ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
2859                         ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
2860                         ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
2861                         ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
2862                         ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
2863                         ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
2864                         ast_cli(fd, "Last DTMF command executed.......................: %s\n", 
2865                         (lastdtmfcommand && strlen(lastdtmfcommand)) ? lastdtmfcommand : not_applicable);
2866                         hours = dailytxtime/3600000;
2867                         dailytxtime %= 3600000;
2868                         minutes = dailytxtime/60000;
2869                         dailytxtime %= 60000;
2870                         seconds = dailytxtime/1000;
2871                         dailytxtime %= 1000;
2872
2873                         ast_cli(fd, "TX time today....................................: %02d:%02d:%02d.%d\n",
2874                                 hours, minutes, seconds, dailytxtime);
2875
2876                         hours = (int) totaltxtime/3600000;
2877                         totaltxtime %= 3600000;
2878                         minutes = (int) totaltxtime/60000;
2879                         totaltxtime %= 60000;
2880                         seconds = (int)  totaltxtime/1000;
2881                         totaltxtime %= 1000;
2882
2883                         ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
2884                                  hours, minutes, seconds, (int) totaltxtime);
2885
2886                         hours = uptime/3600;
2887                         uptime %= 3600;
2888                         minutes = uptime/60;
2889                         uptime %= 60;
2890
2891                         ast_cli(fd, "Uptime...........................................: %02d:%02d:%02d\n",
2892                                 hours, minutes, uptime);
2893
2894                         ast_cli(fd, "Nodes currently connected to us..................: ");
2895                         if(!numoflinks){
2896                               ast_cli(fd,"<NONE>");
2897                         }
2898                         else{
2899                                 for(j = 0 ;j < numoflinks; j++){
2900                                         ast_cli(fd, "%s", listoflinks[j]);
2901                                         if(j % 4 == 3){
2902                                                 ast_cli(fd, "\n");
2903                                                 ast_cli(fd, "                                                 : ");
2904                                         }       
2905                                         else{
2906                                                 if((numoflinks - 1) - j  > 0)
2907                                                         ast_cli(fd, ", ");
2908                                         }
2909                                 }
2910                         }
2911                         ast_cli(fd,"\n");
2912
2913                         ast_cli(fd, "Autopatch........................................: %s\n", patch_ena);
2914                         ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
2915                         ast_cli(fd, "Autopatch called number..........................: %s\n",
2916                         (called_number && strlen(called_number)) ? called_number : not_applicable);
2917                         ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n", reverse_patch_state);
2918                         ast_cli(fd, "User linking commands............................: %s\n", link_ena);
2919                         ast_cli(fd, "User functions...................................: %s\n\n", user_funs);
2920
2921                         for(j = 0; j < numoflinks; j++){ /* ast_free() all link names */
2922                                 ast_free(listoflinks[j]);
2923                         }
2924                         ast_free(called_number);
2925                         ast_free(lastdtmfcommand);
2926                         return RESULT_SUCCESS;
2927                 }
2928         }
2929         return RESULT_FAILURE;
2930 }
2931
2932 /*
2933 * Link stats function
2934 */
2935
2936 static int rpt_do_lstats(int fd, int argc, const char * const *argv)
2937 {
2938         int i,j;
2939         char *connstate;
2940         struct rpt *myrpt;
2941         struct rpt_link *l;
2942         struct rpt_lstat *s,*t;
2943         struct rpt_lstat s_head;
2944         if(argc != 3)
2945                 return RESULT_SHOWUSAGE;
2946
2947         s = NULL;
2948         s_head.next = &s_head;
2949         s_head.prev = &s_head;
2950
2951         for(i = 0; i < nrpts; i++)
2952         {
2953                 if (!strcmp(argv[2],rpt_vars[i].name)){
2954                         /* Make a copy of all stat variables while locked */
2955                         myrpt = &rpt_vars[i];
2956                         rpt_mutex_lock(&myrpt->lock); /* LOCK */
2957                         /* Traverse the list of connected nodes */
2958                         j = 0;
2959                         l = myrpt->links.next;
2960                         while(l && (l != &myrpt->links)){
2961                                 if (l->name[0] == '0'){ /* Skip '0' nodes */
2962                                         l = l->next;
2963                                         continue;
2964                                 }
2965                                 if((s = (struct rpt_lstat *) ast_malloc(sizeof(struct rpt_lstat))) == NULL){
2966                                         ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
2967                                         rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2968                                         return RESULT_FAILURE;
2969                                 }
2970                                 memset(s, 0, sizeof(struct rpt_lstat));
2971                                 strncpy(s->name, l->name, MAXREMSTR - 1);
2972                                 if (l->chan) pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
2973                                 else strcpy(s->peer,"(none)");
2974                                 s->mode = l->mode;
2975                                 s->outbound = l->outbound;
2976                                 s->reconnects = l->reconnects;
2977                                 s->connecttime = l->connecttime;
2978                                 s->thisconnected = l->thisconnected;
2979                                 memcpy(s->chan_stat,l->chan_stat,NRPTSTAT * sizeof(struct rpt_chan_stat));
2980                                 insque((struct qelem *) s, (struct qelem *) s_head.next);
2981                                 memset(l->chan_stat,0,NRPTSTAT * sizeof(struct rpt_chan_stat));
2982                                 l = l->next;
2983                         }
2984                         rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2985                         ast_cli(fd, "NODE      PEER                RECONNECTS  DIRECTION  CONNECT TIME        CONNECT STATE\n");
2986                         ast_cli(fd, "----      ----                ----------  ---------  ------------        -------------\n");
2987
2988                         for(s = s_head.next; s != &s_head; s = s->next){
2989                                 int hours, minutes, seconds;
2990                                 long long connecttime = s->connecttime;
2991                                 char conntime[21];
2992                                 hours = (int) connecttime/3600000;
2993                                 connecttime %= 3600000;
2994                                 minutes = (int) connecttime/60000;
2995                                 connecttime %= 60000;
2996                                 seconds = (int)  connecttime/1000;
2997                                 connecttime %= 1000;
2998                                 snprintf(conntime, 20, "%02d:%02d:%02d.%d",
2999                                         hours, minutes, seconds, (int) connecttime);
3000                                 conntime[20] = 0;
3001                                 if(s->thisconnected)
3002                                         connstate  = "ESTABLISHED";
3003                                 else
3004                                         connstate = "CONNECTING";
3005                                 ast_cli(fd, "%-10s%-20s%-12d%-11s%-20s%-20s\n",
3006                                         s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime, connstate);
3007                         }       
3008                         /* destroy our local link queue */
3009                         s = s_head.next;
3010                         while(s != &s_head){
3011                                 t = s;
3012                                 s = s->next;
3013                                 remque((struct qelem *)t);
3014                                 ast_free(t);
3015                         }                       
3016                         return RESULT_SUCCESS;
3017                 }
3018         }
3019         return RESULT_FAILURE;
3020 }
3021
3022 /*
3023 * List all nodes connected, directly or indirectly
3024 */
3025
3026 static int rpt_do_nodes(int fd, int argc, const char * const *argv)
3027 {
3028         int i,j;
3029         char ns;
3030         char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
3031         struct rpt *myrpt;
3032         if(argc != 3)
3033                 return RESULT_SHOWUSAGE;
3034
3035         for(i = 0; i < nrpts; i++)
3036         {
3037                 if (!strcmp(argv[2],rpt_vars[i].name)){
3038                         /* Make a copy of all stat variables while locked */
3039                         myrpt = &rpt_vars[i];
3040                         rpt_mutex_lock(&myrpt->lock); /* LOCK */
3041                         __mklinklist(myrpt,NULL,lbuf);
3042                         rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
3043                         /* parse em */
3044                         ns = finddelim(lbuf,strs,MAXLINKLIST);
3045                         /* sort em */
3046                         if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
3047                         ast_cli(fd,"\n");
3048                         ast_cli(fd, "************************* CONNECTED NODES *************************\n\n");
3049                         for(j = 0 ;; j++){
3050                                 if(!strs[j]){
3051                                         if(!j){
3052                                                 ast_cli(fd,"<NONE>");
3053                                         }
3054                                         break;
3055                                 }
3056                                 ast_cli(fd, "%s", strs[j]);
3057                                 if(j % 8 == 7){
3058                                         ast_cli(fd, "\n");
3059                                 }
3060                                 else{
3061                                         if(strs[j + 1])
3062                                                 ast_cli(fd, ", ");
3063                                 }
3064                         }
3065                         ast_cli(fd,"\n\n");
3066                         return RESULT_SUCCESS;
3067                 }
3068         }
3069         return RESULT_FAILURE;
3070 }
3071
3072 /*
3073 * List all locally configured nodes
3074 */
3075
3076 static int rpt_do_local_nodes(int fd, int argc, const char * const *argv)
3077 {
3078
3079     int i;
3080     ast_cli(fd, "\nNode\n----\n");
3081     for (i=0; i< nrpts; i++)
3082     {
3083         ast_cli(fd, "%s\n", rpt_vars[i].name);        
3084     } /* for i */
3085     ast_cli(fd,"\n");
3086     return RESULT_SUCCESS;
3087
3088
3089
3090 /*
3091 * reload vars 
3092 */
3093
3094 static int rpt_do_reload(int fd, int argc, const char * const *argv)
3095 {
3096 int     n;
3097
3098         if (argc > 2) return RESULT_SHOWUSAGE;
3099
3100         for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
3101
3102         return RESULT_FAILURE;
3103 }
3104
3105 /*
3106 * restart app_rpt
3107 */
3108                                                                                                                                  
3109 static int rpt_do_restart(int fd, int argc, const char * const *argv)
3110 {
3111 int     i;
3112
3113         if (argc > 2) return RESULT_SHOWUSAGE;
3114         for(i = 0; i < nrpts; i++)
3115         {
3116                 if (rpt_vars[i].rxchannel) ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
3117         }
3118         return RESULT_FAILURE;
3119 }
3120
3121
3122 /*
3123 * send an app_rpt DTMF function from the CLI
3124 */
3125                                                                                                                                  
3126 static int rpt_do_fun(int fd, int argc, const char * const *argv)
3127 {
3128         int     i,busy=0;
3129
3130         if (argc != 4) return RESULT_SHOWUSAGE;
3131
3132         for(i = 0; i < nrpts; i++){
3133                 if(!strcmp(argv[2], rpt_vars[i].name)){
3134                         struct rpt *myrpt = &rpt_vars[i];
3135                         rpt_mutex_lock(&myrpt->lock);
3136                         if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(argv[3])){
3137                                 rpt_mutex_unlock(&myrpt->lock);
3138                                 busy=1;
3139                         }
3140                         if(!busy){
3141                                 myrpt->macrotimer = MACROTIME;
3142                                 strncat(myrpt->macrobuf,argv[3],MAXMACRO - 1);
3143                         }
3144                         rpt_mutex_unlock(&myrpt->lock);
3145                 }
3146         }
3147         if(busy){
3148                 ast_cli(fd, "Function decoder busy");
3149         }
3150         return RESULT_FAILURE;
3151 }
3152 /*
3153         the convention is that macros in the data from the rpt() application
3154         are all at the end of the data, separated by the | and start with a *
3155         when put into the macro buffer, the characters have their high bit
3156         set so the macro processor knows they came from the application data
3157         and to use the alt-functions table.
3158         sph:
3159 */
3160 static int rpt_push_alt_macro(struct rpt *myrpt, char *sptr)
3161 {
3162         int     busy=0;
3163
3164         rpt_mutex_lock(&myrpt->lock);
3165         if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(sptr)){
3166                 rpt_mutex_unlock(&myrpt->lock);
3167                 busy=1;
3168         }
3169         if(!busy){
3170                 int x;
3171                 if (debug)ast_log(LOG_NOTICE, "rpt_push_alt_macro %s\n",sptr);
3172                 myrpt->macrotimer = MACROTIME;
3173                 for(x = 0; *(sptr + x); x++)
3174                     myrpt->macrobuf[x] = *(sptr + x) | 0x80;
3175                 *(sptr + x) = 0;
3176         }
3177         rpt_mutex_unlock(&myrpt->lock);
3178
3179         if(busy)ast_log(LOG_WARNING, "Function decoder busy on app_rpt command macro.\n");
3180
3181         return busy;
3182 }
3183 /*
3184         allows us to test rpt() application data commands
3185 */
3186 static int rpt_do_fun1(int fd, int argc, const char * const *argv)
3187 {
3188         int     i;
3189
3190     if (argc != 4) return RESULT_SHOWUSAGE;
3191
3192         for(i = 0; i < nrpts; i++){
3193                 if(!strcmp(argv[2], rpt_vars[i].name)){
3194                         struct rpt *myrpt = &rpt_vars[i];
3195                         rpt_push_alt_macro(myrpt, (char *) argv[3]);
3196                 }
3197         }
3198         return RESULT_FAILURE;
3199 }
3200 /*
3201 * send an app_rpt **command** from the CLI
3202 */
3203
3204 static int rpt_do_cmd(int fd, int argc, const char * const *argv)
3205 {
3206         int i, l;
3207         int busy=0;
3208         int maxActions = sizeof(function_table)/sizeof(struct function_table_tag);
3209
3210         int thisRpt = -1;
3211         int thisAction = -1;
3212         struct rpt *myrpt = NULL;
3213         if (argc != 6) return RESULT_SHOWUSAGE;
3214         
3215         for(i = 0; i < nrpts; i++)
3216         {
3217                 if(!strcmp(argv[2], rpt_vars[i].name))
3218                 {
3219                         thisRpt = i;
3220                         myrpt = &rpt_vars[i];
3221                         break;
3222                 } /* if !strcmp... */
3223         } /* for i */
3224
3225         if (thisRpt < 0)
3226         {
3227                 ast_cli(fd, "Unknown node number %s.\n", argv[2]);
3228                 return RESULT_FAILURE;
3229         } /* if thisRpt < 0 */
3230         
3231         /* Look up the action */
3232         l = strlen(argv[3]);
3233         for(i = 0 ; i < maxActions; i++)
3234         {
3235                 if(!strncasecmp(argv[3], function_table[i].action, l))
3236                 {
3237                         thisAction = i;
3238                         break;
3239                 } /* if !strncasecmp... */
3240         } /* for i */
3241         
3242         if (thisAction < 0)
3243         {
3244                 ast_cli(fd, "Unknown action name %s.\n", argv[3]);
3245                 return RESULT_FAILURE;
3246         } /* if thisAction < 0 */
3247
3248         /* at this point, it looks like all the arguments make sense... */
3249
3250         rpt_mutex_lock(&myrpt->lock);
3251
3252         if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE)
3253         {
3254                 rpt_vars[thisRpt].cmdAction.state = CMD_STATE_BUSY;
3255                 rpt_vars[thisRpt].cmdAction.functionNumber = thisAction;
3256                 strncpy(rpt_vars[thisRpt].cmdAction.param, argv[4], MAXDTMF);
3257                 strncpy(rpt_vars[thisRpt].cmdAction.digits, argv[5], MAXDTMF);
3258                 rpt_vars[thisRpt].cmdAction.command_source = SOURCE_RPT;
3259                 rpt_vars[thisRpt].cmdAction.state = CMD_STATE_READY;
3260         } /* if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE */
3261         else
3262         {
3263                 busy = 1;
3264         } /* if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE */
3265         rpt_mutex_unlock(&myrpt->lock);
3266
3267         return (busy ? RESULT_FAILURE : RESULT_SUCCESS);
3268 } /* rpt_do_cmd() */
3269
3270 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
3271 {
3272         int res;
3273
3274         if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
3275