Don't reload a configuration file if nothing has changed.
[asterisk/asterisk.git] / apps / app_rpt.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2002-2005, Jim Dixon, WB6NIL
5  *
6  * Jim Dixon, WB6NIL <jim@lambdatel.com>
7  * Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
8  *
9  * See http://www.asterisk.org for more information about
10  * the Asterisk project. Please do not directly contact
11  * any of the maintainers of this project for assistance;
12  * the project provides a web site, mailing lists and IRC
13  * channels for your use.
14  *
15  * This program is free software, distributed under the terms of
16  * the GNU General Public License Version 2. See the LICENSE file
17  * at the top of the source tree.
18  */
19
20 /*! \file
21  *
22  * \brief Radio Repeater / Remote Base program 
23  *  version 0.48 06/13/06
24  * 
25  * \author Jim Dixon, WB6NIL <jim@lambdatel.com>
26  *
27  * \note Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
28  * 
29  * See http://www.zapatatelephony.org/app_rpt.html
30  *
31  *
32  * Repeater / Remote Functions:
33  * "Simple" Mode:  * - autopatch access, # - autopatch hangup
34  * Normal mode:
35  * See the function list in rpt.conf (autopatchup, autopatchdn)
36  * autopatchup can optionally take comma delimited setting=value pairs:
37  *  
38  *
39  * context=string               :       Override default context with "string"
40  * dialtime=ms                  :       Specify the max number of milliseconds between phone number digits (1000 milliseconds = 1 second)
41  * farenddisconnect=1           :       Automatically disconnect when called party hangs up
42  * noct=1                       :       Don't send repeater courtesy tone during autopatch calls
43  * quiet=1                      :       Don't send dial tone, or connect messages. Do not send patch down message when called party hangs up
44  *
45  *
46  * Example: 123=autopatchup,dialtime=20000,noct=1,farenddisconnect=1
47  *
48  *  To send an asterisk (*) while dialing or talking on phone,
49  *  use the autopatch acess code.
50  *
51  *
52  * status cmds:
53  *
54  *  1 - Force ID
55  *  2 - Give Time of Day
56  *  3 - Give software Version
57  *
58  * cop (control operator) cmds:
59  *
60  *  1 - System warm boot
61  *  2 - System enable
62  *  3 - System disable
63  *  4 - Test Tone On
64  *  5 - Dump System Variables on Console (debug)
65  *  6 - PTT (phone mode only)
66  *
67  * ilink cmds:
68  *
69  *  1 - Disconnect specified link
70  *  2 - Connect specified link -- monitor only
71  *  3 - Connect specified link -- tranceive
72  *  4 - Enter command mode on specified link
73  *  5 - System status
74  *  6 - Disconnect all links
75  *
76  * remote cmds:
77  *
78  *  1 - Recall Memory MM  (*000-*099) (Gets memory from rpt.conf)
79  *  2 - Set VFO MMMMM*KKK*O   (Mhz digits, Khz digits, Offset)
80  *  3 - Set Rx PL Tone HHH*D*
81  *  4 - Set Tx PL Tone HHH*D* (Not currently implemented with DHE RBI-1)
82  *  5 - Link Status (long)
83  *  6 - Set operating mode M (FM, USB, LSB, AM, etc)
84  *  100 - RX PL off (Default)
85  *  101 - RX PL On
86  *  102 - TX PL Off (Default)
87  *  103 - TX PL On
88  *  104 - Low Power
89  *  105 - Med Power
90  *  106 - Hi Power
91  *  107 - Bump Down 20 Hz
92  *  108 - Bump Down 100 Hz
93  *  109 - Bump Down 500 Hz
94  *  110 - Bump Up 20 Hz
95  *  111 - Bump Up 100 Hz
96  *  112 - Bump Up 500 Hz
97  *  113 - Scan Down Slow
98  *  114 - Scan Down Medium
99  *  115 - Scan Down Fast
100  *  116 - Scan Up Slow
101  *  117 - Scan Up Medium
102  *  118 - Scan Up Fast
103  *  119 - Transmit allowing auto-tune
104  *  140 - Link Status (brief)
105  *
106  *
107  *
108  * 'duplex' modes:  (defaults to duplex=2)
109  *
110  * 0 - Only remote links key Tx and no main repeat audio.
111  * 1 - Everything other then main Rx keys Tx, no main repeat audio.
112  * 2 - Normal mode
113  * 3 - Normal except no main repeat audio.
114  * 4 - Normal except no main repeat audio during autopatch only
115  *
116 */
117
118 /*** MODULEINFO
119         <depend>zaptel</depend>
120         <depend>tonezone</depend>
121         <defaultenabled>no</defaultenabled>
122  ***/
123
124 /* Un-comment the following to include support for MDC-1200 digital tone
125    signalling protocol (using KA6SQG's GPL'ed implementation) */
126 /* #include "mdc_decode.c" */
127
128 /* Un-comment the following to include support for notch filters in the
129    rx audio stream (using Tony Fisher's mknotch (mkfilter) implementation) */
130 /* #include "rpt_notch.c" */
131
132 /* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
133
134 #define MAXDTMF 32
135 #define MAXMACRO 2048
136 #define MAXGOSUB 2048
137 #define MACROTIME 100
138 #define GOSUBTIME 100
139 #define MACROPTIME 500
140 #define GOSUBPTIME 500
141 #define DTMF_TIMEOUT 3
142
143 #ifdef  __RPT_NOTCH
144 #define MAXFILTERS 10
145 #endif
146
147 #define DISC_TIME 10000  /* report disc after 10 seconds of no connect */
148 #define MAX_RETRIES 5
149
150 #define REDUNDANT_TX_TIME 2000
151
152 #define RETRY_TIMER_MS 5000
153
154 #define MAXPEERSTR 31
155 #define MAXREMSTR 15
156
157 #define DELIMCHR ','
158 #define QUOTECHR 34
159
160 #define NODES "nodes"
161 #define MEMORY "memory"
162 #define MACRO "macro"
163 #define GOSUB "gosub"
164 #define FUNCTIONS "functions"
165 #define TELEMETRY "telemetry"
166 #define MORSE "morse"
167 #define FUNCCHAR '*'
168 #define ENDCHAR '#'
169
170 #define DEFAULT_IOBASE 0x378
171
172 #define MAXCONNECTTIME 5000
173
174 #define MAXNODESTR 300
175
176 #define MAXPATCHCONTEXT 100
177
178 #define ACTIONSIZE 32
179
180 #define TELEPARAMSIZE 256
181
182 #define REM_SCANTIME 100
183
184
185 enum {REM_OFF, REM_MONITOR, REM_TX};
186
187 enum {ID, PROC, TERM, COMPLETE, UNKEY, REMDISC, REMALREADY, REMNOTFOUND, REMGO,
188         CONNECTED, CONNFAIL, STATUS, TIMEOUT, ID1, STATS_TIME,
189         STATS_VERSION, IDTALKOVER, ARB_ALPHA, TEST_TONE, REV_PATCH,
190         TAILMSG, MACRO_NOTFOUND, GOSUB_NOTFOUND, MACRO_BUSY, GOSUB_BUSY, LASTNODEKEY};
191
192 enum {REM_SIMPLEX, REM_MINUS, REM_PLUS};
193
194 enum {REM_LOWPWR, REM_MEDPWR, REM_HIPWR};
195
196 enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_DOKEY};
197
198 enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT, SOURCE_PHONE, SOURCE_DPHONE};
199
200 enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM};
201
202 enum {REM_MODE_FM, REM_MODE_USB, REM_MODE_LSB, REM_MODE_AM};
203
204 enum {HF_SCAN_OFF, HF_SCAN_DOWN_SLOW, HF_SCAN_DOWN_QUICK,
205       HF_SCAN_DOWN_FAST, HF_SCAN_UP_SLOW, HF_SCAN_UP_QUICK, HF_SCAN_UP_FAST};
206
207 #include "asterisk.h"
208
209 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
210
211 #include <signal.h>
212 #include <stdio.h>
213 #include <unistd.h>
214 #include <string.h>
215 #include <stdlib.h>
216 #include <search.h>
217 #include <sys/types.h>
218 #include <sys/stat.h>
219 #include <errno.h>
220 #include <dirent.h>
221 #include <ctype.h>
222 #include <sys/stat.h>
223 #include <sys/time.h>
224 #include <sys/file.h>
225 #include <sys/ioctl.h>
226 #include <sys/io.h>
227 #include <math.h>
228 #include <netinet/in.h>
229 #include <arpa/inet.h>
230
231 #include "asterisk/utils.h"
232 #include "asterisk/lock.h"
233 #include "asterisk/file.h"
234 #include "asterisk/logger.h"
235 #include "asterisk/channel.h"
236 #include "asterisk/callerid.h"
237 #include "asterisk/pbx.h"
238 #include "asterisk/module.h"
239 #include "asterisk/translate.h"
240 #include "asterisk/features.h"
241 #include "asterisk/options.h"
242 #include "asterisk/cli.h"
243 #include "asterisk/config.h"
244 #include "asterisk/say.h"
245 #include "asterisk/localtime.h"
246 #include "asterisk/app.h"
247
248 #include "asterisk/zapata.h"
249
250 static char *app = "Rpt";
251
252 static char *synopsis = "Radio Repeater/Remote Base Control System";
253
254 static char *descrip = 
255 "  Rpt(nodename[,options]):  Radio Remote Link or Remote Base Link Endpoint Process.\n"
256 "\n"
257 "    Not specifying an option puts it in normal endpoint mode (where source\n"
258 "    IP and nodename are verified).\n"
259 "\n"
260 "    Options are as follows:\n"
261 "\n"
262 "        X - Normal endpoint mode WITHOUT security check. Only specify\n"
263 "            this if you have checked security already (like with an IAX2\n"
264 "            user/password or something).\n"
265 "\n"
266 "        Rannounce-string[,timeout[,timeout-destination]] - Amateur Radio\n"
267 "            Reverse Autopatch. Caller is put on hold, and announcement (as\n"
268 "            specified by the 'announce-string') is played on radio system.\n"
269 "            Users of radio system can access autopatch, dial specified\n"
270 "            code, and pick up call. Announce-string is list of names of\n"
271 "            recordings, or \"PARKED\" to substitute code for un-parking,\n"
272 "            or \"NODE\" to substitute node number.\n"
273 "\n"
274 "        P - Phone Control mode. This allows a regular phone user to have\n"
275 "            full control and audio access to the radio system. For the\n"
276 "            user to have DTMF control, the 'phone_functions' parameter\n"
277 "            must be specified for the node in 'rpt.conf'. An additional\n"
278 "            function (cop,6) must be listed so that PTT control is available.\n"
279 "\n"
280 "        D - Dumb Phone Control mode. This allows a regular phone user to\n"
281 "            have full control and audio access to the radio system. In this\n"
282 "            mode, the PTT is activated for the entire length of the call.\n"
283 "            For the user to have DTMF control (not generally recomended in\n"
284 "            this mode), the 'dphone_functions' parameter must be specified\n"
285 "            for the node in 'rpt.conf'. Otherwise no DTMF control will be\n"
286 "            available to the phone user.\n"
287 "\n";
288
289 static unsigned int vmajor = 0;
290 static unsigned int vminor = 47;
291
292 static int debug = 0;  /* FIXME Set this >0 for extra debug output */
293 static int nrpts = 0;
294
295 char *discstr = "!!DISCONNECT!!";
296 static char *remote_rig_ft897 = "ft897";
297 static char *remote_rig_rbi = "rbi";
298
299 #ifdef  OLD_ASTERISK
300 STANDARD_LOCAL_USER;
301 #endif
302
303
304 #define MSWAIT 200
305 #define HANGTIME 5000
306 #define TOTIME 180000
307 #define IDTIME 300000
308 #define MAXRPTS 20
309 #define MAX_STAT_LINKS 32
310 #define POLITEID 30000
311 #define FUNCTDELAY 1500
312
313 static  pthread_t rpt_master_thread;
314
315 struct rpt;
316
317 struct rpt_link
318 {
319         struct rpt_link *next;
320         struct rpt_link *prev;
321         char    mode;                   /* 1 if in tx mode */
322         char    isremote;
323         char    phonemode;
324         char    name[MAXNODESTR];       /* identifier (routing) string */
325         char    lasttx;
326         char    lastrx;
327         char    connected;
328         char    hasconnected;
329         char    outbound;
330         char    disced;
331         char    killme;
332         long    elaptime;
333         long    disctime;
334         long    retrytimer;
335         long    retxtimer;
336         int     retries;
337         int     reconnects;
338         long long connecttime;
339         struct ast_channel *chan;       
340         struct ast_channel *pchan;      
341 } ;
342
343 struct rpt_lstat
344 {
345         struct  rpt_lstat *next;
346         struct  rpt_lstat *prev;
347         char    peer[MAXPEERSTR];
348         char    name[MAXNODESTR];
349         char    mode;
350         char    outbound;
351         char    reconnects;
352         long long       connecttime;
353 } ;
354
355 struct rpt_tele
356 {
357         struct rpt_tele *next;
358         struct rpt_tele *prev;
359         struct rpt *rpt;
360         struct ast_channel *chan;
361         int     mode;
362         struct rpt_link mylink;
363         char param[TELEPARAMSIZE];
364         pthread_t threadid;
365 } ;
366
367 struct function_table_tag
368 {
369         char action[ACTIONSIZE];
370         int (*function)(struct rpt *myrpt, char *param, char *digitbuf, 
371                 int command_source, struct rpt_link *mylink);
372 } ;
373
374 /* Used to store the morse code patterns */
375
376 struct morse_bits
377 {                 
378         int len;
379         int ddcomb;
380 } ;
381
382 struct telem_defaults
383 {
384         char name[20];
385         char value[80];
386 } ;
387
388
389 static struct rpt
390 {
391         ast_mutex_t lock;
392         struct ast_config *cfg;
393         char reload;
394
395         char *name;
396         char *rxchanname;
397         char *txchanname;
398         char *remote;
399
400         struct {
401                 char ourcontext[80];
402                 char ourcallerid[80];
403                 char acctcode[21];
404                 char ident[80];
405                 char tonezone[80];
406                 char simple;
407                 char functions[80];
408                 char link_functions[80];
409                 char phone_functions[80];
410                 char dphone_functions[80];
411                 char nodes[80];
412                 int hangtime;
413                 int totime;
414                 int idtime;
415                 int tailmessagetime;
416                 int tailsquashedtime;
417                 int duplex;
418                 int politeid;
419                 char *tailmsgbuf;
420                 AST_DECLARE_APP_ARGS(tailmsg,
421                         AST_APP_ARG(msgs)[100];
422                 );
423                 char memory[80];
424                 char macro[80];
425                 char gosub[80];
426                 char startupmacro[80];
427                 char startupgosub[80];
428                 int iobase;
429                 char funcchar;
430                 char endchar;
431                 char nobusyout;
432         } p;
433         struct rpt_link links;
434         int unkeytocttimer;
435         char keyed;
436         char exttx;
437         char localtx;
438         char remoterx;
439         char remotetx;
440         char remoteon;
441         char tounkeyed;
442         char tonotify;
443         char enable;
444         char dtmfbuf[MAXDTMF];
445         char macrobuf[MAXMACRO];
446         char gosubbuf[MAXGOSUB];
447         char rem_dtmfbuf[MAXDTMF];
448         char lastdtmfcommand[MAXDTMF];
449         char cmdnode[50];
450         struct ast_channel *rxchannel, *txchannel;
451         struct ast_channel *pchannel, *txpchannel, *remchannel;
452         struct rpt_tele tele;
453         struct timeval lasttv, curtv;
454         pthread_t rpt_call_thread, rpt_thread;
455         time_t dtmf_time, rem_dtmf_time, dtmf_time_rem;
456         int tailtimer, totimer, idtimer, txconf, conf, callmode, cidx, scantimer, tmsgtimer, skedtimer;
457         int mustid, tailid;
458         int tailevent;
459         int telemrefcount;
460         int dtmfidx, rem_dtmfidx;
461         int dailytxtime, dailykerchunks, totalkerchunks, dailykeyups, totalkeyups, timeouts;
462         int totalexecdcommands, dailyexecdcommands;
463         long retxtimer;
464         long long totaltxtime;
465         char mydtmf;
466         char exten[AST_MAX_EXTENSION];
467         char freq[MAXREMSTR], rxpl[MAXREMSTR], txpl[MAXREMSTR];
468         char offset;
469         char powerlevel;
470         char txplon;
471         char rxplon;
472         char remmode;
473         char tunerequest;
474         char hfscanmode;
475         int hfscanstatus;
476         char lastlinknode[MAXNODESTR];
477         char stopgen;
478         char patchfarenddisconnect;
479         char patchnoct;
480         char patchquiet;
481         char patchcontext[MAXPATCHCONTEXT];
482         int patchdialtime;
483         int macro_longest;
484         int gosub_longest;
485         int phone_longestfunc;
486         int dphone_longestfunc;
487         int link_longestfunc;
488         int longestfunc;
489         int longestnode;
490         int threadrestarts;             
491         int tailmessagen;
492         time_t disgorgetime;
493         time_t lastthreadrestarttime;
494         long macrotimer;
495         long gosubtimer;
496         char lastnodewhichkeyedusup[MAXNODESTR];
497 #ifdef  __RPT_NOTCH
498         struct rptfilter
499         {
500                 char desc[100];
501                 float x0;
502                 float x1;
503                 float x2;
504                 float y0;
505                 float y1;
506                 float y2;
507                 float gain;
508                 float const0;
509                 float const1;
510                 float const2;
511         } filters[MAXFILTERS];
512 #endif
513 #ifdef  _MDC_DECODE_H_
514         mdc_decoder_t *mdc;
515         unsigned short lastunit;
516 #endif
517 } rpt_vars[MAXRPTS];    
518
519
520 #ifdef  APP_RPT_LOCK_DEBUG
521
522 #warning COMPILING WITH LOCK-DEBUGGING ENABLED!!
523
524 #define MAXLOCKTHREAD 100
525
526 #define rpt_mutex_lock(x)       _rpt_mutex_lock(x, myrpt, __LINE__)
527 #define rpt_mutex_unlock(x)     _rpt_mutex_unlock(x, myrpt, __LINE__)
528
529 struct lockthread
530 {
531         pthread_t id;
532         int lockcount;
533         int lastlock;
534         int lastunlock;
535 } lockthreads[MAXLOCKTHREAD];
536
537
538 struct by_lightning
539 {
540         int line;
541         struct timeval tv;
542         struct rpt *rpt;
543         struct lockthread lockthread;
544 } lock_ring[32];
545
546
547 int lock_ring_index = 0;
548
549 AST_MUTEX_DEFINE_STATIC(locklock);
550
551 static struct lockthread *get_lockthread(pthread_t id)
552 {
553         int     i;
554
555         for (i = 0; i < MAXLOCKTHREAD; i++) {
556                 if (lockthreads[i].id == id)
557                         return(&lockthreads[i]);
558         }
559         return NULL;
560 }
561
562 static struct lockthread *put_lockthread(pthread_t id)
563 {
564         int     i;
565
566         for (i = 0; i < MAXLOCKTHREAD; i++) {
567                 if (lockthreads[i].id == id)
568                         return(&lockthreads[i]);
569         }
570         for (i = 0; i < MAXLOCKTHREAD; i++) {
571                 if (!lockthreads[i].id) {
572                         lockthreads[i].lockcount = 0;
573                         lockthreads[i].lastlock = 0;
574                         lockthreads[i].lastunlock = 0;
575                         lockthreads[i].id = id;
576                         return &lockthreads[i];
577                 }
578         }
579         return NULL;
580 }
581
582
583 static void rpt_mutex_spew(void)
584 {
585         struct by_lightning lock_ring_copy[32];
586         int lock_ring_index_copy;
587         int i, j;
588         long long diff;
589         char a[100] = "";
590         struct ast_tm tm;
591         struct timeval lasttv;
592
593         ast_mutex_lock(&locklock);
594         memcpy(&lock_ring_copy, &lock_ring, sizeof(lock_ring_copy));
595         lock_ring_index_copy = lock_ring_index;
596         ast_mutex_unlock(&locklock);
597
598         lasttv.tv_sec = lasttv.tv_usec = 0;
599         for (i = 0; i < 32; i++) {
600                 j = (i + lock_ring_index_copy) % 32;
601                 ast_strftime(a, sizeof(a) - 1, "%m/%d/%Y %H:%M:%S",
602                         ast_localtime(&lock_ring_copy[j].tv, &tm, NULL));
603                 diff = 0;
604                 if (lasttv.tv_sec) {
605                         diff = (lock_ring_copy[j].tv.tv_sec - lasttv.tv_sec) * 1000000;
606                         diff += (lock_ring_copy[j].tv.tv_usec - lasttv.tv_usec);
607                 }
608                 lasttv.tv_sec = lock_ring_copy[j].tv.tv_sec;
609                 lasttv.tv_usec = lock_ring_copy[j].tv.tv_usec;
610                 if (!lock_ring_copy[j].tv.tv_sec)
611                         continue;
612                 if (lock_ring_copy[j].line < 0) {
613                         ast_log(LOG_NOTICE, "LOCKDEBUG [#%d] UNLOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
614                                 i - 31, -lock_ring_copy[j].line, lock_ring_copy[j].rpt->name,
615                                 (int) lock_ring_copy[j].lockthread.id, diff, a, (int)lock_ring_copy[j].tv.tv_usec);
616                 } else {
617                         ast_log(LOG_NOTICE, "LOCKDEBUG [#%d] LOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
618                                 i - 31, lock_ring_copy[j].line, lock_ring_copy[j].rpt->name,
619                                 (int) lock_ring_copy[j].lockthread.id, diff, a, (int)lock_ring_copy[j].tv.tv_usec);
620                 }
621         }
622 }
623
624
625 static void _rpt_mutex_lock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
626 {
627         struct lockthread *t;
628         pthread_t id;
629
630         id = pthread_self();
631         ast_mutex_lock(&locklock);
632         t = put_lockthread(id);
633         if (!t) {
634                 ast_mutex_unlock(&locklock);
635                 return;
636         }
637         if (t->lockcount) {
638                 int lastline = t->lastlock;
639                 ast_mutex_unlock(&locklock);
640                 ast_log(LOG_NOTICE, "rpt_mutex_lock: Double lock request line %d node %s pid %x, last lock was line %d\n",
641                                 line, myrpt->name, (int) t->id, lastline);
642                 rpt_mutex_spew();
643                 return;
644         }
645         t->lastlock = line;
646         t->lockcount = 1;
647         gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
648         lock_ring[lock_ring_index].rpt = myrpt;
649         memcpy(&lock_ring[lock_ring_index].lockthread, t, sizeof(struct lockthread));
650         lock_ring[lock_ring_index++].line = line;
651         if (lock_ring_index == 32)
652                 lock_ring_index = 0;
653         ast_mutex_unlock(&locklock);
654         ast_mutex_lock(lockp);
655 }
656
657
658 static void _rpt_mutex_unlock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
659 {
660         struct lockthread *t;
661         pthread_t id;
662
663         id = pthread_self();
664         ast_mutex_lock(&locklock);
665         t = put_lockthread(id);
666         if (!t) {
667                 ast_mutex_unlock(&locklock);
668                 return;
669         }
670         if (!t->lockcount) {
671                 int lastline = t->lastunlock;
672                 ast_mutex_unlock(&locklock);
673                 ast_log(LOG_NOTICE, "rpt_mutex_lock: Double un-lock request line %d node %s pid %x, last un-lock was line %d\n",
674                                 line, myrpt->name, (int) t->id, lastline);
675                 rpt_mutex_spew();
676                 return;
677         }
678         t->lastunlock = line;
679         t->lockcount = 0;
680         gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
681         lock_ring[lock_ring_index].rpt = myrpt;
682         memcpy(&lock_ring[lock_ring_index].lockthread, t, sizeof(struct lockthread));
683         lock_ring[lock_ring_index++].line = -line;
684         if (lock_ring_index == 32)
685                 lock_ring_index = 0;
686         ast_mutex_unlock(&locklock);
687         ast_mutex_unlock(lockp);
688 }
689
690 #else  /* APP_RPT_LOCK_DEBUG */
691
692 #define rpt_mutex_lock(x) ast_mutex_lock(x)
693 #define rpt_mutex_unlock(x) ast_mutex_unlock(x)
694
695 #endif  /* APP_RPT_LOCK_DEBUG */
696
697 /*
698 * CLI extensions
699 */
700
701 /* Debug mode */
702 static int rpt_do_debug(int fd, int argc, char *argv[]);
703 static int rpt_do_dump(int fd, int argc, char *argv[]);
704 static int rpt_do_stats(int fd, int argc, char *argv[]);
705 static int rpt_do_lstats(int fd, int argc, char *argv[]);
706 static int rpt_do_reload(int fd, int argc, char *argv[]);
707 static int rpt_do_restart(int fd, int argc, char *argv[]);
708
709 static char debug_usage[] =
710 "Usage: rpt debug level {0-7}\n"
711 "       Enables debug messages in app_rpt\n";
712
713 static char dump_usage[] =
714 "Usage: rpt dump <nodename>\n"
715 "       Dumps struct debug info to log\n";
716
717 static char dump_stats[] =
718 "Usage: rpt stats <nodename>\n"
719 "       Dumps node statistics to console\n";
720
721 static char dump_lstats[] =
722 "Usage: rpt lstats <nodename>\n"
723 "       Dumps link statistics to console\n";
724
725 static char reload_usage[] =
726 "Usage: rpt reload\n"
727 "       Reloads app_rpt running config parameters\n";
728
729 static char restart_usage[] =
730 "Usage: rpt restart\n"
731 "       Restarts app_rpt\n";
732
733 static struct ast_cli_entry cli_rpt[] = {
734         { { "rpt", "debug", "level" },
735                 rpt_do_debug, "Enable app_rpt debugging",
736                 debug_usage },
737
738         { { "rpt", "dump" },
739                 rpt_do_dump, "Dump app_rpt structs for debugging",
740                 dump_usage },
741
742         { { "rpt", "stats" },
743                 rpt_do_stats, "Dump node statistics",
744                 dump_stats },
745         { { "rpt", "lstats" },
746                 rpt_do_lstats, "Dump link statistics",
747                 dump_lstats },
748
749         { { "rpt", "reload" },
750                 rpt_do_reload, "Reload app_rpt config",
751                 reload_usage },
752
753         { { "rpt", "restart" },
754                 rpt_do_restart, "Restart app_rpt",
755                 restart_usage },
756 };
757
758 /*
759 * Telemetry defaults
760 */
761
762
763 static struct telem_defaults tele_defs[] = {
764         {"ct1", "|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
765         {"ct2", "|t(660,880,150,3072)"},
766         {"ct3", "|t(440,0,150,3072)"},
767         {"ct4", "|t(550,0,150,3072)"},
768         {"ct5", "|t(660,0,150,3072)"},
769         {"ct6", "|t(880,0,150,3072)"},
770         {"ct7", "|t(660,440,150,3072)"},
771         {"ct8", "|t(700,1100,150,3072)"},
772         {"remotemon", "|t(1600,0,75,2048)"},
773         {"remotetx", "|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
774         {"cmdmode", "|t(900,904,200,2048)"},
775         {"functcomplete", "|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
776 } ;
777
778 /*
779 * Forward decl's - these suppress compiler warnings when funcs coded further down the file than their invocation
780 */
781
782 static int setrbi(struct rpt *myrpt);
783
784
785
786 /*
787 * Define function protos for function table here
788 */
789
790 static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
791 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
792 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
793 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
794 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
795 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
796 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
797 static int function_gosub(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
798 /*
799 * Function table
800 */
801
802 static struct function_table_tag function_table[] = {
803         {"cop", function_cop},
804         {"autopatchup", function_autopatchup},
805         {"autopatchdn", function_autopatchdn},
806         {"ilink", function_ilink},
807         {"status", function_status},
808         {"remote", function_remote},
809         {"macro", function_macro},
810         {"gosub", function_gosub},
811 } ;
812
813 /*
814 * Match a keyword in a list, and return index of string plus 1 if there was a match,
815 * else return 0. If param is passed in non-null, then it will be set to the first character past the match
816 */
817
818 static int matchkeyword(char *string, char **param, char *keywords[])
819 {
820         int     i, ls;
821         for (i = 0; keywords[i]; i++) {
822                 ls = strlen(keywords[i]);
823                 if (!ls) {
824                         *param = NULL;
825                         return 0;
826                 }
827                 if (!strncmp(string, keywords[i], ls)) {
828                         if (param)
829                                 *param = string + ls;
830                         return i + 1; 
831                 }
832         }
833         param = NULL;
834         return 0;
835 }
836
837 /*
838 * Skip characters in string which are in charlist, and return a pointer to the
839 * first non-matching character
840 */
841
842 static char *skipchars(char *string, char *charlist)
843 {
844         int i;  
845         while (*string) {
846                 for (i = 0; charlist[i] ; i++) {
847                         if (*string == charlist[i]) {
848                                 string++;
849                                 break;
850                         }
851                 }
852                 if (!charlist[i])
853                         return string;
854         }
855         return string;
856 }       
857                                         
858
859
860 static int myatoi(const char *str)
861 {
862         int     ret;
863
864         if (str == NULL)
865                 return -1;
866         /* leave this %i alone, non-base-10 input is useful here */
867         if (sscanf(str, "%i", &ret) != 1)
868                 return -1;
869         return ret;
870 }
871
872
873 #ifdef  __RPT_NOTCH
874
875 /* rpt filter routine */
876 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
877 {
878         int     i, j;
879         struct rptfilter *f;
880
881         for (i = 0; i < len; i++) {
882                 for (j = 0; j < MAXFILTERS; j++) {
883                         f = &myrpt->filters[j];
884                         if (!*f->desc)
885                                 continue;
886                         f->x0 = f->x1; f->x1 = f->x2;
887                         f->x2 = ((float)buf[i]) / f->gain;
888                         f->y0 = f->y1; f->y1 = f->y2;
889                         f->y2 =   (f->x0 + f->x2)     +  f->const0 * f->x1
890                                 + (f->const1 * f->y0) + (f->const2 * f->y1);
891                         buf[i] = (short)f->y2;
892                 }
893         }
894 }
895
896 #endif
897
898 /* Retrieve an int from a config file */
899 static int retrieve_astcfgint(struct rpt *myrpt, const char *category, const char *name, int min, int max, int defl)
900 {
901         const char *var = ast_variable_retrieve(myrpt->cfg, category, name);
902         int ret;
903
904         if (var) {
905                 ret = myatoi(var);
906                 if (ret < min)
907                         ret = min;
908                 else if (ret > max)
909                         ret = max;
910         } else
911                 ret = defl;
912         return ret;
913 }
914
915
916 static void load_rpt_vars(int n, int init)
917 {
918         int     j;
919         struct ast_variable *vp, *var;
920         struct ast_config *cfg;
921         struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
922 #ifdef  __RPT_NOTCH
923         AST_DECLARE_APP_ARGS(strs,
924                 AST_APP_ARG(str)[100];
925         );
926 #endif
927
928         ast_verb(3, "%s config for repeater %s\n",
929                         (init) ? "Loading initial" : "Re-Loading", rpt_vars[n].name);
930         ast_mutex_lock(&rpt_vars[n].lock);
931         if (rpt_vars[n].cfg)
932                 ast_config_destroy(rpt_vars[n].cfg);
933         cfg = ast_config_load("rpt.conf", config_flags);
934         if (!cfg) {
935                 ast_mutex_unlock(&rpt_vars[n].lock);
936                 ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf.  Radio Repeater disabled.\n");
937                 pthread_exit(NULL);
938         }
939         rpt_vars[n].cfg = cfg;
940         /* Free previously malloc'ed buffer */
941         if (!init && rpt_vars[n].p.tailmsgbuf)
942                 ast_free(rpt_vars[n].p.tailmsgbuf);
943         memset(&rpt_vars[n].p, 0, sizeof(rpt_vars[n].p));
944         if (init) {
945                 char *cp;
946                 int savearea = (char *)&rpt_vars[n].p - (char *)&rpt_vars[n];
947
948                 cp = (char *) &rpt_vars[n].p;
949                 memset(cp + sizeof(rpt_vars[n].p), 0,
950                         sizeof(rpt_vars[n]) - (sizeof(rpt_vars[n].p) + savearea));
951                 rpt_vars[n].tele.next = &rpt_vars[n].tele;
952                 rpt_vars[n].tele.prev = &rpt_vars[n].tele;
953                 rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
954                 rpt_vars[n].tailmessagen = 0;
955         }
956 #ifdef  __RPT_NOTCH
957         /* zot out filters stuff */
958         memset(&rpt_vars[n].filters, 0, sizeof(rpt_vars[n].filters));
959 #endif
960
961         /* Defaults */
962         ast_copy_string(rpt_vars[n].p.ourcontext, rpt_vars[n].name, sizeof(rpt_vars[n].p.ourcontext));
963         rpt_vars[n].p.hangtime = HANGTIME;
964         rpt_vars[n].p.totime = TOTIME;
965         rpt_vars[n].p.duplex = 2;
966         rpt_vars[n].p.idtime = IDTIME;
967         rpt_vars[n].p.politeid = POLITEID;
968         ast_copy_string(rpt_vars[n].p.memory, MEMORY, sizeof(rpt_vars[n].p.memory));
969         ast_copy_string(rpt_vars[n].p.macro, MACRO, sizeof(rpt_vars[n].p.macro));
970         ast_copy_string(rpt_vars[n].p.gosub, GOSUB, sizeof(rpt_vars[n].p.gosub));
971         rpt_vars[n].p.iobase = DEFAULT_IOBASE;
972         ast_copy_string(rpt_vars[n].p.functions, FUNCTIONS, sizeof(rpt_vars[n].p.functions));
973         rpt_vars[n].p.simple = 1;
974         rpt_vars[n].p.funcchar = FUNCCHAR;
975         rpt_vars[n].p.endchar = ENDCHAR;
976         ast_copy_string(rpt_vars[n].p.nodes, NODES, sizeof(rpt_vars[n].p.nodes));
977
978         for (var = ast_variable_browse(cfg, rpt_vars[n].name); var; var = var->next) {
979                 if (!strcmp(var->name, "context")) {
980                         ast_copy_string(rpt_vars[n].p.ourcontext, var->value, sizeof(rpt_vars[n].p.ourcontext));
981                 } else if (!strcmp(var->name, "callerid")) {
982                         ast_copy_string(rpt_vars[n].p.ourcallerid, var->value, sizeof(rpt_vars[n].p.ourcallerid));
983                 } else if (!strcmp(var->name, "accountcode")) {
984                         ast_copy_string(rpt_vars[n].p.acctcode, var->value, sizeof(rpt_vars[n].p.acctcode));
985                 } else if (!strcmp(var->name, "idrecording")) {
986                         ast_copy_string(rpt_vars[n].p.ident, var->value, sizeof(rpt_vars[n].p.ident));
987                 } else if (!strcmp(var->name, "hangtime")) {
988                         rpt_vars[n].p.hangtime = atoi(var->value);
989                 } else if (!strcmp(var->name, "totime")) {
990                         rpt_vars[n].p.totime = atoi(var->value);
991                 } else if (!strcmp(var->name, "tailmessagetime")) {
992                         rpt_vars[n].p.tailmessagetime = atoi(var->value);
993                         if (rpt_vars[n].p.tailmessagetime < 0)
994                                 rpt_vars[n].p.tailmessagetime = 0;
995                         else if (rpt_vars[n].p.tailmessagetime > 2400000)
996                                 rpt_vars[n].p.tailmessagetime = 2400000;
997                 } else if (!strcmp(var->name, "tailsquashedtime")) {
998                         rpt_vars[n].p.tailsquashedtime = atoi(var->value);
999                         if (rpt_vars[n].p.tailsquashedtime < 0)
1000                                 rpt_vars[n].p.tailsquashedtime = 0;
1001                         else if (rpt_vars[n].p.tailsquashedtime > 2400000)
1002                                 rpt_vars[n].p.tailsquashedtime = 2400000;
1003                 } else if (!strcmp(var->name, "duplex")) {
1004                         rpt_vars[n].p.duplex = atoi(var->value);
1005                         if (rpt_vars[n].p.duplex < 0)
1006                                 rpt_vars[n].p.duplex = 0;
1007                         else if (rpt_vars[n].p.duplex > 4)
1008                                 rpt_vars[n].p.duplex = 4;
1009                 } else if (!strcmp(var->name, "idtime")) {
1010                         rpt_vars[n].p.idtime = atoi(var->value);
1011                         if (rpt_vars[n].p.idtime < 60000)
1012                                 rpt_vars[n].p.idtime = 60000;
1013                         else if (rpt_vars[n].p.idtime > 2400000)
1014                                 rpt_vars[n].p.idtime = 2400000;
1015                 } else if (!strcmp(var->name, "politeid")) {
1016                         rpt_vars[n].p.politeid = atoi(var->value);
1017                         if (rpt_vars[n].p.politeid < 30000)
1018                                 rpt_vars[n].p.politeid = 30000;
1019                         else if (rpt_vars[n].p.politeid > 300000)
1020                                 rpt_vars[n].p.politeid = 300000;
1021                 } else if (!strcmp(var->name, "tonezone")) {
1022                         ast_copy_string(rpt_vars[n].p.tonezone, var->value, sizeof(rpt_vars[n].p.tonezone));
1023                 } else if (!strcmp(var->name, "tailmessagelist")) {
1024                         rpt_vars[n].p.tailmsgbuf = ast_strdup(var->value);
1025                         AST_NONSTANDARD_APP_ARGS(rpt_vars[n].p.tailmsg, rpt_vars[n].p.tailmsgbuf, ',');
1026                 } else if (!strcmp(var->name, "memory")) {
1027                         ast_copy_string(rpt_vars[n].p.memory, var->value, sizeof(rpt_vars[n].p.memory));
1028                 } else if (!strcmp(var->name, "macro")) {
1029                         ast_copy_string(rpt_vars[n].p.macro, var->value, sizeof(rpt_vars[n].p.macro));
1030                 } else if (!strcmp(var->name, "gosub")) {
1031                         ast_copy_string(rpt_vars[n].p.gosub, var->value, sizeof(rpt_vars[n].p.gosub));
1032                 } else if (!strcmp(var->name, "startup_macro")) {
1033                         ast_copy_string(rpt_vars[n].p.startupmacro, var->value, sizeof(rpt_vars[n].p.startupmacro));
1034                 } else if (!strcmp(var->name, "startup_gosub")) {
1035                         ast_copy_string(rpt_vars[n].p.startupgosub, var->value, sizeof(rpt_vars[n].p.startupgosub));
1036                 } else if (!strcmp(var->name, "iobase")) {
1037                         /* do not use atoi() here, we need to be able to have
1038                            the input specified in hex or decimal so we use
1039                            sscanf with a %i */
1040                         if (sscanf(var->value, "%i", &rpt_vars[n].p.iobase) != 1)
1041                                 rpt_vars[n].p.iobase = DEFAULT_IOBASE;
1042                 } else if (!strcmp(var->name, "functions")) {
1043                         rpt_vars[n].p.simple = 0;
1044                         ast_copy_string(rpt_vars[n].p.functions, var->value, sizeof(rpt_vars[n].p.functions));
1045                 } else if (!strcmp(var->name, "link_functions")) {
1046                         ast_copy_string(rpt_vars[n].p.link_functions, var->value, sizeof(rpt_vars[n].p.link_functions));
1047                 } else if (!strcmp(var->name, "phone_functions")) {
1048                         ast_copy_string(rpt_vars[n].p.phone_functions, var->value, sizeof(rpt_vars[n].p.phone_functions));
1049                 } else if (!strcmp(var->name, "dphone_functions")) {
1050                         ast_copy_string(rpt_vars[n].p.dphone_functions, var->value, sizeof(rpt_vars[n].p.dphone_functions));
1051                 } else if (!strcmp(var->name, "funcchar")) {
1052                         rpt_vars[n].p.funcchar = *var->value;
1053                 } else if (!strcmp(var->name, "endchar")) {
1054                         rpt_vars[n].p.endchar = *var->value;
1055                 } else if (!strcmp(var->name, "nobusyout")) {
1056                         rpt_vars[n].p.nobusyout = ast_true(var->value);
1057                 } else if (!strcmp(var->name, "nodes")) {
1058                         ast_copy_string(rpt_vars[n].p.nodes, var->value, sizeof(rpt_vars[n].p.nodes));
1059 #ifdef  __RPT_NOTCH
1060                 } else if (!strcmp(var->name, "rxnotch")) {
1061                         char *tmp = ast_strdupa(val);
1062                         AST_NONSTANDARD_APP_ARGS(strs, tmp, ',');
1063                         strs.argc &= ~1; /* force an even number, rounded down */
1064                         if (strs.argc >= 2) {
1065                                 for (j = 0; j < strs.argc; j += 2) {
1066                                         rpt_mknotch(atof(strs.str[j]), atof(strs.str[j + 1]),
1067                                                 &rpt_vars[n].filters[j >> 1].gain,
1068                                                 &rpt_vars[n].filters[j >> 1].const0,
1069                                                 &rpt_vars[n].filters[j >> 1].const1,
1070                                                 &rpt_vars[n].filters[j >> 1].const2);
1071                                         sprintf(rpt_vars[n].filters[j >> 1].desc, "%s Hz, BW = %s",
1072                                                 strs.str[j], strs.str[j + 1]);
1073                                 }
1074                         }
1075 #endif
1076                 }
1077         }
1078
1079         /* If these aren't specified, copy them from the functions property. */
1080         if (ast_strlen_zero(rpt_vars[n].p.link_functions))
1081                 ast_copy_string(rpt_vars[n].p.link_functions, rpt_vars[n].p.functions, sizeof(rpt_vars[n].p.link_functions));
1082
1083         rpt_vars[n].longestnode = 0;
1084         for (vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes); vp; vp = vp->next) {
1085                 if ((j = strlen(vp->name)) > rpt_vars[n].longestnode)
1086                         rpt_vars[n].longestnode = j;
1087         }
1088
1089         /*
1090         * For this repeater, Determine the length of the longest function 
1091         */
1092         rpt_vars[n].longestfunc = 0;
1093         for (vp = ast_variable_browse(cfg, rpt_vars[n].p.functions); vp; vp = vp->next) {
1094                 if ((j = strlen(vp->name)) > rpt_vars[n].longestfunc)
1095                         rpt_vars[n].longestfunc = j;
1096         }
1097
1098         rpt_vars[n].link_longestfunc = 0;
1099         for (vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions); vp; vp = vp->next) {
1100                 if ((j = strlen(vp->name)) > rpt_vars[n].link_longestfunc)
1101                         rpt_vars[n].link_longestfunc = j;
1102         }
1103
1104         rpt_vars[n].phone_longestfunc = 0;
1105         for (vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions); vp; vp = vp->next) {
1106                 if ((j = strlen(vp->name)) > rpt_vars[n].phone_longestfunc)
1107                         rpt_vars[n].phone_longestfunc = j;
1108         }
1109
1110         rpt_vars[n].dphone_longestfunc = 0;
1111         for (vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions); vp; vp = vp->next) {
1112                 if ((j = strlen(vp->name)) > rpt_vars[n].dphone_longestfunc)
1113                         rpt_vars[n].dphone_longestfunc = j;
1114         }
1115
1116         rpt_vars[n].macro_longest = 1;
1117         for (vp = ast_variable_browse(cfg, rpt_vars[n].p.macro); vp; vp = vp->next) {
1118                 if ((j = strlen(vp->name)) > rpt_vars[n].macro_longest)
1119                         rpt_vars[n].macro_longest = j;
1120         }
1121
1122         rpt_vars[n].gosub_longest = 1;
1123         for (vp = ast_variable_browse(cfg, rpt_vars[n].p.gosub); vp; vp = vp->next) {
1124                 if ((j = strlen(vp->name)) > rpt_vars[n].gosub_longest)
1125                         rpt_vars[n].gosub_longest = j;
1126         }
1127         ast_mutex_unlock(&rpt_vars[n].lock);
1128 }
1129
1130 /*
1131 * Enable or disable debug output at a given level at the console
1132 */
1133 static int rpt_do_debug(int fd, int argc, char *argv[])
1134 {
1135         int newlevel;
1136
1137         if (argc != 4)
1138                 return RESULT_SHOWUSAGE;
1139         newlevel = myatoi(argv[3]);
1140         if ((newlevel < 0) || (newlevel > 7))
1141                 return RESULT_SHOWUSAGE;
1142         if (newlevel)
1143                 ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
1144         else
1145                 ast_cli(fd, "app_rpt Debugging disabled\n");
1146
1147         debug = newlevel;                                                                                                                          
1148         return RESULT_SUCCESS;
1149 }
1150
1151 /*
1152 * Dump rpt struct debugging onto console
1153 */
1154 static int rpt_do_dump(int fd, int argc, char *argv[])
1155 {
1156         int i;
1157
1158         if (argc != 3)
1159                 return RESULT_SHOWUSAGE;
1160
1161         for (i = 0; i < nrpts; i++) {
1162                 if (!strcmp(argv[2], rpt_vars[i].name)) {
1163                         rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
1164                         ast_cli(fd, "app_rpt struct dump requested for node %s\n", argv[2]);
1165                         return RESULT_SUCCESS;
1166                 }
1167         }
1168         return RESULT_FAILURE;
1169 }
1170
1171 /*
1172 * Dump statistics onto console
1173 */
1174 static int rpt_do_stats(int fd, int argc, char *argv[])
1175 {
1176         int i, j;
1177         int dailytxtime, dailykerchunks;
1178         int totalkerchunks, dailykeyups, totalkeyups, timeouts;
1179         int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
1180         long long totaltxtime;
1181         struct rpt_link *l;
1182         char *listoflinks[MAX_STAT_LINKS];      
1183         char *lastnodewhichkeyedusup, *lastdtmfcommand;
1184         char *tot_state, *ider_state, *patch_state;
1185         char *reverse_patch_state, *enable_state, *input_signal, *called_number;
1186         struct rpt *myrpt;
1187
1188         static char *not_applicable = "N/A";
1189
1190         if (argc != 3)
1191                 return RESULT_SHOWUSAGE;
1192
1193         for (i = 0 ; i <= MAX_STAT_LINKS; i++)
1194                 listoflinks[i] = NULL;
1195
1196         tot_state = ider_state = 
1197         patch_state = reverse_patch_state = 
1198         input_signal = called_number = 
1199         lastdtmfcommand = not_applicable;
1200
1201         for (i = 0; i < nrpts; i++) {
1202                 if (!strcmp(argv[2], rpt_vars[i].name)) {
1203                         /* Make a copy of all stat variables while locked */
1204                         myrpt = &rpt_vars[i];
1205                         rpt_mutex_lock(&myrpt->lock); /* LOCK */
1206
1207                         dailytxtime = myrpt->dailytxtime;
1208                         totaltxtime = myrpt->totaltxtime;
1209                         dailykeyups = myrpt->dailykeyups;
1210                         totalkeyups = myrpt->totalkeyups;
1211                         dailykerchunks = myrpt->dailykerchunks;
1212                         totalkerchunks = myrpt->totalkerchunks;
1213                         dailyexecdcommands = myrpt->dailyexecdcommands;
1214                         totalexecdcommands = myrpt->totalexecdcommands;
1215                         timeouts = myrpt->timeouts;
1216
1217                         /* Traverse the list of connected nodes */
1218                         reverse_patch_state = "DOWN";
1219                         j = 0;
1220                         l = myrpt->links.next;
1221                         while (l != &myrpt->links) {
1222                                 if (l->name[0] == '0') { /* Skip '0' nodes */
1223                                         reverse_patch_state = "UP";
1224                                         l = l->next;
1225                                         continue;
1226                                 }
1227                                 listoflinks[j] = ast_strdupa(l->name);
1228                                 if (listoflinks[j])
1229                                         j++;
1230                                 l = l->next;
1231                         }
1232
1233                         lastnodewhichkeyedusup = ast_strdupa(myrpt->lastnodewhichkeyedusup);                    
1234                         if ((!lastnodewhichkeyedusup) || (ast_strlen_zero(lastnodewhichkeyedusup)))
1235                                 lastnodewhichkeyedusup = not_applicable;
1236
1237                         if (myrpt->keyed)
1238                                 input_signal = "YES";
1239                         else
1240                                 input_signal = "NO";
1241
1242                         if (myrpt->enable)
1243                                 enable_state = "YES";
1244                         else
1245                                 enable_state = "NO";
1246
1247                         if (!myrpt->totimer)
1248                                 tot_state = "TIMED OUT!";
1249                         else if (myrpt->totimer != myrpt->p.totime)
1250                                 tot_state = "ARMED";
1251                         else
1252                                 tot_state = "RESET";
1253
1254                         if (myrpt->tailid)
1255                                 ider_state = "QUEUED IN TAIL";
1256                         else if (myrpt->mustid)
1257                                 ider_state = "QUEUED FOR CLEANUP";
1258                         else
1259                                 ider_state = "CLEAN";
1260
1261                         switch (myrpt->callmode) {
1262                         case 1:
1263                                 patch_state = "DIALING";
1264                                 break;
1265                         case 2:
1266                                 patch_state = "CONNECTING";
1267                                 break;
1268                         case 3:
1269                                 patch_state = "UP";
1270                                 break;
1271                         case 4:
1272                                 patch_state = "CALL FAILED";
1273                                 break;
1274                         default:
1275                                 patch_state = "DOWN";
1276                         }
1277
1278                         if (!ast_strlen_zero(myrpt->exten))
1279                                 called_number = ast_strdupa(myrpt->exten);
1280
1281                         if (!ast_strlen_zero(myrpt->lastdtmfcommand))
1282                                 lastdtmfcommand = ast_strdupa(myrpt->lastdtmfcommand);
1283
1284                         rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
1285
1286                         ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
1287                         ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
1288                         ast_cli(fd, "Transmitter enabled..............................: %s\n", enable_state);
1289                         ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
1290                         ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
1291                         ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
1292                         ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
1293                         ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
1294                         ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
1295                         ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
1296                         ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
1297                         ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
1298                         ast_cli(fd, "Last DTMF command executed.......................: %s\n", lastdtmfcommand);
1299
1300                         hours = dailytxtime / 3600000;
1301                         dailytxtime %= 3600000;
1302                         minutes = dailytxtime / 60000;
1303                         dailytxtime %= 60000;
1304                         seconds = dailytxtime / 1000;
1305                         dailytxtime %= 1000;
1306
1307                         ast_cli(fd, "TX time today ...................................: %02d:%02d:%02d.%d\n",
1308                                 hours, minutes, seconds, dailytxtime);
1309
1310                         hours = (int) totaltxtime / 3600000;
1311                         totaltxtime %= 3600000;
1312                         minutes = (int) totaltxtime / 60000;
1313                         totaltxtime %= 60000;
1314                         seconds = (int)  totaltxtime / 1000;
1315                         totaltxtime %= 1000;
1316
1317                         ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
1318                                  hours, minutes, seconds, (int) totaltxtime);
1319                         ast_cli(fd, "Nodes currently connected to us..................: ");
1320                         for (j = 0;; j++) {
1321                                 if (!listoflinks[j]) {
1322                                         if (!j) {
1323                                                 ast_cli(fd, "<NONE>");
1324                                         }
1325                                         break;
1326                                 }
1327                                 ast_cli(fd, "%s", listoflinks[j]);
1328                                 if (j % 4 == 3) {
1329                                         ast_cli(fd, "\n");
1330                                         ast_cli(fd, "                                                 : ");
1331                                 } else {
1332                                         if (listoflinks[j + 1])
1333                                                 ast_cli(fd, ", ");
1334                                 }
1335                         }
1336                         ast_cli(fd, "\n");
1337
1338                         ast_cli(fd, "Last node which transmitted to us................: %s\n", lastnodewhichkeyedusup);
1339                         ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
1340                         ast_cli(fd, "Autopatch called number..........................: %s\n", called_number);
1341                         ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n\n", reverse_patch_state);
1342
1343                         return RESULT_SUCCESS;
1344                 }
1345         }
1346         return RESULT_FAILURE;
1347 }
1348
1349 /*
1350 * Link stats function
1351 */
1352 static int rpt_do_lstats(int fd, int argc, char *argv[])
1353 {
1354         int i, j;
1355         struct rpt *myrpt;
1356         struct rpt_link *l;
1357         struct rpt_lstat *s, *t;
1358         struct rpt_lstat s_head;
1359         if (argc != 3)
1360                 return RESULT_SHOWUSAGE;
1361
1362         s = NULL;
1363         s_head.next = &s_head;
1364         s_head.prev = &s_head;
1365
1366         for (i = 0; i < nrpts; i++) {
1367                 if (!strcmp(argv[2], rpt_vars[i].name)) {
1368                         /* Make a copy of all stat variables while locked */
1369                         myrpt = &rpt_vars[i];
1370                         rpt_mutex_lock(&myrpt->lock); /* LOCK */
1371                         /* Traverse the list of connected nodes */
1372                         j = 0;
1373                         l = myrpt->links.next;
1374                         while (l != &myrpt->links) {
1375                                 if (l->name[0] == '0') { /* Skip '0' nodes */
1376                                         l = l->next;
1377                                         continue;
1378                                 }
1379                                 if ((s = ast_calloc(1, sizeof(*s))) == NULL) {
1380                                         ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
1381                                         rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
1382                                         return RESULT_FAILURE;
1383                                 }
1384                                 ast_copy_string(s->name, l->name, MAXREMSTR);
1385                                 pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
1386                                 s->mode = l->mode;
1387                                 s->outbound = l->outbound;
1388                                 s->reconnects = l->reconnects;
1389                                 s->connecttime = l->connecttime;
1390                                 insque((struct qelem *) s, (struct qelem *) s_head.next);
1391                                 l = l->next;
1392                         }
1393                         rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
1394                         ast_cli(fd, "NODE      PEER                RECONNECTS  DIRECTION  CONNECT TIME\n");
1395                         ast_cli(fd, "----      ----                ----------  ---------  ------------\n");
1396
1397                         for (s = s_head.next; s != &s_head; s = s->next) {
1398                                 int hours, minutes, seconds;
1399                                 long long connecttime = s->connecttime;
1400                                 char conntime[31];
1401                                 hours = (int) connecttime/3600000;
1402                                 connecttime %= 3600000;
1403                                 minutes = (int) connecttime/60000;
1404                                 connecttime %= 60000;
1405                                 seconds = (int)  connecttime/1000;
1406                                 connecttime %= 1000;
1407                                 snprintf(conntime, sizeof(conntime), "%02d:%02d:%02d.%d",
1408                                         hours, minutes, seconds, (int) connecttime);
1409                                 ast_cli(fd, "%-10s%-20s%-12d%-11s%-30s\n",
1410                                         s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime);
1411                         }       
1412                         /* destroy our local link queue */
1413                         s = s_head.next;
1414                         while (s != &s_head) {
1415                                 t = s;
1416                                 s = s->next;
1417                                 remque((struct qelem *)t);
1418                                 ast_free(t);
1419                         }                       
1420                         return RESULT_SUCCESS;
1421                 }
1422         }
1423         return RESULT_FAILURE;
1424 }
1425
1426 /*
1427 * reload vars 
1428 */
1429 static int rpt_do_reload(int fd, int argc, char *argv[])
1430 {
1431         int     n;
1432
1433         if (argc > 2)
1434                 return RESULT_SHOWUSAGE;
1435
1436         for (n = 0; n < nrpts; n++)
1437                 rpt_vars[n].reload = 1;
1438
1439         return RESULT_FAILURE;
1440 }
1441
1442 /*
1443 * restart app_rpt
1444 */
1445 static int rpt_do_restart(int fd, int argc, char *argv[])
1446 {
1447         int     i;
1448
1449         if (argc > 2)
1450                 return RESULT_SHOWUSAGE;
1451         for (i = 0; i < nrpts; i++) {
1452                 if (rpt_vars[i].rxchannel)
1453                         ast_softhangup(rpt_vars[i].rxchannel, AST_SOFTHANGUP_DEV);
1454         }
1455         return RESULT_FAILURE;
1456 }
1457
1458 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
1459 {
1460         int res;
1461
1462         if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
1463                 return res;
1464
1465         while (chan->generatordata) {
1466                 if (ast_safe_sleep(chan, 1))
1467                         return -1;
1468         }
1469
1470         return 0;
1471 }
1472
1473 static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
1474 {
1475         return play_tone_pair(chan, freq, 0, duration, amplitude);
1476 }
1477
1478 static int play_silence(struct ast_channel *chan, int duration)
1479 {
1480         return play_tone_pair(chan, 0, 0, duration, 0);
1481 }
1482
1483
1484 static int send_morse(struct ast_channel *chan, const char *string, int speed, int freq, int amplitude)
1485 {
1486
1487         static struct morse_bits mbits[] = {
1488                 {0, 0}, /* SPACE */
1489                 {0, 0}, 
1490                 {6, 18},/* " */
1491                 {0, 0},
1492                 {7, 72},/* $ */
1493                 {0, 0},
1494                 {0, 0},
1495                 {6, 30},/* ' */
1496                 {5, 13},/* ( */
1497                 {6, 29},/* ) */
1498                 {0, 0},
1499                 {5, 10},/* + */
1500                 {6, 51},/* , */
1501                 {6, 33},/* - */
1502                 {6, 42},/* . */
1503                 {5, 9}, /* / */
1504                 {5, 31},/* 0 */
1505                 {5, 30},/* 1 */
1506                 {5, 28},/* 2 */
1507                 {5, 24},/* 3 */
1508                 {5, 16},/* 4 */
1509                 {5, 0}, /* 5 */
1510                 {5, 1}, /* 6 */
1511                 {5, 3}, /* 7 */
1512                 {5, 7}, /* 8 */
1513                 {5, 15},/* 9 */
1514                 {6, 7}, /* : */
1515                 {6, 21},/* ; */
1516                 {0, 0},
1517                 {5, 33},/* = */
1518                 {0, 0},
1519                 {6, 12},/* ? */
1520                 {0, 0},
1521                 {2, 2}, /* A */
1522                 {4, 1}, /* B */
1523                 {4, 5}, /* C */
1524                 {3, 1}, /* D */
1525                 {1, 0}, /* E */
1526                 {4, 4}, /* F */
1527                 {3, 3}, /* G */
1528                 {4, 0}, /* H */
1529                 {2, 0}, /* I */
1530                 {4, 14},/* J */
1531                 {3, 5}, /* K */
1532                 {4, 2}, /* L */
1533                 {2, 3}, /* M */
1534                 {2, 1}, /* N */
1535                 {3, 7}, /* O */
1536                 {4, 6}, /* P */
1537                 {4, 11},/* Q */
1538                 {3, 2}, /* R */
1539                 {3, 0}, /* S */
1540                 {1, 1}, /* T */
1541                 {3, 4}, /* U */
1542                 {4, 8}, /* V */
1543                 {3, 6}, /* W */
1544                 {4, 9}, /* X */
1545                 {4, 13},/* Y */
1546                 {4, 3}  /* Z */
1547         };
1548
1549         int dottime;
1550         int dashtime;
1551         int intralettertime;
1552         int interlettertime;
1553         int interwordtime;
1554         int len, ddcomb;
1555         int res;
1556         int c;
1557         int i;
1558         int flags;
1559                         
1560         res = 0;
1561         
1562         /* Approximate the dot time from the speed arg. */
1563         
1564         dottime = 900 / speed;
1565         
1566         /* Establish timing relationships */
1567         
1568         dashtime = 3 * dottime;
1569         intralettertime = dottime;
1570         interlettertime = dottime * 4 ;
1571         interwordtime = dottime * 7;
1572         
1573         for (; (*string) && (!res); string++) {
1574         
1575                 c = *string;
1576                 
1577                 /* Convert lower case to upper case */
1578                 
1579                 if ((c >= 'a') && (c <= 'z'))
1580                         c -= 0x20;
1581                 
1582                 /* Can't deal with any char code greater than Z, skip it */
1583                 
1584                 if (c  > 'Z')
1585                         continue;
1586                 
1587                 /* If space char, wait the inter word time */
1588                                         
1589                 if (c == ' ') {
1590                         if (!res)
1591                                 res = play_silence(chan, interwordtime);
1592                         continue;
1593                 }
1594                 
1595                 /* Subtract out control char offset to match our table */
1596                 
1597                 c -= 0x20;
1598                 
1599                 /* Get the character data */
1600                 
1601                 len = mbits[c].len;
1602                 ddcomb = mbits[c].ddcomb;
1603                 
1604                 /* Send the character */
1605                 
1606                 for (; len ; len--) {
1607                         if (!res)
1608                                 res = play_tone(chan, freq, (ddcomb & 1) ? dashtime : dottime, amplitude);
1609                         if (!res)
1610                                 res = play_silence(chan, intralettertime);
1611                         ddcomb >>= 1;
1612                 }
1613                 
1614                 /* Wait the interletter time */
1615                 
1616                 if (!res)
1617                         res = play_silence(chan, interlettertime - intralettertime);
1618         }
1619         
1620         /* Wait for all the frames to be sent */
1621         
1622         if (!res) 
1623                 res = ast_waitstream(chan, "");
1624         ast_stopstream(chan);
1625         
1626         /*
1627         * Wait for the zaptel driver to physically write the tone blocks to the hardware
1628         */
1629
1630         for (i = 0; i < 20 ; i++) {
1631                 flags =  ZT_IOMUX_WRITEEMPTY | ZT_IOMUX_NOWAIT; 
1632                 res = ioctl(chan->fds[0], ZT_IOMUX, &flags);
1633                 if (flags & ZT_IOMUX_WRITEEMPTY)
1634                         break;
1635                 if ( ast_safe_sleep(chan, 50)) {
1636                         res = -1;
1637                         break;
1638                 }
1639         }
1640
1641         
1642         return res;
1643 }
1644
1645 static int send_tone_telemetry(struct ast_channel *chan, const char *tonestring)
1646 {
1647         char *stringp;
1648         char *tonesubset;
1649         int f1, f2;
1650         int duration;
1651         int amplitude;
1652         int res;
1653         int i;
1654         int flags;
1655         
1656         res = 0;
1657         
1658         stringp = ast_strdupa(tonestring);
1659
1660         for (;tonestring;) {
1661                 tonesubset = strsep(&stringp, ")");
1662                 if (!tonesubset)
1663                         break;
1664                 if (sscanf(tonesubset, "(%d,%d,%d,%d", &f1, &f2, &duration, &amplitude) != 4)
1665                         break;
1666                 res = play_tone_pair(chan, f1, f2, duration, amplitude);
1667                 if (res)
1668                         break;
1669         }
1670         if (!res)
1671                 res = play_tone_pair(chan, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
1672         
1673         if (!res) 
1674                 res = ast_waitstream(chan, "");
1675         ast_stopstream(chan);
1676
1677         /*
1678         * Wait for the zaptel driver to physically write the tone blocks to the hardware
1679         */
1680
1681         for (i = 0; i < 20 ; i++) {
1682                 flags =  ZT_IOMUX_WRITEEMPTY | ZT_IOMUX_NOWAIT; 
1683                 res = ioctl(chan->fds[0], ZT_IOMUX, &flags);
1684                 if (flags & ZT_IOMUX_WRITEEMPTY)
1685                         break;
1686                 if (ast_safe_sleep(chan, 50)) {
1687                         res = -1;
1688                         break;
1689                 }
1690         }
1691                 
1692         return res;
1693 }
1694         
1695
1696 static int sayfile(struct ast_channel *mychannel, const char *fname)
1697 {
1698         int     res;
1699
1700         res = ast_streamfile(mychannel, fname, mychannel->language);
1701         if (!res) 
1702                 res = ast_waitstream(mychannel, "");
1703         else
1704                  ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1705         ast_stopstream(mychannel);
1706         return res;
1707 }
1708
1709 static int saycharstr(struct ast_channel *mychannel, char *str)
1710 {
1711         int     res;
1712
1713         res = ast_say_character_str(mychannel, str, NULL, mychannel->language);
1714         if (!res) 
1715                 res = ast_waitstream(mychannel, "");
1716         else
1717                  ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1718         ast_stopstream(mychannel);
1719         return res;
1720 }
1721
1722 static int saynum(struct ast_channel *mychannel, int num)
1723 {
1724         int res;
1725         res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
1726         if (!res)
1727                 res = ast_waitstream(mychannel, "");
1728         else
1729                 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1730         ast_stopstream(mychannel);
1731         return res;
1732 }
1733
1734 static int saydigits(struct ast_channel *mychannel, int num)
1735 {
1736         int res;
1737         res = ast_say_digits(mychannel, num, NULL, mychannel->language);
1738         if (!res)
1739                 res = ast_waitstream(mychannel, "");
1740         else
1741                 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
1742         ast_stopstream(mychannel);
1743         return res;
1744 }
1745
1746
1747 static int telem_any(struct rpt *myrpt, struct ast_channel *chan, const char *entry)
1748 {
1749         int res;
1750         char c;
1751         
1752         static int morsespeed;
1753         static int morsefreq;
1754         static int morseampl;
1755         static int morseidfreq = 0;
1756         static int morseidampl;
1757         static char mcat[] = MORSE;
1758         
1759         res = 0;
1760         
1761         if (!morseidfreq) { /* Get the morse parameters if not already loaded */
1762                 morsespeed = retrieve_astcfgint(myrpt, mcat, "speed", 5, 20, 20);
1763                 morsefreq = retrieve_astcfgint(myrpt, mcat, "frequency", 300, 3000, 800);
1764                 morseampl = retrieve_astcfgint(myrpt, mcat, "amplitude", 200, 8192, 4096);
1765                 morseidampl = retrieve_astcfgint(myrpt, mcat, "idamplitude", 200, 8192, 2048);
1766                 morseidfreq = retrieve_astcfgint(myrpt, mcat, "idfrequency", 300, 3000, 330);   
1767         }
1768         
1769         /* Is it a file, or a tone sequence? */
1770                         
1771         if (entry[0] == '|') {
1772                 c = entry[1];
1773                 if ((c >= 'a') && (c <= 'z'))
1774                         c -= 0x20;
1775         
1776                 switch (c) {
1777                 case 'I': /* Morse ID */
1778                         res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
1779                         break;
1780                 case 'M': /* Morse Message */
1781                         res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
1782                         break;
1783                 case 'T': /* Tone sequence */
1784                         res = send_tone_telemetry(chan, entry + 2);
1785                         break;
1786                 default:
1787                         res = -1;
1788                 }
1789         } else
1790                 res = sayfile(chan, entry); /* File */
1791         return res;
1792 }
1793
1794 /*
1795 * This function looks up a telemetry name in the config file, and does a telemetry response as configured.
1796 *
1797 * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
1798 */
1799
1800 static int telem_lookup(struct rpt *myrpt, struct ast_channel *chan, const char *node, const char *name)
1801 {
1802         int res = 0;
1803         int i;
1804         const char *entry = NULL;
1805         const char *telemetry;
1806
1807         /* Retrieve the section name for telemetry from the node section */
1808         if ((telemetry = ast_variable_retrieve(myrpt->cfg, node, TELEMETRY)))
1809                 entry = ast_variable_retrieve(myrpt->cfg, telemetry, name);
1810
1811         /* Try to look up the telemetry name */ 
1812
1813         if (!entry) {
1814                 /* Telemetry name wasn't found in the config file, use the default */
1815                 for (i = 0; i < sizeof(tele_defs) / sizeof(struct telem_defaults); i++) {
1816                         if (!strcasecmp(tele_defs[i].name, name))
1817                                 entry = tele_defs[i].value;
1818                 }
1819         }
1820         if (entry) {    
1821                 if (!ast_strlen_zero(entry))
1822                         telem_any(myrpt, chan, entry);
1823         } else {
1824                 res = -1;
1825         }
1826         return res;
1827 }
1828
1829 /*
1830 * Retrieve a wait interval
1831 */
1832
1833 static int get_wait_interval(struct rpt *myrpt, int type)
1834 {
1835         int interval = 1000;
1836         const char *wait_times = ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
1837
1838         switch (type) {
1839         case DLY_TELEM:
1840                 if (wait_times)
1841                         interval = retrieve_astcfgint(myrpt, wait_times, "telemwait", 500, 5000, 1000);
1842                 break;
1843         case DLY_ID:
1844                 if (wait_times)
1845                         interval = retrieve_astcfgint(myrpt, wait_times, "idwait", 250, 5000, 500);
1846                 else
1847                         interval = 500;
1848                 break;
1849         case DLY_UNKEY:
1850                 if (wait_times)
1851                         interval = retrieve_astcfgint(myrpt, wait_times, "unkeywait", 500, 5000, 1000);
1852                 break;
1853         case DLY_CALLTERM:
1854                 if (wait_times)
1855                         interval = retrieve_astcfgint(myrpt, wait_times, "calltermwait", 500, 5000, 1500);
1856                 break;
1857         default:
1858                 return 0;
1859         }
1860         return interval;
1861 }
1862
1863
1864 /*
1865 * Wait a configurable interval of time 
1866 */
1867
1868
1869 static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
1870 {
1871         int interval;
1872         interval = get_wait_interval(myrpt, type);
1873         if (debug)
1874                 ast_log(LOG_NOTICE, " Delay interval = %d\n", interval);
1875         if (interval)
1876                 ast_safe_sleep(chan, interval);
1877         if (debug)
1878                 ast_log(LOG_NOTICE, "Delay complete\n");
1879         return;
1880 }
1881
1882
1883 static void *rpt_tele_thread(void *this)
1884 {
1885         ZT_CONFINFO ci;  /* conference info */
1886         int     res = 0, haslink, hastx, hasremote, imdone = 0, unkeys_queued, x;
1887         struct rpt_tele *mytele = (struct rpt_tele *)this;
1888         struct rpt_tele *tlist;
1889         struct rpt *myrpt;
1890         struct rpt_link *l, *m, linkbase;
1891         struct ast_channel *mychannel;
1892         const char *p, *ct;
1893         struct timeval tv;
1894         struct ast_tm localtm;
1895 #ifdef  APP_RPT_LOCK_DEBUG
1896         struct lockthread *t;
1897 #endif
1898
1899         /* get a pointer to myrpt */
1900         myrpt = mytele->rpt;
1901
1902         /* Snag copies of a few key myrpt variables */
1903         rpt_mutex_lock(&myrpt->lock);
1904         rpt_mutex_unlock(&myrpt->lock);
1905         
1906         /* allocate a pseudo-channel thru asterisk */
1907         mychannel = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
1908         if (!mychannel) {
1909                 ast_log(LOG_WARNING, "rpt: unable to obtain pseudo channel\n");
1910                 rpt_mutex_lock(&myrpt->lock);
1911                 remque((struct qelem *)mytele);
1912                 ast_log(LOG_NOTICE, "Telemetry thread aborted at line %d, mode: %d\n", __LINE__, mytele->mode); /*@@@@@@@@@@@*/
1913                 rpt_mutex_unlock(&myrpt->lock);
1914                 ast_free(mytele);
1915                 pthread_exit(NULL);
1916         }
1917         rpt_mutex_lock(&myrpt->lock);
1918         mytele->chan = mychannel; /* Save a copy of the channel so we can access it externally if need be */
1919         rpt_mutex_unlock(&myrpt->lock);
1920         
1921         /* make a conference for the tx */
1922         ci.chan = 0;
1923         /* If there's an ID queued, or tail message queued, */
1924         /* only connect the ID audio to the local tx conference so */
1925         /* linked systems can't hear it */
1926         ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) || 
1927                 (mytele->mode == TAILMSG)) ?
1928                         myrpt->txconf : myrpt->conf);
1929         ci.confmode = ZT_CONF_CONFANN;
1930         /* first put the channel on the conference in announce mode */
1931         if (ioctl(mychannel->fds[0], ZT_SETCONF, &ci) == -1) {
1932                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
1933                 rpt_mutex_lock(&myrpt->lock);
1934                 remque((struct qelem *)mytele);
1935                 rpt_mutex_unlock(&myrpt->lock);
1936                 ast_log(LOG_NOTICE, "Telemetry thread aborted at line %d, mode: %d\n", __LINE__, mytele->mode); /*@@@@@@@@@@@*/
1937                 ast_free(mytele);
1938                 ast_hangup(mychannel);
1939                 pthread_exit(NULL);
1940         }
1941         ast_stopstream(mychannel);
1942         switch (mytele->mode) {
1943         case ID:
1944         case ID1:
1945                 /* wait a bit */
1946                 wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM, mychannel);
1947                 res = telem_any(myrpt, mychannel, myrpt->p.ident); 
1948                 imdone=1;       
1949                 break;
1950                 
1951         case TAILMSG:
1952                 res = ast_streamfile(mychannel, myrpt->p.tailmsg.msgs[myrpt->tailmessagen], mychannel->language); 
1953                 break;
1954                 
1955         case IDTALKOVER:
1956                 p = ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover");
1957                 if (p)
1958                         res = telem_any(myrpt, mychannel, p); 
1959                 imdone = 1;     
1960                 break;
1961         case PROC:
1962                 /* wait a little bit longer */
1963                 wait_interval(myrpt, DLY_TELEM, mychannel);
1964                 res = telem_lookup(myrpt, mychannel, myrpt->name, "patchup");
1965                 if (res < 0) { /* Then default message */
1966                         res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
1967                 }
1968                 break;
1969         case TERM:
1970                 /* wait a little bit longer */
1971                 wait_interval(myrpt, DLY_CALLTERM, mychannel);
1972                 res = telem_lookup(myrpt, mychannel, myrpt->name, "patchdown");
1973                 if (res < 0) { /* Then default message */
1974                         res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
1975                 }
1976                 break;
1977         case COMPLETE:
1978                 /* wait a little bit */
1979                 wait_interval(myrpt, DLY_TELEM, mychannel);
1980                 res = telem_lookup(myrpt, mychannel, myrpt->name, "functcomplete");
1981                 break;
1982         case MACRO_NOTFOUND:
1983                 /* wait a little bit */
1984                 wait_interval(myrpt, DLY_TELEM, mychannel);
1985                 res = ast_streamfile(mychannel, "rpt/macro_notfound", mychannel->language);
1986                 break;
1987         case GOSUB_NOTFOUND:
1988                 /* wait a little bit */
1989                 wait_interval(myrpt, DLY_TELEM, mychannel);
1990                 res = ast_streamfile(mychannel, "rpt/gosub_notfound", mychannel->language);
1991                 break;
1992         case MACRO_BUSY:
1993                 /* wait a little bit */
1994                 wait_interval(myrpt, DLY_TELEM, mychannel);
1995                 res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
1996                 break;
1997         case GOSUB_BUSY:
1998                 /* wait a little bit */
1999                 wait_interval(myrpt, DLY_TELEM, mychannel);
2000                 res = ast_streamfile(mychannel, "rpt/gosub_busy", mychannel->language);
2001                 break;
2002         case UNKEY:
2003                 if (myrpt->patchnoct && myrpt->callmode) { /* If no CT during patch configured, then don't send one */
2004                         imdone = 1;
2005                         break;
2006                 }
2007                         
2008                 /*
2009                 * Reset the Unkey to CT timer
2010                 */
2011
2012                 x = get_wait_interval(myrpt, DLY_UNKEY);
2013                 rpt_mutex_lock(&myrpt->lock);
2014                 myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
2015                 rpt_mutex_unlock(&myrpt->lock);
2016
2017                 /*
2018                 * If there's one already queued, don't do another
2019                 */
2020
2021                 tlist = myrpt->tele.next;
2022                 unkeys_queued = 0;
2023                 if (tlist != &myrpt->tele) {
2024                         rpt_mutex_lock(&myrpt->lock);
2025                         while (tlist != &myrpt->tele) {
2026                                 if (tlist->mode == UNKEY)
2027                                         unkeys_queued++;
2028                                 tlist = tlist->next;
2029                         }
2030                         rpt_mutex_unlock(&myrpt->lock);
2031                 }
2032                 if (unkeys_queued > 1) {
2033                         imdone = 1;
2034                         break;
2035                 }
2036
2037                 /* Wait for the telemetry timer to expire */
2038                 /* Periodically check the timer since it can be re-initialized above */
2039                 while (myrpt->unkeytocttimer) {
2040                         int ctint;
2041                         if (myrpt->unkeytocttimer > 100)
2042                                 ctint = 100;
2043                         else
2044                                 ctint = myrpt->unkeytocttimer;
2045                         ast_safe_sleep(mychannel, ctint);
2046                         rpt_mutex_lock(&myrpt->lock);
2047                         if (myrpt->unkeytocttimer < ctint)
2048                                 myrpt->unkeytocttimer = 0;
2049                         else
2050                                 myrpt->unkeytocttimer -= ctint;
2051                         rpt_mutex_unlock(&myrpt->lock);
2052                 }
2053         
2054                 /*
2055                 * Now, the carrier on the rptr rx should be gone. 
2056                 * If it re-appeared, then forget about sending the CT
2057                 */
2058                 if (myrpt->keyed) {
2059                         imdone = 1;
2060                         break;
2061                 }
2062                 
2063                 rpt_mutex_lock(&myrpt->lock); /* Update the kerchunk counters */
2064                 myrpt->dailykerchunks++;
2065                 myrpt->totalkerchunks++;
2066                 rpt_mutex_unlock(&myrpt->lock);
2067         
2068                 haslink = 0;
2069                 hastx = 0;
2070                 hasremote = 0;          
2071                 l = myrpt->links.next;
2072                 if (l != &myrpt->links) {
2073                         rpt_mutex_lock(&myrpt->lock);
2074                         while (l != &myrpt->links) {
2075                                 if (l->name[0] == '0') {
2076                                         l = l->next;
2077                                         continue;
2078                                 }
2079                                 haslink = 1;
2080                                 if (l->mode) {
2081                                         hastx++;
2082                                         if (l->isremote)
2083                                                 hasremote++;
2084                                 }
2085                                 l = l->next;
2086                         }
2087                         rpt_mutex_unlock(&myrpt->lock);
2088                 }
2089                 if (haslink) {
2090                         res = telem_lookup(myrpt, mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
2091                         if (res)
2092                                 ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
2093
2094                         /* if in remote cmd mode, indicate it */
2095                         if (myrpt->cmdnode[0]) {
2096                                 ast_safe_sleep(mychannel, 200);
2097                                 res = telem_lookup(myrpt, mychannel, myrpt->name, "cmdmode");
2098                                 if (res)
2099                                         ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
2100                                 ast_stopstream(mychannel);
2101                         }
2102                 } else if ((ct = ast_variable_retrieve(myrpt->cfg, myrpt->name, "unlinkedct"))) { /* Unlinked Courtesy Tone */
2103                         res = telem_lookup(myrpt, mychannel, myrpt->name, ct);
2104                         if (res)
2105                                 ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);               
2106                 }       
2107                 if (hasremote && (!myrpt->cmdnode[0])) {
2108                         /* set for all to hear */
2109                         ci.chan = 0;
2110                         ci.confno = myrpt->conf;
2111                         ci.confmode = ZT_CONF_CONFANN;
2112                         /* first put the channel on the conference in announce mode */
2113                         if (ioctl(mychannel->fds[0], ZT_SETCONF, &ci) == -1) {
2114                                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2115                                 rpt_mutex_lock(&myrpt->lock);
2116                                 remque((struct qelem *)mytele);
2117                                 rpt_mutex_unlock(&myrpt->lock);
2118                                 ast_log(LOG_NOTICE, "Telemetry thread aborted at line %d, mode: %d\n", __LINE__, mytele->mode); /*@@@@@@@@@@@*/
2119                                 ast_free(mytele);
2120                                 ast_hangup(mychannel);
2121                                 pthread_exit(NULL);
2122                         }
2123                         if ((ct = ast_variable_retrieve(myrpt->cfg, myrpt->name, "remotect"))) { /* Unlinked Courtesy Tone */
2124                                 ast_safe_sleep(mychannel, 200);
2125                                 res = telem_lookup(myrpt, mychannel, myrpt->name, ct);
2126                                 if (res)
2127                                         ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);               
2128                         }       
2129                 }
2130 #ifdef  _MDC_DECODE_H_
2131                 if (myrpt->lastunit) {
2132                         char mystr[10];
2133
2134                         ast_safe_sleep(mychannel, 200);
2135                         /* set for all to hear */
2136                         ci.chan = 0;
2137                         ci.confno = myrpt->txconf;
2138                         ci.confmode = ZT_CONF_CONFANN;
2139                         /* first put the channel on the conference in announce mode */
2140                         if (ioctl(mychannel->fds[0], ZT_SETCONF, &ci) == -1) {
2141                                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2142                                 rpt_mutex_lock(&myrpt->lock);
2143                                 remque((struct qelem *)mytele);
2144                                 rpt_mutex_unlock(&myrpt->lock);
2145                                 ast_log(LOG_NOTICE, "Telemetry thread aborted at line %d, mode: %d\n", __LINE__, mytele->mode); /*@@@@@@@@@@@*/
2146                                 ast_free(mytele);               
2147                                 ast_hangup(mychannel);
2148                                 pthread_exit(NULL);
2149                         }
2150                         snprintf(mystr, sizeof(mystr), "%04x", myrpt->lastunit);
2151                         myrpt->lastunit = 0;
2152                         ast_say_character_str(mychannel, mystr, NULL, mychannel->language);
2153                         break;
2154                 }
2155 #endif
2156                 imdone = 1;
2157                 break;
2158         case REMDISC:
2159                 /* wait a little bit */
2160                 wait_interval(myrpt, DLY_TELEM, mychannel);
2161                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2162                 if (!res) 
2163                         res = ast_waitstream(mychannel, "");
2164                 else
2165                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2166                 ast_stopstream(mychannel);
2167                 ast_say_character_str(mychannel, mytele->mylink.name, NULL, mychannel->language);
2168                 res = ast_streamfile(mychannel, ((mytele->mylink.connected) ? 
2169                         "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
2170                 break;
2171         case REMALREADY:
2172                 /* wait a little bit */
2173                 wait_interval(myrpt, DLY_TELEM, mychannel);
2174                 res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
2175                 break;
2176         case REMNOTFOUND:
2177                 /* wait a little bit */
2178                 wait_interval(myrpt, DLY_TELEM, mychannel);
2179                 res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
2180                 break;
2181         case REMGO:
2182                 /* wait a little bit */
2183                 wait_interval(myrpt, DLY_TELEM, mychannel);
2184                 res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
2185                 break;
2186         case CONNECTED:
2187                 /* wait a little bit */
2188                 wait_interval(myrpt, DLY_TELEM,  mychannel);
2189                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2190                 if (!res) 
2191                         res = ast_waitstream(mychannel, "");
2192                 else
2193                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2194                 ast_stopstream(mychannel);
2195                 ast_say_character_str(mychannel, mytele->mylink.name, NULL, mychannel->language);
2196                 res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
2197                 break;
2198         case CONNFAIL:
2199                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2200                 if (!res) 
2201                         res = ast_waitstream(mychannel, "");
2202                 else
2203                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2204                 ast_stopstream(mychannel);
2205                 ast_say_character_str(mychannel, mytele->mylink.name, NULL, mychannel->language);
2206                 res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
2207                 break;
2208         case STATUS:
2209                 /* wait a little bit */
2210                 wait_interval(myrpt, DLY_TELEM, mychannel);
2211                 hastx = 0;
2212                 linkbase.next = &linkbase;
2213                 linkbase.prev = &linkbase;
2214                 rpt_mutex_lock(&myrpt->lock);
2215                 /* make our own list of links */
2216                 l = myrpt->links.next;
2217                 while (l != &myrpt->links) {
2218                         if (l->name[0] == '0') {
2219                                 l = l->next;
2220                                 continue;
2221                         }
2222                         m = ast_malloc(sizeof(*m));
2223                         if (!m) {
2224                                 ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
2225                                 remque((struct qelem *)mytele);
2226                                 rpt_mutex_unlock(&myrpt->lock);
2227                                 ast_log(LOG_NOTICE, "Telemetry thread aborted at line %d, mode: %d\n", __LINE__, mytele->mode); /*@@@@@@@@@@@*/
2228                                 ast_free(mytele);
2229                                 ast_hangup(mychannel);
2230                                 pthread_exit(NULL);
2231                         }
2232                         memcpy(m, l, sizeof(struct rpt_link));
2233                         m->next = m->prev = NULL;
2234                         insque((struct qelem *)m, (struct qelem *)linkbase.next);
2235                         l = l->next;
2236                 }
2237                 rpt_mutex_unlock(&myrpt->lock);
2238                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2239                 if (!res)
2240                         res = ast_waitstream(mychannel, "");
2241                 else
2242                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2243                 ast_stopstream(mychannel);
2244                 ast_say_character_str(mychannel, myrpt->name, NULL, mychannel->language);
2245                 if (!res) 
2246                         res = ast_waitstream(mychannel, "");
2247                 else
2248                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2249                 ast_stopstream(mychannel);
2250                 if (myrpt->callmode) {
2251                         hastx = 1;
2252                         res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
2253                         if (!res)
2254                                 res = ast_waitstream(mychannel, "");
2255                         else
2256                                  ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2257                         ast_stopstream(mychannel);
2258                 }
2259                 l = linkbase.next;
2260                 while (l != &linkbase) {
2261                         hastx = 1;
2262                         res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2263                         if (!res) 
2264                                 res = ast_waitstream(mychannel, "");
2265                         else
2266                                 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2267                         ast_stopstream(mychannel);
2268                         ast_say_character_str(mychannel, l->name, NULL, mychannel->language);
2269                         if (!res) 
2270                                 res = ast_waitstream(mychannel, "");
2271                         else
2272                                  ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2273                         ast_stopstream(mychannel);
2274                         res = ast_streamfile(mychannel, ((l->mode) ? 
2275                                 "rpt/tranceive" : "rpt/monitor"), mychannel->language);
2276                         if (!res) 
2277                                 res = ast_waitstream(mychannel, "");
2278                         else
2279                                 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2280                         ast_stopstream(mychannel);
2281                         l = l->next;
2282                 }                       
2283                 if (!hastx) {
2284                         res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
2285                         if (!res) 
2286                                 res = ast_waitstream(mychannel, "");
2287                         else
2288                                  ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2289                         ast_stopstream(mychannel);
2290                 }
2291                 /* destroy our local link queue */
2292                 l = linkbase.next;
2293                 while (l != &linkbase) {
2294                         m = l;
2295                         l = l->next;
2296                         remque((struct qelem *)m);
2297                         ast_free(m);
2298                 }                       
2299                 imdone = 1;
2300                 break;
2301
2302         case LASTNODEKEY: /* Identify last node which keyed us up */
2303                 rpt_mutex_lock(&myrpt->lock);
2304                 if (myrpt->lastnodewhichkeyedusup)
2305                         p = ast_strdupa(myrpt->lastnodewhichkeyedusup); /* Make a local copy of the node name */
2306                 else
2307                         p = NULL;
2308                 rpt_mutex_unlock(&myrpt->lock);
2309                 if (!p) {
2310                         imdone = 1; /* no node previously keyed us up, or the node which did has been disconnected */
2311                         break;
2312                 }
2313                 wait_interval(myrpt, DLY_TELEM, mychannel);
2314                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2315                 if (!res) 
2316                         res = ast_waitstream(mychannel, "");
2317                 else
2318                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2319                 ast_stopstream(mychannel);
2320                 ast_say_character_str(mychannel, p, NULL, mychannel->language);
2321                 if (!res) 
2322                         res = ast_waitstream(mychannel, "");
2323                 else
2324                         ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2325                 ast_stopstream(mychannel);
2326                 imdone = 1;
2327                 break;          
2328
2329         case TIMEOUT:
2330                 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
2331                 if (!res) 
2332                         res = ast_waitstream(mychannel, "");
2333                 else
2334                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2335                 ast_stopstream(mychannel);
2336                 ast_say_character_str(mychannel, myrpt->name, NULL, mychannel->language);
2337                 res = ast_streamfile(mychannel, "rpt/timeout", mychannel->language);
2338                 break;
2339                 
2340         case STATS_TIME:
2341                 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
2342                 tv = ast_tvnow();
2343                 ast_localtime(&tv, &localtm, NULL);
2344                 /* Say the phase of the day is before the time */
2345                 if ((localtm.tm_hour >= 0) && (localtm.tm_hour < 12))
2346                         p = "rpt/goodmorning";
2347                 else if ((localtm.tm_hour >= 12) && (localtm.tm_hour < 18))
2348                         p = "rpt/goodafternoon";
2349                 else
2350                         p = "rpt/goodevening";
2351                 if (sayfile(mychannel, p) == -1) {
2352                         imdone = 1;
2353                         break;
2354                 }
2355                 /* Say the time is ... */               
2356                 if (sayfile(mychannel, "rpt/thetimeis") == -1) {
2357                         imdone = 1;
2358                         break;
2359                 }
2360                 /* Say the time */                              
2361                 res = ast_say_time(mychannel, tv.tv_sec, "", mychannel->language);
2362                 if (!res) 
2363                         res = ast_waitstream(mychannel, "");
2364                 ast_stopstream(mychannel);              
2365                 imdone = 1;
2366                 break;
2367         case STATS_VERSION:
2368                 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
2369                 /* Say "version" */
2370                 if (sayfile(mychannel, "rpt/version") == -1) {
2371                         imdone = 1;
2372                         break;
2373                 }
2374                 if (!res) /* Say "X" */
2375                         ast_say_number(mychannel, vmajor, "", mychannel->language, (char *) NULL);
2376                 if (!res) 
2377                         res = ast_waitstream(mychannel, "");
2378                 ast_stopstream(mychannel);      
2379                 if (saycharstr(mychannel, ".") == -1) {
2380                         imdone = 1;
2381                         break;
2382                 }
2383                 if (!res) /* Say "Y" */
2384                         ast_say_number(mychannel, vminor, "", mychannel->language, (char *) NULL);
2385                 if (!res) {
2386                         res = ast_waitstream(mychannel, "");
2387                         ast_stopstream(mychannel);
2388                 } else
2389                          ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2390                 imdone = 1;
2391                 break;
2392         case ARB_ALPHA:
2393                 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
2394                 if (mytele->param)
2395                         saycharstr(mychannel, mytele->param);
2396                 imdone = 1;
2397                 break;
2398         case REV_PATCH:
2399                 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
2400                 if (mytele->param) {
2401                         /* Parts of this section taken from app_parkandannounce */
2402                         char *tpl_working, *tpl_current;
2403                         char *tmp[100], *myparm;
2404                         int looptemp=0, i = 0, dres = 0;
2405
2406                         tpl_working = ast_strdupa(mytele->param);
2407                         myparm = strsep(&tpl_working, ",");
2408                         tpl_current = strsep(&tpl_working, ":");
2409
2410                         while (tpl_current && looptemp < sizeof(tmp)) {
2411                                 tmp[looptemp] = tpl_current;
2412                                 looptemp++;
2413                                 tpl_current = strsep(&tpl_working, ":");
2414                         }
2415
2416                         for (i = 0; i < looptemp; i++) {
2417                                 if (!strcmp(tmp[i], "PARKED")) {
2418                                         ast_say_digits(mychannel, atoi(myparm), "", mychannel->language);
2419                                 } else if (!strcmp(tmp[i], "NODE")) {
2420                                         ast_say_digits(mychannel, atoi(myrpt->name), "", mychannel->language);
2421                                 } else {
2422                                         dres = ast_streamfile(mychannel, tmp[i], mychannel->language);
2423                                         if (!dres) {
2424                                                 dres = ast_waitstream(mychannel, "");
2425                                         } else {
2426                                                 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], mychannel->name);
2427                                                 dres = 0;
2428                                         }
2429                                 }
2430                         }
2431                 }
2432                 imdone = 1;
2433                 break;
2434         case TEST_TONE:
2435                 imdone = 1;
2436                 myrpt->stopgen = 0;
2437                 if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0))) 
2438                         break;
2439                 while (mychannel->generatordata && (!myrpt->stopgen)) {
2440                         if (ast_safe_sleep(mychannel, 1)) break;
2441                         imdone = 1;
2442                 }
2443                 break;
2444         default:
2445                 break;
2446         }
2447
2448         myrpt->stopgen = 0;
2449         if (!imdone) {
2450                 if (!res) 
2451                         res = ast_waitstream(mychannel, "");
2452                 else {
2453                         ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2454                         res = 0;
2455                 }
2456         }
2457         ast_stopstream(mychannel);
2458         rpt_mutex_lock(&myrpt->lock);
2459         if (mytele->mode == TAILMSG) {
2460                 if (!res) {
2461                         myrpt->tailmessagen++;
2462                         if (myrpt->tailmessagen >= myrpt->p.tailmsg.argc)
2463                                 myrpt->tailmessagen = 0;
2464                 } else {
2465                         myrpt->tmsgtimer = myrpt->p.tailsquashedtime;
2466                 }
2467         }
2468         remque((struct qelem *)mytele);
2469         rpt_mutex_unlock(&myrpt->lock);
2470         ast_free(mytele);               
2471         ast_hangup(mychannel);
2472 #ifdef  APP_RPT_LOCK_DEBUG
2473         sleep(5);
2474         ast_mutex_lock(&locklock);
2475         t = get_lockthread(pthread_self());
2476         if (t)
2477                 memset(t, 0, sizeof(struct lockthread));
2478         ast_mutex_unlock(&locklock);
2479 #endif
2480         pthread_exit(NULL);
2481 }
2482
2483 static void rpt_telemetry(struct rpt *myrpt, int mode, void *data)
2484 {
2485         struct rpt_tele *tele;
2486         struct rpt_link *mylink = (struct rpt_link *) data;
2487         int res;
2488
2489         tele = ast_calloc(1, sizeof(*tele));
2490         if (!tele) {
2491                 ast_log(LOG_WARNING, "Unable to allocate memory\n");
2492                 pthread_exit(NULL);
2493         }
2494         tele->rpt = myrpt;
2495         tele->mode = mode;
2496         rpt_mutex_lock(&myrpt->lock);
2497         if ((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED)) {
2498                 if (mylink) {
2499                         memcpy(&tele->mylink, mylink, sizeof(struct rpt_link));
2500                 }
2501         } else if ((mode == ARB_ALPHA) || (mode == REV_PATCH)) {
2502                 ast_copy_string(tele->param, (char *) data, sizeof(tele->param));
2503         }
2504         insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next);
2505         rpt_mutex_unlock(&myrpt->lock);
2506         res = ast_pthread_create_detached(&tele->threadid, NULL, rpt_tele_thread, (void *) tele);
2507         if (res != 0) {
2508                 rpt_mutex_lock(&myrpt->lock);
2509                 remque((struct qlem *) tele); /* We don't like stuck transmitters, remove it from the queue */
2510                 rpt_mutex_unlock(&myrpt->lock); 
2511                 ast_log(LOG_WARNING, "Could not create telemetry thread: %s\n", strerror(res));
2512         }
2513         return;
2514 }
2515
2516 static void *rpt_call(void *this)
2517 {
2518         ZT_CONFINFO ci;  /* conference info */
2519         struct rpt *myrpt = (struct rpt *)this;
2520         int     res;
2521         struct ast_frame wf;
2522         int stopped, congstarted, dialtimer, lastcidx, aborted;
2523         struct ast_channel *mychannel, *genchannel;
2524
2525         myrpt->mydtmf = 0;
2526         /* allocate a pseudo-channel thru asterisk */
2527         mychannel = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
2528         if (!mychannel) {
2529                 ast_log(LOG_ERROR, "rpt: unable to obtain pseudo channel\n");
2530                 pthread_exit(NULL);
2531         }
2532         ci.chan = 0;
2533         ci.confno = myrpt->conf; /* use the pseudo conference */
2534         ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
2535                 | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER; 
2536         /* first put the channel on the conference */
2537         if (ioctl(mychannel->fds[0], ZT_SETCONF, &ci) == -1) {
2538                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2539                 ast_hangup(mychannel);
2540                 myrpt->callmode = 0;
2541                 pthread_exit(NULL);
2542         }
2543         /* allocate a pseudo-channel thru asterisk */
2544         genchannel = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
2545         if (!genchannel) {
2546                 ast_log(LOG_ERROR, "rpt: unable to obtain pseudo channel\n");
2547                 ast_hangup(mychannel);
2548                 pthread_exit(NULL);
2549         }
2550         ci.chan = 0;
2551         ci.confno = myrpt->conf;
2552         ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
2553                 | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER; 
2554         /* first put the channel on the conference */
2555         if (ioctl(genchannel->fds[0], ZT_SETCONF, &ci) == -1) {
2556                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2557                 ast_hangup(mychannel);
2558                 ast_hangup(genchannel);
2559                 myrpt->callmode = 0;
2560                 pthread_exit(NULL);
2561         }
2562         if (myrpt->p.tonezone && (tone_zone_set_zone(mychannel->fds[0], myrpt->p.tonezone) == -1)) {
2563                 ast_log(LOG_WARNING, "Unable to set tone zone %s\n", myrpt->p.tonezone);
2564                 ast_hangup(mychannel);
2565                 ast_hangup(genchannel);
2566                 myrpt->callmode = 0;
2567                 pthread_exit(NULL);
2568         }
2569         if (myrpt->p.tonezone && (tone_zone_set_zone(genchannel->fds[0], myrpt->p.tonezone) == -1)) {
2570                 ast_log(LOG_WARNING, "Unable to set tone zone %s\n", myrpt->p.tonezone);
2571                 ast_hangup(mychannel);
2572                 ast_hangup(genchannel);
2573                 myrpt->callmode = 0;
2574                 pthread_exit(NULL);
2575         }
2576         /* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
2577         if ((!myrpt->patchquiet) && (tone_zone_play_tone(mychannel->fds[0], ZT_TONE_DIALTONE) < 0)) {
2578                 ast_log(LOG_WARNING, "Cannot start dialtone\n");
2579                 ast_hangup(mychannel);
2580                 ast_hangup(genchannel);
2581                 myrpt->callmode = 0;
2582                 pthread_exit(NULL);
2583         }
2584         stopped = 0;
2585         congstarted = 0;
2586         dialtimer = 0;
2587         lastcidx = 0;
2588         aborted = 0;
2589
2590         while ((myrpt->callmode == 1) || (myrpt->callmode == 4)) {
2591                 if ((myrpt->patchdialtime) && (myrpt->callmode == 1) && (myrpt->cidx != lastcidx)) {
2592                         dialtimer = 0;
2593                         lastcidx = myrpt->cidx;
2594                 }               
2595
2596                 if ((myrpt->patchdialtime) && (dialtimer >= myrpt->patchdialtime)) { 
2597                         rpt_mutex_lock(&myrpt->lock);
2598                         aborted = 1;
2599                         myrpt->callmode = 0;
2600                         rpt_mutex_unlock(&myrpt->lock);
2601                         break;
2602                 }
2603         
2604                 if ((!myrpt->patchquiet) && (!stopped) && (myrpt->callmode == 1) && (myrpt->cidx > 0)) {
2605                         stopped = 1;
2606                         /* stop dial tone */
2607                         tone_zone_play_tone(mychannel->fds[0], -1);
2608                 }
2609                 if (myrpt->callmode == 4) {
2610                         if (!congstarted) {
2611                                 congstarted = 1;
2612                                 /* start congestion tone */
2613                                 tone_zone_play_tone(mychannel->fds[0], ZT_TONE_CONGESTION);
2614                         }
2615                 }
2616                 res = ast_safe_sleep(mychannel, MSWAIT);
2617                 if (res < 0) {
2618                         ast_hangup(mychannel);
2619                         ast_hangup(genchannel);
2620                         rpt_mutex_lock(&myrpt->lock);
2621                         myrpt->callmode = 0;
2622                         rpt_mutex_unlock(&myrpt->lock);
2623                         pthread_exit(NULL);
2624                 }
2625                 dialtimer += MSWAIT;
2626         }
2627         /* stop any tone generation */
2628         tone_zone_play_tone(mychannel->fds[0], -1);
2629         /* end if done */
2630         if (!myrpt->callmode) {
2631                 ast_hangup(mychannel);
2632                 ast_hangup(genchannel);
2633                 rpt_mutex_lock(&myrpt->lock);
2634                 myrpt->callmode = 0;
2635                 rpt_mutex_unlock(&myrpt->lock);
2636                 if ((!myrpt->patchquiet) && aborted)
2637                         rpt_telemetry(myrpt, TERM, NULL);
2638                 pthread_exit(NULL);                     
2639         }
2640
2641         if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid) {
2642                 char *name, *loc, *instr;
2643                 instr = ast_strdup(myrpt->p.ourcallerid);
2644                 if (instr) {
2645                         ast_callerid_parse(instr, &name, &loc);
2646                         if (loc) {
2647                                 if (mychannel->cid.cid_num)
2648                                         ast_free(mychannel->cid.cid_num);
2649                                 mychannel->cid.cid_num = ast_strdup(loc);
2650                         }
2651                         if (name) {
2652                                 if (mychannel->cid.cid_name)
2653                                         ast_free(mychannel->cid.cid_name);
2654                                 mychannel->cid.cid_name = ast_strdup(name);
2655                         }
2656                         ast_free(instr);
2657                 }
2658         }
2659
2660         ast_copy_string(mychannel->exten, myrpt->exten, sizeof(mychannel->exten));
2661         ast_copy_string(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context));
2662         
2663         if (myrpt->p.acctcode)
2664                 ast_copy_string((char *)mychannel->accountcode, myrpt->p.acctcode, sizeof(mychannel->accountcode));
2665         mychannel->priority = 1;
2666         ast_channel_undefer_dtmf(mychannel);
2667         if (ast_pbx_start(mychannel) < 0) {
2668                 ast_log(LOG_WARNING, "Unable to start PBX!!\n");
2669                 ast_hangup(mychannel);
2670                 ast_hangup(genchannel);
2671                 rpt_mutex_lock(&myrpt->lock);
2672                 myrpt->callmode = 0;
2673                 rpt_mutex_unlock(&myrpt->lock);
2674                 pthread_exit(NULL);
2675         }
2676         usleep(10000);
2677         rpt_mutex_lock(&myrpt->lock);
2678         myrpt->callmode = 3;
2679         /* set appropriate conference for the pseudo */
2680         ci.chan = 0;
2681         ci.confno = myrpt->conf;
2682         ci.confmode = (myrpt->p.duplex == 2) ? ZT_CONF_CONFANNMON :
2683                 (ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
2684         /* first put the channel on the conference in announce mode */
2685         if (ioctl(myrpt->pchannel->fds[0], ZT_SETCONF, &ci) == -1) {
2686                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2687                 ast_hangup(mychannel);
2688                 ast_hangup(genchannel);
2689                 myrpt->callmode = 0;
2690                 pthread_exit(NULL);
2691         }
2692         while (myrpt->callmode) {
2693                 if ((!mychannel->pbx) && (myrpt->callmode != 4)) {
2694                         if (myrpt->patchfarenddisconnect) { /* If patch is setup for far end disconnect */
2695                                 myrpt->callmode = 0;
2696                                 if (!myrpt->patchquiet) {
2697                                         rpt_mutex_unlock(&myrpt->lock);
2698                                         rpt_telemetry(myrpt, TERM, NULL);
2699                                         rpt_mutex_lock(&myrpt->lock);
2700                                 }
2701                         } else { /* Send congestion until patch is downed by command */
2702                                 myrpt->callmode = 4;
2703                                 rpt_mutex_unlock(&myrpt->lock);
2704                                 /* start congestion tone */
2705                                 tone_zone_play_tone(genchannel->fds[0], ZT_TONE_CONGESTION);
2706                                 rpt_mutex_lock(&myrpt->lock);
2707                         }
2708                 }
2709                 if (myrpt->mydtmf) {
2710                         wf.frametype = AST_FRAME_DTMF;
2711                         wf.subclass = myrpt->mydtmf;
2712                         wf.offset = 0;
2713                         wf.mallocd = 0;
2714                         wf.data = NULL;
2715                         wf.datalen = 0;
2716                         wf.samples = 0;
2717                         rpt_mutex_unlock(&myrpt->lock);
2718                         ast_write(genchannel, &wf); 
2719                         rpt_mutex_lock(&myrpt->lock);
2720                         myrpt->mydtmf = 0;
2721                 }
2722                 rpt_mutex_unlock(&myrpt->lock);
2723                 usleep(MSWAIT * 1000);
2724                 rpt_mutex_lock(&myrpt->lock);
2725         }
2726         rpt_mutex_unlock(&myrpt->lock);
2727         tone_zone_play_tone(genchannel->fds[0], -1);
2728         if (mychannel->pbx)
2729                 ast_softhangup(mychannel, AST_SOFTHANGUP_DEV);
2730         ast_hangup(genchannel);
2731         rpt_mutex_lock(&myrpt->lock);
2732         myrpt->callmode = 0;
2733         rpt_mutex_unlock(&myrpt->lock);
2734         /* set appropriate conference for the pseudo */
2735         ci.chan = 0;
2736         ci.confno = myrpt->conf;
2737         ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? ZT_CONF_CONFANNMON :
2738                 (ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
2739         /* first put the channel on the conference in announce mode */
2740         if (ioctl(myrpt->pchannel->fds[0], ZT_SETCONF, &ci) == -1) {
2741                 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2742         }
2743         pthread_exit(NULL);
2744 }
2745
2746 static void send_link_dtmf(struct rpt *myrpt, char c)
2747 {
2748         char str[300];
2749         struct ast_frame wf;
2750         struct rpt_link *l;
2751
2752         snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c);
2753         wf.frametype = AST_FRAME_TEXT;
2754         wf.subclass = 0;
2755         wf.offset = 0;
2756         wf.mallocd = 1;
2757         wf.datalen = strlen(str) + 1;
2758         wf.samples = 0;
2759         l = myrpt->links.next;
2760         /* first, see if our dude is there */
2761         while (l != &myrpt->links) {
2762                 if (l->name[0] == '0') {
2763                         l = l->next;
2764                         continue;
2765                 }
2766                 /* if we found it, write it and were done */
2767                 if (!strcmp(l->name, myrpt->cmdnode)) {
2768                         wf.data = ast_strdup(str);
2769                         if (l->chan)
2770                                 ast_write(l->chan, &wf);
2771                         return;
2772                 }
2773                 l = l->next;
2774         }
2775         l = myrpt->links.next;
2776         /* if not, give it to everyone */
2777         while (l != &myrpt->links) {
2778                 wf.data = ast_strdup(str);
2779                 if (l->chan)
2780                         ast_write(l->chan, &wf);
2781                 l = l->next;
2782         }
2783         return;
2784 }
2785
2786 /*
2787 * Internet linking function 
2788 */
2789
2790 static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink)
2791 {
2792         const char *val;
2793         char *s, *tele;
2794         char deststr[300] = "", modechange = 0;
2795         char digitbuf[MAXNODESTR];
2796         struct rpt_link *l;
2797         int reconnects = 0;
2798         ZT_CONFINFO ci;  /* conference info */
2799         AST_DECLARE_APP_ARGS(args,
2800                 AST_APP_ARG(s1);
2801                 AST_APP_ARG(s2); /* XXX Never used.  Scratch? XXX */
2802         );
2803
2804         if (!param)
2805                 return DC_ERROR;
2806
2807         if (!myrpt->enable)
2808                 return DC_ERROR;
2809
2810         ast_copy_string(digitbuf, digits, sizeof(digitbuf));
2811         ast_debug(1, "@@@@ ilink param = %s, digitbuf = %s\n", S_OR(param, "(null)"), digitbuf);
2812
2813         switch (myatoi(param)) {
2814         case 1: /* Link off */
2815                 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
2816                         strcpy(digitbuf, myrpt->lastlinknode);
2817                 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
2818                 if (!val) {
2819                         if (strlen(digitbuf) >= myrpt->longestnode)
2820                                 return DC_ERROR;
2821                         break;
2822                 }
2823                 rpt_mutex_lock(&myrpt->lock);
2824                 l = myrpt->links.next;
2825                 /* try to find this one in queue */
2826                 while (l != &myrpt->links) {
2827                         if (l->name[0] == '0') {
2828                                 l = l->next;
2829                                 continue;
2830                         }
2831                         /* if found matching string */
2832                         if (!strcmp(l->name, digitbuf))
2833                                 break;
2834                         l = l->next;
2835                 }
2836                 if (l != &myrpt->links) { /* if found */
2837                         struct ast_frame wf;
2838                         ast_copy_string(myrpt->lastlinknode, digitbuf, MAXNODESTR);
2839                         l->retries = MAX_RETRIES + 1;
2840                         l->disced = 1;
2841                         rpt_mutex_unlock(&myrpt->lock);
2842                         wf.frametype = AST_FRAME_TEXT;
2843                         wf.subclass = 0;
2844                         wf.offset = 0;
2845                         wf.mallocd = 1;
2846                         wf.datalen = strlen(discstr) + 1;
2847                         wf.samples = 0;
2848                         wf.data = ast_strdup(discstr);
2849                         if (l->chan) {
2850                                 ast_write(l->chan, &wf);
2851                                 if (ast_safe_sleep(l->chan, 250) == -1)
2852                                         return DC_ERROR;
2853                                 ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
2854                         }
2855                         rpt_telemetry(myrpt, COMPLETE, NULL);
2856                         return DC_COMPLETE;
2857                 }
2858                 rpt_mutex_unlock(&myrpt->lock); 
2859                 return DC_COMPLETE;
2860         case 2: /* Link Monitor */
2861                 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
2862                         strcpy(digitbuf, myrpt->lastlinknode);
2863                 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
2864                 if (!val) {
2865                         if (strlen(digitbuf) >= myrpt->longestnode)
2866                                 return DC_ERROR;
2867                         break;
2868                 }
2869                 s = ast_strdupa(val);
2870                 AST_NONSTANDARD_APP_ARGS(args, s, ',');
2871                 rpt_mutex_lock(&myrpt->lock);
2872                 l = myrpt->links.next;
2873                 /* try to find this one in queue */
2874                 while (l != &myrpt->links) {
2875                         if (l->name[0] == '0') {
2876                                 l = l->next;
2877                                 continue;
2878                         }
2879                         /* if found matching string */
2880                         if (!strcmp(l->name, digitbuf))
2881                                 break;
2882                         l = l->next;
2883                 }
2884                 /* if found */
2885                 if (l != &myrpt->links) {
2886                         /* if already in this mode, just ignore */
2887                         if ((!l->mode) || (!l->chan)) {
2888                                 rpt_mutex_unlock(&myrpt->lock);
2889                                 rpt_telemetry(myrpt, REMALREADY, NULL);
2890                                 return DC_COMPLETE;
2891                         }
2892                         reconnects = l->reconnects;
2893                         rpt_mutex_unlock(&myrpt->lock);
2894                         if (l->chan)
2895                                 ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
2896                         l->retries = MAX_RETRIES + 1;
2897                         l->disced = 2;
2898                         modechange = 1;
2899                 } else
2900                         rpt_mutex_unlock(&myrpt->lock);
2901                 ast_copy_string(myrpt->lastlinknode, digitbuf, MAXNODESTR);
2902                 /* establish call in monitor mode */
2903                 l = ast_calloc(1, sizeof(*l));
2904                 if (!l) {
2905                         ast_log(LOG_WARNING, "Unable to malloc\n");
2906                         return DC_ERROR;
2907                 }
2908                 snprintf(deststr, sizeof(deststr), "IAX2/%s", args.s1);
2909                 tele = strchr(deststr, '/');
2910                 if (!tele) {
2911                         ast_log(LOG_ERROR, "link2:Dial number (%s) must be in format tech/number\n", deststr);
2912                         return DC_ERROR;
2913                 }
2914                 *tele++ = 0;
2915                 l->isremote = (s && ast_true(s));
2916                 ast_copy_string(l->name, digitbuf, MAXNODESTR);
2917                 l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele, NULL);
2918                 if (modechange)
2919                         l->connected = 1;
2920                 if (l->chan) {
2921                         ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
2922                         ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
2923                         l->chan->whentohangup = 0;
2924                         l->chan->appl = "Apprpt";
2925                         l->chan->data = "(Remote Rx)";
2926                         ast_verb(3, "rpt (remote) initiating call to %s/%s on %s\n",
2927                                         deststr, tele, l->chan->name);
2928                         if (l->chan->cid.cid_num)
2929                                 ast_free(l->chan->cid.cid_num);
2930                         l->chan->cid.cid_num = ast_strdup(myrpt->name);
2931                         ast_call(l->chan, tele, 0);
2932                 } else {
2933                         rpt_telemetry(myrpt, CONNFAIL, l);
2934                         ast_free(l);
2935                         ast_verb(3, "Unable to place call to %s/%s on %s\n",
2936                                         deststr, tele, l->chan->name);
2937                         return DC_ERROR;
2938                 }
2939                 /* allocate a pseudo-channel thru asterisk */
2940                 l->pchan = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
2941                 if (!l->pchan) {
2942                         ast_log(LOG_ERROR, "rpt:Sorry unable to obtain pseudo channel\n");
2943                         ast_hangup(l->chan);
2944                         ast_free(l);
2945                         return DC_ERROR;
2946                 }
2947                 ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
2948                 ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
2949                 /* make a conference for the pseudo-one */
2950                 ci.chan = 0;
2951                 ci.confno = myrpt->conf;
2952                 ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
2953                 /* first put the channel on the conference in proper mode */
2954                 if (ioctl(l->pchan->fds[0], ZT_SETCONF, &ci) == -1) {
2955                         ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2956                         ast_hangup(l->chan);
2957                         ast_hangup(l->pchan);
2958                         ast_free(l);
2959                         return DC_ERROR;
2960                 }
2961                 rpt_mutex_lock(&myrpt->lock);
2962                 l->reconnects = reconnects;
2963                 /* insert at end of queue */
2964                 insque((struct qelem *)l, (struct qelem *)myrpt->links.next);
2965                 rpt_mutex_unlock(&myrpt->lock);
2966                 rpt_telemetry(myrpt, COMPLETE, NULL);
2967                 return DC_COMPLETE;
2968         case 3: /* Link transceive */
2969                 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
2970                         strcpy(digitbuf, myrpt->lastlinknode);
2971                 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
2972                 if (!val) {
2973                         if (strlen(digitbuf) >= myrpt->longestnode)
2974                                 return DC_ERROR;
2975                         break;
2976                 }
2977                 s = ast_strdupa(val);
2978                 AST_NONSTANDARD_APP_ARGS(args, s, ',');
2979                 rpt_mutex_lock(&myrpt->lock);
2980                 l = myrpt->links.next;
2981                 /* try to find this one in queue */
2982                 while (l != &myrpt->links) {
2983                         if (l->name[0] == '0') {
2984                                 l = l->next;
2985                                 continue;
2986                         }
2987                         /* if found matching string */
2988                         if (!strcmp(l->name, digitbuf))
2989                                 break;
2990                         l = l->next;
2991                 }
2992                 /* if found */
2993                 if (l != &myrpt->links) { 
2994                         /* if already in this mode, just ignore */
2995                         if ((l->mode) || (!l->chan)) {
2996                                 rpt_mutex_unlock(&myrpt->lock);
2997                                 rpt_telemetry(myrpt, REMALREADY, NULL);
2998                                 return DC_COMPLETE;
2999                         }
3000                         reconnects = l->reconnects;
3001                         rpt_mutex_unlock(&myrpt->lock);
3002                         if (l->chan)
3003                                 ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
3004                         l->retries = MAX_RETRIES + 1;
3005                         l->disced = 2;
3006                         modechange = 1;
3007                 } else
3008                         rpt_mutex_unlock(&myrpt->lock);
3009                 ast_copy_string(myrpt->lastlinknode, digitbuf, MAXNODESTR);
3010                 /* establish call in tranceive mode */
3011                 l = ast_calloc(1, sizeof(*l));
3012                 if (!l) {
3013                         ast_log(LOG_WARNING, "Unable to malloc\n");
3014                         return DC_ERROR;
3015                 }
3016                 l->mode = 1;
3017                 l->outbound = 1;
3018                 ast_copy_string(l->name, digitbuf, MAXNODESTR);
3019                 l->isremote = (s && ast_true(s));
3020                 if (modechange)
3021                         l->connected = 1;
3022                 snprintf(deststr, sizeof(deststr), "IAX2/%s", args.s1);
3023                 tele = strchr(deststr, '/');
3024                 if (!tele) {
3025                         ast_log(LOG_ERROR, "link3:Dial number (%s) must be in format tech/number\n", deststr);
3026                         ast_free(l);
3027                         return DC_ERROR;
3028                 }
3029                 *tele++ = 0;
3030                 l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele, NULL);
3031                 if (l->chan) {
3032                         ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
3033                         ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
3034                         l->chan->whentohangup = 0;
3035                         l->chan->appl = "Apprpt";
3036                         l->chan->data = "(Remote Rx)";
3037                         ast_verb(3, "rpt (remote) initiating call to %s/%s on %s\n",
3038                                         deststr, tele, l->chan->name);
3039                         if (l->chan->cid.cid_num)
3040                                 ast_free(l->chan->cid.cid_num);
3041                         l->chan->cid.cid_num = ast_strdup(myrpt->name);
3042                         ast_call(l->chan, tele, 999);
3043                 } else {
3044                         rpt_telemetry(myrpt, CONNFAIL, l);
3045                         ast_free(l);
3046                         ast_verb(3, "Unable to place call to %s/%s on %s\n",
3047                                         deststr, tele, l->chan->name);
3048                         return DC_ERROR;
3049                 }
3050                 /* allocate a pseudo-channel thru asterisk */
3051                 l->pchan = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
3052                 if (!l->pchan) {
3053                         ast_log(LOG_ERROR, "rpt:Sorry unable to obtain pseudo channel\n");
3054                         ast_hangup(l->chan);
3055                         ast_free(l);
3056                         return DC_ERROR;
3057                 }
3058                 ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
3059                 ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
3060                 /* make a conference for the tx */
3061                 ci.chan = 0;
3062                 ci.confno = myrpt->conf;
3063                 ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
3064                 /* first put the channel on the conference in proper mode */
3065                 if (ioctl(l->pchan->fds[0], ZT_SETCONF, &ci) == -1) {
3066                         ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
3067                         ast_hangup(l->chan);
3068                         ast_hangup(l->pchan);
3069                         ast_free(l);
3070                         return DC_ERROR;
3071                 }
3072                 rpt_mutex_lock(&myrpt->lock);
3073                 l->reconnects = reconnects;
3074                 /* insert at end of queue */
3075                 insque((struct qelem *)l, (struct qelem *)myrpt->links.next);
3076                 rpt_mutex_unlock(&myrpt->lock);
3077