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