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