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