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