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