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