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