Merged revisions 124450 via svnmerge from
[asterisk/asterisk.git] / apps / app_rpt.c
1 #define NEW_ASTERISK
2 /* #define OLD_ASTERISK */
3 /*
4  * Asterisk -- An open source telephony toolkit.
5  *
6  * Copyright (C) 2002-2008, Jim Dixon, WB6NIL
7  *
8  * Jim Dixon, WB6NIL <jim@lambdatel.com>
9  * Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
10  *
11  * See http://www.asterisk.org for more information about
12  * the Asterisk project. Please do not directly contact
13  * any of the maintainers of this project for assistance;
14  * the project provides a web site, mailing lists and IRC
15  * channels for your use.
16  *
17  * This program is free software, distributed under the terms of
18  * the GNU General Public License Version 2. See the LICENSE file
19  * at the top of the source tree.
20  */
21 /*! \file
22  *
23  * \brief Radio Repeater / Remote Base program 
24  *  version 0.115 5/12/08 2055 EDT
25  * 
26  * \author Jim Dixon, WB6NIL <jim@lambdatel.com>
27  *
28  * \note Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
29  * \note Steven Henke, W9SH, <w9sh@arrl.net> added a few features here and there.
30  *
31  * See http://www.zapatatelephony.org/app_rpt.html
32  *
33  *
34  * Repeater / Remote Functions:
35  * "Simple" Mode:  * - autopatch access, # - autopatch hangup
36  * Normal mode:
37  * See the function list in rpt.conf (autopatchup, autopatchdn)
38  * autopatchup can optionally take comma delimited setting=value pairs:
39  *  
40  *
41  * context=string               :       Override default context with "string"
42  * dialtime=ms                  :       Specify the max number of milliseconds between phone number digits (1000 milliseconds = 1 second)
43  * farenddisconnect=1           :       Automatically disconnect when called party hangs up
44  * noct=1                       :       Don't send repeater courtesy tone during autopatch calls
45  * quiet=1                      :       Don't send dial tone, or connect messages. Do not send patch down message when called party hangs up
46  *
47  *
48  * Example: 123=autopatchup,dialtime=20000,noct=1,farenddisconnect=1
49  *
50  *  To send an asterisk (*) while dialing or talking on phone,
51  *  use the autopatch acess code.
52  *
53  *
54  * status cmds:
55  *
56  *  1 - Force ID (global)
57  *  2 - Give Time of Day (global)
58  *  3 - Give software Version (global)
59  *  11 - Force ID (local only)
60  *  12 - Give Time of Day (local only)
61  *
62  * cop (control operator) cmds:
63  *
64  *  1 - System warm boot
65  *  2 - System enable
66  *  3 - System disable
67  *  4 - Test Tone On/Off
68  *  5 - Dump System Variables on Console (debug)
69  *  6 - PTT (phone mode only)
70  *  7 - Time out timer enable
71  *  8 - Time out timer disable
72  *  9 - Autopatch enable
73  *  10 - Autopatch disable
74  *  11 - Link enable
75  *  12 - Link disable
76  *  13 - Query System State
77  *  14 - Change System State
78  *  15 - Scheduler Enable
79  *  16 - Scheduler Disable
80  *  17 - User functions (time, id, etc) enable
81  *  18 - User functions (time, id, etc) disable
82  *  19 - Select alternate hang timer
83  *  20 - Select standard hang timer 
84  *  21 - Enable Parrot Mode
85  *  22 - Disable Parrot Mode
86  *  23 - Birdbath (Current Parrot Cleanup/Flush)
87  *  24 - Flush all telemetry
88  *  25 - Query last node un-keyed
89  *  26 - Query all nodes keyed/unkeyed
90  *  30 - Recall Memory Setting in Attached Xcvr
91  *  31 - Channel Selector for Parallel Programmed Xcvr
92  *  32 - Touchtone pad test: command + Digit string + # to playback all digits pressed
93  *
94  * ilink cmds:
95  *
96  *  1 - Disconnect specified link
97  *  2 - Connect specified link -- monitor only
98  *  3 - Connect specified link -- tranceive
99  *  4 - Enter command mode on specified link
100  *  5 - System status
101  *  6 - Disconnect all links
102  *  11 - Disconnect a previously permanently connected link
103  *  12 - Permanently connect specified link -- monitor only
104  *  13 - Permanently connect specified link -- tranceive
105  *  15 - Full system status (all nodes)
106  *  16 - Reconnect links disconnected with "disconnect all links"
107  *  200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
108  *
109  * remote cmds:
110  *
111  *  1 - Recall Memory MM  (*000-*099) (Gets memory from rpt.conf)
112  *  2 - Set VFO MMMMM*KKK*O   (Mhz digits, Khz digits, Offset)
113  *  3 - Set Rx PL Tone HHH*D*
114  *  4 - Set Tx PL Tone HHH*D* (Not currently implemented with DHE RBI-1)
115  *  5 - Link Status (long)
116  *  6 - Set operating mode M (FM, USB, LSB, AM, etc)
117  *  100 - RX PL off (Default)
118  *  101 - RX PL On
119  *  102 - TX PL Off (Default)
120  *  103 - TX PL On
121  *  104 - Low Power
122  *  105 - Med Power
123  *  106 - Hi Power
124  *  107 - Bump Down 20 Hz
125  *  108 - Bump Down 100 Hz
126  *  109 - Bump Down 500 Hz
127  *  110 - Bump Up 20 Hz
128  *  111 - Bump Up 100 Hz
129  *  112 - Bump Up 500 Hz
130  *  113 - Scan Down Slow
131  *  114 - Scan Down Medium
132  *  115 - Scan Down Fast
133  *  116 - Scan Up Slow
134  *  117 - Scan Up Medium
135  *  118 - Scan Up Fast
136  *  119 - Transmit allowing auto-tune
137  *  140 - Link Status (brief)
138  *  200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
139  *
140  * playback cmds:
141  *  specify the name of the file to be played (for example, 25=rpt/foo)
142  *
143  *
144  * 'duplex' modes:  (defaults to duplex=2)
145  *
146  * 0 - Only remote links key Tx and no main repeat audio.
147  * 1 - Everything other then main Rx keys Tx, no main repeat audio.
148  * 2 - Normal mode
149  * 3 - Normal except no main repeat audio.
150  * 4 - Normal except no main repeat audio during autopatch only
151  *
152 */
153
154 /*** MODULEINFO
155         <depend>dahdi</depend>
156         <depend>tonezone</depend>
157         <defaultenabled>no</defaultenabled>
158  ***/
159
160 /* Un-comment the following to include support for MDC-1200 digital tone
161    signalling protocol (using KA6SQG's GPL'ed implementation) */
162 /* #include "mdc_decode.c" */
163
164 /* Un-comment the following to include support for notch filters in the
165    rx audio stream (using Tony Fisher's mknotch (mkfilter) implementation) */
166 /* #include "rpt_notch.c" */
167
168 /* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
169
170 #ifdef OLD_ASTERISK
171 #define ast_free free
172 #define ast_malloc malloc
173 #define ast_strdup strdup
174 #endif
175
176
177 #define MAXDTMF 32
178 #define MAXMACRO 2048
179 #define MAXLINKLIST 512
180 #define LINKLISTTIME 10000
181 #define LINKLISTSHORTTIME 200
182 #define LINKPOSTTIME 30000
183 #define LINKPOSTSHORTTIME 200
184 #define KEYPOSTTIME 30000
185 #define KEYPOSTSHORTTIME 200
186 #define MACROTIME 100
187 #define MACROPTIME 500
188 #define DTMF_TIMEOUT 3
189 #define KENWOOD_RETRIES 5
190 #define TOPKEYN 32
191 #define TOPKEYWAIT 3
192 #define TOPKEYMAXSTR 30
193
194 #define AUTHTELLTIME 7000
195 #define AUTHTXTIME 1000
196 #define AUTHLOGOUTTIME 25000
197
198 #ifdef  __RPT_NOTCH
199 #define MAXFILTERS 10
200 #endif
201
202 #define DISC_TIME 10000  /* report disc after 10 seconds of no connect */
203 #define MAX_RETRIES 5
204 #define MAX_RETRIES_PERM 1000000000
205
206 #define REDUNDANT_TX_TIME 2000
207
208 #define RETRY_TIMER_MS 5000
209
210 #define PATCH_DIALPLAN_TIMEOUT 1500
211
212 #ifdef OLD_ASTERISK
213 #define START_DELAY 10
214 #else
215 #define START_DELAY 2
216 #endif
217
218 #define RPT_LOCKOUT_SECS 10
219
220 #define MAXPEERSTR 31
221 #define MAXREMSTR 15
222
223 #define DELIMCHR ','
224 #define QUOTECHR 34
225
226 #define MONITOR_DISK_BLOCKS_PER_MINUTE 38
227
228 #define DEFAULT_MONITOR_MIN_DISK_BLOCKS 10000
229 #define DEFAULT_REMOTE_INACT_TIMEOUT (15 * 60)
230 #define DEFAULT_REMOTE_TIMEOUT (60 * 60)
231 #define DEFAULT_REMOTE_TIMEOUT_WARNING (3 * 60)
232 #define DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ 30
233
234 #define NODES "nodes"
235 #define EXTNODES "extnodes"
236 #define MEMORY "memory"
237 #define MACRO "macro"
238 #define FUNCTIONS "functions"
239 #define TELEMETRY "telemetry"
240 #define MORSE "morse"
241 #define TONEMACRO "tonemacro"
242 #define FUNCCHAR '*'
243 #define ENDCHAR '#'
244 #define EXTNODEFILE "/var/lib/asterisk/rpt_extnodes"
245 #define NODENAMES "rpt/nodenames"
246 #define PARROTFILE "/tmp/parrot_%s_%u"
247
248 #define PARROTTIME 1000
249
250 #define DEFAULT_IOBASE 0x378
251
252 #define DEFAULT_CIV_ADDR 0x58
253
254 #define MAXCONNECTTIME 5000
255
256 #define MAXNODESTR 300
257
258 #define MAXNODELEN 16
259
260 #define MAXIDENTLEN 32
261
262 #define MAXPATCHCONTEXT 100
263
264 #define ACTIONSIZE 32
265
266 #define TELEPARAMSIZE 256
267
268 #define REM_SCANTIME 100
269
270 #define DTMF_LOCAL_TIME 250
271 #define DTMF_LOCAL_STARTTIME 500
272
273 #define IC706_PL_MEMORY_OFFSET 50
274
275 #define VOX_ON_DEBOUNCE_COUNT 3
276 #define VOX_OFF_DEBOUNCE_COUNT 20
277 #define VOX_MAX_THRESHOLD 10000.0
278 #define VOX_MIN_THRESHOLD 3000.0
279 #define VOX_TIMEOUT_MS 5000
280 #define VOX_RECOVER_MS 500
281 #define SIMPLEX_PATCH_DELAY 25
282 #define SIMPLEX_PHONE_DELAY 25
283
284 #define STATPOST_PROGRAM "/usr/bin/wget,-q,--output-document=/dev/null,--no-check-certificate"
285
286 #define ALLOW_LOCAL_CHANNELS
287
288 enum {REM_OFF,REM_MONITOR,REM_TX};
289
290 enum{ID,PROC,TERM,COMPLETE,UNKEY,REMDISC,REMALREADY,REMNOTFOUND,REMGO,
291         CONNECTED,CONNFAIL,STATUS,TIMEOUT,ID1, STATS_TIME, PLAYBACK,
292         STATS_VERSION, IDTALKOVER, ARB_ALPHA, TEST_TONE, REV_PATCH,
293         TAILMSG, MACRO_NOTFOUND, MACRO_BUSY, LASTNODEKEY, FULLSTATUS,
294         MEMNOTFOUND, INVFREQ, REMMODE, REMLOGIN, REMXXX, REMSHORTSTATUS,
295         REMLONGSTATUS, LOGINREQ, SCAN, SCANSTAT, TUNE, SETREMOTE, TOPKEY,
296         TIMEOUT_WARNING, ACT_TIMEOUT_WARNING, LINKUNKEY, UNAUTHTX, PARROT,
297         STATS_TIME_LOCAL};
298
299
300 enum {REM_SIMPLEX,REM_MINUS,REM_PLUS};
301
302 enum {REM_LOWPWR,REM_MEDPWR,REM_HIPWR};
303
304 enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_COMPLETEQUIET, DC_DOKEY};
305
306 enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT, SOURCE_PHONE, SOURCE_DPHONE, SOURCE_ALT};
307
308 enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM, DLY_COMP, DLY_LINKUNKEY, DLY_PARROT};
309
310 enum {REM_MODE_FM,REM_MODE_USB,REM_MODE_LSB,REM_MODE_AM};
311
312 enum {HF_SCAN_OFF,HF_SCAN_DOWN_SLOW,HF_SCAN_DOWN_QUICK,
313       HF_SCAN_DOWN_FAST,HF_SCAN_UP_SLOW,HF_SCAN_UP_QUICK,HF_SCAN_UP_FAST};
314
315 #include "asterisk.h"
316
317 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
318
319 #include <signal.h>
320 #include <stdio.h>
321 #include <unistd.h>
322 #include <string.h>
323 #include <stdlib.h>
324 #include <search.h>
325 #include <sys/types.h>
326 #include <sys/stat.h>
327 #include <errno.h>
328 #include <dirent.h>
329 #include <ctype.h>
330 #include <sys/stat.h>
331 #include <sys/time.h>
332 #include <sys/file.h>
333 #include <sys/ioctl.h>
334 #include <sys/io.h>
335 #include <sys/vfs.h>
336 #include <math.h>
337 #ifdef OLD_ASTERISK
338 #include <linux/zaptel.h>
339 #include <tonezone.h>
340 #else
341 #include <zaptel/zaptel.h>
342 #include <zaptel/tonezone.h>
343 #endif
344 #include <netinet/in.h>
345 #include <arpa/inet.h>
346
347 #include "asterisk/utils.h"
348 #include "asterisk/lock.h"
349 #include "asterisk/file.h"
350 #include "asterisk/logger.h"
351 #include "asterisk/channel.h"
352 #include "asterisk/callerid.h"
353 #include "asterisk/pbx.h"
354 #include "asterisk/module.h"
355 #include "asterisk/translate.h"
356 #include "asterisk/features.h"
357 #include "asterisk/options.h"
358 #include "asterisk/cli.h"
359 #include "asterisk/config.h"
360 #include "asterisk/say.h"
361 #include "asterisk/localtime.h"
362 #include "asterisk/cdr.h"
363 #include "asterisk/options.h"
364 #include "asterisk/manager.h"
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 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         int     submode;
604         unsigned int 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)) return;
1961         n = finddelim(astr,astrs,100);
1962         if (n < 1) return;
1963         ast_mutex_lock(&myrpt->statpost_lock);
1964         seq = ++myrpt->statpost_seqno;
1965         ast_mutex_unlock(&myrpt->statpost_lock);
1966         astrs[n++] = str;
1967         astrs[n] = NULL;
1968         time(&now);
1969         sprintf(str,"%s?node=%s&time=%u&seqno=%u",myrpt->p.statpost_url,
1970                 myrpt->name,(unsigned int) now,seq);
1971         if (pairs) sprintf(str + strlen(str),"&%s",pairs);
1972         if (!(pid = fork()))
1973         {
1974                 execv(astrs[0],astrs);
1975                 ast_log(LOG_ERROR, "exec of %s failed.\n", astrs[0]);
1976                 perror("asterisk");
1977                 exit(0);
1978         }
1979         ast_free(astr);
1980         ast_free(str);
1981         return;
1982 }
1983
1984 static char *node_lookup(struct rpt *myrpt,char *digitbuf)
1985 {
1986
1987 char *val;
1988 int longestnode,j;
1989 struct stat mystat;
1990 static time_t last = 0;
1991 static struct ast_config *ourcfg = NULL;
1992 struct ast_variable *vp;
1993
1994         /* try to look it up locally first */
1995         val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
1996         if (val) return(val);
1997         ast_mutex_lock(&nodelookuplock);
1998         /* if file does not exist */
1999         if (stat(myrpt->p.extnodefile,&mystat) == -1)
2000         {
2001                 if (ourcfg) ast_config_destroy(ourcfg);
2002                 ourcfg = NULL;
2003                 ast_mutex_unlock(&nodelookuplock);
2004                 return(NULL);
2005         }
2006         /* if we need to reload */
2007         if (mystat.st_mtime > last)
2008         {
2009                 if (ourcfg) ast_config_destroy(ourcfg);
2010 #ifdef  NEW_ASTERISK
2011                 ourcfg = ast_config_load(myrpt->p.extnodefile,config_flags);
2012 #else
2013                 ourcfg = ast_config_load(myrpt->p.extnodefile);
2014 #endif
2015                 /* if file not there, just bail */
2016                 if (!ourcfg)
2017                 {
2018                         ast_mutex_unlock(&nodelookuplock);
2019                         return(NULL);
2020                 }
2021                 /* reset "last" time */
2022                 last = mystat.st_mtime;
2023
2024                 /* determine longest node length again */               
2025                 longestnode = 0;
2026                 vp = ast_variable_browse(myrpt->cfg, myrpt->p.nodes);
2027                 while(vp){
2028                         j = strlen(vp->name);
2029                         if (j > longestnode)
2030                                 longestnode = j;
2031                         vp = vp->next;
2032                 }
2033
2034                 vp = ast_variable_browse(ourcfg, myrpt->p.extnodes);
2035                 while(vp){
2036                         j = strlen(vp->name);
2037                         if (j > longestnode)
2038                                 longestnode = j;
2039                         vp = vp->next;
2040                 }
2041
2042                 myrpt->longestnode = longestnode;
2043         }
2044         val = NULL;
2045         if (ourcfg)
2046                 val = (char *) ast_variable_retrieve(ourcfg, myrpt->p.extnodes, digitbuf);
2047         ast_mutex_unlock(&nodelookuplock);
2048         return(val);
2049 }
2050
2051 /*
2052 * Match a keyword in a list, and return index of string plus 1 if there was a match,* else return 0.
2053 * If param is passed in non-null, then it will be set to the first character past the match
2054 */
2055
2056 static int matchkeyword(char *string, char **param, char *keywords[])
2057 {
2058 int     i,ls;
2059         for( i = 0 ; keywords[i] ; i++){
2060                 ls = strlen(keywords[i]);
2061                 if(!ls){
2062                         *param = NULL;
2063                         return 0;
2064                 }
2065                 if(!strncmp(string, keywords[i], ls)){
2066                         if(param)
2067                                 *param = string + ls;
2068                         return i + 1; 
2069                 }
2070         }
2071         *param = NULL;
2072         return 0;
2073 }
2074
2075 /*
2076 * Skip characters in string which are in charlist, and return a pointer to the
2077 * first non-matching character
2078 */
2079
2080 static char *skipchars(char *string, char *charlist)
2081 {
2082 int i;  
2083         while(*string){
2084                 for(i = 0; charlist[i] ; i++){
2085                         if(*string == charlist[i]){
2086                                 string++;
2087                                 break;
2088                         }
2089                 }
2090                 if(!charlist[i])
2091                         return string;
2092         }
2093         return string;
2094 }       
2095                                         
2096
2097
2098 static int myatoi(char *str)
2099 {
2100 int     ret;
2101
2102         if (str == NULL) return -1;
2103         /* leave this %i alone, non-base-10 input is useful here */
2104         if (sscanf(str,"%i",&ret) != 1) return -1;
2105         return ret;
2106 }
2107
2108 static int mycompar(const void *a, const void *b)
2109 {
2110 char    **x = (char **) a;
2111 char    **y = (char **) b;
2112 int     xoff,yoff;
2113
2114         if ((**x < '0') || (**x > '9')) xoff = 1; else xoff = 0;
2115         if ((**y < '0') || (**y > '9')) yoff = 1; else yoff = 0;
2116         return(strcmp((*x) + xoff,(*y) + yoff));
2117 }
2118
2119 static int topcompar(const void *a, const void *b)
2120 {
2121 struct rpt_topkey *x = (struct rpt_topkey *) a;
2122 struct rpt_topkey *y = (struct rpt_topkey *) b;
2123
2124         return(x->timesince - y->timesince);
2125 }
2126
2127 #ifdef  __RPT_NOTCH
2128
2129 /* rpt filter routine */
2130 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
2131 {
2132 int     i,j;
2133 struct  rptfilter *f;
2134
2135         for(i = 0; i < len; i++)
2136         {
2137                 for(j = 0; j < MAXFILTERS; j++)
2138                 {
2139                         f = &myrpt->filters[j];
2140                         if (!*f->desc) continue;
2141                         f->x0 = f->x1; f->x1 = f->x2;
2142                         f->x2 = ((float)buf[i]) / f->gain;
2143                         f->y0 = f->y1; f->y1 = f->y2;
2144                         f->y2 =   (f->x0 + f->x2) +   f->const0 * f->x1
2145                                      + (f->const1 * f->y0) + (f->const2 * f->y1);
2146                         buf[i] = (short)f->y2;
2147                 }
2148         }
2149 }
2150
2151 #endif
2152
2153
2154 /*
2155  Get the time for the machine's time zone
2156  Note: Asterisk requires a copy of localtime
2157  in the /etc directory for this to work properly.
2158  If /etc/localtime is not present, you will get
2159  GMT time! This is especially important on systems
2160  running embedded linux distributions as they don't usually
2161  have support for locales. 
2162
2163  If OLD_ASTERISK is defined, then the older localtime_r
2164  function will be used. The /etc/localtime file is not
2165  required in this case. This provides backward compatibility
2166  with Asterisk 1.2 systems.
2167
2168 */
2169
2170 #ifdef  NEW_ASTERISK
2171 static void rpt_localtime( time_t * t, struct ast_tm *lt)
2172 {
2173 struct timeval tv;
2174
2175         tv.tv_sec = *t;
2176         tv.tv_usec = 0;
2177         ast_localtime(&tv, lt, NULL);
2178
2179 }
2180
2181 #else
2182 static void rpt_localtime( time_t * t, struct tm *lt)
2183 {
2184 #ifdef OLD_ASTERISK
2185         localtime_r(t, lt);
2186 #else
2187         ast_localtime(t, lt, NULL);
2188 #endif
2189 }
2190 #endif
2191
2192
2193 /* Retrieve an int from a config file */
2194                                                                                 
2195 static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl)
2196 {
2197         char *var;
2198         int ret;
2199         char include_zero = 0;
2200
2201         if(min < 0){ /* If min is negative, this means include 0 as a valid entry */
2202                 min = -min;
2203                 include_zero = 1;
2204         }           
2205                                                                      
2206         var = (char *) ast_variable_retrieve(myrpt->cfg, category, name);
2207         if(var){
2208                 ret = myatoi(var);
2209                 if(include_zero && !ret)
2210                         return 0;
2211                 if(ret < min)
2212                         ret = min;
2213                 if(ret > max)
2214                         ret = max;
2215         }
2216         else
2217                 ret = defl;
2218         return ret;
2219 }
2220
2221
2222 static void load_rpt_vars(int n,int init)
2223 {
2224 char *this,*val;
2225 int     i,j,longestnode;
2226 struct ast_variable *vp;
2227 struct ast_config *cfg;
2228 char *strs[100];
2229 char s1[256];
2230 static char *cs_keywords[] = {"rptena","rptdis","apena","apdis","lnkena","lnkdis","totena","totdis","skena","skdis",
2231                                 "ufena","ufdis","atena","atdis",NULL};
2232
2233         if (option_verbose > 2)
2234                 ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n",
2235                         (init) ? "Loading initial" : "Re-Loading",rpt_vars[n].name);
2236         ast_mutex_lock(&rpt_vars[n].lock);
2237         if (rpt_vars[n].cfg) ast_config_destroy(rpt_vars[n].cfg);
2238 #ifdef  NEW_ASTERISK
2239         cfg = ast_config_load("rpt.conf",config_flags);
2240 #else
2241         cfg = ast_config_load("rpt.conf");
2242 #endif
2243         if (!cfg) {
2244                 ast_mutex_unlock(&rpt_vars[n].lock);
2245                 ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
2246                 pthread_exit(NULL);
2247         }
2248         rpt_vars[n].cfg = cfg; 
2249         this = rpt_vars[n].name;
2250         memset(&rpt_vars[n].p,0,sizeof(rpt_vars[n].p));
2251         if (init)
2252         {
2253                 char *cp;
2254                 int savearea = (char *)&rpt_vars[n].p - (char *)&rpt_vars[n];
2255
2256                 cp = (char *) &rpt_vars[n].p;
2257                 memset(cp + sizeof(rpt_vars[n].p),0,
2258                         sizeof(rpt_vars[n]) - (sizeof(rpt_vars[n].p) + savearea));
2259                 rpt_vars[n].tele.next = &rpt_vars[n].tele;
2260                 rpt_vars[n].tele.prev = &rpt_vars[n].tele;
2261                 rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
2262                 rpt_vars[n].tailmessagen = 0;
2263         }
2264 #ifdef  __RPT_NOTCH
2265         /* zot out filters stuff */
2266         memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
2267 #endif
2268         val = (char *) ast_variable_retrieve(cfg,this,"context");
2269         if (val) rpt_vars[n].p.ourcontext = val;
2270         else rpt_vars[n].p.ourcontext = this;
2271         val = (char *) ast_variable_retrieve(cfg,this,"callerid");
2272         if (val) rpt_vars[n].p.ourcallerid = val;
2273         val = (char *) ast_variable_retrieve(cfg,this,"accountcode");
2274         if (val) rpt_vars[n].p.acctcode = val;
2275         val = (char *) ast_variable_retrieve(cfg,this,"idrecording");
2276         if (val) rpt_vars[n].p.ident = val;
2277         val = (char *) ast_variable_retrieve(cfg,this,"hangtime");
2278         if (val) rpt_vars[n].p.hangtime = atoi(val);
2279                 else rpt_vars[n].p.hangtime = HANGTIME;
2280         val = (char *) ast_variable_retrieve(cfg,this,"althangtime");
2281         if (val) rpt_vars[n].p.althangtime = atoi(val);
2282                 else rpt_vars[n].p.althangtime = HANGTIME;
2283         val = (char *) ast_variable_retrieve(cfg,this,"totime");
2284         if (val) rpt_vars[n].p.totime = atoi(val);
2285                 else rpt_vars[n].p.totime = TOTIME;
2286         val = (char *) ast_variable_retrieve(cfg,this,"voxtimeout");
2287         if (val) rpt_vars[n].p.voxtimeout_ms = atoi(val);
2288                 else rpt_vars[n].p.voxtimeout_ms = VOX_TIMEOUT_MS;
2289         val = (char *) ast_variable_retrieve(cfg,this,"voxrecover");
2290         if (val) rpt_vars[n].p.voxrecover_ms = atoi(val);
2291                 else rpt_vars[n].p.voxrecover_ms = VOX_RECOVER_MS;
2292         val = (char *) ast_variable_retrieve(cfg,this,"simplexpatchdelay");
2293         if (val) rpt_vars[n].p.simplexpatchdelay = atoi(val);
2294                 else rpt_vars[n].p.simplexpatchdelay = SIMPLEX_PATCH_DELAY;
2295         val = (char *) ast_variable_retrieve(cfg,this,"simplexphonedelay");
2296         if (val) rpt_vars[n].p.simplexphonedelay = atoi(val);
2297                 else rpt_vars[n].p.simplexphonedelay = SIMPLEX_PHONE_DELAY;
2298         val = (char *) ast_variable_retrieve(cfg,this,"statpost_program");
2299         if (val) rpt_vars[n].p.statpost_program = val;
2300                 else rpt_vars[n].p.statpost_program = STATPOST_PROGRAM;
2301         rpt_vars[n].p.statpost_url = 
2302                 (char *) ast_variable_retrieve(cfg,this,"statpost_url");
2303         rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0);                
2304         rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0);              
2305         rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2);
2306         rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", -60000, 2400000, IDTIME);        /* Enforce a min max including zero */
2307         rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
2308         val = (char *) ast_variable_retrieve(cfg,this,"tonezone");
2309         if (val) rpt_vars[n].p.tonezone = val;
2310         rpt_vars[n].p.tailmessages[0] = 0;
2311         rpt_vars[n].p.tailmessagemax = 0;
2312         val = (char *) ast_variable_retrieve(cfg,this,"tailmessagelist");
2313         if (val) rpt_vars[n].p.tailmessagemax = finddelim(val, rpt_vars[n].p.tailmessages, 500);
2314         val = (char *) ast_variable_retrieve(cfg,this,"memory");
2315         if (!val) val = MEMORY;
2316         rpt_vars[n].p.memory = val;
2317         val = (char *) ast_variable_retrieve(cfg,this,"macro");
2318         if (!val) val = MACRO;
2319         rpt_vars[n].p.macro = val;
2320         val = (char *) ast_variable_retrieve(cfg,this,"tonemacro");
2321         if (!val) val = TONEMACRO;
2322         rpt_vars[n].p.tonemacro = val;
2323         val = (char *) ast_variable_retrieve(cfg,this,"startup_macro");
2324         if (val) rpt_vars[n].p.startupmacro = val;
2325         val = (char *) ast_variable_retrieve(cfg,this,"iobase");
2326         /* do not use atoi() here, we need to be able to have
2327                 the input specified in hex or decimal so we use
2328                 sscanf with a %i */
2329         if ((!val) || (sscanf(val,"%i",&rpt_vars[n].p.iobase) != 1))
2330                 rpt_vars[n].p.iobase = DEFAULT_IOBASE;
2331         val = (char *) ast_variable_retrieve(cfg,this,"ioport");
2332         rpt_vars[n].p.ioport = val;
2333         val = (char *) ast_variable_retrieve(cfg,this,"functions");
2334         if (!val)
2335                 {
2336                         val = FUNCTIONS;
2337                         rpt_vars[n].p.simple = 1;
2338                 } 
2339         rpt_vars[n].p.functions = val;
2340         val =  (char *) ast_variable_retrieve(cfg,this,"link_functions");
2341         if (val) rpt_vars[n].p.link_functions = val;
2342         else 
2343                 rpt_vars[n].p.link_functions = rpt_vars[n].p.functions;
2344         val = (char *) ast_variable_retrieve(cfg,this,"phone_functions");
2345         if (val) rpt_vars[n].p.phone_functions = val;
2346         val = (char *) ast_variable_retrieve(cfg,this,"dphone_functions");
2347         if (val) rpt_vars[n].p.dphone_functions = val;
2348         val = (char *) ast_variable_retrieve(cfg,this,"alt_functions");
2349         if (val) rpt_vars[n].p.alt_functions = val;
2350         val = (char *) ast_variable_retrieve(cfg,this,"funcchar");
2351         if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else 
2352                 rpt_vars[n].p.funcchar = *val;          
2353         val = (char *) ast_variable_retrieve(cfg,this,"endchar");
2354         if (!val) rpt_vars[n].p.endchar = ENDCHAR; else 
2355                 rpt_vars[n].p.endchar = *val;           
2356         val = (char *) ast_variable_retrieve(cfg,this,"nobusyout");
2357         if (val) rpt_vars[n].p.nobusyout = ast_true(val);
2358         val = (char *) ast_variable_retrieve(cfg,this,"notelemtx");
2359         if (val) rpt_vars[n].p.notelemtx = ast_true(val);
2360         val = (char *) ast_variable_retrieve(cfg,this,"propagate_dtmf");
2361         if (val) rpt_vars[n].p.propagate_dtmf = ast_true(val);
2362         val = (char *) ast_variable_retrieve(cfg,this,"propagate_phonedtmf");
2363         if (val) rpt_vars[n].p.propagate_phonedtmf = ast_true(val);
2364         val = (char *) ast_variable_retrieve(cfg,this,"linktolink");
2365         if (val) rpt_vars[n].p.linktolink = ast_true(val);
2366         val = (char *) ast_variable_retrieve(cfg,this,"nodes");
2367         if (!val) val = NODES;
2368         rpt_vars[n].p.nodes = val;
2369         val = (char *) ast_variable_retrieve(cfg,this,"extnodes");
2370         if (!val) val = EXTNODES;
2371         rpt_vars[n].p.extnodes = val;
2372         val = (char *) ast_variable_retrieve(cfg,this,"extnodefile");
2373         if (!val) val = EXTNODEFILE;
2374         rpt_vars[n].p.extnodefile = val;
2375         val = (char *) ast_variable_retrieve(cfg,this,"archivedir");
2376         if (val) rpt_vars[n].p.archivedir = val;
2377         val = (char *) ast_variable_retrieve(cfg,this,"authlevel");
2378         if (val) rpt_vars[n].p.authlevel = atoi(val); 
2379         else rpt_vars[n].p.authlevel = 0;
2380         val = (char *) ast_variable_retrieve(cfg,this,"parrot");
2381         if (val) rpt_vars[n].p.parrotmode = ast_true(val) * 2;
2382         else rpt_vars[n].p.parrotmode = 0;
2383         val = (char *) ast_variable_retrieve(cfg,this,"parrottime");
2384         if (val) rpt_vars[n].p.parrottime = atoi(val); 
2385         else rpt_vars[n].p.parrottime = PARROTTIME;
2386         val = (char *) ast_variable_retrieve(cfg,this,"rptnode");
2387         rpt_vars[n].p.rptnode = val;
2388         val = (char *) ast_variable_retrieve(cfg,this,"mars");
2389         if (val) rpt_vars[n].p.remote_mars = atoi(val); 
2390         else rpt_vars[n].p.remote_mars = 0;
2391         val = (char *) ast_variable_retrieve(cfg,this,"monminblocks");
2392         if (val) rpt_vars[n].p.monminblocks = atol(val); 
2393         else rpt_vars[n].p.monminblocks = DEFAULT_MONITOR_MIN_DISK_BLOCKS;
2394         val = (char *) ast_variable_retrieve(cfg,this,"remote_inact_timeout");
2395         if (val) rpt_vars[n].p.remoteinacttimeout = atoi(val); 
2396         else rpt_vars[n].p.remoteinacttimeout = DEFAULT_REMOTE_INACT_TIMEOUT;
2397         val = (char *) ast_variable_retrieve(cfg,this,"civaddr");
2398         if (val) rpt_vars[n].p.civaddr = atoi(val); 
2399         else rpt_vars[n].p.civaddr = DEFAULT_CIV_ADDR;
2400         val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout");
2401         if (val) rpt_vars[n].p.remotetimeout = atoi(val); 
2402         else rpt_vars[n].p.remotetimeout = DEFAULT_REMOTE_TIMEOUT;
2403         val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning");
2404         if (val) rpt_vars[n].p.remotetimeoutwarning = atoi(val); 
2405         else rpt_vars[n].p.remotetimeoutwarning = DEFAULT_REMOTE_TIMEOUT_WARNING;
2406         val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning_freq");
2407         if (val) rpt_vars[n].p.remotetimeoutwarningfreq = atoi(val); 
2408         else rpt_vars[n].p.remotetimeoutwarningfreq = DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ;
2409 #ifdef  __RPT_NOTCH
2410         val = (char *) ast_variable_retrieve(cfg,this,"rxnotch");
2411         if (val) {
2412                 i = finddelim(val,strs,MAXFILTERS * 2);
2413                 i &= ~1; /* force an even number, rounded down */
2414                 if (i >= 2) for(j = 0; j < i; j += 2)
2415                 {
2416                         rpt_mknotch(atof(strs[j]),atof(strs[j + 1]),
2417                           &rpt_vars[n].filters[j >> 1].gain,
2418                             &rpt_vars[n].filters[j >> 1].const0,
2419                                 &rpt_vars[n].filters[j >> 1].const1,
2420                                     &rpt_vars[n].filters[j >> 1].const2);
2421                         sprintf(rpt_vars[n].filters[j >> 1].desc,"%s Hz, BW = %s",
2422                                 strs[j],strs[j + 1]);
2423                 }
2424
2425         }
2426 #endif
2427         val = (char *) ast_variable_retrieve(cfg,this,"inxlat");
2428         if (val) {
2429                 memset(&rpt_vars[n].p.inxlat,0,sizeof(struct rpt_xlat));
2430                 i = finddelim(val,strs,3);
2431                 if (i) strncpy(rpt_vars[n].p.inxlat.funccharseq,strs[0],MAXXLAT - 1);
2432                 if (i > 1) strncpy(rpt_vars[n].p.inxlat.endcharseq,strs[1],MAXXLAT - 1);
2433                 if (i > 2) strncpy(rpt_vars[n].p.inxlat.passchars,strs[2],MAXXLAT - 1);
2434         }
2435         val = (char *) ast_variable_retrieve(cfg,this,"outxlat");
2436         if (val) {
2437                 memset(&rpt_vars[n].p.outxlat,0,sizeof(struct rpt_xlat));
2438                 i = finddelim(val,strs,3);
2439                 if (i) strncpy(rpt_vars[n].p.outxlat.funccharseq,strs[0],MAXXLAT - 1);
2440                 if (i > 1) strncpy(rpt_vars[n].p.outxlat.endcharseq,strs[1],MAXXLAT - 1);
2441                 if (i > 2) strncpy(rpt_vars[n].p.outxlat.passchars,strs[2],MAXXLAT - 1);
2442         }
2443         /* retreive the stanza name for the control states if there is one */
2444         val = (char *) ast_variable_retrieve(cfg,this,"controlstates");
2445         rpt_vars[n].p.csstanzaname = val;
2446                 
2447         /* retreive the stanza name for the scheduler if there is one */
2448         val = (char *) ast_variable_retrieve(cfg,this,"scheduler");
2449         rpt_vars[n].p.skedstanzaname = val;
2450
2451         /* retreive the stanza name for the txlimits */
2452         val = (char *) ast_variable_retrieve(cfg,this,"txlimits");
2453         rpt_vars[n].p.txlimitsstanzaname = val;
2454
2455         longestnode = 0;
2456
2457         vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
2458                 
2459         while(vp){
2460                 j = strlen(vp->name);
2461                 if (j > longestnode)
2462                         longestnode = j;
2463                 vp = vp->next;
2464         }
2465
2466         rpt_vars[n].longestnode = longestnode;
2467                 
2468         /*
2469         * For this repeater, Determine the length of the longest function 
2470         */
2471         rpt_vars[n].longestfunc = 0;
2472         vp = ast_variable_browse(cfg, rpt_vars[n].p.functions);
2473         while(vp){
2474                 j = strlen(vp->name);
2475                 if (j > rpt_vars[n].longestfunc)
2476                         rpt_vars[n].longestfunc = j;
2477                 vp = vp->next;
2478         }
2479         /*
2480         * For this repeater, Determine the length of the longest function 
2481         */
2482         rpt_vars[n].link_longestfunc = 0;
2483         vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions);
2484         while(vp){
2485                 j = strlen(vp->name);
2486                 if (j > rpt_vars[n].link_longestfunc)
2487                         rpt_vars[n].link_longestfunc = j;
2488                 vp = vp->next;
2489         }
2490         rpt_vars[n].phone_longestfunc = 0;
2491         if (rpt_vars[n].p.phone_functions)
2492         {
2493                 vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions);
2494                 while(vp){
2495                         j = strlen(vp->name);
2496                         if (j > rpt_vars[n].phone_longestfunc)
2497                                 rpt_vars[n].phone_longestfunc = j;
2498                         vp = vp->next;
2499                 }
2500         }
2501         rpt_vars[n].dphone_longestfunc = 0;
2502         if (rpt_vars[n].p.dphone_functions)
2503         {
2504                 vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions);
2505                 while(vp){
2506                         j = strlen(vp->name);
2507                         if (j > rpt_vars[n].dphone_longestfunc)
2508                                 rpt_vars[n].dphone_longestfunc = j;
2509                         vp = vp->next;
2510                 }
2511         }
2512         rpt_vars[n].alt_longestfunc = 0;
2513         if (rpt_vars[n].p.alt_functions)
2514         {
2515                 vp = ast_variable_browse(cfg, rpt_vars[n].p.alt_functions);
2516                 while(vp){
2517                         j = strlen(vp->name);
2518                         if (j > rpt_vars[n].alt_longestfunc)
2519                                 rpt_vars[n].alt_longestfunc = j;
2520                         vp = vp->next;
2521                 }
2522         }
2523         rpt_vars[n].macro_longest = 1;
2524         vp = ast_variable_browse(cfg, rpt_vars[n].p.macro);
2525         while(vp){
2526                 j = strlen(vp->name);
2527                 if (j > rpt_vars[n].macro_longest)
2528                         rpt_vars[n].macro_longest = j;
2529                 vp = vp->next;
2530         }
2531         
2532         /* Browse for control states */
2533         if(rpt_vars[n].p.csstanzaname)
2534                 vp = ast_variable_browse(cfg, rpt_vars[n].p.csstanzaname);
2535         else
2536                 vp = NULL;
2537         for( i = 0 ; vp && (i < MAX_SYSSTATES) ; i++){ /* Iterate over the number of control state lines in the stanza */
2538                 int k,nukw,statenum;
2539                 statenum=atoi(vp->name);
2540                 strncpy(s1, vp->value, 255);
2541                 s1[255] = 0;
2542                 nukw  = finddelim(s1,strs,32);
2543                 
2544                 for (k = 0 ; k < nukw ; k++){ /* for each user specified keyword */     
2545                         for(j = 0 ; cs_keywords[j] != NULL ; j++){ /* try to match to one in our internal table */
2546                                 if(!strcmp(strs[k],cs_keywords[j])){
2547                                         switch(j){
2548                                                 case 0: /* rptena */
2549                                                         rpt_vars[n].p.s[statenum].txdisable = 0;
2550                                                         break;
2551                                                 case 1: /* rptdis */
2552                                                         rpt_vars[n].p.s[statenum].txdisable = 1;
2553                                                         break;
2554                         
2555                                                 case 2: /* apena */
2556                                                         rpt_vars[n].p.s[statenum].autopatchdisable = 0;
2557                                                         break;
2558
2559                                                 case 3: /* apdis */
2560                                                         rpt_vars[n].p.s[statenum].autopatchdisable = 1;
2561                                                         break;
2562
2563                                                 case 4: /* lnkena */
2564                                                         rpt_vars[n].p.s[statenum].linkfundisable = 0;
2565                                                         break;
2566         
2567                                                 case 5: /* lnkdis */
2568                                                         rpt_vars[n].p.s[statenum].linkfundisable = 1;
2569                                                         break;
2570
2571                                                 case 6: /* totena */
2572                                                         rpt_vars[n].p.s[statenum].totdisable = 0;
2573                                                         break;
2574                                         
2575                                                 case 7: /* totdis */
2576                                                         rpt_vars[n].p.s[statenum].totdisable = 1;
2577                                                         break;
2578
2579                                                 case 8: /* skena */
2580                                                         rpt_vars[n].p.s[statenum].schedulerdisable = 0;
2581                                                         break;
2582
2583                                                 case 9: /* skdis */
2584                                                         rpt_vars[n].p.s[statenum].schedulerdisable = 1;
2585                                                         break;
2586
2587                                                 case 10: /* ufena */
2588                                                         rpt_vars[n].p.s[statenum].userfundisable = 0;
2589                                                         break;
2590
2591                                                 case 11: /* ufdis */
2592                                                         rpt_vars[n].p.s[statenum].userfundisable = 1;
2593                                                         break;
2594
2595                                                 case 12: /* atena */
2596                                                         rpt_vars[n].p.s[statenum].alternatetail = 1;
2597                                                         break;
2598
2599                                                 case 13: /* atdis */
2600                                                         rpt_vars[n].p.s[statenum].alternatetail = 0;
2601                                                         break;
2602                         
2603                                                 default:
2604                                                         ast_log(LOG_WARNING,
2605                                                                 "Unhandled control state keyword %s", cs_keywords[i]);
2606                                                         break;
2607                                         }
2608                                 }
2609                         }
2610                 }
2611                 vp = vp->next;
2612         }
2613         ast_mutex_unlock(&rpt_vars[n].lock);
2614 }
2615
2616 /*
2617 * Enable or disable debug output at a given level at the console
2618 */
2619                                                                                                                                  
2620 static int rpt_do_debug(int fd, int argc, char *argv[])
2621 {
2622         int newlevel;
2623
2624         if (argc != 4)
2625                 return RESULT_SHOWUSAGE;
2626         newlevel = myatoi(argv[3]);
2627         if((newlevel < 0) || (newlevel > 7))
2628                 return RESULT_SHOWUSAGE;
2629         if(newlevel)
2630                 ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
2631         else
2632                 ast_cli(fd, "app_rpt Debugging disabled\n");
2633
2634         debug = newlevel;                                                                                                                          
2635         return RESULT_SUCCESS;
2636 }
2637
2638 /*
2639 * Dump rpt struct debugging onto console
2640 */
2641                                                                                                                                  
2642 static int rpt_do_dump(int fd, int argc, char *argv[])
2643 {
2644         int i;
2645
2646         if (argc != 3)
2647                 return RESULT_SHOWUSAGE;
2648
2649         for(i = 0; i < nrpts; i++)
2650         {
2651                 if (!strcmp(argv[2],rpt_vars[i].name))
2652                 {
2653                         rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
2654                         ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
2655                         return RESULT_SUCCESS;
2656                 }
2657         }
2658         return RESULT_FAILURE;
2659 }
2660
2661 /*
2662 * Dump statistics onto console
2663 */
2664
2665 static int rpt_do_stats(int fd, int argc, char *argv[])
2666 {
2667         int i,j,numoflinks;
2668         int dailytxtime, dailykerchunks;
2669         time_t now;
2670         int totalkerchunks, dailykeyups, totalkeyups, timeouts;
2671         int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
2672         int uptime;
2673         long long totaltxtime;
2674         struct  rpt_link *l;
2675         char *listoflinks[MAX_STAT_LINKS];      
2676         char *lastdtmfcommand,*parrot_ena;
2677         char *tot_state, *ider_state, *patch_state;
2678         char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
2679         char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
2680         struct rpt *myrpt;
2681
2682         static char *not_applicable = "N/A";
2683
2684         if(argc != 3)
2685                 return RESULT_SHOWUSAGE;
2686
2687         tot_state = ider_state = 
2688         patch_state = reverse_patch_state = 
2689         input_signal = not_applicable;
2690         called_number = lastdtmfcommand = NULL;
2691
2692         time(&now);
2693         for(i = 0; i < nrpts; i++)
2694         {
2695                 if (!strcmp(argv[2],rpt_vars[i].name)){
2696                         /* Make a copy of all stat variables while locked */
2697                         myrpt = &rpt_vars[i];
2698                         rpt_mutex_lock(&myrpt->lock); /* LOCK */
2699                         uptime = (int)(now - starttime);
2700                         dailytxtime = myrpt->dailytxtime;
2701                         totaltxtime = myrpt->totaltxtime;
2702                         dailykeyups = myrpt->dailykeyups;
2703                         totalkeyups = myrpt->totalkeyups;
2704                         dailykerchunks = myrpt->dailykerchunks;
2705                         totalkerchunks = myrpt->totalkerchunks;
2706                         dailyexecdcommands = myrpt->dailyexecdcommands;
2707                         totalexecdcommands = myrpt->totalexecdcommands;
2708                         timeouts = myrpt->timeouts;
2709
2710                         /* Traverse the list of connected nodes */
2711                         reverse_patch_state = "DOWN";
2712                         numoflinks = 0;
2713                         l = myrpt->links.next;
2714                         while(l && (l != &myrpt->links)){
2715                                 if(numoflinks >= MAX_STAT_LINKS){
2716                                         ast_log(LOG_NOTICE,
2717                                         "maximum number of links exceeds %d in rpt_do_stats()!",MAX_STAT_LINKS);
2718                                         break;
2719                                 }
2720                                 if (l->name[0] == '0'){ /* Skip '0' nodes */
2721                                         reverse_patch_state = "UP";
2722                                         l = l->next;
2723                                         continue;
2724                                 }
2725                                 listoflinks[numoflinks] = ast_strdup(l->name);
2726                                 if(listoflinks[numoflinks] == NULL){
2727                                         break;
2728                                 }
2729                                 else{
2730                                         numoflinks++;
2731                                 }
2732                                 l = l->next;
2733                         }
2734
2735                         if(myrpt->keyed)
2736                                 input_signal = "YES";
2737                         else
2738                                 input_signal = "NO";
2739
2740                         if(myrpt->p.parrotmode)
2741                                 parrot_ena = "ENABLED";
2742                         else
2743                                 parrot_ena = "DISABLED";
2744
2745                         if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
2746                                 sys_ena = "DISABLED";
2747                         else
2748                                 sys_ena = "ENABLED";
2749
2750                         if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
2751                                 tot_ena = "DISABLED";
2752                         else
2753                                 tot_ena = "ENABLED";
2754
2755                         if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
2756                                 link_ena = "DISABLED";
2757                         else
2758                                 link_ena = "ENABLED";
2759
2760                         if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
2761                                 patch_ena = "DISABLED";
2762                         else
2763                                 patch_ena = "ENABLED";
2764
2765                         if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
2766                                 sch_ena = "DISABLED";
2767                         else
2768                                 sch_ena = "ENABLED";
2769
2770                         if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
2771                                 user_funs = "DISABLED";
2772                         else
2773                                 user_funs = "ENABLED";
2774
2775                         if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
2776                                 tail_type = "ALTERNATE";
2777                         else
2778                                 tail_type = "STANDARD";
2779
2780                         if(!myrpt->totimer)
2781                                 tot_state = "TIMED OUT!";
2782                         else if(myrpt->totimer != myrpt->p.totime)
2783                                 tot_state = "ARMED";
2784                         else
2785                                 tot_state = "RESET";
2786
2787                         if(myrpt->tailid)
2788                                 ider_state = "QUEUED IN TAIL";
2789                         else if(myrpt->mustid)
2790                                 ider_state = "QUEUED FOR CLEANUP";
2791                         else
2792                                 ider_state = "CLEAN";
2793
2794                         switch(myrpt->callmode){
2795                                 case 1:
2796                                         patch_state = "DIALING";
2797                                         break;
2798                                 case 2:
2799                                         patch_state = "CONNECTING";
2800                                         break;
2801                                 case 3:
2802                                         patch_state = "UP";
2803                                         break;
2804
2805                                 case 4:
2806                                         patch_state = "CALL FAILED";
2807                                         break;
2808
2809                                 default:
2810                                         patch_state = "DOWN";
2811                         }
2812
2813                         if(strlen(myrpt->exten)){
2814                                 called_number = ast_strdup(myrpt->exten);
2815                         }
2816
2817                         if(strlen(myrpt->lastdtmfcommand)){
2818                                 lastdtmfcommand = ast_strdup(myrpt->lastdtmfcommand);
2819                         }
2820                         rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2821
2822                         ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
2823                         ast_cli(fd, "Selected system state............................: %d\n", myrpt->p.sysstate_cur);
2824                         ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
2825                         ast_cli(fd, "System...........................................: %s\n", sys_ena);
2826                         ast_cli(fd, "Parrot Mode......................................: %s\n", parrot_ena);
2827                         ast_cli(fd, "Scheduler........................................: %s\n", sch_ena);
2828                         ast_cli(fd, "Tail Time........................................: %s\n", tail_type);
2829                         ast_cli(fd, "Time out timer...................................: %s\n", tot_ena);
2830                         ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
2831                         ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
2832                         ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
2833                         ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
2834                         ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
2835                         ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
2836                         ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
2837                         ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
2838                         ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
2839                         ast_cli(fd, "Last DTMF command executed.......................: %s\n", 
2840                         (lastdtmfcommand && strlen(lastdtmfcommand)) ? lastdtmfcommand : not_applicable);
2841                         hours = dailytxtime/3600000;
2842                         dailytxtime %= 3600000;
2843                         minutes = dailytxtime/60000;
2844                         dailytxtime %= 60000;
2845                         seconds = dailytxtime/1000;
2846                         dailytxtime %= 1000;
2847
2848                         ast_cli(fd, "TX time today....................................: %02d:%02d:%02d.%d\n",
2849                                 hours, minutes, seconds, dailytxtime);
2850
2851                         hours = (int) totaltxtime/3600000;
2852                         totaltxtime %= 3600000;
2853                         minutes = (int) totaltxtime/60000;
2854                         totaltxtime %= 60000;
2855                         seconds = (int)  totaltxtime/1000;
2856                         totaltxtime %= 1000;
2857
2858                         ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
2859                                  hours, minutes, seconds, (int) totaltxtime);
2860
2861                         hours = uptime/3600;
2862                         uptime %= 3600;
2863                         minutes = uptime/60;
2864                         uptime %= 60;
2865
2866                         ast_cli(fd, "Uptime...........................................: %02d:%02d:%02d\n",
2867                                 hours, minutes, uptime);
2868
2869                         ast_cli(fd, "Nodes currently connected to us..................: ");
2870                         if(!numoflinks){
2871                               ast_cli(fd,"<NONE>");
2872                         }
2873                         else{
2874                                 for(j = 0 ;j < numoflinks; j++){
2875                                         ast_cli(fd, "%s", listoflinks[j]);
2876                                         if(j % 4 == 3){
2877                                                 ast_cli(fd, "\n");
2878                                                 ast_cli(fd, "                                                 : ");
2879                                         }       
2880                                         else{
2881                                                 if((numoflinks - 1) - j  > 0)
2882                                                         ast_cli(fd, ", ");
2883                                         }
2884                                 }
2885                         }
2886                         ast_cli(fd,"\n");
2887
2888                         ast_cli(fd, "Autopatch........................................: %s\n", patch_ena);
2889                         ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
2890                         ast_cli(fd, "Autopatch called number..........................: %s\n",
2891                         (called_number && strlen(called_number)) ? called_number : not_applicable);
2892                         ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n", reverse_patch_state);
2893                         ast_cli(fd, "User linking commands............................: %s\n", link_ena);
2894                         ast_cli(fd, "User functions...................................: %s\n\n", user_funs);
2895
2896                         for(j = 0; j < numoflinks; j++){ /* ast_free() all link names */
2897                                 ast_free(listoflinks[j]);
2898                         }
2899                         if(called_number){
2900                                 ast_free(called_number);
2901                         }
2902                         if(lastdtmfcommand){
2903                                 ast_free(lastdtmfcommand);
2904                         }
2905                         return RESULT_SUCCESS;
2906                 }
2907         }
2908         return RESULT_FAILURE;
2909 }
2910
2911 /*
2912 * Link stats function
2913 */
2914
2915 static int rpt_do_lstats(int fd, int argc, char *argv[])
2916 {
2917         int i,j;
2918         char *connstate;
2919         struct rpt *myrpt;
2920         struct rpt_link *l;
2921         struct rpt_lstat *s,*t;
2922         struct rpt_lstat s_head;
2923         if(argc != 3)
2924                 return RESULT_SHOWUSAGE;
2925
2926         s = NULL;
2927         s_head.next = &s_head;
2928         s_head.prev = &s_head;
2929
2930         for(i = 0; i < nrpts; i++)
2931         {
2932                 if (!strcmp(argv[2],rpt_vars[i].name)){
2933                         /* Make a copy of all stat variables while locked */
2934                         myrpt = &rpt_vars[i];
2935                         rpt_mutex_lock(&myrpt->lock); /* LOCK */
2936                         /* Traverse the list of connected nodes */
2937                         j = 0;
2938                         l = myrpt->links.next;
2939                         while(l && (l != &myrpt->links)){
2940                                 if (l->name[0] == '0'){ /* Skip '0' nodes */
2941                                         l = l->next;
2942                                         continue;
2943                                 }
2944                                 if((s = (struct rpt_lstat *) ast_malloc(sizeof(struct rpt_lstat))) == NULL){
2945                                         ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
2946                                         rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2947                                         return RESULT_FAILURE;
2948                                 }
2949                                 memset(s, 0, sizeof(struct rpt_lstat));
2950                                 strncpy(s->name, l->name, MAXREMSTR - 1);
2951                                 if (l->chan) pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
2952                                 else strcpy(s->peer,"(none)");
2953                                 s->mode = l->mode;
2954                                 s->outbound = l->outbound;
2955                                 s->reconnects = l->reconnects;
2956                                 s->connecttime = l->connecttime;
2957                                 s->thisconnected = l->thisconnected;
2958                                 memcpy(s->chan_stat,l->chan_stat,NRPTSTAT * sizeof(struct rpt_chan_stat));
2959                                 insque((struct qelem *) s, (struct qelem *) s_head.next);
2960                                 memset(l->chan_stat,0,NRPTSTAT * sizeof(struct rpt_chan_stat));
2961                                 l = l->next;
2962                         }
2963                         rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2964                         ast_cli(fd, "NODE      PEER                RECONNECTS  DIRECTION  CONNECT TIME        CONNECT STATE\n");
2965                         ast_cli(fd, "----      ----                ----------  ---------  ------------        -------------\n");
2966
2967                         for(s = s_head.next; s != &s_head; s = s->next){
2968                                 int hours, minutes, seconds;
2969                                 long long connecttime = s->connecttime;
2970                                 char conntime[21];
2971                                 hours = (int) connecttime/3600000;
2972                                 connecttime %= 3600000;
2973                                 minutes = (int) connecttime/60000;
2974                                 connecttime %= 60000;
2975                                 seconds = (int)  connecttime/1000;
2976                                 connecttime %= 1000;
2977                                 snprintf(conntime, 20, "%02d:%02d:%02d.%d",
2978                                         hours, minutes, seconds, (int) connecttime);
2979                                 conntime[20] = 0;
2980                                 if(s->thisconnected)
2981                                         connstate  = "ESTABLISHED";
2982                                 else
2983                                         connstate = "CONNECTING";
2984                                 ast_cli(fd, "%-10s%-20s%-12d%-11s%-20s%-20s\n",
2985                                         s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime, connstate);
2986                         }       
2987                         /* destroy our local link queue */
2988                         s = s_head.next;
2989                         while(s != &s_head){
2990                                 t = s;
2991                                 s = s->next;
2992                                 remque((struct qelem *)t);
2993                                 ast_free(t);
2994                         }                       
2995                         return RESULT_SUCCESS;
2996                 }
2997         }
2998         return RESULT_FAILURE;
2999 }
3000
3001 /*
3002 * List all nodes connected, directly or indirectly
3003 */
3004
3005 static int rpt_do_nodes(int fd, int argc, char *argv[])
3006 {
3007         int i,j;
3008         char ns;
3009         char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
3010         struct rpt *myrpt;
3011         if(argc != 3)
3012                 return RESULT_SHOWUSAGE;
3013
3014         for(i = 0; i < nrpts; i++)
3015         {
3016                 if (!strcmp(argv[2],rpt_vars[i].name)){
3017                         /* Make a copy of all stat variables while locked */
3018                         myrpt = &rpt_vars[i];
3019                         rpt_mutex_lock(&myrpt->lock); /* LOCK */
3020                         __mklinklist(myrpt,NULL,lbuf);
3021                         rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
3022                         /* parse em */
3023                         ns = finddelim(lbuf,strs,MAXLINKLIST);
3024                         /* sort em */
3025                         if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
3026                         ast_cli(fd,"\n");
3027                         ast_cli(fd, "************************* CONNECTED NODES *************************\n\n");
3028                         for(j = 0 ;; j++){
3029                                 if(!strs[j]){
3030                                         if(!j){
3031                                                 ast_cli(fd,"<NONE>");
3032                                         }
3033                                         break;
3034                                 }
3035                                 ast_cli(fd, "%s", strs[j]);
3036                                 if(j % 8 == 7){
3037                                         ast_cli(fd, "\n");
3038                                 }
3039                                 else{
3040                                         if(strs[j + 1])
3041                                                 ast_cli(fd, ", ");
3042                                 }
3043                         }
3044                         ast_cli(fd,"\n\n");
3045                         return RESULT_SUCCESS;
3046                 }
3047         }
3048         return RESULT_FAILURE;
3049 }
3050
3051 /*
3052 * List all locally configured nodes
3053 */
3054
3055 static int rpt_do_local_nodes(int fd, int argc, char *argv[])
3056 {
3057
3058     int i;
3059     ast_cli(fd, "\nNode\n----\n");
3060     for (i=0; i< nrpts; i++)
3061     {
3062         ast_cli(fd, "%s\n", rpt_vars[i].name);        
3063     } /* for i */
3064     ast_cli(fd,"\n");
3065     return RESULT_SUCCESS;
3066
3067
3068
3069 /*
3070 * reload vars 
3071 */
3072
3073 static int rpt_do_reload(int fd, int argc, char *argv[])
3074 {
3075 int     n;
3076
3077         if (argc > 2) return RESULT_SHOWUSAGE;
3078
3079         for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
3080
3081         return RESULT_FAILURE;
3082 }
3083
3084 /*
3085 * restart app_rpt
3086 */
3087                                                                                                                                  
3088 static int rpt_do_restart(int fd, int argc, char *argv[])
3089 {
3090 int     i;
3091
3092         if (argc > 2) return RESULT_SHOWUSAGE;
3093         for(i = 0; i < nrpts; i++)
3094         {
3095                 if (rpt_vars[i].rxchannel) ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
3096         }
3097         return RESULT_FAILURE;
3098 }
3099
3100
3101 /*
3102 * send an app_rpt DTMF function from the CLI
3103 */
3104                                                                                                                                  
3105 static int rpt_do_fun(int fd, int argc, char *argv[])
3106 {
3107         int     i,busy=0;
3108
3109         if (argc != 4) return RESULT_SHOWUSAGE;
3110
3111         for(i = 0; i < nrpts; i++){
3112                 if(!strcmp(argv[2], rpt_vars[i].name)){
3113                         struct rpt *myrpt = &rpt_vars[i];
3114                         rpt_mutex_lock(&myrpt->lock);
3115                         if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(argv[3])){
3116                                 rpt_mutex_unlock(&myrpt->lock);
3117                                 busy=1;
3118                         }
3119                         if(!busy){
3120                                 myrpt->macrotimer = MACROTIME;
3121                                 strncat(myrpt->macrobuf,argv[3],MAXMACRO - 1);
3122                         }
3123                         rpt_mutex_unlock(&myrpt->lock);
3124                 }
3125         }
3126         if(busy){
3127                 ast_cli(fd, "Function decoder busy");
3128         }
3129         return RESULT_FAILURE;
3130 }
3131 /*
3132         the convention is that macros in the data from the rpt() application
3133         are all at the end of the data, separated by the | and start with a *
3134         when put into the macro buffer, the characters have their high bit
3135         set so the macro processor knows they came from the application data
3136         and to use the alt-functions table.
3137         sph:
3138 */
3139 static int rpt_push_alt_macro(struct rpt *myrpt, char *sptr)
3140 {
3141         int     busy=0;
3142
3143         rpt_mutex_lock(&myrpt->lock);
3144         if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(sptr)){
3145                 rpt_mutex_unlock(&myrpt->lock);
3146                 busy=1;
3147         }
3148         if(!busy){
3149                 int x;
3150                 if (debug)ast_log(LOG_NOTICE, "rpt_push_alt_macro %s\n",sptr);
3151                 myrpt->macrotimer = MACROTIME;
3152                 for(x = 0; *(sptr + x); x++)
3153                     myrpt->macrobuf[x] = *(sptr + x) | 0x80;
3154                 *(sptr + x) = 0;
3155         }
3156         rpt_mutex_unlock(&myrpt->lock);
3157
3158         if(busy)ast_log(LOG_WARNING, "Function decoder busy on app_rpt command macro.\n");
3159
3160         return busy;
3161 }
3162 /*
3163         allows us to test rpt() application data commands
3164 */
3165 static int rpt_do_fun1(int fd, int argc, char *argv[])
3166 {
3167         int     i;
3168
3169     if (argc != 4) return RESULT_SHOWUSAGE;
3170
3171         for(i = 0; i < nrpts; i++){
3172                 if(!strcmp(argv[2], rpt_vars[i].name)){
3173                         struct rpt *myrpt = &rpt_vars[i];
3174                         rpt_push_alt_macro(myrpt,argv[3]);
3175                 }
3176         }
3177         return RESULT_FAILURE;
3178 }
3179 /*
3180 * send an app_rpt **command** from the CLI
3181 */
3182
3183 static int rpt_do_cmd(int fd, int argc, char *argv[])
3184 {
3185         int i, l;
3186         int busy=0;
3187         int maxActions = sizeof(function_table)/sizeof(struct function_table_tag);
3188
3189         int thisRpt = -1;
3190         int thisAction = -1;
3191         struct rpt *myrpt = NULL;
3192         if (argc != 6) return RESULT_SHOWUSAGE;
3193         
3194         for(i = 0; i < nrpts; i++)
3195         {
3196                 if(!strcmp(argv[2], rpt_vars[i].name))
3197                 {
3198                         thisRpt = i;
3199                         myrpt = &rpt_vars[i];
3200                         break;
3201                 } /* if !strcmp... */
3202         } /* for i */
3203
3204         if (thisRpt < 0)
3205         {
3206                 ast_cli(fd, "Unknown node number %s.\n", argv[2]);
3207                 return RESULT_FAILURE;
3208         } /* if thisRpt < 0 */
3209         
3210         /* Look up the action */
3211         l = strlen(argv[3]);
3212         for(i = 0 ; i < maxActions; i++)
3213         {
3214                 if(!strncasecmp(argv[3], function_table[i].action, l))
3215                 {
3216                         thisAction = i;
3217                         break;
3218                 } /* if !strncasecmp... */
3219         } /* for i */
3220         
3221         if (thisAction < 0)
3222         {
3223                 ast_cli(fd, "Unknown action name %s.\n", argv[3]);
3224                 return RESULT_FAILURE;
3225         } /* if thisAction < 0 */
3226
3227         /* at this point, it looks like all the arguments make sense... */
3228
3229         rpt_mutex_lock(&myrpt->lock);
3230
3231         if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE)
3232         {
3233                 rpt_vars[thisRpt].cmdAction.state = CMD_STATE_BUSY;
3234                 rpt_vars[thisRpt].cmdAction.functionNumber = thisAction;
3235                 strncpy(rpt_vars[thisRpt].cmdAction.param, argv[4], MAXDTMF);
3236                 strncpy(rpt_vars[thisRpt].cmdAction.digits, argv[5], MAXDTMF);
3237                 rpt_vars[thisRpt].cmdAction.command_source = SOURCE_RPT;
3238                 rpt_vars[thisRpt].cmdAction.state = CMD_STATE_READY;
3239         } /* if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE */
3240         else
3241         {
3242                 busy = 1;
3243         } /* if (rpt_vars[thisRpt].cmdAction.state == CMD_STATE_IDLE */
3244         rpt_mutex_unlock(&myrpt->lock);
3245
3246         return (busy ? RESULT_FAILURE : RESULT_SUCCESS);
3247 } /* rpt_do_cmd() */
3248
3249 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
3250 {
3251         int res;
3252
3253         if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
3254                 return res;
3255                                                                                                                                             
3256         while(chan->generatordata) {
3257                 if (ast_safe_sleep(chan,1)) return -1;
3258         }
3259
3260         return 0;
3261 }
3262
3263 static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
3264 {
3265         return play_tone_pair(chan, freq, 0, duration, amplitude);
3266 }
3267
3268 static int play_silence(struct ast_channel *c