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