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