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