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