Eliminate several needless checks and fix a few memory leaks
[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
886 AST_MUTEX_DEFINE_STATIC(nodeloglock);
887
888 AST_MUTEX_DEFINE_STATIC(nodelookuplock);
889
890 #ifdef  APP_RPT_LOCK_DEBUG
891
892 #warning COMPILING WITH LOCK-DEBUGGING ENABLED!!
893
894 #define MAXLOCKTHREAD 100
895
896 #define rpt_mutex_lock(x) _rpt_mutex_lock(x,myrpt,__LINE__)
897 #define rpt_mutex_unlock(x) _rpt_mutex_unlock(x,myrpt,__LINE__)
898
899 struct lockthread
900 {
901         pthread_t id;
902         int lockcount;
903         int lastlock;
904         int lastunlock;
905 } lockthreads[MAXLOCKTHREAD];
906
907
908 struct by_lightning
909 {
910         int line;
911         struct timeval tv;
912         struct rpt *rpt;
913         struct lockthread lockthread;
914 } lock_ring[32];
915
916 int lock_ring_index = 0;
917
918 AST_MUTEX_DEFINE_STATIC(locklock);
919
920 static struct lockthread *get_lockthread(pthread_t id)
921 {
922 int     i;
923
924         for(i = 0; i < MAXLOCKTHREAD; i++)
925         {
926                 if (lockthreads[i].id == id) return(&lockthreads[i]);
927         }
928         return(NULL);
929 }
930
931 static struct lockthread *put_lockthread(pthread_t id)
932 {
933 int     i;
934
935         for(i = 0; i < MAXLOCKTHREAD; i++)
936         {
937                 if (lockthreads[i].id == id)
938                         return(&lockthreads[i]);
939         }
940         for(i = 0; i < MAXLOCKTHREAD; i++)
941         {
942                 if (!lockthreads[i].id)
943                 {
944                         lockthreads[i].lockcount = 0;
945                         lockthreads[i].lastlock = 0;
946                         lockthreads[i].lastunlock = 0;
947                         lockthreads[i].id = id;
948                         return(&lockthreads[i]);
949                 }
950         }
951         return(NULL);
952 }
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 /*
1074 * Return 1 if rig is multimode capable
1075 */
1076
1077 static int multimode_capable(struct rpt *myrpt)
1078 {
1079         if(!strcmp(myrpt->remoterig, remote_rig_ft897))
1080                 return 1;
1081         if(!strcmp(myrpt->remoterig, remote_rig_ic706))
1082                 return 1;
1083         return 0;
1084 }       
1085
1086 static void voxinit_rpt(struct rpt *myrpt,char enable)
1087 {
1088
1089         myrpt->vox.speech_energy = 0.0;
1090         myrpt->vox.noise_energy = 0.0;
1091         myrpt->vox.enacount = 0;
1092         myrpt->vox.voxena = 0;
1093         if (!enable) myrpt->vox.voxena = -1;
1094         myrpt->vox.lastvox = 0;
1095         myrpt->vox.ondebcnt = VOX_ON_DEBOUNCE_COUNT;
1096         myrpt->vox.offdebcnt = VOX_OFF_DEBOUNCE_COUNT;
1097         myrpt->wasvox = 0;
1098         myrpt->voxtotimer = 0;
1099         myrpt->voxtostate = 0;
1100 }
1101
1102 static void voxinit_link(struct rpt_link *mylink,char enable)
1103 {
1104
1105         mylink->vox.speech_energy = 0.0;
1106         mylink->vox.noise_energy = 0.0;
1107         mylink->vox.enacount = 0;
1108         mylink->vox.voxena = 0;
1109         if (!enable) mylink->vox.voxena = -1;
1110         mylink->vox.lastvox = 0;
1111         mylink->vox.ondebcnt = VOX_ON_DEBOUNCE_COUNT;
1112         mylink->vox.offdebcnt = VOX_OFF_DEBOUNCE_COUNT;
1113         mylink->wasvox = 0;
1114         mylink->voxtotimer = 0;
1115         mylink->voxtostate = 0;
1116 }
1117
1118 static int dovox(struct vox *v,short *buf,int bs)
1119 {
1120
1121         int i;
1122         float   esquare = 0.0;
1123         float   energy = 0.0;
1124         float   threshold = 0.0;
1125         
1126         if (v->voxena < 0) return(v->lastvox);
1127         for(i = 0; i < bs; i++)
1128         {
1129                 esquare += (float) buf[i] * (float) buf[i];
1130         }
1131         energy = sqrt(esquare);
1132
1133         if (energy >= v->speech_energy)
1134                 v->speech_energy += (energy - v->speech_energy) / 4;
1135         else
1136                 v->speech_energy += (energy - v->speech_energy) / 64;
1137
1138         if (energy >= v->noise_energy)
1139                 v->noise_energy += (energy - v->noise_energy) / 64;
1140         else
1141                 v->noise_energy += (energy - v->noise_energy) / 4;
1142         
1143         if (v->voxena) threshold = v->speech_energy / 8;
1144         else
1145         {
1146                 threshold = mymax(v->speech_energy / 16,v->noise_energy * 2);
1147                 threshold = mymin(threshold,VOX_MAX_THRESHOLD);
1148         }
1149         threshold = mymax(threshold,VOX_MIN_THRESHOLD);
1150         if (energy > threshold)
1151         {
1152                 if (v->voxena) v->noise_energy *= 0.75;
1153                 v->voxena = 1;
1154         } else  v->voxena = 0;
1155         if (v->lastvox != v->voxena)
1156         {
1157                 if (v->enacount++ >= ((v->lastvox) ? v->offdebcnt : v->ondebcnt))
1158                 {
1159                         v->lastvox = v->voxena;
1160                         v->enacount = 0;
1161                 }
1162         } else v->enacount = 0;
1163         return(v->lastvox);
1164 }
1165
1166
1167
1168
1169 /*
1170 * CLI extensions
1171 */
1172
1173 /* Debug mode */
1174 static int rpt_do_debug(int fd, int argc, char *argv[]);
1175 static int rpt_do_dump(int fd, int argc, char *argv[]);
1176 static int rpt_do_stats(int fd, int argc, char *argv[]);
1177 static int rpt_do_lstats(int fd, int argc, char *argv[]);
1178 static int rpt_do_nodes(int fd, int argc, char *argv[]);
1179 static int rpt_do_local_nodes(int fd, int argc, char *argv[]);
1180 static int rpt_do_reload(int fd, int argc, char *argv[]);
1181 static int rpt_do_restart(int fd, int argc, char *argv[]);
1182 static int rpt_do_fun(int fd, int argc, char *argv[]);
1183 static int rpt_do_fun1(int fd, int argc, char *argv[]);
1184 static int rpt_do_cmd(int fd, int argc, char *argv[]);
1185
1186 static char debug_usage[] =
1187 "Usage: rpt debug level {0-7}\n"
1188 "       Enables debug messages in app_rpt\n";
1189
1190 static char dump_usage[] =
1191 "Usage: rpt dump <nodename>\n"
1192 "       Dumps struct debug info to log\n";
1193
1194 static char dump_stats[] =
1195 "Usage: rpt stats <nodename>\n"
1196 "       Dumps node statistics to console\n";
1197
1198 static char dump_lstats[] =
1199 "Usage: rpt lstats <nodename>\n"
1200 "       Dumps link statistics to console\n";
1201
1202 static char dump_nodes[] =
1203 "Usage: rpt nodes <nodename>\n"
1204 "       Dumps a list of directly and indirectly connected nodes to the console\n";
1205
1206 static char usage_local_nodes[] =
1207 "Usage: rpt localnodes\n"
1208 "       Dumps a list of the locally configured node numbers to the console.\n";
1209
1210 static char reload_usage[] =
1211 "Usage: rpt reload\n"
1212 "       Reloads app_rpt running config parameters\n";
1213
1214 static char restart_usage[] =
1215 "Usage: rpt restart\n"
1216 "       Restarts app_rpt\n";
1217
1218 static char fun_usage[] =
1219 "Usage: rpt fun <nodename> <command>\n"
1220 "       Send a DTMF function to a node\n";
1221
1222 static char cmd_usage[] =
1223 "Usage: rpt cmd <nodename> <cmd-name> <cmd-index> <cmd-args.\n"
1224 "       Send a command to a node.\n        i.e. rpt cmd 2000 ilink 3 2001\n";
1225
1226 #ifndef NEW_ASTERISK
1227
1228 static struct ast_cli_entry  cli_debug =
1229         { { "rpt", "debug", "level" }, rpt_do_debug, 
1230                 "Enable app_rpt debugging", debug_usage };
1231
1232 static struct ast_cli_entry  cli_dump =
1233         { { "rpt", "dump" }, rpt_do_dump,
1234                 "Dump app_rpt structs for debugging", dump_usage };
1235
1236 static struct ast_cli_entry  cli_stats =
1237         { { "rpt", "stats" }, rpt_do_stats,
1238                 "Dump node statistics", dump_stats };
1239
1240 static struct ast_cli_entry  cli_nodes =
1241         { { "rpt", "nodes" }, rpt_do_nodes,
1242                 "Dump node list", dump_nodes };
1243
1244 static struct ast_cli_entry  cli_local_nodes =
1245         { { "rpt", "localnodes" }, rpt_do_local_nodes,
1246                 "Dump list of local node numbers", usage_local_nodes };
1247
1248 static struct ast_cli_entry  cli_lstats =
1249         { { "rpt", "lstats" }, rpt_do_lstats,
1250                 "Dump link statistics", dump_lstats };
1251
1252 static struct ast_cli_entry  cli_reload =
1253         { { "rpt", "reload" }, rpt_do_reload,
1254                 "Reload app_rpt config", reload_usage };
1255
1256 static struct ast_cli_entry  cli_restart =
1257         { { "rpt", "restart" }, rpt_do_restart,
1258                 "Restart app_rpt", restart_usage };
1259
1260 static struct ast_cli_entry  cli_fun =
1261         { { "rpt", "fun" }, rpt_do_fun,
1262                 "Execute a DTMF function", fun_usage };
1263
1264 static struct ast_cli_entry  cli_fun1 =
1265         { { "rpt", "fun1" }, rpt_do_fun1,
1266                 "Execute a DTMF function", fun_usage };
1267
1268 static struct ast_cli_entry  cli_cmd =
1269         { { "rpt", "cmd" }, rpt_do_cmd,
1270                 "Execute a DTMF function", cmd_usage };
1271
1272 #endif
1273
1274 /*
1275 * Telemetry defaults
1276 */
1277
1278
1279 static struct telem_defaults tele_defs[] = {
1280         {"ct1","|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
1281         {"ct2","|t(660,880,150,3072)"},
1282         {"ct3","|t(440,0,150,3072)"},
1283         {"ct4","|t(550,0,150,3072)"},
1284         {"ct5","|t(660,0,150,3072)"},
1285         {"ct6","|t(880,0,150,3072)"},
1286         {"ct7","|t(660,440,150,3072)"},
1287         {"ct8","|t(700,1100,150,3072)"},
1288         {"remotemon","|t(1600,0,75,2048)"},
1289         {"remotetx","|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
1290         {"cmdmode","|t(900,904,200,2048)"},
1291         {"functcomplete","|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
1292 } ;
1293
1294 /*
1295 * Forward decl's - these suppress compiler warnings when funcs coded further down the file than thier invokation
1296 */
1297
1298 static int setrbi(struct rpt *myrpt);
1299 static int set_ft897(struct rpt *myrpt);
1300 static int set_ic706(struct rpt *myrpt);
1301 static int setkenwood(struct rpt *myrpt);
1302 static int set_tm271(struct rpt *myrpt);
1303 static int setrbi_check(struct rpt *myrpt);
1304
1305
1306
1307 /*
1308 * Define function protos for function table here
1309 */
1310
1311 static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1312 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1313 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1314 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1315 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1316 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1317 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1318 static int function_playback(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1319 /*
1320 * Function table
1321 */
1322
1323 static struct function_table_tag function_table[] = {
1324         {"cop", function_cop},
1325         {"autopatchup", function_autopatchup},
1326         {"autopatchdn", function_autopatchdn},
1327         {"ilink", function_ilink},
1328         {"status", function_status},
1329         {"remote", function_remote},
1330         {"macro", function_macro},
1331         {"playback", function_playback}
1332 } ;
1333
1334 static long diskavail(struct rpt *myrpt)
1335 {
1336 struct  statfs statfsbuf;
1337
1338         if (!myrpt->p.archivedir) return(0);
1339         if (statfs(myrpt->p.archivedir,&statfsbuf) == -1)
1340         {
1341                 ast_log(LOG_WARNING,"Cannot get filesystem size for %s node %s\n",
1342                         myrpt->p.archivedir,myrpt->name);
1343                 return(-1);
1344         }
1345         return(statfsbuf.f_bavail);
1346 }
1347
1348 static void flush_telem(struct rpt *myrpt)
1349 {
1350         struct rpt_tele *telem;
1351         if(debug > 2)
1352                 ast_log(LOG_NOTICE, "flush_telem()!!");
1353         rpt_mutex_lock(&myrpt->lock);
1354         telem = myrpt->tele.next;
1355         while(telem != &myrpt->tele)
1356         {
1357                 if (telem->mode != SETREMOTE) ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
1358                 telem = telem->next;
1359         }
1360         rpt_mutex_unlock(&myrpt->lock);
1361 }
1362 /*
1363         return via error priority
1364 */
1365 static int priority_jump(struct rpt *myrpt, struct ast_channel *chan)
1366 {
1367         int res=0;
1368
1369         // if (ast_test_flag(&flags,OPT_JUMP) && ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101) == 0){
1370         if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101) == 0){
1371                 res = 0;
1372         } else {
1373                 res = -1;
1374         }
1375         return res;
1376 }
1377 /*
1378 */
1379 static int linkcount(struct rpt *myrpt)
1380 {
1381         struct  rpt_link *l;
1382         char *reverse_patch_state;
1383         int numoflinks;
1384
1385         reverse_patch_state = "DOWN";
1386         numoflinks = 0;
1387         l = myrpt->links.next;
1388         while(l && (l != &myrpt->links)){
1389                 if(numoflinks >= MAX_STAT_LINKS){
1390                         ast_log(LOG_WARNING,
1391                         "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
1392                         break;
1393                 }
1394                 //if (l->name[0] == '0'){ /* Skip '0' nodes */
1395                 //      reverse_patch_state = "UP";
1396                 //      l = l->next;
1397                 //      continue;
1398                 //}
1399                 numoflinks++;
1400          
1401                 l = l->next;
1402         }
1403         ast_log(LOG_NOTICE, "numoflinks=%i\n",numoflinks);
1404         return numoflinks;
1405 }
1406 /*
1407  * Retrieve a memory channel
1408  * Return 0 if sucessful,
1409  * -1 if channel not found,
1410  *  1 if parse error
1411  */
1412 static int retreive_memory(struct rpt *myrpt, char *memory)
1413 {
1414         char tmp[30], *s, *s1, *val;
1415
1416         if (debug)ast_log(LOG_NOTICE, "memory=%s block=%s\n",memory,myrpt->p.memory);
1417
1418         val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.memory, memory);
1419         if (!val){
1420                 return -1;
1421         }                       
1422         strncpy(tmp,val,sizeof(tmp) - 1);
1423         tmp[sizeof(tmp)-1] = 0;
1424
1425         s = strchr(tmp,',');
1426         if (!s)
1427                 return 1; 
1428         *s++ = 0;
1429         s1 = strchr(s,',');
1430         if (!s1)
1431                 return 1;
1432         *s1++ = 0;
1433         strncpy(myrpt->freq, tmp, sizeof(myrpt->freq) - 1);
1434         strncpy(myrpt->rxpl, s, sizeof(myrpt->rxpl) - 1);
1435         strncpy(myrpt->txpl, s, sizeof(myrpt->rxpl) - 1);
1436         myrpt->remmode = REM_MODE_FM;
1437         myrpt->offset = REM_SIMPLEX;
1438         myrpt->powerlevel = REM_MEDPWR;
1439         myrpt->txplon = myrpt->rxplon = 0;
1440         while(*s1){
1441                 switch(*s1++){
1442                         case 'A':
1443                         case 'a':
1444                                 strcpy(myrpt->rxpl, "100.0");
1445                                 strcpy(myrpt->txpl, "100.0");
1446                                 myrpt->remmode = REM_MODE_AM;   
1447                                 break;
1448                         case 'B':
1449                         case 'b':
1450                                 strcpy(myrpt->rxpl, "100.0");
1451                                 strcpy(myrpt->txpl, "100.0");
1452                                 myrpt->remmode = REM_MODE_LSB;
1453                                 break;
1454                         case 'F':
1455                                 myrpt->remmode = REM_MODE_FM;
1456                                 break;
1457                         case 'L':
1458                         case 'l':
1459                                 myrpt->powerlevel = REM_LOWPWR;
1460                                 break;                                  
1461                         case 'H':
1462                         case 'h':
1463                                 myrpt->powerlevel = REM_HIPWR;
1464                                 break;
1465                                         
1466                         case 'M':
1467                         case 'm':
1468                                 myrpt->powerlevel = REM_MEDPWR;
1469                                 break;
1470                                                 
1471                         case '-':
1472                                 myrpt->offset = REM_MINUS;
1473                                 break;
1474                                                 
1475                         case '+':
1476                                 myrpt->offset = REM_PLUS;
1477                                 break;
1478                                                 
1479                         case 'S':
1480                         case 's':
1481                                 myrpt->offset = REM_SIMPLEX;
1482                                 break;
1483                                                 
1484                         case 'T':
1485                         case 't':
1486                                 myrpt->txplon = 1;
1487                                 break;
1488                                                 
1489                         case 'R':
1490                         case 'r':
1491                                 myrpt->rxplon = 1;
1492                                 break;
1493
1494                         case 'U':
1495                         case 'u':
1496                                 strcpy(myrpt->rxpl, "100.0");
1497                                 strcpy(myrpt->txpl, "100.0");
1498                                 myrpt->remmode = REM_MODE_USB;
1499                                 break;
1500                         default:
1501                                 return 1;
1502                 }
1503         }
1504         return 0;
1505 }
1506 /*
1507
1508 */
1509 static void birdbath(struct rpt *myrpt)
1510 {
1511         struct rpt_tele *telem;
1512         if(debug > 2)
1513                 ast_log(LOG_NOTICE, "birdbath!!");
1514         rpt_mutex_lock(&myrpt->lock);
1515         telem = myrpt->tele.next;
1516         while(telem != &myrpt->tele)
1517         {
1518                 if (telem->mode == PARROT) ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
1519                 telem = telem->next;
1520         }
1521         rpt_mutex_unlock(&myrpt->lock);
1522 }
1523
1524 static void do_dtmf_phone(struct rpt *myrpt, struct rpt_link *mylink, char c)
1525 {
1526 struct        rpt_link *l;
1527
1528        l = myrpt->links.next;
1529        /* go thru all the links */
1530        while(l != &myrpt->links)
1531        {
1532                if (!l->phonemode)
1533                {
1534                        l = l->next;
1535                        continue;
1536                }
1537                /* dont send to self */
1538                if (mylink && (l == mylink))
1539                {
1540                        l = l->next;
1541                        continue;
1542                }
1543 #ifdef  NEW_ASTERISK
1544                if (l->chan) ast_senddigit(l->chan,c,0);
1545 #else
1546                if (l->chan) ast_senddigit(l->chan,c);
1547 #endif
1548                l = l->next;
1549        }
1550        return;
1551 }
1552
1553 /* node logging function */
1554 static void donodelog(struct rpt *myrpt,char *str)
1555 {
1556 struct nodelog *nodep;
1557 char    datestr[100];
1558
1559         if (!myrpt->p.archivedir) return;
1560         nodep = (struct nodelog *)ast_malloc(sizeof(struct nodelog));
1561         if (nodep == NULL)
1562         {
1563                 ast_log(LOG_ERROR,"Cannot get memory for node log");
1564                 return;
1565         }
1566         time(&nodep->timestamp);
1567         strncpy(nodep->archivedir,myrpt->p.archivedir,
1568                 sizeof(nodep->archivedir) - 1);
1569         strftime(datestr,sizeof(datestr) - 1,"%Y%m%d%H%M%S",
1570                 localtime(&nodep->timestamp));
1571         snprintf(nodep->str,sizeof(nodep->str) - 1,"%s %s,%s\n",
1572                 myrpt->name,datestr,str);
1573         ast_mutex_lock(&nodeloglock);
1574         insque((struct qelem *) nodep, (struct qelem *) nodelog.prev);
1575         ast_mutex_unlock(&nodeloglock);
1576 }
1577
1578 /* must be called locked */
1579 static void do_dtmf_local(struct rpt *myrpt, char c)
1580 {
1581 int     i;
1582 char    digit;
1583 static const char* dtmf_tones[] = {
1584         "!941+1336/200,!0/200", /* 0 */
1585         "!697+1209/200,!0/200", /* 1 */
1586         "!697+1336/200,!0/200", /* 2 */
1587         "!697+1477/200,!0/200", /* 3 */
1588         "!770+1209/200,!0/200", /* 4 */
1589         "!770+1336/200,!0/200", /* 5 */
1590         "!770+1477/200,!0/200", /* 6 */
1591         "!852+1209/200,!0/200", /* 7 */
1592         "!852+1336/200,!0/200", /* 8 */
1593         "!852+1477/200,!0/200", /* 9 */
1594         "!697+1633/200,!0/200", /* A */
1595         "!770+1633/200,!0/200", /* B */
1596         "!852+1633/200,!0/200", /* C */
1597         "!941+1633/200,!0/200", /* D */
1598         "!941+1209/200,!0/200", /* * */
1599         "!941+1477/200,!0/200" };       /* # */
1600
1601
1602         if (c)
1603         {
1604                 snprintf(myrpt->dtmf_local_str + strlen(myrpt->dtmf_local_str),sizeof(myrpt->dtmf_local_str) - 1,"%c",c);
1605                 if (!myrpt->dtmf_local_timer) 
1606                          myrpt->dtmf_local_timer = DTMF_LOCAL_STARTTIME;
1607         }
1608         /* if at timeout */
1609         if (myrpt->dtmf_local_timer == 1)
1610         {
1611                 if(debug > 6)
1612                         ast_log(LOG_NOTICE,"time out dtmf_local_timer=%i\n",myrpt->dtmf_local_timer);
1613
1614                 /* if anything in the string */
1615                 if (myrpt->dtmf_local_str[0])
1616                 {
1617                         digit = myrpt->dtmf_local_str[0];
1618                         myrpt->dtmf_local_str[0] = 0;
1619                         for(i = 1; myrpt->dtmf_local_str[i]; i++)
1620                         {
1621                                 myrpt->dtmf_local_str[i - 1] =
1622                                         myrpt->dtmf_local_str[i];
1623                         }
1624                         myrpt->dtmf_local_str[i - 1] = 0;
1625                         myrpt->dtmf_local_timer = DTMF_LOCAL_TIME;
1626                         rpt_mutex_unlock(&myrpt->lock);
1627                         if (digit >= '0' && digit <='9')
1628                                 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'0'], 0);
1629                         else if (digit >= 'A' && digit <= 'D')
1630                                 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'A'+10], 0);
1631                         else if (digit == '*')
1632                                 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[14], 0);
1633                         else if (digit == '#')
1634                                 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[15], 0);
1635                         else {
1636                                 /* not handled */
1637                                 ast_log(LOG_DEBUG, "Unable to generate DTMF tone '%c' for '%s'\n", digit, myrpt->txchannel->name);
1638                         }
1639                         rpt_mutex_lock(&myrpt->lock);
1640                 }
1641                 else
1642                 {
1643                         myrpt->dtmf_local_timer = 0;
1644                 }
1645         }
1646 }
1647
1648 static int setdtr(int fd, int enable)
1649 {
1650 struct termios mode;
1651
1652         if (fd < 0) return -1;
1653         if (tcgetattr(fd, &mode)) {
1654                 ast_log(LOG_WARNING, "Unable to get serial parameters for dtr: %s\n", strerror(errno));
1655                 return -1;
1656         }
1657         if (enable)
1658         {
1659                 cfsetspeed(&mode, B9600);
1660         }
1661         else
1662         {
1663                 cfsetspeed(&mode, B0);
1664                 usleep(100000);
1665         }
1666         if (tcsetattr(fd, TCSADRAIN, &mode)) {
1667                 ast_log(LOG_WARNING, "Unable to set serial parameters for dtr: %s\n", strerror(errno));
1668                 return -1;
1669         }
1670         if (enable) usleep(100000);
1671         return 0;
1672 }
1673
1674 static int openserial(struct rpt *myrpt,char *fname)
1675 {
1676         struct termios mode;
1677         int fd;
1678
1679         fd = open(fname,O_RDWR);
1680         if (fd == -1)
1681         {
1682                 ast_log(LOG_WARNING,"Cannot open serial port %s\n",fname);
1683                 return -1;
1684         }
1685         memset(&mode, 0, sizeof(mode));
1686         if (tcgetattr(fd, &mode)) {
1687                 ast_log(LOG_WARNING, "Unable to get serial parameters on %s: %s\n", fname, strerror(errno));
1688                 return -1;
1689         }
1690 #ifndef SOLARIS
1691         cfmakeraw(&mode);
1692 #else
1693         mode.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
1694                         |INLCR|IGNCR|ICRNL|IXON);
1695         mode.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
1696         mode.c_cflag &= ~(CSIZE|PARENB|CRTSCTS);
1697         mode.c_cflag |= CS8;
1698         mode.c_cc[VTIME] = 3;
1699         mode.c_cc[VMIN] = 1; 
1700 #endif
1701
1702         cfsetispeed(&mode, B9600);
1703         cfsetospeed(&mode, B9600);
1704         if (tcsetattr(fd, TCSANOW, &mode)) 
1705                 ast_log(LOG_WARNING, "Unable to set serial parameters on %s: %s\n", fname, strerror(errno));
1706         if(!strcmp(myrpt->remoterig, remote_rig_kenwood)) setdtr(fd,0); 
1707         usleep(100000);
1708         if (debug)ast_log(LOG_NOTICE,"Opened serial port %s\n",fname);
1709         return(fd);     
1710 }
1711
1712 static void mdc1200_notify(struct rpt *myrpt,char *fromnode, unsigned int unit)
1713 {
1714         if (!fromnode)
1715         {
1716                 ast_verbose("Got MDC-1200 ID %04X from local system (%s)\n",
1717                         unit,myrpt->name);
1718         }
1719         else
1720         {
1721                 ast_verbose("Got MDC-1200 ID %04X from node %s (%s)\n",
1722                         unit,fromnode,myrpt->name);
1723         }
1724 }
1725
1726 #ifdef  _MDC_DECODE_H_
1727
1728 static void mdc1200_send(struct rpt *myrpt, unsigned int unit)
1729 {
1730 struct rpt_link *l;
1731 struct  ast_frame wf;
1732 char    str[200];
1733
1734
1735         sprintf(str,"I %s %04X",myrpt->name,unit);
1736
1737         wf.frametype = AST_FRAME_TEXT;
1738         wf.subclass = 0;
1739         wf.offset = 0;
1740         wf.mallocd = 0;
1741         wf.datalen = strlen(str) + 1;
1742         wf.samples = 0;
1743
1744
1745         l = myrpt->links.next;
1746         /* otherwise, send it to all of em */
1747         while(l != &myrpt->links)
1748         {
1749                 if (l->name[0] == '0') 
1750                 {
1751                         l = l->next;
1752                         continue;
1753                 }
1754                 wf.data = str;
1755                 if (l->chan) ast_write(l->chan,&wf); 
1756                 l = l->next;
1757         }
1758         return;
1759 }
1760
1761 #endif
1762
1763 static char func_xlat(struct rpt *myrpt,char c,struct rpt_xlat *xlat)
1764 {
1765 time_t  now;
1766 int     gotone;
1767
1768         time(&now);
1769         gotone = 0;
1770         /* if too much time, reset the skate machine */
1771         if ((now - xlat->lastone) > MAXXLATTIME)
1772         {
1773                 xlat->funcindex = xlat->endindex = 0;
1774         }
1775         if (xlat->funccharseq[0] && (c == xlat->funccharseq[xlat->funcindex++]))
1776         {
1777                 time(&xlat->lastone);
1778                 gotone = 1;
1779                 if (!xlat->funccharseq[xlat->funcindex])
1780                 {
1781                         xlat->funcindex = xlat->endindex = 0;
1782                         return(myrpt->p.funcchar);
1783                 }
1784         } else xlat->funcindex = 0;
1785         if (xlat->endcharseq[0] && (c == xlat->endcharseq[xlat->endindex++]))
1786         {
1787                 time(&xlat->lastone);
1788                 gotone = 1;
1789                 if (!xlat->endcharseq[xlat->endindex])
1790                 {
1791                         xlat->funcindex = xlat->endindex = 0;
1792                         return(myrpt->p.endchar);
1793                 }
1794         } else xlat->endindex = 0;
1795         /* if in middle of decode seq, send nothing back */
1796         if (gotone) return(0);
1797         /* if no pass chars specified, return em all */
1798         if (!xlat->passchars[0]) return(c);
1799         /* if a "pass char", pass it */
1800         if (strchr(xlat->passchars,c)) return(c);
1801         return(0);
1802 }
1803
1804 /*
1805  * Return a pointer to the first non-whitespace character
1806  */
1807
1808 static char *eatwhite(char *s)
1809 {
1810         while((*s == ' ') || (*s == 0x09)){ /* get rid of any leading white space */
1811                 if(!*s)
1812                         break;
1813                 s++;
1814         }
1815         return s;
1816 }
1817
1818 /*
1819 * Break up a delimited string into a table of substrings
1820 *
1821 * str - delimited string ( will be modified )
1822 * strp- list of pointers to substrings (this is built by this function), NULL will be placed at end of list
1823 * limit- maximum number of substrings to process
1824 */
1825         
1826
1827
1828 static int finddelim(char *str, char *strp[], int limit)
1829 {
1830 int     i,l,inquo;
1831
1832         inquo = 0;
1833         i = 0;
1834         strp[i++] = str;
1835         if (!*str)
1836            {
1837                 strp[0] = 0;
1838                 return(0);
1839            }
1840         for(l = 0; *str && (l < limit) ; str++)
1841            {
1842                 if (*str == QUOTECHR)
1843                    {
1844                         if (inquo)
1845                            {
1846                                 *str = 0;
1847                                 inquo = 0;
1848                            }
1849                         else
1850                            {
1851                                 strp[i - 1] = str + 1;
1852                                 inquo = 1;
1853                            }
1854                 }
1855                 if ((*str == DELIMCHR) && (!inquo))
1856                 {
1857                         *str = 0;
1858                         l++;
1859                         strp[i++] = str + 1;
1860                 }
1861            }
1862         strp[i] = 0;
1863         return(i);
1864
1865 }
1866 /*
1867         send asterisk frame text message on the current tx channel
1868 */
1869 static int send_usb_txt(struct rpt *myrpt, char *txt) 
1870 {
1871         struct ast_frame wf;
1872  
1873         if (debug)ast_log(LOG_NOTICE, "send_usb_txt %s\n",txt);
1874         wf.frametype = AST_FRAME_TEXT;
1875         wf.subclass = 0;
1876         wf.offset = 0;
1877         wf.mallocd = 0;
1878         wf.datalen = strlen(txt) + 1;
1879         wf.data.ptr = txt;
1880         wf.samples = 0;
1881         ast_write(myrpt->txchannel,&wf); 
1882         return 0;
1883 }
1884 /* must be called locked */
1885 static void __mklinklist(struct rpt *myrpt, struct rpt_link *mylink, char *buf)
1886 {
1887 struct rpt_link *l;
1888 char mode;
1889 int     i,spos;
1890
1891         buf[0] = 0; /* clear output buffer */
1892         if (myrpt->remote) return;
1893         /* go thru all links */
1894         for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
1895         {
1896                 /* if is not a real link, ignore it */
1897                 if (l->name[0] == '0') continue;
1898                 /* dont count our stuff */
1899                 if (l == mylink) continue;
1900                 if (mylink && (!strcmp(l->name,mylink->name))) continue;
1901                 /* figure out mode to report */
1902                 mode = 'T'; /* use Tranceive by default */
1903                 if (!l->mode) mode = 'R'; /* indicate RX for our mode */
1904                 if (!l->thisconnected)  mode = 'C'; /* indicate connecting */
1905                 spos = strlen(buf); /* current buf size (b4 we add our stuff) */
1906                 if (spos)
1907                 {
1908                         strcat(buf,",");
1909                         spos++;
1910                 }
1911                 /* add nodes into buffer */
1912                 if (l->linklist[0])
1913                 {
1914                         snprintf(buf + spos,MAXLINKLIST - spos,
1915                                 "%c%s,%s",mode,l->name,l->linklist);
1916                 }
1917                 else /* if no nodes, add this node into buffer */
1918                 {
1919                         snprintf(buf + spos,MAXLINKLIST - spos,
1920                                 "%c%s",mode,l->name);
1921                 }
1922                 /* if we are in tranceive mode, let all modes stand */
1923                 if (mode == 'T') continue;
1924                 /* downgrade everyone on this node if appropriate */
1925                 for(i = spos; buf[i]; i++)
1926                 {
1927                         if (buf[i] == 'T') buf[i] = mode;
1928                         if ((buf[i] == 'R') && (mode == 'C')) buf[i] = mode;
1929                 }
1930         }
1931         return;
1932 }
1933
1934 /* must be called locked */
1935 static void __kickshort(struct rpt *myrpt)
1936 {
1937 struct rpt_link *l;
1938
1939         for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
1940         {
1941                 /* if is not a real link, ignore it */
1942                 if (l->name[0] == '0') continue;
1943                 l->linklisttimer = LINKLISTSHORTTIME;
1944         }
1945         myrpt->linkposttimer = LINKPOSTSHORTTIME;
1946         return;
1947 }
1948
1949 static void statpost(struct rpt *myrpt,char *pairs)
1950 {
1951 char *str,*astr;
1952 char *astrs[100];
1953 int     n,pid;
1954 time_t  now;
1955 unsigned int seq;
1956
1957         if (!myrpt->p.statpost_url) return;
1958         str = ast_malloc(strlen(pairs) + strlen(myrpt->p.statpost_url) + 200);
1959         astr = ast_strdup(myrpt->p.statpost_program);
1960         if ((!str) || (!astr)) {
1961                 ast_free(str);
1962                 ast_free(astr);
1963                 return;
1964         }
1965         n = finddelim(astr,astrs,100);
1966         if (n < 1) return;
1967         ast_mutex_lock(&myrpt->statpost_lock);
1968         seq = ++myrpt->statpost_seqno;
1969         ast_mutex_unlock(&myrpt->statpost_lock);
1970         astrs[n++] = str;
1971         astrs[n] = NULL;
1972         time(&now);
1973         sprintf(str,"%s?node=%s&time=%u&seqno=%u",myrpt->p.statpost_url,
1974                 myrpt->name,(unsigned int) now,seq);
1975         if (pairs) sprintf(str + strlen(str),"&%s",pairs);
1976         if (!(pid = ast_safe_fork(0)))
1977         {
1978                 execv(astrs[0],astrs);
1979                 ast_log(LOG_ERROR, "exec of %s failed.\n", astrs[0]);
1980                 perror("asterisk");
1981                 exit(0);
1982         }
1983         ast_free(astr);
1984         ast_free(str);
1985         return;
1986 }
1987
1988 static char *node_lookup(struct rpt *myrpt,char *digitbuf)
1989 {
1990
1991 char *val;
1992 int longestnode,j;
1993 struct stat mystat;
1994 static time_t last = 0;
1995 static struct ast_config *ourcfg = NULL;
1996 struct ast_variable *vp;
1997
1998         /* try to look it up locally first */
1999         val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
2000         if (val) return(val);
2001         ast_mutex_lock(&nodelookuplock);
2002         /* if file does not exist */
2003         if (stat(myrpt->p.extnodefile,&mystat) == -1)
2004         {
2005                 if (ourcfg) ast_config_destroy(ourcfg);
2006                 ourcfg = NULL;
2007                 ast_mutex_unlock(&nodelookuplock);
2008                 return(NULL);
2009         }
2010         /* if we need to reload */
2011         if (mystat.st_mtime > last)
2012         {
2013                 if (ourcfg) ast_config_destroy(ourcfg);
2014 #ifdef  NEW_ASTERISK
2015                 ourcfg = ast_config_load(myrpt->p.extnodefile,config_flags);
2016 #else
2017                 ourcfg = ast_config_load(myrpt->p.extnodefile);
2018 #endif
2019                 /* if file not there, just bail */
2020                 if (!ourcfg || ourcfg == CONFIG_STATUS_FILEINVALID)
2021                 {
2022                         ast_mutex_unlock(&nodelookuplock);
2023                         return(NULL);
2024                 }
2025                 /* reset "last" time */
2026                 last = mystat.st_mtime;
2027
2028                 /* determine longest node length again */               
2029                 longestnode = 0;
2030                 vp = ast_variable_browse(myrpt->cfg, myrpt->p.nodes);
2031                 while(vp){
2032                         j = strlen(vp->name);
2033                         if (j > longestnode)
2034                                 longestnode = j;
2035                         vp = vp->next;
2036                 }
2037
2038                 vp = ast_variable_browse(ourcfg, myrpt->p.extnodes);
2039                 while(vp){
2040                         j = strlen(vp->name);
2041                         if (j > longestnode)
2042                                 longestnode = j;
2043                         vp = vp->next;
2044                 }
2045
2046                 myrpt->longestnode = longestnode;
2047         }
2048         val = NULL;
2049         if (ourcfg)
2050                 val = (char *) ast_variable_retrieve(ourcfg, myrpt->p.extnodes, digitbuf);
2051         ast_mutex_unlock(&nodelookuplock);
2052         return(val);
2053 }
2054
2055 /*
2056 * Match a keyword in a list, and return index of string plus 1 if there was a match,* else return 0.
2057 * If param is passed in non-null, then it will be set to the first character past the match
2058 */
2059
2060 static int matchkeyword(char *string, char **param, char *keywords[])
2061 {
2062 int     i,ls;
2063         for( i = 0 ; keywords[i] ; i++){
2064                 ls = strlen(keywords[i]);
2065                 if(!ls){
2066                         *param = NULL;
2067                         return 0;
2068                 }
2069                 if(!strncmp(string, keywords[i], ls)){
2070                         if(param)
2071                                 *param = string + ls;
2072                         return i + 1; 
2073                 }
2074         }
2075         *param = NULL;
2076         return 0;
2077 }
2078
2079 /*
2080 * Skip characters in string which are in charlist, and return a pointer to the
2081 * first non-matching character
2082 */
2083
2084 static char *skipchars(char *string, char *charlist)
2085 {
2086 int i;  
2087         while(*string){
2088                 for(i = 0; charlist[i] ; i++){
2089                         if(*string == charlist[i]){
2090                                 string++;
2091                                 break;
2092                         }
2093                 }
2094                 if(!charlist[i])
2095                         return string;
2096         }
2097         return string;
2098 }       
2099                                         
2100
2101
2102 static int myatoi(char *str)
2103 {
2104 int     ret;
2105
2106         if (str == NULL) return -1;
2107         /* leave this %i alone, non-base-10 input is useful here */
2108         if (sscanf(str,"%i",&ret) != 1) return -1;
2109         return ret;
2110 }
2111
2112 static int mycompar(const void *a, const void *b)
2113 {
2114 char    **x = (char **) a;
2115 char    **y = (char **) b;
2116 int     xoff,yoff;
2117
2118         if ((**x < '0') || (**x > '9')) xoff = 1; else xoff = 0;
2119         if ((**y < '0') || (**y > '9')) yoff = 1; else yoff = 0;
2120         return(strcmp((*x) + xoff,(*y) + yoff));
2121 }
2122
2123 static int topcompar(const void *a, const void *b)
2124 {
2125 struct rpt_topkey *x = (struct rpt_topkey *) a;
2126 struct rpt_topkey *y = (struct rpt_topkey *) b;
2127
2128         return(x->timesince - y->timesince);
2129 }
2130
2131 #ifdef  __RPT_NOTCH
2132
2133 /* rpt filter routine */
2134 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
2135 {
2136 int     i,j;
2137 struct  rptfilter *f;
2138
2139         for(i = 0; i < len; i++)
2140         {
2141                 for(j = 0; j < MAXFILTERS; j++)
2142                 {
2143                         f = &myrpt->filters[j];
2144                         if (!*f->desc) continue;
2145                         f->x0 = f->x1; f->x1 = f->x2;
2146                         f->x2 = ((float)buf[i]) / f->gain;
2147                         f->y0 = f->y1; f->y1 = f->y2;
2148                         f->y2 =   (f->x0 + f->x2) +   f->const0 * f->x1
2149                                      + (f->const1 * f->y0) + (f->const2 * f->y1);
2150                         buf[i] = (short)f->y2;
2151                 }
2152         }
2153 }
2154
2155 #endif
2156
2157
2158 /*
2159  Get the time for the machine's time zone
2160  Note: Asterisk requires a copy of localtime
2161  in the /etc directory for this to work properly.
2162  If /etc/localtime is not present, you will get
2163  GMT time! This is especially important on systems
2164  running embedded linux distributions as they don't usually
2165  have support for locales. 
2166
2167  If OLD_ASTERISK is defined, then the older localtime_r
2168  function will be used. The /etc/localtime file is not
2169  required in this case. This provides backward compatibility
2170  with Asterisk 1.2 systems.
2171
2172 */
2173
2174 #ifdef  NEW_ASTERISK
2175 static void rpt_localtime( time_t * t, struct ast_tm *lt)
2176 {
2177         struct timeval when;
2178
2179         when.tv_sec = *t;
2180         when.tv_usec = 0;
2181         ast_localtime(&when, lt, NULL);
2182 }
2183
2184 #else
2185 static void rpt_localtime( time_t * t, struct tm *lt)
2186 {
2187 #ifdef OLD_ASTERISK
2188         localtime_r(t, lt);
2189 #else
2190         ast_localtime(t, lt, NULL);
2191 #endif
2192 }
2193 #endif
2194
2195
2196 /* Retrieve an int from a config file */
2197                                                                                 
2198 static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl)
2199 {
2200         char *var;
2201         int ret;
2202         char include_zero = 0;
2203
2204         if(min < 0){ /* If min is negative, this means include 0 as a valid entry */
2205                 min = -min;
2206                 include_zero = 1;
2207         }           
2208                                                                      
2209         var = (char *) ast_variable_retrieve(myrpt->cfg, category, name);
2210         if(var){
2211                 ret = myatoi(var);
2212                 if(include_zero && !ret)
2213                         return 0;
2214                 if(ret < min)
2215                         ret = min;
2216                 if(ret > max)
2217                         ret = max;
2218         }
2219         else
2220                 ret = defl;
2221         return ret;
2222 }
2223
2224
2225 static void load_rpt_vars(int n,int init)
2226 {
2227 char *this,*val;
2228 int     i,j,longestnode;
2229 struct ast_variable *vp;
2230 struct ast_config *cfg;
2231 char *strs[100];
2232 char s1[256];
2233 static char *cs_keywords[] = {"rptena","rptdis","apena","apdis","lnkena","lnkdis","totena","totdis","skena","skdis",
2234                                 "ufena","ufdis","atena","atdis",NULL};
2235
2236         if (option_verbose > 2)
2237                 ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n",
2238                         (init) ? "Loading initial" : "Re-Loading",rpt_vars[n].name);
2239         ast_mutex_lock(&rpt_vars[n].lock);
2240         if (rpt_vars[n].cfg) ast_config_destroy(rpt_vars[n].cfg);
2241 #ifdef  NEW_ASTERISK
2242         cfg = ast_config_load("rpt.conf",config_flags);
2243 #else
2244         cfg = ast_config_load("rpt.conf");
2245 #endif
2246         if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
2247                 ast_mutex_unlock(&rpt_vars[n].lock);
2248                 ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
2249                 pthread_exit(NULL);
2250         }
2251         rpt_vars[n].cfg = cfg; 
2252         this = rpt_vars[n].name;
2253         memset(&rpt_vars[n].p,0,sizeof(rpt_vars[n].p));
2254         if (init)
2255         {
2256                 char *cp;
2257                 int savearea = (char *)&rpt_vars[n].p - (char *)&rpt_vars[n];
2258
2259                 cp = (char *) &rpt_vars[n].p;
2260                 memset(cp + sizeof(rpt_vars[n].p),0,
2261                         sizeof(rpt_vars[n]) - (sizeof(rpt_vars[n].p) + savearea));
2262                 rpt_vars[n].tele.next = &rpt_vars[n].tele;
2263                 rpt_vars[n].tele.prev = &rpt_vars[n].tele;
2264                 rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
2265                 rpt_vars[n].tailmessagen = 0;
2266         }
2267 #ifdef  __RPT_NOTCH
2268         /* zot out filters stuff */
2269         memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
2270 #endif
2271         val = (char *) ast_variable_retrieve(cfg,this,"context");
2272         if (val) rpt_vars[n].p.ourcontext = val;
2273         else rpt_vars[n].p.ourcontext = this;
2274         val = (char *) ast_variable_retrieve(cfg,this,"callerid");
2275         if (val) rpt_vars[n].p.ourcallerid = val;
2276         val = (char *) ast_variable_retrieve(cfg,this,"accountcode");
2277         if (val) rpt_vars[n].p.acctcode = val;
2278         val = (char *) ast_variable_retrieve(cfg,this,"idrecording");
2279         if (val) rpt_vars[n].p.ident = val;
2280         val = (char *) ast_variable_retrieve(cfg,this,"hangtime");
2281         if (val) rpt_vars[n].p.hangtime = atoi(val);
2282                 else rpt_vars[n].p.hangtime = HANGTIME;
2283         val = (char *) ast_variable_retrieve(cfg,this,"althangtime");
2284         if (val) rpt_vars[n].p.althangtime = atoi(val);
2285                 else rpt_vars[n].p.althangtime = HANGTIME;
2286         val = (char *) ast_variable_retrieve(cfg,this,"totime");
2287         if (val) rpt_vars[n].p.totime = atoi(val);
2288                 else rpt_vars[n].p.totime = TOTIME;
2289         val = (char *) ast_variable_retrieve(cfg,this,"voxtimeout");
2290         if (val) rpt_vars[n].p.voxtimeout_ms = atoi(val);
2291                 else rpt_vars[n].p.voxtimeout_ms = VOX_TIMEOUT_MS;
2292         val = (char *) ast_variable_retrieve(cfg,this,"voxrecover");
2293         if (val) rpt_vars[n].p.voxrecover_ms = atoi(val);
2294                 else rpt_vars[n].p.voxrecover_ms = VOX_RECOVER_MS;
2295         val = (char *) ast_variable_retrieve(cfg,this,"simplexpatchdelay");
2296         if (val) rpt_vars[n].p.simplexpatchdelay = atoi(val);
2297                 else rpt_vars[n].p.simplexpatchdelay = SIMPLEX_PATCH_DELAY;
2298         val = (char *) ast_variable_retrieve(cfg,this,"simplexphonedelay");
2299         if (val) rpt_vars[n].p.simplexphonedelay = atoi(val);
2300                 else rpt_vars[n].p.simplexphonedelay = SIMPLEX_PHONE_DELAY;
2301         val = (char *) ast_variable_retrieve(cfg,this,"statpost_program");
2302         if (val) rpt_vars[n].p.statpost_program = val;
2303                 else rpt_vars[n].p.statpost_program = STATPOST_PROGRAM;
2304         rpt_vars[n].p.statpost_url = 
2305                 (char *) ast_variable_retrieve(cfg,this,"statpost_url");
2306         rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0);                
2307         rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0);              
2308         rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2);
2309         rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", -60000, 2400000, IDTIME);        /* Enforce a min max including zero */
2310         rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
2311         val = (char *) ast_variable_retrieve(cfg,this,"tonezone");
2312         if (val) rpt_vars[n].p.tonezone = val;
2313         rpt_vars[n].p.tailmessages[0] = 0;
2314         rpt_vars[n].p.tailmessagemax = 0;
2315         val = (char *) ast_variable_retrieve(cfg,this,"tailmessagelist");
2316         if (val) rpt_vars[n].p.tailmessagemax = finddelim(val, rpt_vars[n].p.tailmessages, 500);
2317         val = (char *) ast_variable_retrieve(cfg,this,"memory");
2318         if (!val) val = MEMORY;
2319         rpt_vars[n].p.memory = val;
2320         val = (char *) ast_variable_retrieve(cfg,this,"macro");
2321         if (!val) val = MACRO;
2322         rpt_vars[n].p.macro = val;
2323         val = (char *) ast_variable_retrieve(cfg,this,"tonemacro");
2324         if (!val) val = TONEMACRO;
2325         rpt_vars[n].p.tonemacro = val;
2326         val = (char *) ast_variable_retrieve(cfg,this,"startup_macro");
2327         if (val) rpt_vars[n].p.startupmacro = val;
2328         val = (char *) ast_variable_retrieve(cfg,this,"iobase");
2329         /* do not use atoi() here, we need to be able to have
2330                 the input specified in hex or decimal so we use
2331                 sscanf with a %i */
2332         if ((!val) || (sscanf(val,"%i",&rpt_vars[n].p.iobase) != 1))
2333                 rpt_vars[n].p.iobase = DEFAULT_IOBASE;
2334         val = (char *) ast_variable_retrieve(cfg,this,"ioport");
2335         rpt_vars[n].p.ioport = val;
2336         val = (char *) ast_variable_retrieve(cfg,this,"functions");
2337         if (!val)
2338                 {
2339                         val = FUNCTIONS;
2340                         rpt_vars[n].p.simple = 1;
2341                 } 
2342         rpt_vars[n].p.functions = val;
2343         val =  (char *) ast_variable_retrieve(cfg,this,"link_functions");
2344         if (val) rpt_vars[n].p.link_functions = val;
2345         else 
2346                 rpt_vars[n].p.link_functions = rpt_vars[n].p.functions;
2347         val = (char *) ast_variable_retrieve(cfg,this,"phone_functions");
2348         if (val) rpt_vars[n].p.phone_functions = val;
2349         val = (char *) ast_variable_retrieve(cfg,this,"dphone_functions");
2350         if (val) rpt_vars[n].p.dphone_functions = val;
2351         val = (char *) ast_variable_retrieve(cfg,this,"alt_functions");
2352         if (val) rpt_vars[n].p.alt_functions = val;
2353         val = (char *) ast_variable_retrieve(cfg,this,"funcchar");
2354         if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else 
2355                 rpt_vars[n].p.funcchar = *val;          
2356         val = (char *) ast_variable_retrieve(cfg,this,"endchar");
2357         if (!val) rpt_vars[n].p.endchar = ENDCHAR; else 
2358                 rpt_vars[n].p.endchar = *val;           
2359         val = (char *) ast_variable_retrieve(cfg,this,"nobusyout");
2360         if (val) rpt_vars[n].p.nobusyout = ast_true(val);
2361         val = (char *) ast_variable_retrieve(cfg,this,"notelemtx");
2362         if (val) rpt_vars[n].p.notelemtx = ast_true(val);
2363         val = (char *) ast_variable_retrieve(cfg,this,"propagate_dtmf");
2364         if (val) rpt_vars[n].p.propagate_dtmf = ast_true(val);
2365         val = (char *) ast_variable_retrieve(cfg,this,"propagate_phonedtmf");
2366         if (val) rpt_vars[n].p.propagate_phonedtmf = ast_true(val);
2367         val = (char *) ast_variable_retrieve(cfg,this,"linktolink");
2368         if (val) rpt_vars[n].p.linktolink = ast_true(val);
2369         val = (char *) ast_variable_retrieve(cfg,this,"nodes");
2370         if (!val) val = NODES;
2371         rpt_vars[n].p.nodes = val;
2372         val = (char *) ast_variable_retrieve(cfg,this,"extnodes");
2373         if (!val) val = EXTNODES;
2374         rpt_vars[n].p.extnodes = val;
2375         val = (char *) ast_variable_retrieve(cfg,this,"extnodefile");
2376         if (!val) val = EXTNODEFILE;
2377         rpt_vars[n].p.extnodefile = val;
2378         val = (char *) ast_variable_retrieve(cfg,this,"archivedir");
2379         if (val) rpt_vars[n].p.archivedir = val;
2380         val = (char *) ast_variable_retrieve(cfg,this,"authlevel");
2381         if (val) rpt_vars[n].p.authlevel = atoi(val); 
2382         else rpt_vars[n].p.authlevel = 0;
2383         val = (char *) ast_variable_retrieve(cfg,this,"parrot");
2384         if (val) rpt_vars[n].p.parrotmode = ast_true(val) * 2;
2385         else rpt_vars[n].p.parrotmode = 0;
2386         val = (char *) ast_variable_retrieve(cfg,this,"parrottime");
2387         if (val) rpt_vars[n].p.parrottime = atoi(val); 
2388         else rpt_vars[n].p.parrottime = PARROTTIME;
2389         val = (char *) ast_variable_retrieve(cfg,this,"rptnode");
2390         rpt_vars[n].p.rptnode = val;
2391         val = (char *) ast_variable_retrieve(cfg,this,"mars");
2392         if (val) rpt_vars[n].p.remote_mars = atoi(val); 
2393         else rpt_vars[n].p.remote_mars = 0;
2394         val = (char *) ast_variable_retrieve(cfg,this,"monminblocks");
2395         if (val) rpt_vars[n].p.monminblocks = atol(val); 
2396         else rpt_vars[n].p.monminblocks = DEFAULT_MONITOR_MIN_DISK_BLOCKS;
2397         val = (char *) ast_variable_retrieve(cfg,this,"remote_inact_timeout");
2398         if (val) rpt_vars[n].p.remoteinacttimeout = atoi(val); 
2399         else rpt_vars[n].p.remoteinacttimeout = DEFAULT_REMOTE_INACT_TIMEOUT;
2400         val = (char *) ast_variable_retrieve(cfg,this,"civaddr");
2401         if (val) rpt_vars[n].p.civaddr = atoi(val); 
2402         else rpt_vars[n].p.civaddr = DEFAULT_CIV_ADDR;
2403         val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout");
2404         if (val) rpt_vars[n].p.remotetimeout = atoi(val); 
2405         else rpt_vars[n].p.remotetimeout = DEFAULT_REMOTE_TIMEOUT;
2406         val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning");
2407         if (val) rpt_vars[n].p.remotetimeoutwarning = atoi(val); 
2408         else rpt_vars[n].p.remotetimeoutwarning = DEFAULT_REMOTE_TIMEOUT_WARNING;
2409         val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning_freq");
2410         if (val) rpt_vars[n].p.remotetimeoutwarningfreq = atoi(val); 
2411         else rpt_vars[n].p.remotetimeoutwarningfreq = DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ;
2412 #ifdef  __RPT_NOTCH
2413         val = (char *) ast_variable_retrieve(cfg,this,"rxnotch");
2414         if (val) {
2415                 i = finddelim(val,strs,MAXFILTERS * 2);
2416                 i &= ~1; /* force an even number, rounded down */
2417                 if (i >= 2) for(j = 0; j < i; j += 2)
2418                 {
2419                         rpt_mknotch(atof(strs[j]),atof(strs[j + 1]),
2420                           &rpt_vars[n].filters[j >> 1].gain,
2421                             &rpt_vars[n].filters[j >> 1].const0,
2422                                 &rpt_vars[n].filters[j >> 1].const1,
2423                                     &rpt_vars[n].filters[j >> 1].const2);
2424                         sprintf(rpt_vars[n].filters[j >> 1].desc,"%s Hz, BW = %s",
2425                                 strs[j],strs[j + 1]);
2426                 }
2427
2428         }
2429 #endif
2430         val = (char *) ast_variable_retrieve(cfg,this,"inxlat");
2431         if (val) {
2432                 memset(&rpt_vars[n].p.inxlat,0,sizeof(struct rpt_xlat));
2433                 i = finddelim(val,strs,3);
2434                 if (i) strncpy(rpt_vars[n].p.inxlat.funccharseq,strs[0],MAXXLAT - 1);
2435                 if (i > 1) strncpy(rpt_vars[n].p.inxlat.endcharseq,strs[1],MAXXLAT - 1);
2436                 if (i > 2) strncpy(rpt_vars[n].p.inxlat.passchars,strs[2],MAXXLAT - 1);
2437         }
2438         val = (char *) ast_variable_retrieve(cfg,this,"outxlat");
2439         if (val) {
2440                 memset(&rpt_vars[n].p.outxlat,0,sizeof(struct rpt_xlat));
2441                 i = finddelim(val,strs,3);
2442                 if (i) strncpy(rpt_vars[n].p.outxlat.funccharseq,strs[0],MAXXLAT - 1);
2443                 if (i > 1) strncpy(rpt_vars[n].p.outxlat.endcharseq,strs[1],MAXXLAT - 1);
2444                 if (i > 2) strncpy(rpt_vars[n].p.outxlat.passchars,strs[2],MAXXLAT - 1);
2445         }
2446         /* retreive the stanza name for the control states if there is one */
2447         val = (char *) ast_variable_retrieve(cfg,this,"controlstates");
2448         rpt_vars[n].p.csstanzaname = val;
2449                 
2450         /* retreive the stanza name for the scheduler if there is one */
2451         val = (char *) ast_variable_retrieve(cfg,this,"scheduler");
2452         rpt_vars[n].p.skedstanzaname = val;
2453
2454         /* retreive the stanza name for the txlimits */
2455         val = (char *) ast_variable_retrieve(cfg,this,"txlimits");
2456         rpt_vars[n].p.txlimitsstanzaname = val;
2457
2458         longestnode = 0;
2459
2460         vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
2461                 
2462         while(vp){
2463                 j = strlen(vp->name);
2464                 if (j > longestnode)
2465                         longestnode = j;
2466                 vp = vp->next;
2467         }
2468
2469         rpt_vars[n].longestnode = longestnode;
2470                 
2471         /*
2472         * For this repeater, Determine the length of the longest function 
2473         */
2474         rpt_vars[n].longestfunc = 0;
2475         vp = ast_variable_browse(cfg, rpt_vars[n].p.functions);
2476         while(vp){
2477                 j = strlen(vp->name);
2478                 if (j > rpt_vars[n].longestfunc)
2479                         rpt_vars[n].longestfunc = j;
2480                 vp = vp->next;
2481         }
2482         /*
2483         * For this repeater, Determine the length of the longest function 
2484         */
2485         rpt_vars[n].link_longestfunc = 0;
2486         vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions);
2487         while(vp){
2488                 j = strlen(vp->name);
2489                 if (j > rpt_vars[n].link_longestfunc)
2490                         rpt_vars[n].link_longestfunc = j;
2491                 vp = vp->next;
2492         }
2493         rpt_vars[n].phone_longestfunc = 0;
2494         if (rpt_vars[n].p.phone_functions)
2495         {
2496                 vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions);
2497                 while(vp){
2498                         j = strlen(vp->name);
2499                         if (j > rpt_vars[n].phone_longestfunc)
2500                                 rpt_vars[n].phone_longestfunc = j;
2501                         vp = vp->next;
2502                 }
2503         }
2504         rpt_vars[n].dphone_longestfunc = 0;
2505         if (rpt_vars[n].p.dphone_functions)
2506         {
2507                 vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions);
2508                 while(vp){
2509                         j = strlen(vp->name);
2510                         if (j > rpt_vars[n].dphone_longestfunc)
2511                                 rpt_vars[n].dphone_longestfunc = j;
2512                         vp = vp->next;
2513                 }
2514         }
2515         rpt_vars[n].alt_longestfunc = 0;
2516         if (rpt_vars[n].p.alt_functions)
2517         {
2518                 vp = ast_variable_browse(cfg, rpt_vars[n].p.alt_functions);
2519                 while(vp){
2520                         j = strlen(vp->name);
2521                         if (j > rpt_vars[n].alt_longestfunc)
2522                                 rpt_vars[n].alt_longestfunc = j;
2523                         vp = vp->next;
2524                 }
2525         }
2526         rpt_vars[n].macro_longest = 1;
2527         vp = ast_variable_browse(cfg, rpt_vars[n].p.macro);
2528         while(vp){
2529                 j = strlen(vp->name);
2530                 if (j > rpt_vars[n].macro_longest)
2531                         rpt_vars[n].macro_longest = j;
2532                 vp = vp->next;
2533         }
2534         
2535         /* Browse for control states */
2536         if(rpt_vars[n].p.csstanzaname)
2537                 vp = ast_variable_browse(cfg, rpt_vars[n].p.csstanzaname);
2538         else
2539                 vp = NULL;
2540         for( i = 0 ; vp && (i < MAX_SYSSTATES) ; i++){ /* Iterate over the number of control state lines in the stanza */
2541                 int k,nukw,statenum;
2542                 statenum=atoi(vp->name);
2543                 strncpy(s1, vp->value, 255);
2544                 s1[255] = 0;
2545                 nukw  = finddelim(s1,strs,32);
2546                 
2547                 for (k = 0 ; k < nukw ; k++){ /* for each user specified keyword */     
2548                         for(j = 0 ; cs_keywords[j] != NULL ; j++){ /* try to match to one in our internal table */
2549                                 if(!strcmp(strs[k],cs_keywords[j])){
2550                                         switch(j){
2551                                                 case 0: /* rptena */
2552                                                         rpt_vars[n].p.s[statenum].txdisable = 0;
2553                                                         break;
2554                                                 case 1: /* rptdis */
2555                                                         rpt_vars[n].p.s[statenum].txdisable = 1;
2556                                                         break;
2557                         
2558                                                 case 2: /* apena */
2559                                                         rpt_vars[n].p.s[statenum].autopatchdisable = 0;
2560                                                         break;
2561
2562                                                 case 3: /* apdis */
2563                                                         rpt_vars[n].p.s[statenum].autopatchdisable = 1;
2564                                                         break;
2565
2566                                                 case 4: /* lnkena */
2567                                                         rpt_vars[n].p.s[statenum].linkfundisable = 0;
2568                                                         break;
2569         
2570                                                 case 5: /* lnkdis */
2571                                                         rpt_vars[n].p.s[statenum].linkfundisable = 1;
2572                                                         break;
2573
2574                                                 case 6: /* totena */
2575                                                         rpt_vars[n].p.s[statenum].totdisable = 0;
2576                                                         break;
2577                                         
2578                                                 case 7: /* totdis */
2579                                                         rpt_vars[n].p.s[statenum].totdisable = 1;
2580                                                         break;
2581
2582                                                 case 8: /* skena */
2583                                                         rpt_vars[n].p.s[statenum].schedulerdisable = 0;
2584                                                         break;
2585
2586                                                 case 9: /* skdis */
2587                                                         rpt_vars[n].p.s[statenum].schedulerdisable = 1;
2588                                                         break;
2589
2590                                                 case 10: /* ufena */
2591                                                         rpt_vars[n].p.s[statenum].userfundisable = 0;
2592                                                         break;
2593
2594                                                 case 11: /* ufdis */
2595                                                         rpt_vars[n].p.s[statenum].userfundisable = 1;
2596                                                         break;
2597
2598                                                 case 12: /* atena */
2599                                                         rpt_vars[n].p.s[statenum].alternatetail = 1;
2600                                                         break;
2601
2602                                                 case 13: /* atdis */
2603                                                         rpt_vars[n].p.s[statenum].alternatetail = 0;
2604                                                         break;
2605                         
2606                                                 default:
2607                                                         ast_log(LOG_WARNING,
2608                                                                 "Unhandled control state keyword %s", cs_keywords[i]);
2609                                                         break;
2610                                         }
2611                                 }
2612                         }
2613                 }
2614                 vp = vp->next;
2615         }
2616         ast_mutex_unlock(&rpt_vars[n].lock);
2617 }
2618
2619 /*
2620 * Enable or disable debug output at a given level at the console
2621 */
2622                                                                                                                                  
2623 static int rpt_do_debug(int fd, int argc, char *argv[])
2624 {
2625         int newlevel;
2626
2627         if (argc != 4)
2628                 return RESULT_SHOWUSAGE;
2629         newlevel = myatoi(argv[3]);
2630         if((newlevel < 0) || (newlevel > 7))
2631                 return RESULT_SHOWUSAGE;
2632         if(newlevel)
2633                 ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
2634         else
2635                 ast_cli(fd, "app_rpt Debugging disabled\n");
2636
2637         debug = newlevel;                                                                                                                          
2638         return RESULT_SUCCESS;
2639 }
2640
2641 /*
2642 * Dump rpt struct debugging onto console
2643 */
2644                                                                                                                                  
2645 static int rpt_do_dump(int fd, int argc, char *argv[])
2646 {
2647         int i;
2648
2649         if (argc != 3)
2650                 return RESULT_SHOWUSAGE;
2651
2652         for(i = 0; i < nrpts; i++)
2653         {
2654                 if (!strcmp(argv[2],rpt_vars[i].name))
2655                 {
2656                         rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
2657                         ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
2658                         return RESULT_SUCCESS;
2659                 }
2660         }
2661         return RESULT_FAILURE;
2662 }
2663
2664 /*
2665 * Dump statistics onto console
2666 */
2667
2668 static int rpt_do_stats(int fd, int argc, char *argv[])
2669 {
2670         int i,j,numoflinks;
2671         int dailytxtime, dailykerchunks;
2672         time_t now;
2673         int totalkerchunks, dailykeyups, totalkeyups, timeouts;
2674         int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
2675         int uptime;
2676         long long totaltxtime;
2677         struct  rpt_link *l;
2678         char *listoflinks[MAX_STAT_LINKS];      
2679         char *lastdtmfcommand,*parrot_ena;
2680         char *tot_state, *ider_state, *patch_state;
2681         char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
2682         char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
2683         struct rpt *myrpt;
2684
2685         static char *not_applicable = "N/A";
2686
2687         if(argc != 3)
2688                 return RESULT_SHOWUSAGE;
2689
2690         tot_state = ider_state = 
2691         patch_state = reverse_patch_state = 
2692         input_signal = not_applicable;
2693         called_number = lastdtmfcommand = NULL;
2694
2695         time(&now);
2696         for(i = 0; i < nrpts; i++)
2697         {
2698                 if (!strcmp(argv[2],rpt_vars[i].name)){
2699                         /* Make a copy of all stat variables while locked */
2700                         myrpt = &rpt_vars[i];
2701                         rpt_mutex_lock(&myrpt->lock); /* LOCK */
2702                         uptime = (int)(now - starttime);
2703                         dailytxtime = myrpt->dailytxtime;
2704                         totaltxtime = myrpt->totaltxtime;
2705                         dailykeyups = myrpt->dailykeyups;
2706                         totalkeyups = myrpt->totalkeyups;
2707                         dailykerchunks = myrpt->dailykerchunks;
2708                         totalkerchunks = myrpt->totalkerchunks;
2709                         dailyexecdcommands = myrpt->dailyexecdcommands;
2710                         totalexecdcommands = myrpt->totalexecdcommands;
2711                         timeouts = myrpt->timeouts;
2712
2713                         /* Traverse the list of connected nodes */
2714                         reverse_patch_state = "DOWN";
2715                         numoflinks = 0;
2716                         l = myrpt->links.next;
2717                         while(l && (l != &myrpt->links)){
2718                                 if(numoflinks >= MAX_STAT_LINKS){
2719                                         ast_log(LOG_NOTICE,
2720                                         "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
2721                                         break;
2722                                 }
2723                                 if (l->name[0] == '0'){ /* Skip '0' nodes */
2724                                         reverse_patch_state = "UP";
2725                                         l = l->next;
2726                                         continue;
2727                                 }
2728                                 listoflinks[numoflinks] = ast_strdup(l->name);
2729                                 if(listoflinks[numoflinks] == NULL){
2730                                         break;
2731                                 }
2732                                 else{
2733                                         numoflinks++;
2734                                 }
2735                                 l = l->next;
2736                         }
2737
2738                         if(myrpt->keyed)
2739                                 input_signal = "YES";
2740                         else
2741                                 input_signal = "NO";
2742
2743                         if(myrpt->p.parrotmode)
2744                                 parrot_ena = "ENABLED";
2745                         else
2746                                 parrot_ena = "DISABLED";
2747
2748                         if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
2749                                 sys_ena = "DISABLED";
2750                         else
2751                                 sys_ena = "ENABLED";
2752
2753                         if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
2754                                 tot_ena = "DISABLED";
2755                         else
2756                                 tot_ena = "ENABLED";
2757
2758                         if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
2759                                 link_ena = "DISABLED";
2760                         else
2761                                 link_ena = "ENABLED";
2762
2763                         if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
2764                                 patch_ena = "DISABLED";
2765                         else
2766                                 patch_ena = "ENABLED";
2767
2768                         if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
2769                                 sch_ena = "DISABLED";
2770                         else
2771                                 sch_ena = "ENABLED";
2772
2773                         if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
2774                                 user_funs = "DISABLED";
2775                         else
2776                                 user_funs = "ENABLED";
2777
2778                         if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
2779                                 tail_type = "ALTERNATE";
2780                         else
2781                                 tail_type = "STANDARD";
2782
2783                         if(!myrpt->totimer)
2784                                 tot_state = "TIMED OUT!";
2785                         else if(myrpt->totimer != myrpt->p.totime)
2786                                 tot_state = "ARMED";
2787                         else
2788                                 tot_state = "RESET";
2789
2790                         if(myrpt->tailid)
2791                                 ider_state = "QUEUED IN TAIL";
2792                         else if(myrpt->mustid)
2793                                 ider_state = "QUEUED FOR CLEANUP";
2794                         else
2795                                 ider_state = "CLEAN";
2796
2797                         switch(myrpt->callmode){
2798                                 case 1:
2799                                         patch_state = "DIALING";
2800                                         break;
2801                                 case 2:
2802                                         patch_state = "CONNECTING";
2803                                         break;
2804                                 case 3:
2805                                         patch_state = "UP";
2806                                         break;
2807
2808                                 case 4:
2809                                         patch_state = "CALL FAILED";
2810                                         break;
2811
2812                                 default:
2813                                         patch_state = "DOWN";
2814                         }
2815
2816                         if(strlen(myrpt->exten)){
2817                                 called_number = ast_strdup(myrpt->exten);
2818                         }
2819
2820                         if(strlen(myrpt->lastdtmfcommand)){
2821                                 lastdtmfcommand = ast_strdup(myrpt->lastdtmfcommand);
2822                         }
2823                         rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2824
2825                         ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
2826                         ast_cli(fd, "Selected system state............................: %d\n", myrpt->p.sysstate_cur);
2827                         ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
2828                         ast_cli(fd, "System...........................................: %s\n", sys_ena);
2829                         ast_cli(fd, "Parrot Mode......................................: %s\n", parrot_ena);
2830                         ast_cli(fd, "Scheduler........................................: %s\n", sch_ena);
2831                         ast_cli(fd, "Tail Time........................................: %s\n", tail_type);
2832                         ast_cli(fd, "Time out timer...................................: %s\n", tot_ena);
2833                         ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
2834                         ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
2835                         ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
2836                         ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
2837                         ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
2838                         ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
2839                         ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
2840                         ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
2841                         ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
2842                         ast_cli(fd, "Last DTMF command executed.......................: %s\n", 
2843                         (lastdtmfcommand && strlen(lastdtmfcommand)) ? lastdtmfcommand : not_applicable);
2844                         hours = dailytxtime/3600000;
2845                         dailytxtime %= 3600000;
2846                         minutes = dailytxtime/60000;
2847                         dailytxtime %= 60000;
2848                         seconds = dailytxtime/1000;
2849                         dailytxtime %= 1000;
2850
2851                         ast_cli(fd, "TX time today....................................: %02d:%02d:%02d.%d\n",
2852                                 hours, minutes, seconds, dailytxtime);
2853
2854                         hours = (int) totaltxtime/3600000;
2855                         totaltxtime %= 3600000;
2856                         minutes = (int) totaltxtime/60000;
2857                         totaltxtime %= 60000;
2858                         seconds = (int)  totaltxtime/1000;
2859                         totaltxtime %= 1000;
2860
2861                         ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
2862                                  hours, minutes, seconds, (int) totaltxtime);
2863
2864                         hours = uptime/3600;
2865                         uptime %= 3600;
2866                         minutes = uptime/60;
2867                         uptime %= 60;
2868
2869                         ast_cli(fd, "Uptime...........................................: %02d:%02d:%02d\n",
2870                                 hours, minutes, uptime);
2871
2872                         ast_cli(fd, "Nodes currently connected to us..................: ");
2873                         if(!numoflinks){
2874                               ast_cli(fd,"<NONE>");
2875                         }
2876                         else{
2877                                 for(j = 0 ;j < numoflinks; j++){
2878                                         ast_cli(fd, "%s", listoflinks[j]);
2879                                         if(j % 4 == 3){
2880                                                 ast_cli(fd, "\n");
2881                                                 ast_cli(fd, "                                                 : ");
2882                                         }       
2883                                         else{
2884                                                 if((numoflinks - 1) - j  > 0)
2885                                                         ast_cli(fd, ", ");
2886                                         }
2887                                 }
2888                         }
2889                         ast_cli(fd,"\n");
2890
2891                         ast_cli(fd, "Autopatch........................................: %s\n", patch_ena);
2892                         ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
2893                         ast_cli(fd, "Autopatch called number..........................: %s\n",
2894                         (called_number && strlen(called_number)) ? called_number : not_applicable);
2895                         ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n", reverse_patch_state);
2896                         ast_cli(fd, "User linking commands............................: %s\n", link_ena);
2897                         ast_cli(fd, "User functions...................................: %s\n\n", user_funs);
2898
2899                         for(j = 0; j < numoflinks; j++){ /* ast_free() all link names */
2900                                 ast_free(listoflinks[j]);
2901                         }
2902                         ast_free(called_number);
2903                         ast_free(lastdtmfcommand);
2904                         return RESULT_SUCCESS;
2905                 }
2906         }
2907         return RESULT_FAILURE;
2908 }
2909
2910 /*
2911 * Link stats function
2912 */
2913
2914 static int rpt_do_lstats(int fd, int argc, char *argv[])
2915 {
2916         int i,j;
2917         char *connstate;
2918         struct rpt *myrpt;
2919         struct rpt_link *l;
2920         struct rpt_lstat *s,*t;
2921         struct rpt_lstat s_head;
2922         if(argc != 3)
2923                 return RESULT_SHOWUSAGE;
2924
2925         s = NULL;
2926         s_head.next = &s_head;
2927         s_head.prev = &s_head;
2928
2929         for(i = 0; i < nrpts; i++)
2930         {
2931                 if (!strcmp(argv[2],rpt_vars[i].name)){
2932                         /* Make a copy of all stat variables while locked */
2933                         myrpt = &rpt_vars[i];
2934                         rpt_mutex_lock(&myrpt->lock); /* LOCK */
2935                         /* Traverse the list of connected nodes */
2936                         j = 0;
2937                         l = myrpt->links.next;
2938                         while(l && (l != &myrpt->links)){
2939                                 if (l->name[0] == '0'){ /* Skip '0' nodes */
2940                                         l = l->next;
2941                                         continue;
2942                                 }
2943                                 if((s = (struct rpt_lstat *) ast_malloc(sizeof(struct rpt_lstat))) == NULL){
2944                                         ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
2945                                         rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2946                                         return RESULT_FAILURE;
2947                                 }
2948                                 memset(s, 0, sizeof(struct rpt_lstat));
2949                                 strncpy(s->name, l->name, MAXREMSTR - 1);
2950                                 if (l->chan) pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
2951                                 else strcpy(s->peer,"(none)");
2952                                 s->mode = l->mode;
2953                                 s->outbound = l->outbound;
2954                                 s->reconnects = l->reconnects;
2955                                 s->connecttime = l->connecttime;
2956                                 s->thisconnected = l->thisconnected;
2957                                 memcpy(s->chan_stat,l->chan_stat,NRPTSTAT * sizeof(struct rpt_chan_stat));
2958                                 insque((struct qelem *) s, (struct qelem *) s_head.next);
2959                                 memset(l->chan_stat,0,NRPTSTAT * sizeof(struct rpt_chan_stat));
2960                                 l = l->next;
2961                         }
2962                         rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2963                         ast_cli(fd, "NODE      PEER                RECONNECTS  DIRECTION  CONNECT TIME        CONNECT STATE\n");
2964                         ast_cli(fd, "----      ----                ----------  ---------  ------------        -------------\n");
2965
2966                         for(s = s_head.next; s != &s_head; s = s->next){
2967                                 int hours, minutes, seconds;
2968                                 long long connecttime = s->connecttime;
2969                                 char conntime[21];
2970                                 hours = (int) connecttime/3600000;
2971                                 connecttime %= 3600000;
2972                                 minutes = (int) connecttime/60000;
2973                                 connecttime %= 60000;
2974                                 seconds = (int)  connecttime/1000;
2975                                 connecttime %= 1000;
2976                                 snprintf(conntime, 20, "%02d:%02d:%02d.%d",
2977                                         hours, minutes, seconds, (int) connecttime);
2978                                 conntime[20] = 0;
2979                                 if(s->thisconnected)
2980                                         connstate  = "ESTABLISHED";
2981                                 else
2982                                         connstate = "CONNECTING";
2983                                 ast_cli(fd, "%-10s%-20s%-12d%-11s%-20s%-20s\n",
2984                                         s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime, connstate);
2985                         }       
2986                         /* destroy our local link queue */
2987                         s = s_head.next;
2988                         while(s != &s_head){
2989                                 t = s;
2990                                 s = s->next;
2991                                 remque((struct qelem *)t);
2992                                 ast_free(t);
2993                         }                       
2994                         return RESULT_SUCCESS;
2995                 }
2996         }
2997         return RESULT_FAILURE;
2998 }
2999
3000 /*
3001 * List all nodes connected, directly or indirectly
3002 */
3003
3004 static int rpt_do_nodes(int fd, int argc, char *argv[])
3005 {
3006         int i,j;
3007         char ns;
3008         char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
3009         struct rpt *myrpt;
3010         if(argc != 3)
3011                 return RESULT_SHOWUSAGE;
3012
3013         for(i = 0; i < nrpts; i++)
3014         {
3015                 if (!strcmp(argv[2],rpt_vars[i].name)){
3016                         /* Make a copy of all stat variables while locked */
3017                         myrpt = &rpt_vars[i];
3018                         rpt_mutex_lock(&myrpt->lock); /* LOCK */
3019                         __mklinklist(myrpt,NULL,lbuf);
3020                         rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
3021                         /* parse em */
3022                         ns = finddelim(lbuf,strs,MAXLINKLIST);
3023                         /* sort em */
3024                         if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
3025                         ast_cli(fd,"\n");
3026                         ast_cli(fd, "************************* CONNECTED NODES *************************\n\n");
3027                         for(j = 0 ;; j++){
3028                                 if(!strs[j]){
3029                                         if(!j){
3030                                                 ast_cli(fd,"<NONE>");
3031                                         }
3032                                         break;
3033                                 }
3034                                 ast_cli(fd, "%s", strs[j]);
3035                                 if(j % 8 == 7){
3036                                         ast_cli(fd, "\n");
3037                                 }
3038                                 else{
3039                                         if(strs[j + 1])
3040                                                 ast_cli(fd, ", ");
3041                                 }
3042                         }
3043                         ast_cli(fd,"\n\n");
3044                         return RESULT_SUCCESS;
3045                 }
3046         }
3047         return RESULT_FAILURE;
3048 }
3049
3050 /*
3051 * List all locally configured nodes
3052 */
3053
3054 static int rpt_do_local_nodes(int fd, int argc, char *argv[])
3055 {
3056
3057     int i;
3058     ast_cli(fd, "\nNode\n----\n");
3059     for (i=0; i< nrpts; i++)
3060     {
3061         ast_cli(fd, "%s\n", rpt_vars[i].name);        
3062     } /* for i */
3063     ast_cli(fd,"\n");
3064     return RESULT_SUCCESS;
3065
3066
3067
3068 /*
3069 * reload vars 
3070 */
3071
3072 static int rpt_do_reload(int fd, int argc, char *argv[])
3073 {
3074 int     n;
3075
3076         if (argc > 2) return RESULT_SHOWUSAGE;
3077
3078         for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
3079
3080         return RESULT_FAILURE;
3081 }
3082
3083 /*
3084 * restart app_rpt
3085 */
3086                                                                                                                                  
3087 static int rpt_do_restart(int fd, int argc, char *argv[])
3088 {
3089 int     i;
3090
3091         if (argc > 2) return RESULT_SHOWUSAGE;
3092         for(i = 0; i < nrpts; i++)
3093         {
3094                 if (rpt_vars[i].rxchannel) ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
3095         }
3096         return RESULT_FAILURE;
3097 }
3098
3099
3100 /*
3101 * send an app_rpt DTMF function from the CLI
3102 */
3103                                                                                                                                  
3104 static int rpt_do_fun(int fd, int argc, char *argv[])
3105 {
3106         int     i,busy=0;
3107
3108         if (argc != 4) return RESULT_SHOWUSAGE;
3109
3110         for(i = 0; i < nrpts; i++){
3111                 if(!strcmp(argv[2], rpt_vars[i].name)){
3112                         struct rpt *myrpt = &rpt_vars[i];
3113                         rpt_mutex_lock(&myrpt->lock);
3114                         if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(argv[3])){
3115                                 rpt_mutex_unlock(&myrpt->lock);
3116                                 busy=1;
3117                         }
3118                         if(!busy){
3119                                 myrpt->macrotimer = MACROTIME;
3120                                 strncat(myrpt->macrobuf,argv[3],MAXMACRO - 1);
3121                         }
3122                         rpt_mutex_unlock(&myrpt->lock);
3123                 }
3124         }
3125         if(busy){
3126                 ast_cli(fd, "Function decoder busy");
3127         }
3128         return RESULT_FAILURE;
3129 }
3130 /*
3131         the convention is that macros in the data from the rpt() application
3132         are all at the end of the data, separated by the | and start with a *
3133         when put into the macro buffer, the characters have their high bit
3134         set so the macro processor knows they came from the application data
3135         and to use the alt-functions table.
3136         sph:
3137 */
3138 static int rpt_push_alt_macro(struct rpt *myrpt, char *sptr)
3139 {
3140         int     busy=0;
3141
3142         rpt_mutex_lock(&myrpt->lock);
3143         if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(sptr)){
3144                 rpt_mutex_unlock(&myrpt->lock);
3145                 busy=1;
3146         }
3147         if(!busy){
3148                 int x;
3149                 if (debug)ast_log(LOG_NOTICE, "rpt_push_alt_macro %s\n",sptr);
3150                 myrpt->macrotimer = MACROTIME;
3151                 for(x = 0; *(sptr + x); x++)
3152                     myrpt->macrobuf[x] = *(sptr + x) | 0x80;
3153                 *(sptr + x) = 0;
3154         }
3155         rpt_mutex_unlock(&myrpt->lock);
3156
3157         if(busy)ast_log(LOG_WARNING, "Function decoder busy on app_rpt command macro.\n");
3158
3159         return busy;
3160 }
3161 /*
3162         allows us to test rpt() application data commands
3163 */
3164 static int rpt_do_fun1(int fd, int argc, char *argv[])
3165 {
3166         int     i;
3167
3168     if (argc != 4) return RESULT_SHOWUSAGE;
3169
3170         for(i = 0; i < nrpts; i++){
3171                 if(!strcmp(argv[2], rpt_vars[i].name)){
3172                         struct rpt *myrpt = &rpt_vars[i];
3173                         rpt_push_alt_macro(myrpt,argv[3]);
3174                 }
3175         }
3176         return RESULT_FAILURE;
3177 }
3178 /*
3179 * send an app_rpt **command** from the CLI
3180 */
3181
3182 static int rpt_do_cmd(int fd, int argc, char *argv[])
3183 {
3184         int i, l;
3185         int busy=0;
3186         int maxActions = sizeof(function_table)/sizeof(struct function_table_tag);
3187
3188         int thisRpt = -1;
3189         int thisAction = -1;
3190         struct rpt *myrpt = NULL;
3191         if (argc != 6) return RESULT_SHOWUSAGE;
3192         
3193         for(i = 0; i < nrpts; i++)
3194         {
3195                 if(!strcmp(argv[2], rpt_vars[i].name))
3196                 {
3197                         thisRpt = i;
3198                         myrpt = &rpt_vars[i];
3199                         break;
3200                 } /* if !strcmp... */
3201         } /* for i */
3202
3203         if (thisRpt < 0)
3204         {
3205                 ast_cli(fd, "Unknown node number %s.\n", argv[2]);
3206                 return RESULT_FAILURE;
3207         } /* if thisRpt < 0 */
3208         
3209         /* Look up the action */
3210         l = strlen(argv[3]);
3211         for(i = 0 ; i < maxActions; i++)
3212         {
3213                 if(!strncasecmp(argv[3], function_table[i].action, l))
3214                 {
3215                         thisAction = i;
3216                         break;
3217                 } /* if !strncasecmp... */
3218         } /* for i */
3219         
3220         if (thisAction < 0)
3221         {
3222                 ast_cli(fd, "Unknown action name %s.\n", argv[3]);
3223                 return RESULT_FAILURE;
3224         } /* if thisAction < 0 */
3225
3226         /* at this point, it looks like all the arguments make sense... */
3227
3228         rpt_mutex_lock(&myrpt->lock);
3229
3230         if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE)
3231         {
3232                 rpt_vars[thisRpt].cmdAction.state = CMD_STATE_BUSY;
3233                 rpt_vars[thisRpt].cmdAction.functionNumber = thisAction;
3234                 strncpy(rpt_vars[thisRpt].cmdAction.param, argv[4], MAXDTMF);
3235                 strncpy(rpt_vars[thisRpt].cmdAction.digits, argv[5], MAXDTMF);
3236                 rpt_vars[thisRpt].cmdAction.command_source = SOURCE_RPT;
3237                 rpt_vars[thisRpt].cmdAction.state = CMD_STATE_READY;
3238         } /* if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE */
3239         else
3240         {
3241                 busy = 1;
3242         } /* if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE */
3243         rpt_mutex_unlock(&myrpt->lock);
3244
3245         return (busy ? RESULT_FAILURE : RESULT_SUCCESS);
3246 } /* rpt_do_cmd() */
3247
3248 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
3249 {
3250         int res;
3251
3252         if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
3253                 return res;
3254                                                                                                                                             
3255         while(chan->generatordata) {
3256                 if (ast_safe_sleep(chan,1)) return -1;
3257         }
3258
3259         return 0;
3260 }
3261
3262 static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
3263 {
3264         return play_tone_pair(chan, freq, 0, duration, amplitude);
3265 }
3266
3267 static int play_silence(struct ast_channel *chan, int duration)
3268 {