update comment to match the state of the code
[asterisk-bristuff.git] / apps / app_rpt.c
blobe7f7b003c8a0525e9c3e843d0b5a8929f9dd3325
1 /* #define OLD_ASTERISK */
2 #define OLDKEY
3 /*
4 * Asterisk -- An open source telephony toolkit.
6 * Copyright (C) 2002-2007, Jim Dixon, WB6NIL
8 * Jim Dixon, WB6NIL <jim@lambdatel.com>
9 * Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
11 * See http://www.asterisk.org for more information about
12 * the Asterisk project. Please do not directly contact
13 * any of the maintainers of this project for assistance;
14 * the project provides a web site, mailing lists and IRC
15 * channels for your use.
17 * This program is free software, distributed under the terms of
18 * the GNU General Public License Version 2. See the LICENSE file
19 * at the top of the source tree.
21 /*! \file
23 * \brief Radio Repeater / Remote Base program
24 * version 0.73 09/04/07
26 * \author Jim Dixon, WB6NIL <jim@lambdatel.com>
28 * \note Serious contributions by Steve RoDgers, WA6ZFT <hwstar@rodgers.sdcoxmail.com>
30 * See http://www.zapatatelephony.org/app_rpt.html
33 * Repeater / Remote Functions:
34 * "Simple" Mode: * - autopatch access, # - autopatch hangup
35 * Normal mode:
36 * See the function list in rpt.conf (autopatchup, autopatchdn)
37 * autopatchup can optionally take comma delimited setting=value pairs:
40 * context=string : Override default context with "string"
41 * dialtime=ms : Specify the max number of milliseconds between phone number digits (1000 milliseconds = 1 second)
42 * farenddisconnect=1 : Automatically disconnect when called party hangs up
43 * noct=1 : Don't send repeater courtesy tone during autopatch calls
44 * quiet=1 : Don't send dial tone, or connect messages. Do not send patch down message when called party hangs up
47 * Example: 123=autopatchup,dialtime=20000,noct=1,farenddisconnect=1
49 * To send an asterisk (*) while dialing or talking on phone,
50 * use the autopatch acess code.
53 * status cmds:
55 * 1 - Force ID
56 * 2 - Give Time of Day
57 * 3 - Give software Version
59 * cop (control operator) cmds:
61 * 1 - System warm boot
62 * 2 - System enable
63 * 3 - System disable
64 * 4 - Test Tone On/Off
65 * 5 - Dump System Variables on Console (debug)
66 * 6 - PTT (phone mode only)
67 * 7 - Time out timer enable
68 * 8 - Time out timer disable
69 * 9 - Autopatch enable
70 * 10 - Autopatch disable
71 * 11 - Link enable
72 * 12 - Link disable
73 * 13 - Query System State
74 * 14 - Change System State
75 * 15 - Scheduler Enable
76 * 16 - Scheduler Disable
77 * 17 - User functions (time, id, etc) enable
78 * 18 - User functions (time, id, etc) disable
79 * 19 - Select alternate hang timer
80 * 20 - Select standard hang timer
82 * ilink cmds:
84 * 1 - Disconnect specified link
85 * 2 - Connect specified link -- monitor only
86 * 3 - Connect specified link -- tranceive
87 * 4 - Enter command mode on specified link
88 * 5 - System status
89 * 6 - Disconnect all links
90 * 11 - Disconnect a previously permanently connected link
91 * 12 - Permanently connect specified link -- monitor only
92 * 13 - Permanently connect specified link -- tranceive
93 * 15 - Full system status (all nodes)
94 * 16 - Reconnect links disconnected with "disconnect all links"
95 * 200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
97 * remote cmds:
99 * 1 - Recall Memory MM (*000-*099) (Gets memory from rpt.conf)
100 * 2 - Set VFO MMMMM*KKK*O (Mhz digits, Khz digits, Offset)
101 * 3 - Set Rx PL Tone HHH*D*
102 * 4 - Set Tx PL Tone HHH*D* (Not currently implemented with DHE RBI-1)
103 * 5 - Link Status (long)
104 * 6 - Set operating mode M (FM, USB, LSB, AM, etc)
105 * 100 - RX PL off (Default)
106 * 101 - RX PL On
107 * 102 - TX PL Off (Default)
108 * 103 - TX PL On
109 * 104 - Low Power
110 * 105 - Med Power
111 * 106 - Hi Power
112 * 107 - Bump Down 20 Hz
113 * 108 - Bump Down 100 Hz
114 * 109 - Bump Down 500 Hz
115 * 110 - Bump Up 20 Hz
116 * 111 - Bump Up 100 Hz
117 * 112 - Bump Up 500 Hz
118 * 113 - Scan Down Slow
119 * 114 - Scan Down Medium
120 * 115 - Scan Down Fast
121 * 116 - Scan Up Slow
122 * 117 - Scan Up Medium
123 * 118 - Scan Up Fast
124 * 119 - Transmit allowing auto-tune
125 * 140 - Link Status (brief)
126 * 200 thru 215 - (Send DTMF 0-9,*,#,A-D) (200=0, 201=1, 210=*, etc)
129 * 'duplex' modes: (defaults to duplex=2)
131 * 0 - Only remote links key Tx and no main repeat audio.
132 * 1 - Everything other then main Rx keys Tx, no main repeat audio.
133 * 2 - Normal mode
134 * 3 - Normal except no main repeat audio.
135 * 4 - Normal except no main repeat audio during autopatch only
139 /*** MODULEINFO
140 <depend>zaptel</depend>
141 <depend>tonezone</depend>
142 <defaultenabled>no</defaultenabled>
143 ***/
145 /* Un-comment the following to include support for MDC-1200 digital tone
146 signalling protocol (using KA6SQG's GPL'ed implementation) */
147 /* #include "mdc_decode.c" */
149 /* Un-comment the following to include support for notch filters in the
150 rx audio stream (using Tony Fisher's mknotch (mkfilter) implementation) */
151 /* #include "rpt_notch.c" */
153 /* maximum digits in DTMF buffer, and seconds after * for DTMF command timeout */
155 #define MAXDTMF 32
156 #define MAXMACRO 2048
157 #define MAXLINKLIST 512
158 #define LINKLISTTIME 10000
159 #define LINKLISTSHORTTIME 200
160 #define MACROTIME 100
161 #define MACROPTIME 500
162 #define DTMF_TIMEOUT 3
163 #define KENWOOD_RETRIES 5
165 #define AUTHTELLTIME 7000
166 #define AUTHTXTIME 1000
167 #define AUTHLOGOUTTIME 25000
169 #ifdef __RPT_NOTCH
170 #define MAXFILTERS 10
171 #endif
173 #define DISC_TIME 10000 /* report disc after 10 seconds of no connect */
174 #define MAX_RETRIES 5
175 #define MAX_RETRIES_PERM 1000000000
177 #define REDUNDANT_TX_TIME 2000
179 #define RETRY_TIMER_MS 5000
181 #define START_DELAY 2
183 #define MAXPEERSTR 31
184 #define MAXREMSTR 15
186 #define DELIMCHR ','
187 #define QUOTECHR 34
189 #define MONITOR_DISK_BLOCKS_PER_MINUTE 38
191 #define DEFAULT_MONITOR_MIN_DISK_BLOCKS 10000
192 #define DEFAULT_REMOTE_INACT_TIMEOUT (15 * 60)
193 #define DEFAULT_REMOTE_TIMEOUT (60 * 60)
194 #define DEFAULT_REMOTE_TIMEOUT_WARNING (3 * 60)
195 #define DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ 30
197 #define NODES "nodes"
198 #define EXTNODES "extnodes"
199 #define MEMORY "memory"
200 #define MACRO "macro"
201 #define FUNCTIONS "functions"
202 #define TELEMETRY "telemetry"
203 #define MORSE "morse"
204 #define FUNCCHAR '*'
205 #define ENDCHAR '#'
206 #define EXTNODEFILE "/var/lib/asterisk/rpt_extnodes"
208 #define DEFAULT_IOBASE 0x378
210 #define DEFAULT_CIV_ADDR 0x58
212 #define MAXCONNECTTIME 5000
214 #define MAXNODESTR 300
216 #define MAXPATCHCONTEXT 100
218 #define ACTIONSIZE 32
220 #define TELEPARAMSIZE 256
222 #define REM_SCANTIME 100
224 #define DTMF_LOCAL_TIME 250
225 #define DTMF_LOCAL_STARTTIME 500
227 #define IC706_PL_MEMORY_OFFSET 50
229 #define ALLOW_LOCAL_CHANNELS
231 enum {REM_OFF,REM_MONITOR,REM_TX};
233 enum{ID,PROC,TERM,COMPLETE,UNKEY,REMDISC,REMALREADY,REMNOTFOUND,REMGO,
234 CONNECTED,CONNFAIL,STATUS,TIMEOUT,ID1, STATS_TIME,
235 STATS_VERSION, IDTALKOVER, ARB_ALPHA, TEST_TONE, REV_PATCH,
236 TAILMSG, MACRO_NOTFOUND, MACRO_BUSY, LASTNODEKEY, FULLSTATUS,
237 MEMNOTFOUND, INVFREQ, REMMODE, REMLOGIN, REMXXX, REMSHORTSTATUS,
238 REMLONGSTATUS, LOGINREQ, SCAN, SCANSTAT, TUNE, SETREMOTE,
239 TIMEOUT_WARNING, ACT_TIMEOUT_WARNING, LINKUNKEY, UNAUTHTX};
242 enum {REM_SIMPLEX,REM_MINUS,REM_PLUS};
244 enum {REM_LOWPWR,REM_MEDPWR,REM_HIPWR};
246 enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_COMPLETEQUIET, DC_DOKEY};
248 enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT, SOURCE_PHONE, SOURCE_DPHONE};
250 enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM, DLY_COMP, DLY_LINKUNKEY};
252 enum {REM_MODE_FM,REM_MODE_USB,REM_MODE_LSB,REM_MODE_AM};
254 enum {HF_SCAN_OFF,HF_SCAN_DOWN_SLOW,HF_SCAN_DOWN_QUICK,
255 HF_SCAN_DOWN_FAST,HF_SCAN_UP_SLOW,HF_SCAN_UP_QUICK,HF_SCAN_UP_FAST};
257 #include "asterisk.h"
259 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
261 #include <signal.h>
262 #include <stdio.h>
263 #include <unistd.h>
264 #include <string.h>
265 #include <stdlib.h>
266 #include <search.h>
267 #include <sys/types.h>
268 #include <sys/stat.h>
269 #include <errno.h>
270 #include <dirent.h>
271 #include <ctype.h>
272 #include <sys/stat.h>
273 #include <sys/time.h>
274 #include <sys/file.h>
275 #include <sys/ioctl.h>
276 #include <sys/io.h>
277 #include <sys/vfs.h>
278 #include <math.h>
279 #ifdef OLD_ASTERISK
280 #include <linux/zaptel.h>
281 #include <tonezone.h>
282 #else
283 #include <zaptel/zaptel.h>
284 #include <zaptel/tonezone.h>
285 #endif
286 #include <netinet/in.h>
287 #include <arpa/inet.h>
289 #include "asterisk/utils.h"
290 #include "asterisk/lock.h"
291 #include "asterisk/file.h"
292 #include "asterisk/logger.h"
293 #include "asterisk/channel.h"
294 #include "asterisk/callerid.h"
295 #include "asterisk/pbx.h"
296 #include "asterisk/module.h"
297 #include "asterisk/translate.h"
298 #include "asterisk/features.h"
299 #include "asterisk/options.h"
300 #include "asterisk/cli.h"
301 #include "asterisk/config.h"
302 #include "asterisk/say.h"
303 #include "asterisk/localtime.h"
304 #include "asterisk/cdr.h"
305 #include "asterisk/options.h"
306 #include <termios.h>
308 /* Start a tone-list going */
309 int ast_playtones_start(struct ast_channel *chan, int vol, const char* tonelist, int interruptible);
310 /*! Stop the tones from playing */
311 void ast_playtones_stop(struct ast_channel *chan);
313 static char *tdesc = "Radio Repeater / Remote Base version 0.73 09/04/2007";
315 static char *app = "Rpt";
317 static char *synopsis = "Radio Repeater/Remote Base Control System";
319 static char *descrip =
320 " Rpt(nodename[|options]): Radio Remote Link or Remote Base Link Endpoint Process.\n"
321 "\n"
322 " Not specifying an option puts it in normal endpoint mode (where source\n"
323 " IP and nodename are verified).\n"
324 "\n"
325 " Options are as follows:\n"
326 "\n"
327 " X - Normal endpoint mode WITHOUT security check. Only specify\n"
328 " this if you have checked security already (like with an IAX2\n"
329 " user/password or something).\n"
330 "\n"
331 " Rannounce-string[|timeout[|timeout-destination]] - Amateur Radio\n"
332 " Reverse Autopatch. Caller is put on hold, and announcement (as\n"
333 " specified by the 'announce-string') is played on radio system.\n"
334 " Users of radio system can access autopatch, dial specified\n"
335 " code, and pick up call. Announce-string is list of names of\n"
336 " recordings, or \"PARKED\" to substitute code for un-parking,\n"
337 " or \"NODE\" to substitute node number.\n"
338 "\n"
339 " P - Phone Control mode. This allows a regular phone user to have\n"
340 " full control and audio access to the radio system. For the\n"
341 " user to have DTMF control, the 'phone_functions' parameter\n"
342 " must be specified for the node in 'rpt.conf'. An additional\n"
343 " function (cop,6) must be listed so that PTT control is available.\n"
344 "\n"
345 " D - Dumb Phone Control mode. This allows a regular phone user to\n"
346 " have full control and audio access to the radio system. In this\n"
347 " mode, the PTT is activated for the entire length of the call.\n"
348 " For the user to have DTMF control (not generally recomended in\n"
349 " this mode), the 'dphone_functions' parameter must be specified\n"
350 " for the node in 'rpt.conf'. Otherwise no DTMF control will be\n"
351 " available to the phone user.\n"
352 "\n";
354 static int debug = 0; /* Set this >0 for extra debug output */
355 static int nrpts = 0;
357 static char remdtmfstr[] = "0123456789*#ABCD";
359 enum {TOP_TOP,TOP_WON,WON_BEFREAD,BEFREAD_AFTERREAD};
361 int max_chan_stat [] = {22000,1000,22000,100,22000,2000,22000};
363 #define NRPTSTAT 7
365 struct rpt_chan_stat
367 struct timeval last;
368 long long total;
369 unsigned long count;
370 unsigned long largest;
371 struct timeval largest_time;
374 char *discstr = "!!DISCONNECT!!";
375 static char *remote_rig_ft897="ft897";
376 static char *remote_rig_rbi="rbi";
377 static char *remote_rig_kenwood="kenwood";
378 static char *remote_rig_ic706="ic706";
380 #ifdef OLD_ASTERISK
381 STANDARD_LOCAL_USER;
382 LOCAL_USER_DECL;
383 #endif
385 #define MSWAIT 200
386 #define HANGTIME 5000
387 #define TOTIME 180000
388 #define IDTIME 300000
389 #define MAXRPTS 20
390 #define MAX_STAT_LINKS 32
391 #define POLITEID 30000
392 #define FUNCTDELAY 1500
394 #define MAXXLAT 20
395 #define MAXXLATTIME 3
397 #define MAX_SYSSTATES 10
399 struct rpt_xlat
401 char funccharseq[MAXXLAT];
402 char endcharseq[MAXXLAT];
403 char passchars[MAXXLAT];
404 int funcindex;
405 int endindex;
406 time_t lastone;
409 static time_t starttime = 0;
411 static pthread_t rpt_master_thread;
413 struct rpt;
415 struct rpt_link
417 struct rpt_link *next;
418 struct rpt_link *prev;
419 char mode; /* 1 if in tx mode */
420 char isremote;
421 char phonemode;
422 char name[MAXNODESTR]; /* identifier (routing) string */
423 char lasttx;
424 char lastrx;
425 char lastrx1;
426 char connected;
427 char hasconnected;
428 char perma;
429 char thisconnected;
430 char outbound;
431 char disced;
432 char killme;
433 long elaptime;
434 long disctime;
435 long retrytimer;
436 long retxtimer;
437 long rerxtimer;
438 int retries;
439 int max_retries;
440 int reconnects;
441 long long connecttime;
442 struct ast_channel *chan;
443 struct ast_channel *pchan;
444 char linklist[MAXLINKLIST];
445 time_t linklistreceived;
446 long linklisttimer;
447 int dtmfed;
448 int linkunkeytocttimer;
449 struct ast_frame *lastf1,*lastf2;
450 struct rpt_chan_stat chan_stat[NRPTSTAT];
453 struct rpt_lstat
455 struct rpt_lstat *next;
456 struct rpt_lstat *prev;
457 char peer[MAXPEERSTR];
458 char name[MAXNODESTR];
459 char mode;
460 char outbound;
461 char reconnects;
462 char thisconnected;
463 long long connecttime;
464 struct rpt_chan_stat chan_stat[NRPTSTAT];
467 struct rpt_tele
469 struct rpt_tele *next;
470 struct rpt_tele *prev;
471 struct rpt *rpt;
472 struct ast_channel *chan;
473 int mode;
474 struct rpt_link mylink;
475 char param[TELEPARAMSIZE];
476 int submode;
477 pthread_t threadid;
480 struct function_table_tag
482 char action[ACTIONSIZE];
483 int (*function)(struct rpt *myrpt, char *param, char *digitbuf,
484 int command_source, struct rpt_link *mylink);
487 /* Used to store the morse code patterns */
489 struct morse_bits
491 int len;
492 int ddcomb;
495 struct telem_defaults
497 char name[20];
498 char value[80];
502 struct sysstate
504 char txdisable;
505 char totdisable;
506 char linkfundisable;
507 char autopatchdisable;
508 char schedulerdisable;
509 char userfundisable;
510 char alternatetail;
513 static struct rpt
515 ast_mutex_t lock;
516 ast_mutex_t remlock;
517 struct ast_config *cfg;
518 char reload;
520 char *name;
521 char *rxchanname;
522 char *txchanname;
523 char *remote;
524 struct rpt_chan_stat chan_stat[NRPTSTAT];
525 unsigned int scram;
527 struct {
528 char *ourcontext;
529 char *ourcallerid;
530 char *acctcode;
531 char *ident;
532 char *tonezone;
533 char simple;
534 char *functions;
535 char *link_functions;
536 char *phone_functions;
537 char *dphone_functions;
538 char *nodes;
539 char *extnodes;
540 char *extnodefile;
541 int hangtime;
542 int althangtime;
543 int totime;
544 int idtime;
545 int tailmessagetime;
546 int tailsquashedtime;
547 int duplex;
548 int politeid;
549 char *tailmessages[500];
550 int tailmessagemax;
551 char *memory;
552 char *macro;
553 char *startupmacro;
554 int iobase;
555 char *ioport;
556 char funcchar;
557 char endchar;
558 char nobusyout;
559 char notelemtx;
560 char propagate_dtmf;
561 char propagate_phonedtmf;
562 char linktolink;
563 unsigned char civaddr;
564 struct rpt_xlat inxlat;
565 struct rpt_xlat outxlat;
566 char *archivedir;
567 int authlevel;
568 char *csstanzaname;
569 char *skedstanzaname;
570 char *txlimitsstanzaname;
571 long monminblocks;
572 int remoteinacttimeout;
573 int remotetimeout;
574 int remotetimeoutwarning;
575 int remotetimeoutwarningfreq;
576 int sysstate_cur;
577 struct sysstate s[MAX_SYSSTATES];
578 } p;
579 struct rpt_link links;
580 int unkeytocttimer;
581 char keyed;
582 char exttx;
583 char localtx;
584 char remoterx;
585 char remotetx;
586 char remoteon;
587 char remtxfreqok;
588 char tounkeyed;
589 char tonotify;
590 char dtmfbuf[MAXDTMF];
591 char macrobuf[MAXMACRO];
592 char rem_dtmfbuf[MAXDTMF];
593 char lastdtmfcommand[MAXDTMF];
594 char cmdnode[50];
595 struct ast_channel *rxchannel,*txchannel, *monchannel;
596 struct ast_channel *pchannel,*txpchannel, *zaprxchannel, *zaptxchannel;
597 struct ast_frame *lastf1,*lastf2;
598 struct rpt_tele tele;
599 struct timeval lasttv,curtv;
600 pthread_t rpt_call_thread,rpt_thread;
601 time_t dtmf_time,rem_dtmf_time,dtmf_time_rem;
602 int tailtimer,totimer,idtimer,txconf,conf,callmode,cidx,scantimer,tmsgtimer,skedtimer;
603 int mustid,tailid;
604 int tailevent;
605 int telemrefcount;
606 int dtmfidx,rem_dtmfidx;
607 int dailytxtime,dailykerchunks,totalkerchunks,dailykeyups,totalkeyups,timeouts;
608 int totalexecdcommands, dailyexecdcommands;
609 long retxtimer;
610 long rerxtimer;
611 long long totaltxtime;
612 char mydtmf;
613 char exten[AST_MAX_EXTENSION];
614 char freq[MAXREMSTR],rxpl[MAXREMSTR],txpl[MAXREMSTR];
615 char offset;
616 char powerlevel;
617 char txplon;
618 char rxplon;
619 char remmode;
620 char tunerequest;
621 char hfscanmode;
622 int hfscanstatus;
623 char hfscanstop;
624 char lastlinknode[MAXNODESTR];
625 char savednodes[MAXNODESTR];
626 int stopgen;
627 char patchfarenddisconnect;
628 char patchnoct;
629 char patchquiet;
630 char patchcontext[MAXPATCHCONTEXT];
631 int patchdialtime;
632 int macro_longest;
633 int phone_longestfunc;
634 int dphone_longestfunc;
635 int link_longestfunc;
636 int longestfunc;
637 int longestnode;
638 int threadrestarts;
639 int tailmessagen;
640 time_t disgorgetime;
641 time_t lastthreadrestarttime;
642 long macrotimer;
643 char lastnodewhichkeyedusup[MAXNODESTR];
644 int dtmf_local_timer;
645 char dtmf_local_str[100];
646 struct ast_filestream *monstream;
647 char loginuser[50];
648 char loginlevel[10];
649 long authtelltimer;
650 long authtimer;
651 int iofd;
652 time_t start_time,last_activity_time;
653 #ifdef __RPT_NOTCH
654 struct rptfilter
656 char desc[100];
657 float x0;
658 float x1;
659 float x2;
660 float y0;
661 float y1;
662 float y2;
663 float gain;
664 float const0;
665 float const1;
666 float const2;
667 } filters[MAXFILTERS];
668 #endif
669 #ifdef _MDC_DECODE_H_
670 mdc_decoder_t *mdc;
671 unsigned short lastunit;
672 #endif
673 } rpt_vars[MAXRPTS];
675 struct nodelog {
676 struct nodelog *next;
677 struct nodelog *prev;
678 time_t timestamp;
679 char archivedir[MAXNODESTR];
680 char str[MAXNODESTR * 2];
681 } nodelog;
683 static int service_scan(struct rpt *myrpt);
684 static int set_mode_ft897(struct rpt *myrpt, char newmode);
685 static int set_mode_ic706(struct rpt *myrpt, char newmode);
686 static int simple_command_ft897(struct rpt *myrpt, char command);
687 static int setrem(struct rpt *myrpt);
689 AST_MUTEX_DEFINE_STATIC(nodeloglock);
691 AST_MUTEX_DEFINE_STATIC(nodelookuplock);
693 #ifdef APP_RPT_LOCK_DEBUG
695 #warning COMPILING WITH LOCK-DEBUGGING ENABLED!!
697 #define MAXLOCKTHREAD 100
699 #define rpt_mutex_lock(x) _rpt_mutex_lock(x,myrpt,__LINE__)
700 #define rpt_mutex_unlock(x) _rpt_mutex_unlock(x,myrpt,__LINE__)
702 struct lockthread
704 pthread_t id;
705 int lockcount;
706 int lastlock;
707 int lastunlock;
708 } lockthreads[MAXLOCKTHREAD];
711 struct by_lightning
713 int line;
714 struct timeval tv;
715 struct rpt *rpt;
716 struct lockthread lockthread;
717 } lock_ring[32];
719 int lock_ring_index = 0;
721 AST_MUTEX_DEFINE_STATIC(locklock);
723 static struct lockthread *get_lockthread(pthread_t id)
725 int i;
727 for(i = 0; i < MAXLOCKTHREAD; i++)
729 if (lockthreads[i].id == id) return(&lockthreads[i]);
731 return(NULL);
734 static struct lockthread *put_lockthread(pthread_t id)
736 int i;
738 for(i = 0; i < MAXLOCKTHREAD; i++)
740 if (lockthreads[i].id == id)
741 return(&lockthreads[i]);
743 for(i = 0; i < MAXLOCKTHREAD; i++)
745 if (!lockthreads[i].id)
747 lockthreads[i].lockcount = 0;
748 lockthreads[i].lastlock = 0;
749 lockthreads[i].lastunlock = 0;
750 lockthreads[i].id = id;
751 return(&lockthreads[i]);
754 return(NULL);
758 static void rpt_mutex_spew(void)
760 struct by_lightning lock_ring_copy[32];
761 int lock_ring_index_copy;
762 int i,j;
763 long long diff;
764 char a[100];
765 struct timeval lasttv;
767 ast_mutex_lock(&locklock);
768 memcpy(&lock_ring_copy, &lock_ring, sizeof(lock_ring_copy));
769 lock_ring_index_copy = lock_ring_index;
770 ast_mutex_unlock(&locklock);
772 lasttv.tv_sec = lasttv.tv_usec = 0;
773 for(i = 0 ; i < 32 ; i++)
775 j = (i + lock_ring_index_copy) % 32;
776 strftime(a,sizeof(a) - 1,"%m/%d/%Y %H:%M:%S",
777 localtime(&lock_ring_copy[j].tv.tv_sec));
778 diff = 0;
779 if(lasttv.tv_sec)
781 diff = (lock_ring_copy[j].tv.tv_sec - lasttv.tv_sec)
782 * 1000000;
783 diff += (lock_ring_copy[j].tv.tv_usec - lasttv.tv_usec);
785 lasttv.tv_sec = lock_ring_copy[j].tv.tv_sec;
786 lasttv.tv_usec = lock_ring_copy[j].tv.tv_usec;
787 if (!lock_ring_copy[j].tv.tv_sec) continue;
788 if (lock_ring_copy[j].line < 0)
790 ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] UNLOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
791 i - 31,-lock_ring_copy[j].line,lock_ring_copy[j].rpt->name,(int) lock_ring_copy[j].lockthread.id,diff,a,(int)lock_ring_copy[j].tv.tv_usec);
793 else
795 ast_log(LOG_NOTICE,"LOCKDEBUG [#%d] LOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
796 i - 31,lock_ring_copy[j].line,lock_ring_copy[j].rpt->name,(int) lock_ring_copy[j].lockthread.id,diff,a,(int)lock_ring_copy[j].tv.tv_usec);
802 static void _rpt_mutex_lock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
804 struct lockthread *t;
805 pthread_t id;
807 id = pthread_self();
808 ast_mutex_lock(&locklock);
809 t = put_lockthread(id);
810 if (!t)
812 ast_mutex_unlock(&locklock);
813 return;
815 if (t->lockcount)
817 int lastline = t->lastlock;
818 ast_mutex_unlock(&locklock);
819 ast_log(LOG_NOTICE,"rpt_mutex_lock: Double lock request line %d node %s pid %x, last lock was line %d\n",line,myrpt->name,(int) t->id,lastline);
820 rpt_mutex_spew();
821 return;
823 t->lastlock = line;
824 t->lockcount = 1;
825 gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
826 lock_ring[lock_ring_index].rpt = myrpt;
827 memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
828 lock_ring[lock_ring_index++].line = line;
829 if(lock_ring_index == 32)
830 lock_ring_index = 0;
831 ast_mutex_unlock(&locklock);
832 ast_mutex_lock(lockp);
836 static void _rpt_mutex_unlock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
838 struct lockthread *t;
839 pthread_t id;
841 id = pthread_self();
842 ast_mutex_lock(&locklock);
843 t = put_lockthread(id);
844 if (!t)
846 ast_mutex_unlock(&locklock);
847 return;
849 if (!t->lockcount)
851 int lastline = t->lastunlock;
852 ast_mutex_unlock(&locklock);
853 ast_log(LOG_NOTICE,"rpt_mutex_lock: Double un-lock request line %d node %s pid %x, last un-lock was line %d\n",line,myrpt->name,(int) t->id,lastline);
854 rpt_mutex_spew();
855 return;
857 t->lastunlock = line;
858 t->lockcount = 0;
859 gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
860 lock_ring[lock_ring_index].rpt = myrpt;
861 memcpy(&lock_ring[lock_ring_index].lockthread,t,sizeof(struct lockthread));
862 lock_ring[lock_ring_index++].line = -line;
863 if(lock_ring_index == 32)
864 lock_ring_index = 0;
865 ast_mutex_unlock(&locklock);
866 ast_mutex_unlock(lockp);
869 #else /* APP_RPT_LOCK_DEBUG */
871 #define rpt_mutex_lock(x) ast_mutex_lock(x)
872 #define rpt_mutex_unlock(x) ast_mutex_unlock(x)
874 #endif /* APP_RPT_LOCK_DEBUG */
877 * Return 1 if rig is multimode capable
880 static int multimode_capable(struct rpt *myrpt)
882 if(!strcmp(myrpt->remote, remote_rig_ft897))
883 return 1;
884 if(!strcmp(myrpt->remote, remote_rig_ic706))
885 return 1;
886 return 0;
890 * CLI extensions
893 /* Debug mode */
894 static int rpt_do_debug(int fd, int argc, char *argv[]);
895 static int rpt_do_dump(int fd, int argc, char *argv[]);
896 static int rpt_do_stats(int fd, int argc, char *argv[]);
897 static int rpt_do_lstats(int fd, int argc, char *argv[]);
898 static int rpt_do_nodes(int fd, int argc, char *argv[]);
899 static int rpt_do_reload(int fd, int argc, char *argv[]);
900 static int rpt_do_restart(int fd, int argc, char *argv[]);
901 static int rpt_do_fun(int fd, int argc, char *argv[]);
903 static char debug_usage[] =
904 "Usage: rpt debug level {0-7}\n"
905 " Enables debug messages in app_rpt\n";
907 static char dump_usage[] =
908 "Usage: rpt dump <nodename>\n"
909 " Dumps struct debug info to log\n";
911 static char dump_stats[] =
912 "Usage: rpt stats <nodename>\n"
913 " Dumps node statistics to console\n";
915 static char dump_lstats[] =
916 "Usage: rpt lstats <nodename>\n"
917 " Dumps link statistics to console\n";
919 static char dump_nodes[] =
920 "Usage: rpt nodes <nodename>\n"
921 " Dumps a list of directly and indirectly connected nodes to the console\n";
923 static char reload_usage[] =
924 "Usage: rpt reload\n"
925 " Reloads app_rpt running config parameters\n";
927 static char restart_usage[] =
928 "Usage: rpt restart\n"
929 " Restarts app_rpt\n";
931 static char fun_usage[] =
932 "Usage: rpt fun <nodename> <command>\n"
933 " Send a DTMF function to a node\n";
936 static struct ast_cli_entry cli_debug =
937 { { "rpt", "debug", "level" }, rpt_do_debug,
938 "Enable app_rpt debugging", debug_usage };
940 static struct ast_cli_entry cli_dump =
941 { { "rpt", "dump" }, rpt_do_dump,
942 "Dump app_rpt structs for debugging", dump_usage };
944 static struct ast_cli_entry cli_stats =
945 { { "rpt", "stats" }, rpt_do_stats,
946 "Dump node statistics", dump_stats };
948 static struct ast_cli_entry cli_nodes =
949 { { "rpt", "nodes" }, rpt_do_nodes,
950 "Dump node list", dump_nodes };
952 static struct ast_cli_entry cli_lstats =
953 { { "rpt", "lstats" }, rpt_do_lstats,
954 "Dump link statistics", dump_lstats };
956 static struct ast_cli_entry cli_reload =
957 { { "rpt", "reload" }, rpt_do_reload,
958 "Reload app_rpt config", reload_usage };
960 static struct ast_cli_entry cli_restart =
961 { { "rpt", "restart" }, rpt_do_restart,
962 "Restart app_rpt", restart_usage };
964 static struct ast_cli_entry cli_fun =
965 { { "rpt", "fun" }, rpt_do_fun,
966 "Execute a DTMF function", fun_usage };
969 * Telemetry defaults
973 static struct telem_defaults tele_defs[] = {
974 {"ct1","|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
975 {"ct2","|t(660,880,150,3072)"},
976 {"ct3","|t(440,0,150,3072)"},
977 {"ct4","|t(550,0,150,3072)"},
978 {"ct5","|t(660,0,150,3072)"},
979 {"ct6","|t(880,0,150,3072)"},
980 {"ct7","|t(660,440,150,3072)"},
981 {"ct8","|t(700,1100,150,3072)"},
982 {"remotemon","|t(1600,0,75,2048)"},
983 {"remotetx","|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
984 {"cmdmode","|t(900,904,200,2048)"},
985 {"functcomplete","|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
989 * Forward decl's - these suppress compiler warnings when funcs coded further down the file than thier invokation
992 static int setrbi(struct rpt *myrpt);
993 static int set_ft897(struct rpt *myrpt);
994 static int set_ic706(struct rpt *myrpt);
995 static int setkenwood(struct rpt *myrpt);
996 static int setrbi_check(struct rpt *myrpt);
1001 * Define function protos for function table here
1004 static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1005 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1006 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1007 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1008 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1009 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1010 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
1012 * Function table
1015 static struct function_table_tag function_table[] = {
1016 {"cop", function_cop},
1017 {"autopatchup", function_autopatchup},
1018 {"autopatchdn", function_autopatchdn},
1019 {"ilink", function_ilink},
1020 {"status", function_status},
1021 {"remote", function_remote},
1022 {"macro", function_macro}
1025 static long diskavail(struct rpt *myrpt)
1027 struct statfs statfsbuf;
1029 if (!myrpt->p.archivedir) return(0);
1030 if (statfs(myrpt->p.archivedir,&statfsbuf) == -1)
1032 ast_log(LOG_WARNING,"Cannot get filesystem size for %s node %s\n",
1033 myrpt->p.archivedir,myrpt->name);
1034 return(-1);
1036 return(statfsbuf.f_bavail);
1039 static void do_dtmf_phone(struct rpt *myrpt, struct rpt_link *mylink, char c)
1041 struct rpt_link *l;
1043 l = myrpt->links.next;
1044 /* go thru all the links */
1045 while(l != &myrpt->links)
1047 if (!l->phonemode)
1049 l = l->next;
1050 continue;
1052 /* dont send to self */
1053 if (mylink && (l == mylink))
1055 l = l->next;
1056 continue;
1058 if (l->chan) ast_senddigit(l->chan,c);
1059 l = l->next;
1061 return;
1064 /* node logging function */
1065 static void donodelog(struct rpt *myrpt,char *str)
1067 struct nodelog *nodep;
1068 char datestr[100];
1070 if (!myrpt->p.archivedir) return;
1071 nodep = (struct nodelog *)malloc(sizeof(struct nodelog));
1072 if (nodep == NULL)
1074 ast_log(LOG_ERROR,"Cannot get memory for node log");
1075 return;
1077 time(&nodep->timestamp);
1078 strncpy(nodep->archivedir,myrpt->p.archivedir,
1079 sizeof(nodep->archivedir) - 1);
1080 strftime(datestr,sizeof(datestr) - 1,"%Y%m%d%H%M%S",
1081 localtime(&nodep->timestamp));
1082 snprintf(nodep->str,sizeof(nodep->str) - 1,"%s %s,%s\n",
1083 myrpt->name,datestr,str);
1084 ast_mutex_lock(&nodeloglock);
1085 insque((struct qelem *) nodep, (struct qelem *) nodelog.prev);
1086 ast_mutex_unlock(&nodeloglock);
1089 /* must be called locked */
1090 static void do_dtmf_local(struct rpt *myrpt, char c)
1092 int i;
1093 char digit;
1094 static const char* dtmf_tones[] = {
1095 "!941+1336/200,!0/200", /* 0 */
1096 "!697+1209/200,!0/200", /* 1 */
1097 "!697+1336/200,!0/200", /* 2 */
1098 "!697+1477/200,!0/200", /* 3 */
1099 "!770+1209/200,!0/200", /* 4 */
1100 "!770+1336/200,!0/200", /* 5 */
1101 "!770+1477/200,!0/200", /* 6 */
1102 "!852+1209/200,!0/200", /* 7 */
1103 "!852+1336/200,!0/200", /* 8 */
1104 "!852+1477/200,!0/200", /* 9 */
1105 "!697+1633/200,!0/200", /* A */
1106 "!770+1633/200,!0/200", /* B */
1107 "!852+1633/200,!0/200", /* C */
1108 "!941+1633/200,!0/200", /* D */
1109 "!941+1209/200,!0/200", /* * */
1110 "!941+1477/200,!0/200" }; /* # */
1113 if (c)
1115 snprintf(myrpt->dtmf_local_str + strlen(myrpt->dtmf_local_str),sizeof(myrpt->dtmf_local_str) - 1,"%c",c);
1116 if (!myrpt->dtmf_local_timer)
1117 myrpt->dtmf_local_timer = DTMF_LOCAL_STARTTIME;
1119 /* if at timeout */
1120 if (myrpt->dtmf_local_timer == 1)
1122 /* if anything in the string */
1123 if (myrpt->dtmf_local_str[0])
1125 digit = myrpt->dtmf_local_str[0];
1126 myrpt->dtmf_local_str[0] = 0;
1127 for(i = 1; myrpt->dtmf_local_str[i]; i++)
1129 myrpt->dtmf_local_str[i - 1] =
1130 myrpt->dtmf_local_str[i];
1132 myrpt->dtmf_local_str[i - 1] = 0;
1133 myrpt->dtmf_local_timer = DTMF_LOCAL_TIME;
1134 rpt_mutex_unlock(&myrpt->lock);
1135 if (digit >= '0' && digit <='9')
1136 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'0'], 0);
1137 else if (digit >= 'A' && digit <= 'D')
1138 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[digit-'A'+10], 0);
1139 else if (digit == '*')
1140 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[14], 0);
1141 else if (digit == '#')
1142 ast_playtones_start(myrpt->txchannel, 0, dtmf_tones[15], 0);
1143 else {
1144 /* not handled */
1145 ast_log(LOG_DEBUG, "Unable to generate DTMF tone '%c' for '%s'\n", digit, myrpt->txchannel->name);
1147 rpt_mutex_lock(&myrpt->lock);
1149 else
1151 myrpt->dtmf_local_timer = 0;
1156 static int openserial(char *fname)
1158 struct termios mode;
1159 int fd;
1161 fd = open(fname,O_RDWR);
1162 if (fd == -1)
1164 ast_log(LOG_WARNING,"Cannot open serial port %s\n",fname);
1165 return -1;
1167 memset(&mode, 0, sizeof(mode));
1168 if (tcgetattr(fd, &mode)) {
1169 ast_log(LOG_WARNING, "Unable to get serial parameters on %s: %s\n", fname, strerror(errno));
1170 return -1;
1172 #ifndef SOLARIS
1173 cfmakeraw(&mode);
1174 #else
1175 mode.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
1176 |INLCR|IGNCR|ICRNL|IXON);
1177 mode.c_oflag &= ~OPOST;
1178 mode.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
1179 mode.c_cflag &= ~(CSIZE|PARENB|CRTSCTS);
1180 mode.c_cflag |= CS8;
1181 mode.c_cc[TIME] = 3;
1182 mode.c_cc[MAX] = 1;
1183 #endif
1185 cfsetispeed(&mode, B9600);
1186 cfsetospeed(&mode, B9600);
1187 if (tcsetattr(fd, TCSANOW, &mode))
1188 ast_log(LOG_WARNING, "Unable to set serial parameters on %s: %s\n", fname, strerror(errno));
1189 return(fd);
1192 static void mdc1200_notify(struct rpt *myrpt,char *fromnode, unsigned int unit)
1194 if (!fromnode)
1196 ast_verbose("Got MDC-1200 ID %04X from local system (%s)\n",
1197 unit,myrpt->name);
1199 else
1201 ast_verbose("Got MDC-1200 ID %04X from node %s (%s)\n",
1202 unit,fromnode,myrpt->name);
1206 #ifdef _MDC_DECODE_H_
1208 static void mdc1200_send(struct rpt *myrpt, unsigned int unit)
1210 struct rpt_link *l;
1211 struct ast_frame wf;
1212 char str[200];
1215 sprintf(str,"I %s %04X",myrpt->name,unit);
1217 wf.frametype = AST_FRAME_TEXT;
1218 wf.subclass = 0;
1219 wf.offset = 0;
1220 wf.mallocd = 0;
1221 wf.datalen = strlen(str) + 1;
1222 wf.samples = 0;
1225 l = myrpt->links.next;
1226 /* otherwise, send it to all of em */
1227 while(l != &myrpt->links)
1229 if (l->name[0] == '0')
1231 l = l->next;
1232 continue;
1234 wf.data = str;
1235 if (l->chan) ast_write(l->chan,&wf);
1236 l = l->next;
1238 return;
1241 #endif
1243 static char func_xlat(struct rpt *myrpt,char c,struct rpt_xlat *xlat)
1245 time_t now;
1246 int gotone;
1248 time(&now);
1249 gotone = 0;
1250 /* if too much time, reset the skate machine */
1251 if ((now - xlat->lastone) > MAXXLATTIME)
1253 xlat->funcindex = xlat->endindex = 0;
1255 if (xlat->funccharseq[0] && (c == xlat->funccharseq[xlat->funcindex++]))
1257 time(&xlat->lastone);
1258 gotone = 1;
1259 if (!xlat->funccharseq[xlat->funcindex])
1261 xlat->funcindex = xlat->endindex = 0;
1262 return(myrpt->p.funcchar);
1264 } else xlat->funcindex = 0;
1265 if (xlat->endcharseq[0] && (c == xlat->endcharseq[xlat->endindex++]))
1267 time(&xlat->lastone);
1268 gotone = 1;
1269 if (!xlat->endcharseq[xlat->endindex])
1271 xlat->funcindex = xlat->endindex = 0;
1272 return(myrpt->p.endchar);
1274 } else xlat->endindex = 0;
1275 /* if in middle of decode seq, send nothing back */
1276 if (gotone) return(0);
1277 /* if no pass chars specified, return em all */
1278 if (!xlat->passchars[0]) return(c);
1279 /* if a "pass char", pass it */
1280 if (strchr(xlat->passchars,c)) return(c);
1281 return(0);
1285 * Return a pointer to the first non-whitespace character
1288 static char *eatwhite(char *s)
1290 while((*s == ' ') || (*s == 0x09)){ /* get rid of any leading white space */
1291 if(!*s)
1292 break;
1293 s++;
1295 return s;
1299 * Break up a delimited string into a table of substrings
1301 * str - delimited string ( will be modified )
1302 * strp- list of pointers to substrings (this is built by this function), NULL will be placed at end of list
1303 * limit- maximum number of substrings to process
1308 static int finddelim(char *str, char *strp[], int limit)
1310 int i,l,inquo;
1312 inquo = 0;
1313 i = 0;
1314 strp[i++] = str;
1315 if (!*str)
1317 strp[0] = 0;
1318 return(0);
1320 for(l = 0; *str && (l < limit) ; str++)
1322 if (*str == QUOTECHR)
1324 if (inquo)
1326 *str = 0;
1327 inquo = 0;
1329 else
1331 strp[i - 1] = str + 1;
1332 inquo = 1;
1335 if ((*str == DELIMCHR) && (!inquo))
1337 *str = 0;
1338 l++;
1339 strp[i++] = str + 1;
1342 strp[i] = 0;
1343 return(i);
1347 /* must be called locked */
1348 static void __mklinklist(struct rpt *myrpt, struct rpt_link *mylink, char *buf)
1350 struct rpt_link *l;
1351 char mode;
1352 int i,spos;
1354 buf[0] = 0; /* clear output buffer */
1355 /* go thru all links */
1356 for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
1358 /* if is not a real link, ignore it */
1359 if (l->name[0] == '0') continue;
1360 /* dont count our stuff */
1361 if (l == mylink) continue;
1362 if (mylink && (!strcmp(l->name,mylink->name))) continue;
1363 /* figure out mode to report */
1364 mode = 'T'; /* use Tranceive by default */
1365 if (!l->mode) mode = 'R'; /* indicate RX for our mode */
1366 if (!l->thisconnected) mode = 'C'; /* indicate connecting */
1367 spos = strlen(buf); /* current buf size (b4 we add our stuff) */
1368 if (spos)
1370 strcat(buf,",");
1371 spos++;
1373 /* add nodes into buffer */
1374 if (l->linklist[0])
1376 snprintf(buf + spos,MAXLINKLIST - spos,
1377 "%c%s,%s",mode,l->name,l->linklist);
1379 else /* if no nodes, add this node into buffer */
1381 snprintf(buf + spos,MAXLINKLIST - spos,
1382 "%c%s",mode,l->name);
1384 /* if we are in tranceive mode, let all modes stand */
1385 if (mode == 'T') continue;
1386 /* downgrade everyone on this node if appropriate */
1387 for(i = spos; buf[i]; i++)
1389 if (buf[i] == 'T') buf[i] = mode;
1390 if ((buf[i] == 'R') && (mode == 'C')) buf[i] = mode;
1393 return;
1396 /* must be called locked */
1397 static void __kickshort(struct rpt *myrpt)
1399 struct rpt_link *l;
1401 for(l = myrpt->links.next; l != &myrpt->links; l = l->next)
1403 /* if is not a real link, ignore it */
1404 if (l->name[0] == '0') continue;
1405 l->linklisttimer = LINKLISTSHORTTIME;
1407 return;
1410 static char *node_lookup(struct rpt *myrpt,char *digitbuf)
1413 char *val;
1414 int longestnode,j;
1415 struct stat mystat;
1416 static time_t last = 0;
1417 static struct ast_config *ourcfg = NULL;
1418 struct ast_variable *vp;
1420 /* try to look it up locally first */
1421 val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
1422 if (val) return(val);
1423 ast_mutex_lock(&nodelookuplock);
1424 /* if file does not exist */
1425 if (stat(myrpt->p.extnodefile,&mystat) == -1)
1427 if (ourcfg) ast_config_destroy(ourcfg);
1428 ourcfg = NULL;
1429 ast_mutex_unlock(&nodelookuplock);
1430 return(NULL);
1432 /* if we need to reload */
1433 if (mystat.st_mtime > last)
1435 if (ourcfg) ast_config_destroy(ourcfg);
1436 ourcfg = ast_config_load(myrpt->p.extnodefile);
1437 /* if file not there, just bail */
1438 if (!ourcfg)
1440 ast_mutex_unlock(&nodelookuplock);
1441 return(NULL);
1443 /* reset "last" time */
1444 last = mystat.st_mtime;
1446 /* determine longest node length again */
1447 longestnode = 0;
1448 vp = ast_variable_browse(myrpt->cfg, myrpt->p.nodes);
1449 while(vp){
1450 j = strlen(vp->name);
1451 if (j > longestnode)
1452 longestnode = j;
1453 vp = vp->next;
1456 vp = ast_variable_browse(ourcfg, myrpt->p.extnodes);
1457 while(vp){
1458 j = strlen(vp->name);
1459 if (j > longestnode)
1460 longestnode = j;
1461 vp = vp->next;
1464 myrpt->longestnode = longestnode;
1466 val = NULL;
1467 if (ourcfg)
1468 val = (char *) ast_variable_retrieve(ourcfg, myrpt->p.extnodes, digitbuf);
1469 ast_mutex_unlock(&nodelookuplock);
1470 return(val);
1474 * Match a keyword in a list, and return index of string plus 1 if there was a match,* else return 0.
1475 * If param is passed in non-null, then it will be set to the first character past the match
1478 static int matchkeyword(char *string, char **param, char *keywords[])
1480 int i,ls;
1481 for( i = 0 ; keywords[i] ; i++){
1482 ls = strlen(keywords[i]);
1483 if(!ls){
1484 *param = NULL;
1485 return 0;
1487 if(!strncmp(string, keywords[i], ls)){
1488 if(param)
1489 *param = string + ls;
1490 return i + 1;
1493 param = NULL;
1494 return 0;
1498 * Skip characters in string which are in charlist, and return a pointer to the
1499 * first non-matching character
1502 static char *skipchars(char *string, char *charlist)
1504 int i;
1505 while(*string){
1506 for(i = 0; charlist[i] ; i++){
1507 if(*string == charlist[i]){
1508 string++;
1509 break;
1512 if(!charlist[i])
1513 return string;
1515 return string;
1520 static int myatoi(char *str)
1522 int ret;
1524 if (str == NULL) return -1;
1525 /* leave this %i alone, non-base-10 input is useful here */
1526 if (sscanf(str,"%i",&ret) != 1) return -1;
1527 return ret;
1530 static int mycompar(const void *a, const void *b)
1532 char **x = (char **) a;
1533 char **y = (char **) b;
1534 int xoff,yoff;
1536 if ((**x < '0') || (**x > '9')) xoff = 1; else xoff = 0;
1537 if ((**y < '0') || (**y > '9')) yoff = 1; else yoff = 0;
1538 return(strcmp((*x) + xoff,(*y) + yoff));
1541 #ifdef __RPT_NOTCH
1543 /* rpt filter routine */
1544 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
1546 int i,j;
1547 struct rptfilter *f;
1549 for(i = 0; i < len; i++)
1551 for(j = 0; j < MAXFILTERS; j++)
1553 f = &myrpt->filters[j];
1554 if (!*f->desc) continue;
1555 f->x0 = f->x1; f->x1 = f->x2;
1556 f->x2 = ((float)buf[i]) / f->gain;
1557 f->y0 = f->y1; f->y1 = f->y2;
1558 f->y2 = (f->x0 + f->x2) + f->const0 * f->x1
1559 + (f->const1 * f->y0) + (f->const2 * f->y1);
1560 buf[i] = (short)f->y2;
1565 #endif
1569 Get the time for the machine's time zone
1570 Note: Asterisk requires a copy of localtime
1571 in the /etc directory for this to work properly.
1572 If /etc/localtime is not present, you will get
1573 GMT time! This is especially important on systems
1574 running embedded linux distributions as they don't usually
1575 have support for locales.
1577 If OLD_ASTERISK is defined, then the older localtime_r
1578 function will be used. The /etc/localtime file is not
1579 required in this case. This provides backward compatibility
1580 with Asterisk 1.2 systems.
1584 static void rpt_localtime( time_t * t, struct tm *lt)
1586 #ifdef OLD_ASTERISK
1587 localtime_r(t, lt);
1588 #else
1589 ast_localtime(t, lt, NULL);
1590 #endif
1593 /* Retrieve an int from a config file */
1595 static int retrieve_astcfgint(struct rpt *myrpt,char *category, char *name, int min, int max, int defl)
1597 char *var;
1598 int ret;
1599 char include_zero = 0;
1601 if(min < 0){ /* If min is negative, this means include 0 as a valid entry */
1602 min = -min;
1603 include_zero = 1;
1606 var = (char *) ast_variable_retrieve(myrpt->cfg, category, name);
1607 if(var){
1608 ret = myatoi(var);
1609 if(include_zero && !ret)
1610 return 0;
1611 if(ret < min)
1612 ret = min;
1613 if(ret > max)
1614 ret = max;
1616 else
1617 ret = defl;
1618 return ret;
1622 static void load_rpt_vars(int n,int init)
1624 char *this,*val;
1625 int i,j,longestnode;
1626 struct ast_variable *vp;
1627 struct ast_config *cfg;
1628 char *strs[100];
1629 char s1[256];
1630 static char *cs_keywords[] = {"rptena","rptdis","apena","apdis","lnkena","lnkdis","totena","totdis","skena","skdis",
1631 "ufena","ufdis","atena","atdis",NULL};
1633 if (option_verbose > 2)
1634 ast_verbose(VERBOSE_PREFIX_3 "%s config for repeater %s\n",
1635 (init) ? "Loading initial" : "Re-Loading",rpt_vars[n].name);
1636 ast_mutex_lock(&rpt_vars[n].lock);
1637 if (rpt_vars[n].cfg) ast_config_destroy(rpt_vars[n].cfg);
1638 cfg = ast_config_load("rpt.conf");
1639 if (!cfg) {
1640 ast_mutex_unlock(&rpt_vars[n].lock);
1641 ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf. Radio Repeater disabled.\n");
1642 pthread_exit(NULL);
1644 rpt_vars[n].cfg = cfg;
1645 this = rpt_vars[n].name;
1646 memset(&rpt_vars[n].p,0,sizeof(rpt_vars[n].p));
1647 if (init)
1649 char *cp;
1650 int savearea = (char *)&rpt_vars[n].p - (char *)&rpt_vars[n];
1652 cp = (char *) &rpt_vars[n].p;
1653 memset(cp + sizeof(rpt_vars[n].p),0,
1654 sizeof(rpt_vars[n]) - (sizeof(rpt_vars[n].p) + savearea));
1655 rpt_vars[n].tele.next = &rpt_vars[n].tele;
1656 rpt_vars[n].tele.prev = &rpt_vars[n].tele;
1657 rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
1658 rpt_vars[n].tailmessagen = 0;
1660 #ifdef __RPT_NOTCH
1661 /* zot out filters stuff */
1662 memset(&rpt_vars[n].filters,0,sizeof(rpt_vars[n].filters));
1663 #endif
1664 val = (char *) ast_variable_retrieve(cfg,this,"context");
1665 if (val) rpt_vars[n].p.ourcontext = val;
1666 else rpt_vars[n].p.ourcontext = this;
1667 val = (char *) ast_variable_retrieve(cfg,this,"callerid");
1668 if (val) rpt_vars[n].p.ourcallerid = val;
1669 val = (char *) ast_variable_retrieve(cfg,this,"accountcode");
1670 if (val) rpt_vars[n].p.acctcode = val;
1671 val = (char *) ast_variable_retrieve(cfg,this,"idrecording");
1672 if (val) rpt_vars[n].p.ident = val;
1673 val = (char *) ast_variable_retrieve(cfg,this,"hangtime");
1674 if (val) rpt_vars[n].p.hangtime = atoi(val);
1675 else rpt_vars[n].p.hangtime = HANGTIME;
1676 val = (char *) ast_variable_retrieve(cfg,this,"althangtime");
1677 if (val) rpt_vars[n].p.althangtime = atoi(val);
1678 else rpt_vars[n].p.althangtime = HANGTIME;
1679 val = (char *) ast_variable_retrieve(cfg,this,"totime");
1680 if (val) rpt_vars[n].p.totime = atoi(val);
1681 else rpt_vars[n].p.totime = TOTIME;
1682 rpt_vars[n].p.tailmessagetime = retrieve_astcfgint(&rpt_vars[n],this, "tailmessagetime", 0, 2400000, 0);
1683 rpt_vars[n].p.tailsquashedtime = retrieve_astcfgint(&rpt_vars[n],this, "tailsquashedtime", 0, 2400000, 0);
1684 rpt_vars[n].p.duplex = retrieve_astcfgint(&rpt_vars[n],this,"duplex",0,4,2);
1685 rpt_vars[n].p.idtime = retrieve_astcfgint(&rpt_vars[n],this, "idtime", -60000, 2400000, IDTIME); /* Enforce a min max including zero */
1686 rpt_vars[n].p.politeid = retrieve_astcfgint(&rpt_vars[n],this, "politeid", 30000, 300000, POLITEID); /* Enforce a min max */
1687 val = (char *) ast_variable_retrieve(cfg,this,"tonezone");
1688 if (val) rpt_vars[n].p.tonezone = val;
1689 rpt_vars[n].p.tailmessages[0] = 0;
1690 rpt_vars[n].p.tailmessagemax = 0;
1691 val = (char *) ast_variable_retrieve(cfg,this,"tailmessagelist");
1692 if (val) rpt_vars[n].p.tailmessagemax = finddelim(val, rpt_vars[n].p.tailmessages, 500);
1693 val = (char *) ast_variable_retrieve(cfg,this,"memory");
1694 if (!val) val = MEMORY;
1695 rpt_vars[n].p.memory = val;
1696 val = (char *) ast_variable_retrieve(cfg,this,"macro");
1697 if (!val) val = MACRO;
1698 rpt_vars[n].p.macro = val;
1699 val = (char *) ast_variable_retrieve(cfg,this,"startup_macro");
1700 if (val) rpt_vars[n].p.startupmacro = val;
1701 val = (char *) ast_variable_retrieve(cfg,this,"iobase");
1702 /* do not use atoi() here, we need to be able to have
1703 the input specified in hex or decimal so we use
1704 sscanf with a %i */
1705 if ((!val) || (sscanf(val,"%i",&rpt_vars[n].p.iobase) != 1))
1706 rpt_vars[n].p.iobase = DEFAULT_IOBASE;
1707 val = (char *) ast_variable_retrieve(cfg,this,"ioport");
1708 rpt_vars[n].p.ioport = val;
1709 val = (char *) ast_variable_retrieve(cfg,this,"functions");
1710 if (!val)
1712 val = FUNCTIONS;
1713 rpt_vars[n].p.simple = 1;
1715 rpt_vars[n].p.functions = val;
1716 val = (char *) ast_variable_retrieve(cfg,this,"link_functions");
1717 if (val) rpt_vars[n].p.link_functions = val;
1718 else
1719 rpt_vars[n].p.link_functions = rpt_vars[n].p.functions;
1720 val = (char *) ast_variable_retrieve(cfg,this,"phone_functions");
1721 if (val) rpt_vars[n].p.phone_functions = val;
1722 val = (char *) ast_variable_retrieve(cfg,this,"dphone_functions");
1723 if (val) rpt_vars[n].p.dphone_functions = val;
1724 val = (char *) ast_variable_retrieve(cfg,this,"funcchar");
1725 if (!val) rpt_vars[n].p.funcchar = FUNCCHAR; else
1726 rpt_vars[n].p.funcchar = *val;
1727 val = (char *) ast_variable_retrieve(cfg,this,"endchar");
1728 if (!val) rpt_vars[n].p.endchar = ENDCHAR; else
1729 rpt_vars[n].p.endchar = *val;
1730 val = (char *) ast_variable_retrieve(cfg,this,"nobusyout");
1731 if (val) rpt_vars[n].p.nobusyout = ast_true(val);
1732 val = (char *) ast_variable_retrieve(cfg,this,"notelemtx");
1733 if (val) rpt_vars[n].p.notelemtx = ast_true(val);
1734 val = (char *) ast_variable_retrieve(cfg,this,"propagate_dtmf");
1735 if (val) rpt_vars[n].p.propagate_dtmf = ast_true(val);
1736 val = (char *) ast_variable_retrieve(cfg,this,"propagate_phonedtmf");
1737 if (val) rpt_vars[n].p.propagate_phonedtmf = ast_true(val);
1738 val = (char *) ast_variable_retrieve(cfg,this,"linktolink");
1739 if (val) rpt_vars[n].p.linktolink = ast_true(val);
1740 val = (char *) ast_variable_retrieve(cfg,this,"nodes");
1741 if (!val) val = NODES;
1742 rpt_vars[n].p.nodes = val;
1743 val = (char *) ast_variable_retrieve(cfg,this,"extnodes");
1744 if (!val) val = EXTNODES;
1745 rpt_vars[n].p.extnodes = val;
1746 val = (char *) ast_variable_retrieve(cfg,this,"extnodefile");
1747 if (!val) val = EXTNODEFILE;
1748 rpt_vars[n].p.extnodefile = val;
1749 val = (char *) ast_variable_retrieve(cfg,this,"archivedir");
1750 if (val) rpt_vars[n].p.archivedir = val;
1751 val = (char *) ast_variable_retrieve(cfg,this,"authlevel");
1752 if (val) rpt_vars[n].p.authlevel = atoi(val);
1753 else rpt_vars[n].p.authlevel = 0;
1754 val = (char *) ast_variable_retrieve(cfg,this,"monminblocks");
1755 if (val) rpt_vars[n].p.monminblocks = atol(val);
1756 else rpt_vars[n].p.monminblocks = DEFAULT_MONITOR_MIN_DISK_BLOCKS;
1757 val = (char *) ast_variable_retrieve(cfg,this,"remote_inact_timeout");
1758 if (val) rpt_vars[n].p.remoteinacttimeout = atoi(val);
1759 else rpt_vars[n].p.remoteinacttimeout = DEFAULT_REMOTE_INACT_TIMEOUT;
1760 val = (char *) ast_variable_retrieve(cfg,this,"civaddr");
1761 if (val) rpt_vars[n].p.civaddr = atoi(val);
1762 else rpt_vars[n].p.civaddr = DEFAULT_CIV_ADDR;
1763 val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout");
1764 if (val) rpt_vars[n].p.remotetimeout = atoi(val);
1765 else rpt_vars[n].p.remotetimeout = DEFAULT_REMOTE_TIMEOUT;
1766 val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning");
1767 if (val) rpt_vars[n].p.remotetimeoutwarning = atoi(val);
1768 else rpt_vars[n].p.remotetimeoutwarning = DEFAULT_REMOTE_TIMEOUT_WARNING;
1769 val = (char *) ast_variable_retrieve(cfg,this,"remote_timeout_warning_freq");
1770 if (val) rpt_vars[n].p.remotetimeoutwarningfreq = atoi(val);
1771 else rpt_vars[n].p.remotetimeoutwarningfreq = DEFAULT_REMOTE_TIMEOUT_WARNING_FREQ;
1772 #ifdef __RPT_NOTCH
1773 val = (char *) ast_variable_retrieve(cfg,this,"rxnotch");
1774 if (val) {
1775 i = finddelim(val,strs,MAXFILTERS * 2);
1776 i &= ~1; /* force an even number, rounded down */
1777 if (i >= 2) for(j = 0; j < i; j += 2)
1779 rpt_mknotch(atof(strs[j]),atof(strs[j + 1]),
1780 &rpt_vars[n].filters[j >> 1].gain,
1781 &rpt_vars[n].filters[j >> 1].const0,
1782 &rpt_vars[n].filters[j >> 1].const1,
1783 &rpt_vars[n].filters[j >> 1].const2);
1784 sprintf(rpt_vars[n].filters[j >> 1].desc,"%s Hz, BW = %s",
1785 strs[j],strs[j + 1]);
1789 #endif
1790 val = (char *) ast_variable_retrieve(cfg,this,"inxlat");
1791 if (val) {
1792 memset(&rpt_vars[n].p.inxlat,0,sizeof(struct rpt_xlat));
1793 i = finddelim(val,strs,3);
1794 if (i) strncpy(rpt_vars[n].p.inxlat.funccharseq,strs[0],MAXXLAT - 1);
1795 if (i > 1) strncpy(rpt_vars[n].p.inxlat.endcharseq,strs[1],MAXXLAT - 1);
1796 if (i > 2) strncpy(rpt_vars[n].p.inxlat.passchars,strs[2],MAXXLAT - 1);
1798 val = (char *) ast_variable_retrieve(cfg,this,"outxlat");
1799 if (val) {
1800 memset(&rpt_vars[n].p.outxlat,0,sizeof(struct rpt_xlat));
1801 i = finddelim(val,strs,3);
1802 if (i) strncpy(rpt_vars[n].p.outxlat.funccharseq,strs[0],MAXXLAT - 1);
1803 if (i > 1) strncpy(rpt_vars[n].p.outxlat.endcharseq,strs[1],MAXXLAT - 1);
1804 if (i > 2) strncpy(rpt_vars[n].p.outxlat.passchars,strs[2],MAXXLAT - 1);
1806 /* retreive the stanza name for the control states if there is one */
1807 val = (char *) ast_variable_retrieve(cfg,this,"controlstates");
1808 rpt_vars[n].p.csstanzaname = val;
1810 /* retreive the stanza name for the scheduler if there is one */
1811 val = (char *) ast_variable_retrieve(cfg,this,"scheduler");
1812 rpt_vars[n].p.skedstanzaname = val;
1814 /* retreive the stanza name for the txlimits */
1815 val = (char *) ast_variable_retrieve(cfg,this,"txlimits");
1816 rpt_vars[n].p.txlimitsstanzaname = val;
1818 longestnode = 0;
1820 vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes);
1822 while(vp){
1823 j = strlen(vp->name);
1824 if (j > longestnode)
1825 longestnode = j;
1826 vp = vp->next;
1829 rpt_vars[n].longestnode = longestnode;
1832 * For this repeater, Determine the length of the longest function
1834 rpt_vars[n].longestfunc = 0;
1835 vp = ast_variable_browse(cfg, rpt_vars[n].p.functions);
1836 while(vp){
1837 j = strlen(vp->name);
1838 if (j > rpt_vars[n].longestfunc)
1839 rpt_vars[n].longestfunc = j;
1840 vp = vp->next;
1843 * For this repeater, Determine the length of the longest function
1845 rpt_vars[n].link_longestfunc = 0;
1846 vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions);
1847 while(vp){
1848 j = strlen(vp->name);
1849 if (j > rpt_vars[n].link_longestfunc)
1850 rpt_vars[n].link_longestfunc = j;
1851 vp = vp->next;
1853 rpt_vars[n].phone_longestfunc = 0;
1854 if (rpt_vars[n].p.phone_functions)
1856 vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions);
1857 while(vp){
1858 j = strlen(vp->name);
1859 if (j > rpt_vars[n].phone_longestfunc)
1860 rpt_vars[n].phone_longestfunc = j;
1861 vp = vp->next;
1864 rpt_vars[n].dphone_longestfunc = 0;
1865 if (rpt_vars[n].p.dphone_functions)
1867 vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions);
1868 while(vp){
1869 j = strlen(vp->name);
1870 if (j > rpt_vars[n].dphone_longestfunc)
1871 rpt_vars[n].dphone_longestfunc = j;
1872 vp = vp->next;
1875 rpt_vars[n].macro_longest = 1;
1876 vp = ast_variable_browse(cfg, rpt_vars[n].p.macro);
1877 while(vp){
1878 j = strlen(vp->name);
1879 if (j > rpt_vars[n].macro_longest)
1880 rpt_vars[n].macro_longest = j;
1881 vp = vp->next;
1884 /* Browse for control states */
1885 if(rpt_vars[n].p.csstanzaname)
1886 vp = ast_variable_browse(cfg, rpt_vars[n].p.csstanzaname);
1887 else
1888 vp = NULL;
1889 for( i = 0 ; vp && (i < MAX_SYSSTATES) ; i++){ /* Iterate over the number of control state lines in the stanza */
1890 int k,nukw,statenum;
1891 statenum=atoi(vp->name);
1892 strncpy(s1, vp->value, 255);
1893 s1[255] = 0;
1894 nukw = finddelim(s1,strs,32);
1896 for (k = 0 ; k < nukw ; k++){ /* for each user specified keyword */
1897 for(j = 0 ; cs_keywords[j] != NULL ; j++){ /* try to match to one in our internal table */
1898 if(!strcmp(strs[k],cs_keywords[j])){
1899 switch(j){
1900 case 0: /* rptena */
1901 rpt_vars[n].p.s[statenum].txdisable = 0;
1902 break;
1903 case 1: /* rptdis */
1904 rpt_vars[n].p.s[statenum].txdisable = 1;
1905 break;
1907 case 2: /* apena */
1908 rpt_vars[n].p.s[statenum].autopatchdisable = 0;
1909 break;
1911 case 3: /* apdis */
1912 rpt_vars[n].p.s[statenum].autopatchdisable = 1;
1913 break;
1915 case 4: /* lnkena */
1916 rpt_vars[n].p.s[statenum].linkfundisable = 0;
1917 break;
1919 case 5: /* lnkdis */
1920 rpt_vars[n].p.s[statenum].linkfundisable = 1;
1921 break;
1923 case 6: /* totena */
1924 rpt_vars[n].p.s[statenum].totdisable = 0;
1925 break;
1927 case 7: /* totdis */
1928 rpt_vars[n].p.s[statenum].totdisable = 1;
1929 break;
1931 case 8: /* skena */
1932 rpt_vars[n].p.s[statenum].schedulerdisable = 0;
1933 break;
1935 case 9: /* skdis */
1936 rpt_vars[n].p.s[statenum].schedulerdisable = 1;
1937 break;
1939 case 10: /* ufena */
1940 rpt_vars[n].p.s[statenum].userfundisable = 0;
1941 break;
1943 case 11: /* ufdis */
1944 rpt_vars[n].p.s[statenum].userfundisable = 1;
1945 break;
1947 case 12: /* atena */
1948 rpt_vars[n].p.s[statenum].alternatetail = 1;
1949 break;
1951 case 13: /* atdis */
1952 rpt_vars[n].p.s[statenum].alternatetail = 0;
1953 break;
1955 default:
1956 ast_log(LOG_WARNING,
1957 "Unhandled control state keyword %s", cs_keywords[i]);
1958 break;
1963 vp = vp->next;
1965 ast_mutex_unlock(&rpt_vars[n].lock);
1969 * Enable or disable debug output at a given level at the console
1972 static int rpt_do_debug(int fd, int argc, char *argv[])
1974 int newlevel;
1976 if (argc != 4)
1977 return RESULT_SHOWUSAGE;
1978 newlevel = myatoi(argv[3]);
1979 if((newlevel < 0) || (newlevel > 7))
1980 return RESULT_SHOWUSAGE;
1981 if(newlevel)
1982 ast_cli(fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
1983 else
1984 ast_cli(fd, "app_rpt Debugging disabled\n");
1986 debug = newlevel;
1987 return RESULT_SUCCESS;
1991 * Dump rpt struct debugging onto console
1994 static int rpt_do_dump(int fd, int argc, char *argv[])
1996 int i;
1998 if (argc != 3)
1999 return RESULT_SHOWUSAGE;
2001 for(i = 0; i < nrpts; i++)
2003 if (!strcmp(argv[2],rpt_vars[i].name))
2005 rpt_vars[i].disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
2006 ast_cli(fd, "app_rpt struct dump requested for node %s\n",argv[2]);
2007 return RESULT_SUCCESS;
2010 return RESULT_FAILURE;
2014 * Dump statistics onto console
2017 static int rpt_do_stats(int fd, int argc, char *argv[])
2019 int i,j;
2020 int dailytxtime, dailykerchunks;
2021 int totalkerchunks, dailykeyups, totalkeyups, timeouts;
2022 int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
2023 long long totaltxtime;
2024 struct rpt_link *l;
2025 char *listoflinks[MAX_STAT_LINKS];
2026 char *lastnodewhichkeyedusup, *lastdtmfcommand;
2027 char *tot_state, *ider_state, *patch_state;
2028 char *reverse_patch_state, *sys_ena, *tot_ena, *link_ena, *patch_ena;
2029 char *sch_ena, *input_signal, *called_number, *user_funs, *tail_type;
2030 struct rpt *myrpt;
2032 static char *not_applicable = "N/A";
2034 if(argc != 3)
2035 return RESULT_SHOWUSAGE;
2037 for(i = 0 ; i < MAX_STAT_LINKS; i++)
2038 listoflinks[i] = NULL;
2040 tot_state = ider_state =
2041 patch_state = reverse_patch_state =
2042 input_signal = called_number =
2043 lastdtmfcommand = not_applicable;
2045 for(i = 0; i < nrpts; i++)
2047 if (!strcmp(argv[2],rpt_vars[i].name)){
2048 /* Make a copy of all stat variables while locked */
2049 myrpt = &rpt_vars[i];
2050 rpt_mutex_lock(&myrpt->lock); /* LOCK */
2052 dailytxtime = myrpt->dailytxtime;
2053 totaltxtime = myrpt->totaltxtime;
2054 dailykeyups = myrpt->dailykeyups;
2055 totalkeyups = myrpt->totalkeyups;
2056 dailykerchunks = myrpt->dailykerchunks;
2057 totalkerchunks = myrpt->totalkerchunks;
2058 dailyexecdcommands = myrpt->dailyexecdcommands;
2059 totalexecdcommands = myrpt->totalexecdcommands;
2060 timeouts = myrpt->timeouts;
2062 /* Traverse the list of connected nodes */
2063 reverse_patch_state = "DOWN";
2064 j = 0;
2065 l = myrpt->links.next;
2066 while(l && (l != &myrpt->links)){
2067 if (l->name[0] == '0'){ /* Skip '0' nodes */
2068 reverse_patch_state = "UP";
2069 l = l->next;
2070 continue;
2072 listoflinks[j] = ast_strdupa(l->name);
2073 if(listoflinks[j])
2074 j++;
2075 l = l->next;
2078 lastnodewhichkeyedusup = ast_strdupa(myrpt->lastnodewhichkeyedusup);
2079 if((!lastnodewhichkeyedusup) || (!strlen(lastnodewhichkeyedusup)))
2080 lastnodewhichkeyedusup = not_applicable;
2082 if(myrpt->keyed)
2083 input_signal = "YES";
2084 else
2085 input_signal = "NO";
2087 if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable)
2088 sys_ena = "DISABLED";
2089 else
2090 sys_ena = "ENABLED";
2092 if(myrpt->p.s[myrpt->p.sysstate_cur].totdisable)
2093 tot_ena = "DISABLED";
2094 else
2095 tot_ena = "ENABLED";
2097 if(myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable)
2098 link_ena = "DISABLED";
2099 else
2100 link_ena = "ENABLED";
2102 if(myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
2103 patch_ena = "DISABLED";
2104 else
2105 patch_ena = "ENABLED";
2107 if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable)
2108 sch_ena = "DISABLED";
2109 else
2110 sch_ena = "ENABLED";
2112 if(myrpt->p.s[myrpt->p.sysstate_cur].userfundisable)
2113 user_funs = "DISABLED";
2114 else
2115 user_funs = "ENABLED";
2117 if(myrpt->p.s[myrpt->p.sysstate_cur].alternatetail)
2118 tail_type = "ALTERNATE";
2119 else
2120 tail_type = "STANDARD";
2122 if(!myrpt->totimer)
2123 tot_state = "TIMED OUT!";
2124 else if(myrpt->totimer != myrpt->p.totime)
2125 tot_state = "ARMED";
2126 else
2127 tot_state = "RESET";
2129 if(myrpt->tailid)
2130 ider_state = "QUEUED IN TAIL";
2131 else if(myrpt->mustid)
2132 ider_state = "QUEUED FOR CLEANUP";
2133 else
2134 ider_state = "CLEAN";
2136 switch(myrpt->callmode){
2137 case 1:
2138 patch_state = "DIALING";
2139 break;
2140 case 2:
2141 patch_state = "CONNECTING";
2142 break;
2143 case 3:
2144 patch_state = "UP";
2145 break;
2147 case 4:
2148 patch_state = "CALL FAILED";
2149 break;
2151 default:
2152 patch_state = "DOWN";
2155 if(strlen(myrpt->exten)){
2156 called_number = ast_strdupa(myrpt->exten);
2157 if(!called_number)
2158 called_number = not_applicable;
2161 if(strlen(myrpt->lastdtmfcommand)){
2162 lastdtmfcommand = ast_strdupa(myrpt->lastdtmfcommand);
2163 if(!lastdtmfcommand)
2164 lastdtmfcommand = not_applicable;
2167 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2169 ast_cli(fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
2170 ast_cli(fd, "Selected system state............................: %d\n", myrpt->p.sysstate_cur);
2171 ast_cli(fd, "Signal on input..................................: %s\n", input_signal);
2172 ast_cli(fd, "System...........................................: %s\n", sys_ena);
2173 ast_cli(fd, "Scheduler........................................: %s\n", sch_ena);
2174 ast_cli(fd, "Tail Time........................................: %s\n", tail_type);
2175 ast_cli(fd, "Time out timer...................................: %s\n", tot_ena);
2176 ast_cli(fd, "Time out timer state.............................: %s\n", tot_state);
2177 ast_cli(fd, "Time outs since system initialization............: %d\n", timeouts);
2178 ast_cli(fd, "Identifier state.................................: %s\n", ider_state);
2179 ast_cli(fd, "Kerchunks today..................................: %d\n", dailykerchunks);
2180 ast_cli(fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
2181 ast_cli(fd, "Keyups today.....................................: %d\n", dailykeyups);
2182 ast_cli(fd, "Keyups since system initialization...............: %d\n", totalkeyups);
2183 ast_cli(fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
2184 ast_cli(fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
2185 ast_cli(fd, "Last DTMF command executed.......................: %s\n", lastdtmfcommand);
2186 hours = dailytxtime/3600000;
2187 dailytxtime %= 3600000;
2188 minutes = dailytxtime/60000;
2189 dailytxtime %= 60000;
2190 seconds = dailytxtime/1000;
2191 dailytxtime %= 1000;
2193 ast_cli(fd, "TX time today ...................................: %02d:%02d:%02d.%d\n",
2194 hours, minutes, seconds, dailytxtime);
2196 hours = (int) totaltxtime/3600000;
2197 totaltxtime %= 3600000;
2198 minutes = (int) totaltxtime/60000;
2199 totaltxtime %= 60000;
2200 seconds = (int) totaltxtime/1000;
2201 totaltxtime %= 1000;
2203 ast_cli(fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
2204 hours, minutes, seconds, (int) totaltxtime);
2205 ast_cli(fd, "Nodes currently connected to us..................: ");
2206 for(j = 0 ;; j++){
2207 if(!listoflinks[j]){
2208 if(!j){
2209 ast_cli(fd,"<NONE>");
2211 break;
2213 ast_cli(fd, "%s", listoflinks[j]);
2214 if(j % 4 == 3){
2215 ast_cli(fd, "\n");
2216 ast_cli(fd, " : ");
2218 else{
2219 if(listoflinks[j + 1])
2220 ast_cli(fd, ", ");
2223 ast_cli(fd,"\n");
2225 ast_cli(fd, "Last node which transmitted to us................: %s\n", lastnodewhichkeyedusup);
2226 ast_cli(fd, "Autopatch........................................: %s\n", patch_ena);
2227 ast_cli(fd, "Autopatch state..................................: %s\n", patch_state);
2228 ast_cli(fd, "Autopatch called number..........................: %s\n", called_number);
2229 ast_cli(fd, "Reverse patch/IAXRPT connected...................: %s\n", reverse_patch_state);
2230 ast_cli(fd, "User linking commands............................: %s\n", link_ena);
2231 ast_cli(fd, "User functions...................................: %s\n\n", user_funs);
2232 return RESULT_SUCCESS;
2235 return RESULT_FAILURE;
2239 * Link stats function
2242 static int rpt_do_lstats(int fd, int argc, char *argv[])
2244 int i,j;
2245 char *connstate;
2246 struct rpt *myrpt;
2247 struct rpt_link *l;
2248 struct rpt_lstat *s,*t;
2249 struct rpt_lstat s_head;
2250 if(argc != 3)
2251 return RESULT_SHOWUSAGE;
2253 s = NULL;
2254 s_head.next = &s_head;
2255 s_head.prev = &s_head;
2257 for(i = 0; i < nrpts; i++)
2259 if (!strcmp(argv[2],rpt_vars[i].name)){
2260 /* Make a copy of all stat variables while locked */
2261 myrpt = &rpt_vars[i];
2262 rpt_mutex_lock(&myrpt->lock); /* LOCK */
2263 /* Traverse the list of connected nodes */
2264 j = 0;
2265 l = myrpt->links.next;
2266 while(l && (l != &myrpt->links)){
2267 if (l->name[0] == '0'){ /* Skip '0' nodes */
2268 l = l->next;
2269 continue;
2271 if((s = (struct rpt_lstat *) malloc(sizeof(struct rpt_lstat))) == NULL){
2272 ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
2273 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2274 return RESULT_FAILURE;
2276 memset(s, 0, sizeof(struct rpt_lstat));
2277 strncpy(s->name, l->name, MAXREMSTR - 1);
2278 if (l->chan) pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
2279 else strcpy(s->peer,"(none)");
2280 s->mode = l->mode;
2281 s->outbound = l->outbound;
2282 s->reconnects = l->reconnects;
2283 s->connecttime = l->connecttime;
2284 s->thisconnected = l->thisconnected;
2285 memcpy(s->chan_stat,l->chan_stat,NRPTSTAT * sizeof(struct rpt_chan_stat));
2286 insque((struct qelem *) s, (struct qelem *) s_head.next);
2287 memset(l->chan_stat,0,NRPTSTAT * sizeof(struct rpt_chan_stat));
2288 l = l->next;
2290 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2291 ast_cli(fd, "NODE PEER RECONNECTS DIRECTION CONNECT TIME CONNECT STATE\n");
2292 ast_cli(fd, "---- ---- ---------- --------- ------------ -------------\n");
2294 for(s = s_head.next; s != &s_head; s = s->next){
2295 int hours, minutes, seconds;
2296 long long connecttime = s->connecttime;
2297 char conntime[21];
2298 hours = (int) connecttime/3600000;
2299 connecttime %= 3600000;
2300 minutes = (int) connecttime/60000;
2301 connecttime %= 60000;
2302 seconds = (int) connecttime/1000;
2303 connecttime %= 1000;
2304 snprintf(conntime, 20, "%02d:%02d:%02d.%d",
2305 hours, minutes, seconds, (int) connecttime);
2306 conntime[20] = 0;
2307 if(s->thisconnected)
2308 connstate = "ESTABLISHED";
2309 else
2310 connstate = "CONNECTING";
2311 ast_cli(fd, "%-10s%-20s%-12d%-11s%-20s%-20s\n",
2312 s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime, connstate);
2314 /* destroy our local link queue */
2315 s = s_head.next;
2316 while(s != &s_head){
2317 t = s;
2318 s = s->next;
2319 remque((struct qelem *)t);
2320 free(t);
2322 return RESULT_SUCCESS;
2325 return RESULT_FAILURE;
2329 * List all nodes connected, directly or indirectly
2332 static int rpt_do_nodes(int fd, int argc, char *argv[])
2334 int i,j;
2335 char ns;
2336 char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
2337 struct rpt *myrpt;
2338 if(argc != 3)
2339 return RESULT_SHOWUSAGE;
2341 for(i = 0; i < nrpts; i++)
2343 if (!strcmp(argv[2],rpt_vars[i].name)){
2344 /* Make a copy of all stat variables while locked */
2345 myrpt = &rpt_vars[i];
2346 rpt_mutex_lock(&myrpt->lock); /* LOCK */
2347 __mklinklist(myrpt,NULL,lbuf);
2348 rpt_mutex_unlock(&myrpt->lock); /* UNLOCK */
2349 /* parse em */
2350 ns = finddelim(lbuf,strs,MAXLINKLIST);
2351 /* sort em */
2352 if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
2353 ast_cli(fd,"\n");
2354 ast_cli(fd, "************************* CONNECTED NODES *************************\n\n");
2355 for(j = 0 ;; j++){
2356 if(!strs[j]){
2357 if(!j){
2358 ast_cli(fd,"<NONE>");
2360 break;
2362 ast_cli(fd, "%s", strs[j]);
2363 if(j % 8 == 7){
2364 ast_cli(fd, "\n");
2366 else{
2367 if(strs[j + 1])
2368 ast_cli(fd, ", ");
2371 ast_cli(fd,"\n\n");
2372 return RESULT_SUCCESS;
2375 return RESULT_FAILURE;
2379 * reload vars
2382 static int rpt_do_reload(int fd, int argc, char *argv[])
2384 int n;
2386 if (argc > 2) return RESULT_SHOWUSAGE;
2388 for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
2390 return RESULT_FAILURE;
2394 * restart app_rpt
2397 static int rpt_do_restart(int fd, int argc, char *argv[])
2399 int i;
2401 if (argc > 2) return RESULT_SHOWUSAGE;
2402 for(i = 0; i < nrpts; i++)
2404 if (rpt_vars[i].rxchannel) ast_softhangup(rpt_vars[i].rxchannel,AST_SOFTHANGUP_DEV);
2406 return RESULT_FAILURE;
2411 * send an app_rpt DTMF function from the CLI
2414 static int rpt_do_fun(int fd, int argc, char *argv[])
2416 int i,busy=0;
2418 if (argc != 4) return RESULT_SHOWUSAGE;
2420 for(i = 0; i < nrpts; i++){
2421 if(!strcmp(argv[2], rpt_vars[i].name)){
2422 struct rpt *myrpt = &rpt_vars[i];
2423 rpt_mutex_lock(&myrpt->lock);
2424 if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(argv[3])){
2425 rpt_mutex_unlock(&myrpt->lock);
2426 busy=1;
2428 if(!busy){
2429 myrpt->macrotimer = MACROTIME;
2430 strncat(myrpt->macrobuf,argv[3],MAXMACRO - 1);
2432 rpt_mutex_unlock(&myrpt->lock);
2435 if(busy){
2436 ast_cli(fd, "Function decoder busy");
2438 return RESULT_FAILURE;
2443 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
2445 int res;
2447 if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
2448 return res;
2450 while(chan->generatordata) {
2451 if (ast_safe_sleep(chan,1)) return -1;
2454 return 0;
2457 static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
2459 return play_tone_pair(chan, freq, 0, duration, amplitude);
2462 static int play_silence(struct ast_channel *chan, int duration)
2464 return play_tone_pair(chan, 0, 0, duration, 0);
2468 static int send_morse(struct ast_channel *chan, char *string, int speed, int freq, int amplitude)
2471 static struct morse_bits mbits[] = {
2472 {0, 0}, /* SPACE */
2473 {0, 0},
2474 {6, 18},/* " */
2475 {0, 0},
2476 {7, 72},/* $ */
2477 {0, 0},
2478 {0, 0},
2479 {6, 30},/* ' */
2480 {5, 13},/* ( */
2481 {6, 29},/* ) */
2482 {0, 0},
2483 {5, 10},/* + */
2484 {6, 51},/* , */
2485 {6, 33},/* - */
2486 {6, 42},/* . */
2487 {5, 9}, /* / */
2488 {5, 31},/* 0 */
2489 {5, 30},/* 1 */
2490 {5, 28},/* 2 */
2491 {5, 24},/* 3 */
2492 {5, 16},/* 4 */
2493 {5, 0}, /* 5 */
2494 {5, 1}, /* 6 */
2495 {5, 3}, /* 7 */
2496 {5, 7}, /* 8 */
2497 {5, 15},/* 9 */
2498 {6, 7}, /* : */
2499 {6, 21},/* ; */
2500 {0, 0},
2501 {5, 33},/* = */
2502 {0, 0},
2503 {6, 12},/* ? */
2504 {0, 0},
2505 {2, 2}, /* A */
2506 {4, 1}, /* B */
2507 {4, 5}, /* C */
2508 {3, 1}, /* D */
2509 {1, 0}, /* E */
2510 {4, 4}, /* F */
2511 {3, 3}, /* G */
2512 {4, 0}, /* H */
2513 {2, 0}, /* I */
2514 {4, 14},/* J */
2515 {3, 5}, /* K */
2516 {4, 2}, /* L */
2517 {2, 3}, /* M */
2518 {2, 1}, /* N */
2519 {3, 7}, /* O */
2520 {4, 6}, /* P */
2521 {4, 11},/* Q */
2522 {3, 2}, /* R */
2523 {3, 0}, /* S */
2524 {1, 1}, /* T */
2525 {3, 4}, /* U */
2526 {4, 8}, /* V */
2527 {3, 6}, /* W */
2528 {4, 9}, /* X */
2529 {4, 13},/* Y */
2530 {4, 3} /* Z */
2534 int dottime;
2535 int dashtime;
2536 int intralettertime;
2537 int interlettertime;
2538 int interwordtime;
2539 int len, ddcomb;
2540 int res;
2541 int c;
2542 int i;
2543 int flags;
2545 res = 0;
2547 /* Approximate the dot time from the speed arg. */
2549 dottime = 900/speed;
2551 /* Establish timing releationships */
2553 dashtime = 3 * dottime;
2554 intralettertime = dottime;
2555 interlettertime = dottime * 4 ;
2556 interwordtime = dottime * 7;
2558 for(;(*string) && (!res); string++){
2560 c = *string;
2562 /* Convert lower case to upper case */
2564 if((c >= 'a') && (c <= 'z'))
2565 c -= 0x20;
2567 /* Can't deal with any char code greater than Z, skip it */
2569 if(c > 'Z')
2570 continue;
2572 /* If space char, wait the inter word time */
2574 if(c == ' '){
2575 if(!res)
2576 res = play_silence(chan, interwordtime);
2577 continue;
2580 /* Subtract out control char offset to match our table */
2582 c -= 0x20;
2584 /* Get the character data */
2586 len = mbits[c].len;
2587 ddcomb = mbits[c].ddcomb;
2589 /* Send the character */
2591 for(; len ; len--){
2592 if(!res)
2593 res = play_tone(chan, freq, (ddcomb & 1) ? dashtime : dottime, amplitude);
2594 if(!res)
2595 res = play_silence(chan, intralettertime);
2596 ddcomb >>= 1;
2599 /* Wait the interletter time */
2601 if(!res)
2602 res = play_silence(chan, interlettertime - intralettertime);
2605 /* Wait for all the frames to be sent */
2607 if (!res)
2608 res = ast_waitstream(chan, "");
2609 ast_stopstream(chan);
2612 * Wait for the zaptel driver to physically write the tone blocks to the hardware
2615 for(i = 0; i < 20 ; i++){
2616 flags = ZT_IOMUX_WRITEEMPTY | ZT_IOMUX_NOWAIT;
2617 res = ioctl(chan->fds[0], ZT_IOMUX, &flags);
2618 if(flags & ZT_IOMUX_WRITEEMPTY)
2619 break;
2620 if( ast_safe_sleep(chan, 50)){
2621 res = -1;
2622 break;
2627 return res;
2630 static int send_tone_telemetry(struct ast_channel *chan, char *tonestring)
2632 char *stringp;
2633 char *tonesubset;
2634 int f1,f2;
2635 int duration;
2636 int amplitude;
2637 int res;
2638 int i;
2639 int flags;
2641 res = 0;
2643 stringp = ast_strdupa(tonestring);
2645 for(;tonestring;){
2646 tonesubset = strsep(&stringp,")");
2647 if(!tonesubset)
2648 break;
2649 if(sscanf(tonesubset,"(%d,%d,%d,%d", &f1, &f2, &duration, &amplitude) != 4)
2650 break;
2651 res = play_tone_pair(chan, f1, f2, duration, amplitude);
2652 if(res)
2653 break;
2655 if(!res)
2656 res = play_tone_pair(chan, 0, 0, 100, 0); /* This is needed to ensure the last tone segment is timed correctly */
2658 if (!res)
2659 res = ast_waitstream(chan, "");
2660 ast_stopstream(chan);
2663 * Wait for the zaptel driver to physically write the tone blocks to the hardware
2666 for(i = 0; i < 20 ; i++){
2667 flags = ZT_IOMUX_WRITEEMPTY | ZT_IOMUX_NOWAIT;
2668 res = ioctl(chan->fds[0], ZT_IOMUX, &flags);
2669 if(flags & ZT_IOMUX_WRITEEMPTY)
2670 break;
2671 if( ast_safe_sleep(chan, 50)){
2672 res = -1;
2673 break;
2677 return res;
2681 static int sayfile(struct ast_channel *mychannel,char *fname)
2683 int res;
2685 res = ast_streamfile(mychannel, fname, mychannel->language);
2686 if (!res)
2687 res = ast_waitstream(mychannel, "");
2688 else
2689 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2690 ast_stopstream(mychannel);
2691 return res;
2694 static int saycharstr(struct ast_channel *mychannel,char *str)
2696 int res;
2698 res = ast_say_character_str(mychannel,str,NULL,mychannel->language);
2699 if (!res)
2700 res = ast_waitstream(mychannel, "");
2701 else
2702 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2703 ast_stopstream(mychannel);
2704 return res;
2707 static int saynum(struct ast_channel *mychannel, int num)
2709 int res;
2710 res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
2711 if(!res)
2712 res = ast_waitstream(mychannel, "");
2713 else
2714 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
2715 ast_stopstream(mychannel);
2716 return res;
2720 static int telem_any(struct rpt *myrpt,struct ast_channel *chan, char *entry)
2722 int res;
2723 char c;
2725 static int morsespeed;
2726 static int morsefreq;
2727 static int morseampl;
2728 static int morseidfreq = 0;
2729 static int morseidampl;
2730 static char mcat[] = MORSE;
2732 res = 0;
2734 if(!morseidfreq){ /* Get the morse parameters if not already loaded */
2735 morsespeed = retrieve_astcfgint(myrpt, mcat, "speed", 5, 20, 20);
2736 morsefreq = retrieve_astcfgint(myrpt, mcat, "frequency", 300, 3000, 800);
2737 morseampl = retrieve_astcfgint(myrpt, mcat, "amplitude", 200, 8192, 4096);
2738 morseidampl = retrieve_astcfgint(myrpt, mcat, "idamplitude", 200, 8192, 2048);
2739 morseidfreq = retrieve_astcfgint(myrpt, mcat, "idfrequency", 300, 3000, 330);
2742 /* Is it a file, or a tone sequence? */
2744 if(entry[0] == '|'){
2745 c = entry[1];
2746 if((c >= 'a')&&(c <= 'z'))
2747 c -= 0x20;
2749 switch(c){
2750 case 'I': /* Morse ID */
2751 res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
2752 break;
2754 case 'M': /* Morse Message */
2755 res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
2756 break;
2758 case 'T': /* Tone sequence */
2759 res = send_tone_telemetry(chan, entry + 2);
2760 break;
2761 default:
2762 res = -1;
2765 else
2766 res = sayfile(chan, entry); /* File */
2767 return res;
2771 * This function looks up a telemetry name in the config file, and does a telemetry response as configured.
2773 * 4 types of telemtry are handled: Morse ID, Morse Message, Tone Sequence, and a File containing a recording.
2776 static int telem_lookup(struct rpt *myrpt,struct ast_channel *chan, char *node, char *name)
2779 int res;
2780 int i;
2781 char *entry;
2782 char *telemetry;
2783 char *telemetry_save;
2785 res = 0;
2786 telemetry_save = NULL;
2787 entry = NULL;
2789 /* Retrieve the section name for telemetry from the node section */
2790 telemetry = (char *) ast_variable_retrieve(myrpt->cfg, node, TELEMETRY);
2791 if(telemetry ){
2792 telemetry_save = ast_strdupa(telemetry);
2793 if(!telemetry_save){
2794 ast_log(LOG_WARNING,"ast_strdupa() failed in telem_lookup()\n");
2795 return res;
2797 entry = (char *) ast_variable_retrieve(myrpt->cfg, telemetry_save, name);
2800 /* Try to look up the telemetry name */
2802 if(!entry){
2803 /* Telemetry name wasn't found in the config file, use the default */
2804 for(i = 0; i < sizeof(tele_defs)/sizeof(struct telem_defaults) ; i++){
2805 if(!strcasecmp(tele_defs[i].name, name))
2806 entry = tele_defs[i].value;
2809 if(entry){
2810 if(strlen(entry))
2811 telem_any(myrpt,chan, entry);
2813 else{
2814 res = -1;
2816 return res;
2820 * Retrieve a wait interval
2823 static int get_wait_interval(struct rpt *myrpt, int type)
2825 int interval;
2826 char *wait_times;
2827 char *wait_times_save;
2829 wait_times_save = NULL;
2830 wait_times = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
2832 if(wait_times){
2833 wait_times_save = ast_strdupa(wait_times);
2834 if(!wait_times_save){
2835 ast_log(LOG_WARNING, "Out of memory in wait_interval()\n");
2836 wait_times = NULL;
2840 switch(type){
2841 case DLY_TELEM:
2842 if(wait_times)
2843 interval = retrieve_astcfgint(myrpt,wait_times_save, "telemwait", 500, 5000, 1000);
2844 else
2845 interval = 1000;
2846 break;
2848 case DLY_ID:
2849 if(wait_times)
2850 interval = retrieve_astcfgint(myrpt,wait_times_save, "idwait",250,5000,500);
2851 else
2852 interval = 500;
2853 break;
2855 case DLY_UNKEY:
2856 if(wait_times)
2857 interval = retrieve_astcfgint(myrpt,wait_times_save, "unkeywait",500,5000,1000);
2858 else
2859 interval = 1000;
2860 break;
2862 case DLY_LINKUNKEY:
2863 if(wait_times)
2864 interval = retrieve_astcfgint(myrpt,wait_times_save, "linkunkeywait",500,5000,1000);
2865 else
2866 interval = 1000;
2867 break;
2869 case DLY_CALLTERM:
2870 if(wait_times)
2871 interval = retrieve_astcfgint(myrpt,wait_times_save, "calltermwait",500,5000,1500);
2872 else
2873 interval = 1500;
2874 break;
2876 case DLY_COMP:
2877 if(wait_times)
2878 interval = retrieve_astcfgint(myrpt,wait_times_save, "compwait",500,5000,200);
2879 else
2880 interval = 200;
2881 break;
2883 default:
2884 return 0;
2886 return interval;
2891 * Wait a configurable interval of time
2895 static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
2897 int interval;
2898 interval = get_wait_interval(myrpt, type);
2899 if(debug)
2900 ast_log(LOG_NOTICE," Delay interval = %d\n", interval);
2901 if(interval)
2902 ast_safe_sleep(chan,interval);
2903 if(debug)
2904 ast_log(LOG_NOTICE,"Delay complete\n");
2905 return;
2908 static int split_freq(char *mhz, char *decimals, char *freq);
2910 static void *rpt_tele_thread(void *this)
2912 ZT_CONFINFO ci; /* conference info */
2913 int res = 0,haslink,hastx,hasremote,imdone = 0, unkeys_queued, x;
2914 struct rpt_tele *mytele = (struct rpt_tele *)this;
2915 struct rpt_tele *tlist;
2916 struct rpt *myrpt;
2917 struct rpt_link *l,*l1,linkbase;
2918 struct ast_channel *mychannel;
2919 int vmajor, vminor, m;
2920 char *p,*ct,*ct_copy,*ident, *nodename,*cp;
2921 time_t t;
2922 struct tm localtm;
2923 char lbuf[MAXLINKLIST],*strs[MAXLINKLIST];
2924 int i,ns,rbimode;
2925 char mhz[MAXREMSTR];
2926 char decimals[MAXREMSTR];
2927 struct zt_params par;
2930 /* get a pointer to myrpt */
2931 myrpt = mytele->rpt;
2933 /* Snag copies of a few key myrpt variables */
2934 rpt_mutex_lock(&myrpt->lock);
2935 nodename = ast_strdupa(myrpt->name);
2936 if (myrpt->p.ident) ident = ast_strdupa(myrpt->p.ident);
2937 else ident = "";
2938 rpt_mutex_unlock(&myrpt->lock);
2940 /* allocate a pseudo-channel thru asterisk */
2941 mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
2942 if (!mychannel)
2944 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
2945 rpt_mutex_lock(&myrpt->lock);
2946 remque((struct qelem *)mytele);
2947 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
2948 rpt_mutex_unlock(&myrpt->lock);
2949 free(mytele);
2950 pthread_exit(NULL);
2952 #ifdef AST_CDR_FLAG_POST_DISABLED
2953 ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
2954 #endif
2955 rpt_mutex_lock(&myrpt->lock);
2956 mytele->chan = mychannel;
2957 rpt_mutex_unlock(&myrpt->lock);
2958 /* make a conference for the tx */
2959 ci.chan = 0;
2960 /* If there's an ID queued, or tail message queued, */
2961 /* only connect the ID audio to the local tx conference so */
2962 /* linked systems can't hear it */
2963 ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) ||
2964 (mytele->mode == TAILMSG) || (mytele->mode == LINKUNKEY)) || (mytele->mode == TIMEOUT) ?
2965 myrpt->txconf : myrpt->conf);
2966 ci.confmode = ZT_CONF_CONFANN;
2967 /* first put the channel on the conference in announce mode */
2968 if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
2970 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
2971 rpt_mutex_lock(&myrpt->lock);
2972 remque((struct qelem *)mytele);
2973 rpt_mutex_unlock(&myrpt->lock);
2974 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
2975 free(mytele);
2976 ast_hangup(mychannel);
2977 pthread_exit(NULL);
2979 ast_stopstream(mychannel);
2980 switch(mytele->mode)
2982 case ID:
2983 case ID1:
2984 /* wait a bit */
2985 wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM,mychannel);
2986 res = telem_any(myrpt,mychannel, ident);
2987 imdone=1;
2988 break;
2990 case TAILMSG:
2991 res = ast_streamfile(mychannel, myrpt->p.tailmessages[myrpt->tailmessagen], mychannel->language);
2992 break;
2994 case IDTALKOVER:
2995 p = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "idtalkover");
2996 if(p)
2997 res = telem_any(myrpt,mychannel, p);
2998 imdone=1;
2999 break;
3001 case PROC:
3002 /* wait a little bit longer */
3003 wait_interval(myrpt, DLY_TELEM, mychannel);
3004 res = telem_lookup(myrpt, mychannel, myrpt->name, "patchup");
3005 if(res < 0){ /* Then default message */
3006 res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
3008 break;
3009 case TERM:
3010 /* wait a little bit longer */
3011 wait_interval(myrpt, DLY_CALLTERM, mychannel);
3012 res = telem_lookup(myrpt, mychannel, myrpt->name, "patchdown");
3013 if(res < 0){ /* Then default message */
3014 res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
3016 break;
3017 case COMPLETE:
3018 /* wait a little bit */
3019 wait_interval(myrpt, DLY_TELEM, mychannel);
3020 res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
3021 break;
3022 case MACRO_NOTFOUND:
3023 /* wait a little bit */
3024 wait_interval(myrpt, DLY_TELEM, mychannel);
3025 res = ast_streamfile(mychannel, "rpt/macro_notfound", mychannel->language);
3026 break;
3027 case MACRO_BUSY:
3028 /* wait a little bit */
3029 wait_interval(myrpt, DLY_TELEM, mychannel);
3030 res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
3031 break;
3032 case UNKEY:
3033 if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
3034 imdone = 1;
3035 break;
3039 * Reset the Unkey to CT timer
3042 x = get_wait_interval(myrpt, DLY_UNKEY);
3043 rpt_mutex_lock(&myrpt->lock);
3044 myrpt->unkeytocttimer = x; /* Must be protected as it is changed below */
3045 rpt_mutex_unlock(&myrpt->lock);
3048 * If there's one already queued, don't do another
3051 tlist = myrpt->tele.next;
3052 unkeys_queued = 0;
3053 if (tlist != &myrpt->tele)
3055 rpt_mutex_lock(&myrpt->lock);
3056 while(tlist != &myrpt->tele){
3057 if (tlist->mode == UNKEY) unkeys_queued++;
3058 tlist = tlist->next;
3060 rpt_mutex_unlock(&myrpt->lock);
3062 if( unkeys_queued > 1){
3063 imdone = 1;
3064 break;
3067 /* Wait for the telemetry timer to expire */
3068 /* Periodically check the timer since it can be re-initialized above */
3069 while(myrpt->unkeytocttimer)
3071 int ctint;
3072 if(myrpt->unkeytocttimer > 100)
3073 ctint = 100;
3074 else
3075 ctint = myrpt->unkeytocttimer;
3076 ast_safe_sleep(mychannel, ctint);
3077 rpt_mutex_lock(&myrpt->lock);
3078 if(myrpt->unkeytocttimer < ctint)
3079 myrpt->unkeytocttimer = 0;
3080 else
3081 myrpt->unkeytocttimer -= ctint;
3082 rpt_mutex_unlock(&myrpt->lock);
3086 * Now, the carrier on the rptr rx should be gone.
3087 * If it re-appeared, then forget about sending the CT
3089 if(myrpt->keyed){
3090 imdone = 1;
3091 break;
3094 rpt_mutex_lock(&myrpt->lock); /* Update the kerchunk counters */
3095 myrpt->dailykerchunks++;
3096 myrpt->totalkerchunks++;
3097 rpt_mutex_unlock(&myrpt->lock);
3099 haslink = 0;
3100 hastx = 0;
3101 hasremote = 0;
3102 l = myrpt->links.next;
3103 if (l != &myrpt->links)
3105 rpt_mutex_lock(&myrpt->lock);
3106 while(l != &myrpt->links)
3108 if (l->name[0] == '0')
3110 l = l->next;
3111 continue;
3113 haslink = 1;
3114 if (l->mode) {
3115 hastx++;
3116 if (l->isremote) hasremote++;
3118 l = l->next;
3120 rpt_mutex_unlock(&myrpt->lock);
3122 if (haslink)
3125 res = telem_lookup(myrpt,mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
3126 if(res)
3127 ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
3130 /* if in remote cmd mode, indicate it */
3131 if (myrpt->cmdnode[0])
3133 ast_safe_sleep(mychannel,200);
3134 res = telem_lookup(myrpt,mychannel, myrpt->name, "cmdmode");
3135 if(res)
3136 ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
3137 ast_stopstream(mychannel);
3140 else if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "unlinkedct"))){ /* Unlinked Courtesy Tone */
3141 ct_copy = ast_strdupa(ct);
3142 res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
3143 if(res)
3144 ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);
3146 if (hasremote && (!myrpt->cmdnode[0]))
3148 /* set for all to hear */
3149 ci.chan = 0;
3150 ci.confno = myrpt->conf;
3151 ci.confmode = ZT_CONF_CONFANN;
3152 /* first put the channel on the conference in announce mode */
3153 if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
3155 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
3156 rpt_mutex_lock(&myrpt->lock);
3157 remque((struct qelem *)mytele);
3158 rpt_mutex_unlock(&myrpt->lock);
3159 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
3160 free(mytele);
3161 ast_hangup(mychannel);
3162 pthread_exit(NULL);
3164 if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "remotect"))){ /* Unlinked Courtesy Tone */
3165 ast_safe_sleep(mychannel,200);
3166 ct_copy = ast_strdupa(ct);
3167 res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
3168 if(res)
3169 ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);
3172 #if defined(_MDC_DECODE_H_) && defined(MDC_SAY_WHEN_DOING_CT)
3173 if (myrpt->lastunit)
3175 char mystr[10];
3177 ast_safe_sleep(mychannel,200);
3178 /* set for all to hear */
3179 ci.chan = 0;
3180 ci.confno = myrpt->txconf;
3181 ci.confmode = ZT_CONF_CONFANN;
3182 /* first put the channel on the conference in announce mode */
3183 if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
3185 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
3186 rpt_mutex_lock(&myrpt->lock);
3187 remque((struct qelem *)mytele);
3188 rpt_mutex_unlock(&myrpt->lock);
3189 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
3190 free(mytele);
3191 ast_hangup(mychannel);
3192 pthread_exit(NULL);
3194 sprintf(mystr,"%04x",myrpt->lastunit);
3195 myrpt->lastunit = 0;
3196 ast_say_character_str(mychannel,mystr,NULL,mychannel->language);
3197 break;
3199 #endif
3200 imdone = 1;
3201 break;
3202 case LINKUNKEY:
3203 if(myrpt->patchnoct && myrpt->callmode){ /* If no CT during patch configured, then don't send one */
3204 imdone = 1;
3205 break;
3209 * Reset the Unkey to CT timer
3212 x = get_wait_interval(myrpt, DLY_LINKUNKEY);
3213 mytele->mylink.linkunkeytocttimer = x; /* Must be protected as it is changed below */
3216 * If there's one already queued, don't do another
3219 tlist = myrpt->tele.next;
3220 unkeys_queued = 0;
3221 if (tlist != &myrpt->tele)
3223 rpt_mutex_lock(&myrpt->lock);
3224 while(tlist != &myrpt->tele){
3225 if (tlist->mode == LINKUNKEY) unkeys_queued++;
3226 tlist = tlist->next;
3228 rpt_mutex_unlock(&myrpt->lock);
3230 if( unkeys_queued > 1){
3231 imdone = 1;
3232 break;
3235 /* Wait for the telemetry timer to expire */
3236 /* Periodically check the timer since it can be re-initialized above */
3237 while(mytele->mylink.linkunkeytocttimer)
3239 int ctint;
3240 if(mytele->mylink.linkunkeytocttimer > 100)
3241 ctint = 100;
3242 else
3243 ctint = mytele->mylink.linkunkeytocttimer;
3244 ast_safe_sleep(mychannel, ctint);
3245 rpt_mutex_lock(&myrpt->lock);
3246 if(mytele->mylink.linkunkeytocttimer < ctint)
3247 mytele->mylink.linkunkeytocttimer = 0;
3248 else
3249 mytele->mylink.linkunkeytocttimer -= ctint;
3250 rpt_mutex_unlock(&myrpt->lock);
3253 if((ct = (char *) ast_variable_retrieve(myrpt->cfg, nodename, "linkunkeyct"))){ /* Unlinked Courtesy Tone */
3254 ct_copy = ast_strdupa(ct);
3255 res = telem_lookup(myrpt,mychannel, myrpt->name, ct_copy);
3256 if(res)
3257 ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);
3259 imdone = 1;
3260 break;
3261 case REMDISC:
3262 /* wait a little bit */
3263 wait_interval(myrpt, DLY_TELEM, mychannel);
3264 l = myrpt->links.next;
3265 haslink = 0;
3266 /* dont report if a link for this one still on system */
3267 if (l != &myrpt->links)
3269 rpt_mutex_lock(&myrpt->lock);
3270 while(l != &myrpt->links)
3272 if (l->name[0] == '0')
3274 l = l->next;
3275 continue;
3277 if (!strcmp(l->name,mytele->mylink.name))
3279 haslink = 1;
3280 break;
3282 l = l->next;
3284 rpt_mutex_unlock(&myrpt->lock);
3286 if (haslink)
3288 imdone = 1;
3289 break;
3291 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3292 if (!res)
3293 res = ast_waitstream(mychannel, "");
3294 else
3295 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3296 ast_stopstream(mychannel);
3297 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
3298 res = ast_streamfile(mychannel, ((mytele->mylink.hasconnected) ?
3299 "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
3300 break;
3301 case REMALREADY:
3302 /* wait a little bit */
3303 wait_interval(myrpt, DLY_TELEM, mychannel);
3304 res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
3305 break;
3306 case REMNOTFOUND:
3307 /* wait a little bit */
3308 wait_interval(myrpt, DLY_TELEM, mychannel);
3309 res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
3310 break;
3311 case REMGO:
3312 /* wait a little bit */
3313 wait_interval(myrpt, DLY_TELEM, mychannel);
3314 res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
3315 break;
3316 case CONNECTED:
3317 /* wait a little bit */
3318 wait_interval(myrpt, DLY_TELEM, mychannel);
3319 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3320 if (!res)
3321 res = ast_waitstream(mychannel, "");
3322 else
3323 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3324 ast_stopstream(mychannel);
3325 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
3326 res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
3327 if (!res)
3328 res = ast_waitstream(mychannel, "");
3329 else
3330 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3331 ast_stopstream(mychannel);
3332 res = ast_streamfile(mychannel, "digits/2", mychannel->language);
3333 if (!res)
3334 res = ast_waitstream(mychannel, "");
3335 else
3336 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3337 ast_stopstream(mychannel);
3338 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3339 if (!res)
3340 res = ast_waitstream(mychannel, "");
3341 else
3342 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3343 ast_stopstream(mychannel);
3344 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
3345 imdone = 1;
3346 break;
3347 case CONNFAIL:
3348 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3349 if (!res)
3350 res = ast_waitstream(mychannel, "");
3351 else
3352 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3353 ast_stopstream(mychannel);
3354 ast_say_character_str(mychannel,mytele->mylink.name,NULL,mychannel->language);
3355 res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
3356 break;
3357 case MEMNOTFOUND:
3358 /* wait a little bit */
3359 wait_interval(myrpt, DLY_TELEM, mychannel);
3360 res = ast_streamfile(mychannel, "rpt/memory_notfound", mychannel->language);
3361 break;
3362 case SETREMOTE:
3363 ast_mutex_lock(&myrpt->remlock);
3364 res = 0;
3365 if(!strcmp(myrpt->remote, remote_rig_ft897))
3367 res = set_ft897(myrpt);
3369 if(!strcmp(myrpt->remote, remote_rig_ic706))
3371 res = set_ic706(myrpt);
3373 else if(!strcmp(myrpt->remote, remote_rig_rbi))
3375 if (ioperm(myrpt->p.iobase,1,1) == -1)
3377 rpt_mutex_unlock(&myrpt->lock);
3378 ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
3379 res = -1;
3381 else res = setrbi(myrpt);
3383 else if(!strcmp(myrpt->remote, remote_rig_kenwood))
3385 res = setkenwood(myrpt);
3386 if (ast_safe_sleep(mychannel,200) == -1)
3388 ast_mutex_unlock(&myrpt->remlock);
3389 res = -1;
3390 break;
3392 i = ZT_FLUSH_EVENT;
3393 if (ioctl(myrpt->zaptxchannel->fds[0],ZT_FLUSH,&i) == -1)
3395 ast_mutex_unlock(&myrpt->remlock);
3396 ast_log(LOG_ERROR,"Cant flush events");
3397 res = -1;
3398 break;
3400 if (ioctl(myrpt->zaprxchannel->fds[0],ZT_GET_PARAMS,&par) == -1)
3402 ast_mutex_unlock(&myrpt->remlock);
3403 ast_log(LOG_ERROR,"Cant get params");
3404 res = -1;
3405 break;
3407 myrpt->remoterx =
3408 (par.rxisoffhook || (myrpt->tele.next != &myrpt->tele));
3410 ast_mutex_unlock(&myrpt->remlock);
3411 if (!res)
3413 imdone = 1;
3414 break;
3416 /* fall thru to invalid freq */
3417 case INVFREQ:
3418 /* wait a little bit */
3419 wait_interval(myrpt, DLY_TELEM, mychannel);
3420 res = ast_streamfile(mychannel, "rpt/invalid-freq", mychannel->language);
3421 break;
3422 case REMMODE:
3423 cp = 0;
3424 wait_interval(myrpt, DLY_TELEM, mychannel);
3425 switch(myrpt->remmode)
3427 case REM_MODE_FM:
3428 saycharstr(mychannel,"FM");
3429 break;
3430 case REM_MODE_USB:
3431 saycharstr(mychannel,"USB");
3432 break;
3433 case REM_MODE_LSB:
3434 saycharstr(mychannel,"LSB");
3435 break;
3436 case REM_MODE_AM:
3437 saycharstr(mychannel,"AM");
3438 break;
3440 wait_interval(myrpt, DLY_COMP, mychannel);
3441 if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
3442 break;
3443 case LOGINREQ:
3444 wait_interval(myrpt, DLY_TELEM, mychannel);
3445 sayfile(mychannel,"rpt/login");
3446 saycharstr(mychannel,myrpt->name);
3447 break;
3448 case REMLOGIN:
3449 wait_interval(myrpt, DLY_TELEM, mychannel);
3450 saycharstr(mychannel,myrpt->loginuser);
3451 sayfile(mychannel,"rpt/node");
3452 saycharstr(mychannel,myrpt->name);
3453 wait_interval(myrpt, DLY_COMP, mychannel);
3454 if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
3455 break;
3456 case REMXXX:
3457 wait_interval(myrpt, DLY_TELEM, mychannel);
3458 res = 0;
3459 switch(mytele->submode)
3461 case 100: /* RX PL Off */
3462 sayfile(mychannel, "rpt/rxpl");
3463 sayfile(mychannel, "rpt/off");
3464 break;
3465 case 101: /* RX PL On */
3466 sayfile(mychannel, "rpt/rxpl");
3467 sayfile(mychannel, "rpt/on");
3468 break;
3469 case 102: /* TX PL Off */
3470 sayfile(mychannel, "rpt/txpl");
3471 sayfile(mychannel, "rpt/off");
3472 break;
3473 case 103: /* TX PL On */
3474 sayfile(mychannel, "rpt/txpl");
3475 sayfile(mychannel, "rpt/on");
3476 break;
3477 case 104: /* Low Power */
3478 sayfile(mychannel, "rpt/lopwr");
3479 break;
3480 case 105: /* Medium Power */
3481 sayfile(mychannel, "rpt/medpwr");
3482 break;
3483 case 106: /* Hi Power */
3484 sayfile(mychannel, "rpt/hipwr");
3485 break;
3486 case 113: /* Scan down slow */
3487 sayfile(mychannel,"rpt/down");
3488 sayfile(mychannel, "rpt/slow");
3489 break;
3490 case 114: /* Scan down quick */
3491 sayfile(mychannel,"rpt/down");
3492 sayfile(mychannel, "rpt/quick");
3493 break;
3494 case 115: /* Scan down fast */
3495 sayfile(mychannel,"rpt/down");
3496 sayfile(mychannel, "rpt/fast");
3497 break;
3498 case 116: /* Scan up slow */
3499 sayfile(mychannel,"rpt/up");
3500 sayfile(mychannel, "rpt/slow");
3501 break;
3502 case 117: /* Scan up quick */
3503 sayfile(mychannel,"rpt/up");
3504 sayfile(mychannel, "rpt/quick");
3505 break;
3506 case 118: /* Scan up fast */
3507 sayfile(mychannel,"rpt/up");
3508 sayfile(mychannel, "rpt/fast");
3509 break;
3510 default:
3511 res = -1;
3513 wait_interval(myrpt, DLY_COMP, mychannel);
3514 if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
3515 break;
3516 case SCAN:
3517 ast_mutex_lock(&myrpt->remlock);
3518 if (myrpt->hfscanstop)
3520 myrpt->hfscanstatus = 0;
3521 myrpt->hfscanmode = 0;
3522 myrpt->hfscanstop = 0;
3523 mytele->mode = SCANSTAT;
3524 ast_mutex_unlock(&myrpt->remlock);
3525 if (ast_safe_sleep(mychannel,1000) == -1) break;
3526 sayfile(mychannel, "rpt/stop");
3527 imdone = 1;
3528 break;
3530 if (myrpt->hfscanstatus > -2) service_scan(myrpt);
3531 i = myrpt->hfscanstatus;
3532 myrpt->hfscanstatus = 0;
3533 if (i) mytele->mode = SCANSTAT;
3534 ast_mutex_unlock(&myrpt->remlock);
3535 if (i < 0) sayfile(mychannel, "rpt/stop");
3536 else if (i > 0) saynum(mychannel,i);
3537 imdone = 1;
3538 break;
3539 case TUNE:
3540 ast_mutex_lock(&myrpt->remlock);
3541 if (!strcmp(myrpt->remote,remote_rig_ic706))
3543 set_mode_ic706(myrpt, REM_MODE_AM);
3544 if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
3545 ast_safe_sleep(mychannel,500);
3546 set_mode_ic706(myrpt, myrpt->remmode);
3547 myrpt->tunerequest = 0;
3548 ast_mutex_unlock(&myrpt->remlock);
3549 imdone = 1;
3550 break;
3552 set_mode_ft897(myrpt, REM_MODE_AM);
3553 simple_command_ft897(myrpt, 8);
3554 if(play_tone(mychannel, 800, 6000, 8192) == -1) break;
3555 simple_command_ft897(myrpt, 0x88);
3556 ast_safe_sleep(mychannel,500);
3557 set_mode_ft897(myrpt, myrpt->remmode);
3558 myrpt->tunerequest = 0;
3559 ast_mutex_unlock(&myrpt->remlock);
3560 imdone = 1;
3561 break;
3562 case REMSHORTSTATUS:
3563 case REMLONGSTATUS:
3564 wait_interval(myrpt, DLY_TELEM, mychannel);
3565 res = sayfile(mychannel,"rpt/node");
3566 if(!res)
3567 res = saycharstr(mychannel, myrpt->name);
3568 if(!res)
3569 res = sayfile(mychannel,"rpt/frequency");
3570 if(!res)
3571 res = split_freq(mhz, decimals, myrpt->freq);
3572 if (!multimode_capable(myrpt)) decimals[3] = 0;
3573 if(!res){
3574 m = atoi(mhz);
3575 if(m < 100)
3576 res = saynum(mychannel, m);
3577 else
3578 res = saycharstr(mychannel, mhz);
3580 if(!res)
3581 res = sayfile(mychannel, "letters/dot");
3582 if(!res)
3583 res = saycharstr(mychannel, decimals);
3585 if(res) break;
3586 if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
3587 switch(myrpt->offset){
3589 case REM_MINUS:
3590 res = sayfile(mychannel,"rpt/minus");
3591 break;
3593 case REM_SIMPLEX:
3594 res = sayfile(mychannel,"rpt/simplex");
3595 break;
3597 case REM_PLUS:
3598 res = sayfile(mychannel,"rpt/plus");
3599 break;
3601 default:
3602 break;
3605 else{ /* Must be USB, LSB, or AM */
3606 switch(myrpt->remmode){
3608 case REM_MODE_USB:
3609 res = saycharstr(mychannel, "USB");
3610 break;
3612 case REM_MODE_LSB:
3613 res = saycharstr(mychannel, "LSB");
3614 break;
3616 case REM_MODE_AM:
3617 res = saycharstr(mychannel, "AM");
3618 break;
3621 default:
3622 break;
3626 if (res == -1) break;
3628 if(mytele->mode == REMSHORTSTATUS){ /* Short status? */
3629 wait_interval(myrpt, DLY_COMP, mychannel);
3630 if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
3631 break;
3634 if (strcmp(myrpt->remote,remote_rig_ic706))
3636 switch(myrpt->powerlevel){
3638 case REM_LOWPWR:
3639 res = sayfile(mychannel,"rpt/lopwr") ;
3640 break;
3641 case REM_MEDPWR:
3642 res = sayfile(mychannel,"rpt/medpwr");
3643 break;
3644 case REM_HIPWR:
3645 res = sayfile(mychannel,"rpt/hipwr");
3646 break;
3650 rbimode = ((!strncmp(myrpt->remote,remote_rig_rbi,3))
3651 || (!strncmp(myrpt->remote,remote_rig_ic706,3)));
3652 if (res || (sayfile(mychannel,"rpt/rxpl") == -1)) break;
3653 if (rbimode && (sayfile(mychannel,"rpt/txpl") == -1)) break;
3654 if ((sayfile(mychannel,"rpt/frequency") == -1) ||
3655 (saycharstr(mychannel,myrpt->rxpl) == -1)) break;
3656 if ((!rbimode) && ((sayfile(mychannel,"rpt/txpl") == -1) ||
3657 (sayfile(mychannel,"rpt/frequency") == -1) ||
3658 (saycharstr(mychannel,myrpt->txpl) == -1))) break;
3659 if(myrpt->remmode == REM_MODE_FM){ /* Mode FM? */
3660 if ((sayfile(mychannel,"rpt/rxpl") == -1) ||
3661 (sayfile(mychannel,((myrpt->rxplon) ? "rpt/on" : "rpt/off")) == -1) ||
3662 (sayfile(mychannel,"rpt/txpl") == -1) ||
3663 (sayfile(mychannel,((myrpt->txplon) ? "rpt/on" : "rpt/off")) == -1))
3665 break;
3668 wait_interval(myrpt, DLY_COMP, mychannel);
3669 if (!res) res = telem_lookup(myrpt,mychannel, myrpt->name, "functcomplete");
3670 break;
3671 case STATUS:
3672 /* wait a little bit */
3673 wait_interval(myrpt, DLY_TELEM, mychannel);
3674 hastx = 0;
3675 linkbase.next = &linkbase;
3676 linkbase.prev = &linkbase;
3677 rpt_mutex_lock(&myrpt->lock);
3678 /* make our own list of links */
3679 l = myrpt->links.next;
3680 while(l != &myrpt->links)
3682 if (l->name[0] == '0')
3684 l = l->next;
3685 continue;
3687 l1 = malloc(sizeof(struct rpt_link));
3688 if (!l1)
3690 ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
3691 remque((struct qelem *)mytele);
3692 rpt_mutex_unlock(&myrpt->lock);
3693 ast_log(LOG_NOTICE,"Telemetry thread aborted at line %d, mode: %d\n",__LINE__, mytele->mode); /*@@@@@@@@@@@*/
3694 free(mytele);
3695 ast_hangup(mychannel);
3696 pthread_exit(NULL);
3698 memcpy(l1,l,sizeof(struct rpt_link));
3699 l1->next = l1->prev = NULL;
3700 insque((struct qelem *)l1,(struct qelem *)linkbase.next);
3701 l = l->next;
3703 rpt_mutex_unlock(&myrpt->lock);
3704 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3705 if (!res)
3706 res = ast_waitstream(mychannel, "");
3707 else
3708 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3709 ast_stopstream(mychannel);
3710 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
3711 if (!res)
3712 res = ast_waitstream(mychannel, "");
3713 else
3714 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3715 ast_stopstream(mychannel);
3716 if (myrpt->callmode)
3718 hastx = 1;
3719 res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
3720 if (!res)
3721 res = ast_waitstream(mychannel, "");
3722 else
3723 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3724 ast_stopstream(mychannel);
3726 l = linkbase.next;
3727 while(l != &linkbase)
3729 char *s;
3731 hastx = 1;
3732 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3733 if (!res)
3734 res = ast_waitstream(mychannel, "");
3735 else
3736 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3737 ast_stopstream(mychannel);
3738 ast_say_character_str(mychannel,l->name,NULL,mychannel->language);
3739 if (!res)
3740 res = ast_waitstream(mychannel, "");
3741 else
3742 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3743 ast_stopstream(mychannel);
3744 s = "rpt/tranceive";
3745 if (!l->mode) s = "rpt/monitor";
3746 if (!l->thisconnected) s = "rpt/connecting";
3747 res = ast_streamfile(mychannel, s, mychannel->language);
3748 if (!res)
3749 res = ast_waitstream(mychannel, "");
3750 else
3751 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3752 ast_stopstream(mychannel);
3753 l = l->next;
3755 if (!hastx)
3757 res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
3758 if (!res)
3759 res = ast_waitstream(mychannel, "");
3760 else
3761 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3762 ast_stopstream(mychannel);
3764 /* destroy our local link queue */
3765 l = linkbase.next;
3766 while(l != &linkbase)
3768 l1 = l;
3769 l = l->next;
3770 remque((struct qelem *)l1);
3771 free(l1);
3773 imdone = 1;
3774 break;
3775 case FULLSTATUS:
3776 rpt_mutex_lock(&myrpt->lock);
3777 /* get all the nodes */
3778 __mklinklist(myrpt,NULL,lbuf);
3779 rpt_mutex_unlock(&myrpt->lock);
3780 /* parse em */
3781 ns = finddelim(lbuf,strs,MAXLINKLIST);
3782 /* sort em */
3783 if (ns) qsort((void *)strs,ns,sizeof(char *),mycompar);
3784 /* wait a little bit */
3785 wait_interval(myrpt, DLY_TELEM, mychannel);
3786 hastx = 0;
3787 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3788 if (!res)
3789 res = ast_waitstream(mychannel, "");
3790 else
3791 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3792 ast_stopstream(mychannel);
3793 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
3794 if (!res)
3795 res = ast_waitstream(mychannel, "");
3796 else
3797 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3798 ast_stopstream(mychannel);
3799 if (myrpt->callmode)
3801 hastx = 1;
3802 res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
3803 if (!res)
3804 res = ast_waitstream(mychannel, "");
3805 else
3806 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3807 ast_stopstream(mychannel);
3809 /* go thru all the nodes in list */
3810 for(i = 0; i < ns; i++)
3812 char *s,mode = 'T';
3814 /* if a mode spec at first, handle it */
3815 if ((*strs[i] < '0') || (*strs[i] > '9'))
3817 mode = *strs[i];
3818 strs[i]++;
3821 hastx = 1;
3822 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3823 if (!res)
3824 res = ast_waitstream(mychannel, "");
3825 else
3826 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3827 ast_stopstream(mychannel);
3828 ast_say_character_str(mychannel,strs[i],NULL,mychannel->language);
3829 if (!res)
3830 res = ast_waitstream(mychannel, "");
3831 else
3832 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3833 ast_stopstream(mychannel);
3834 s = "rpt/tranceive";
3835 if (mode == 'R') s = "rpt/monitor";
3836 if (mode == 'C') s = "rpt/connecting";
3837 res = ast_streamfile(mychannel, s, mychannel->language);
3838 if (!res)
3839 res = ast_waitstream(mychannel, "");
3840 else
3841 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3842 ast_stopstream(mychannel);
3844 if (!hastx)
3846 res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
3847 if (!res)
3848 res = ast_waitstream(mychannel, "");
3849 else
3850 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3851 ast_stopstream(mychannel);
3853 imdone = 1;
3854 break;
3856 case LASTNODEKEY: /* Identify last node which keyed us up */
3857 rpt_mutex_lock(&myrpt->lock);
3858 if(myrpt->lastnodewhichkeyedusup)
3859 p = ast_strdupa(myrpt->lastnodewhichkeyedusup); /* Make a local copy of the node name */
3860 else
3861 p = NULL;
3862 rpt_mutex_unlock(&myrpt->lock);
3863 if(!p){
3864 imdone = 1; /* no node previously keyed us up, or the node which did has been disconnected */
3865 break;
3867 wait_interval(myrpt, DLY_TELEM, mychannel);
3868 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3869 if (!res)
3870 res = ast_waitstream(mychannel, "");
3871 else
3872 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3873 ast_stopstream(mychannel);
3874 ast_say_character_str(mychannel, p, NULL, mychannel->language);
3875 if (!res)
3876 res = ast_waitstream(mychannel, "");
3877 else
3878 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3879 ast_stopstream(mychannel);
3880 imdone = 1;
3881 break;
3883 case UNAUTHTX: /* Say unauthorized transmit frequency */
3884 wait_interval(myrpt, DLY_TELEM, mychannel);
3885 res = ast_streamfile(mychannel, "rpt/unauthtx", mychannel->language);
3886 if (!res)
3887 res = ast_waitstream(mychannel, "");
3888 else
3889 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3890 ast_stopstream(mychannel);
3891 imdone = 1;
3892 break;
3895 case TIMEOUT:
3896 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3897 if (!res)
3898 res = ast_waitstream(mychannel, "");
3899 else
3900 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3901 ast_stopstream(mychannel);
3902 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
3903 res = ast_streamfile(mychannel, "rpt/timeout", mychannel->language);
3904 break;
3906 case TIMEOUT_WARNING:
3907 time(&t);
3908 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3909 if (!res)
3910 res = ast_waitstream(mychannel, "");
3911 else
3912 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3913 ast_stopstream(mychannel);
3914 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
3915 res = ast_streamfile(mychannel, "rpt/timeout-warning", mychannel->language);
3916 if (!res)
3917 res = ast_waitstream(mychannel, "");
3918 else
3919 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3920 ast_stopstream(mychannel);
3921 if(!res) /* Say number of seconds */
3922 ast_say_number(mychannel, myrpt->p.remotetimeout -
3923 (t - myrpt->last_activity_time),
3924 "", mychannel->language, (char *) NULL);
3925 if (!res)
3926 res = ast_waitstream(mychannel, "");
3927 ast_stopstream(mychannel);
3928 res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
3929 break;
3931 case ACT_TIMEOUT_WARNING:
3932 time(&t);
3933 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
3934 if (!res)
3935 res = ast_waitstream(mychannel, "");
3936 else
3937 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3938 ast_stopstream(mychannel);
3939 ast_say_character_str(mychannel,myrpt->name,NULL,mychannel->language);
3940 res = ast_streamfile(mychannel, "rpt/act-timeout-warning", mychannel->language);
3941 if (!res)
3942 res = ast_waitstream(mychannel, "");
3943 else
3944 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
3945 ast_stopstream(mychannel);
3946 if(!res) /* Say number of seconds */
3947 ast_say_number(mychannel, myrpt->p.remoteinacttimeout -
3948 (t - myrpt->last_activity_time),
3949 "", mychannel->language, (char *) NULL);
3950 if (!res)
3951 res = ast_waitstream(mychannel, "");
3952 ast_stopstream(mychannel);
3953 res = ast_streamfile(mychannel, "queue-seconds", mychannel->language);
3954 break;
3956 case STATS_TIME:
3957 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
3958 t = time(NULL);
3959 rpt_localtime(&t, &localtm);
3960 /* Say the phase of the day is before the time */
3961 if((localtm.tm_hour >= 0) && (localtm.tm_hour < 12))
3962 p = "rpt/goodmorning";
3963 else if((localtm.tm_hour >= 12) && (localtm.tm_hour < 18))
3964 p = "rpt/goodafternoon";
3965 else
3966 p = "rpt/goodevening";
3967 if (sayfile(mychannel,p) == -1)
3969 imdone = 1;
3970 break;
3972 /* Say the time is ... */
3973 if (sayfile(mychannel,"rpt/thetimeis") == -1)
3975 imdone = 1;
3976 break;
3978 /* Say the time */
3979 res = ast_say_time(mychannel, t, "", mychannel->language);
3980 if (!res)
3981 res = ast_waitstream(mychannel, "");
3982 ast_stopstream(mychannel);
3983 imdone = 1;
3984 break;
3985 case STATS_VERSION:
3986 p = strstr(tdesc, "version");
3987 if(!p)
3988 break;
3989 if(sscanf(p, "version %d.%d", &vmajor, &vminor) != 2)
3990 break;
3991 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
3992 /* Say "version" */
3993 if (sayfile(mychannel,"rpt/version") == -1)
3995 imdone = 1;
3996 break;
3998 if(!res) /* Say "X" */
3999 ast_say_number(mychannel, vmajor, "", mychannel->language, (char *) NULL);
4000 if (!res)
4001 res = ast_waitstream(mychannel, "");
4002 ast_stopstream(mychannel);
4003 if (saycharstr(mychannel,".") == -1)
4005 imdone = 1;
4006 break;
4008 if(!res) /* Say "Y" */
4009 ast_say_number(mychannel, vminor, "", mychannel->language, (char *) NULL);
4010 if (!res){
4011 res = ast_waitstream(mychannel, "");
4012 ast_stopstream(mychannel);
4014 else
4015 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
4016 imdone = 1;
4017 break;
4018 case ARB_ALPHA:
4019 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
4020 if(mytele->param)
4021 saycharstr(mychannel, mytele->param);
4022 imdone = 1;
4023 break;
4024 case REV_PATCH:
4025 wait_interval(myrpt, DLY_TELEM, mychannel); /* Wait a little bit */
4026 if(mytele->param) {
4028 /* Parts of this section taken from app_parkandannounce */
4029 char *tpl_working, *tpl_current;
4030 char *tmp[100], *myparm;
4031 int looptemp=0,i=0, dres = 0;
4034 tpl_working = strdupa(mytele->param);
4035 myparm = strsep(&tpl_working,",");
4036 tpl_current=strsep(&tpl_working, ":");
4038 while(tpl_current && looptemp < sizeof(tmp)) {
4039 tmp[looptemp]=tpl_current;
4040 looptemp++;
4041 tpl_current=strsep(&tpl_working,":");
4044 for(i=0; i<looptemp; i++) {
4045 if(!strcmp(tmp[i], "PARKED")) {
4046 ast_say_digits(mychannel, atoi(myparm), "", mychannel->language);
4047 } else if(!strcmp(tmp[i], "NODE")) {
4048 ast_say_digits(mychannel, atoi(myrpt->name), "", mychannel->language);
4049 } else {
4050 dres = ast_streamfile(mychannel, tmp[i], mychannel->language);
4051 if(!dres) {
4052 dres = ast_waitstream(mychannel, "");
4053 } else {
4054 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], mychannel->name);
4055 dres = 0;
4060 imdone = 1;
4061 break;
4062 case TEST_TONE:
4063 imdone = 1;
4064 if (myrpt->stopgen) break;
4065 myrpt->stopgen = -1;
4066 if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0)))
4068 myrpt->stopgen = 0;
4069 break;
4071 while(mychannel->generatordata && (myrpt->stopgen <= 0)) {
4072 if (ast_safe_sleep(mychannel,1)) break;
4073 imdone = 1;
4075 myrpt->stopgen = 0;
4076 break;
4077 default:
4078 break;
4080 if (!imdone)
4082 if (!res)
4083 res = ast_waitstream(mychannel, "");
4084 else {
4085 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
4086 res = 0;
4089 ast_stopstream(mychannel);
4090 rpt_mutex_lock(&myrpt->lock);
4091 if (mytele->mode == TAILMSG)
4093 if (!res)
4095 myrpt->tailmessagen++;
4096 if(myrpt->tailmessagen >= myrpt->p.tailmessagemax) myrpt->tailmessagen = 0;
4098 else
4100 myrpt->tmsgtimer = myrpt->p.tailsquashedtime;
4103 remque((struct qelem *)mytele);
4104 rpt_mutex_unlock(&myrpt->lock);
4105 free(mytele);
4106 ast_hangup(mychannel);
4107 #ifdef APP_RPT_LOCK_DEBUG
4109 struct lockthread *t;
4111 sleep(5);
4112 ast_mutex_lock(&locklock);
4113 t = get_lockthread(pthread_self());
4114 if (t) memset(t,0,sizeof(struct lockthread));
4115 ast_mutex_unlock(&locklock);
4117 #endif
4118 pthread_exit(NULL);
4121 static void rpt_telemetry(struct rpt *myrpt,int mode, void *data)
4123 struct rpt_tele *tele;
4124 struct rpt_link *mylink = (struct rpt_link *) data;
4125 int res;
4126 pthread_attr_t attr;
4128 tele = malloc(sizeof(struct rpt_tele));
4129 if (!tele)
4131 ast_log(LOG_WARNING, "Unable to allocate memory\n");
4132 pthread_exit(NULL);
4133 return;
4135 /* zero it out */
4136 memset((char *)tele,0,sizeof(struct rpt_tele));
4137 tele->rpt = myrpt;
4138 tele->mode = mode;
4139 rpt_mutex_lock(&myrpt->lock);
4140 if((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED) ||
4141 (mode == LINKUNKEY)){
4142 memset(&tele->mylink,0,sizeof(struct rpt_link));
4143 if (mylink){
4144 memcpy(&tele->mylink,mylink,sizeof(struct rpt_link));
4147 else if ((mode == ARB_ALPHA) || (mode == REV_PATCH)) {
4148 strncpy(tele->param, (char *) data, TELEPARAMSIZE - 1);
4149 tele->param[TELEPARAMSIZE - 1] = 0;
4151 if (mode == REMXXX) tele->submode = (int) data;
4152 insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next);
4153 rpt_mutex_unlock(&myrpt->lock);
4154 pthread_attr_init(&attr);
4155 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
4156 res = ast_pthread_create(&tele->threadid,&attr,rpt_tele_thread,(void *) tele);
4157 if(res < 0){
4158 rpt_mutex_lock(&myrpt->lock);
4159 remque((struct qlem *) tele); /* We don't like stuck transmitters, remove it from the queue */
4160 rpt_mutex_unlock(&myrpt->lock);
4161 ast_log(LOG_WARNING, "Could not create telemetry thread: %s",strerror(res));
4163 return;
4166 static void *rpt_call(void *this)
4168 ZT_CONFINFO ci; /* conference info */
4169 struct rpt *myrpt = (struct rpt *)this;
4170 int res;
4171 int stopped,congstarted,dialtimer,lastcidx,aborted;
4172 struct ast_channel *mychannel,*genchannel;
4175 myrpt->mydtmf = 0;
4176 /* allocate a pseudo-channel thru asterisk */
4177 mychannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
4178 if (!mychannel)
4180 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
4181 pthread_exit(NULL);
4183 #ifdef AST_CDR_FLAG_POST_DISABLED
4184 ast_set_flag(mychannel->cdr,AST_CDR_FLAG_POST_DISABLED);
4185 #endif
4186 ci.chan = 0;
4187 ci.confno = myrpt->conf; /* use the pseudo conference */
4188 ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
4189 | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER;
4190 /* first put the channel on the conference */
4191 if (ioctl(mychannel->fds[0],ZT_SETCONF,&ci) == -1)
4193 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
4194 ast_hangup(mychannel);
4195 myrpt->callmode = 0;
4196 pthread_exit(NULL);
4198 /* allocate a pseudo-channel thru asterisk */
4199 genchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
4200 if (!genchannel)
4202 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
4203 ast_hangup(mychannel);
4204 pthread_exit(NULL);
4206 #ifdef AST_CDR_FLAG_POST_DISABLED
4207 ast_set_flag(genchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
4208 #endif
4209 ci.chan = 0;
4210 ci.confno = myrpt->conf;
4211 ci.confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER
4212 | ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER;
4213 /* first put the channel on the conference */
4214 if (ioctl(genchannel->fds[0],ZT_SETCONF,&ci) == -1)
4216 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
4217 ast_hangup(mychannel);
4218 ast_hangup(genchannel);
4219 myrpt->callmode = 0;
4220 pthread_exit(NULL);
4222 if (myrpt->p.tonezone && (tone_zone_set_zone(mychannel->fds[0],myrpt->p.tonezone) == -1))
4224 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
4225 ast_hangup(mychannel);
4226 ast_hangup(genchannel);
4227 myrpt->callmode = 0;
4228 pthread_exit(NULL);
4230 if (myrpt->p.tonezone && (tone_zone_set_zone(genchannel->fds[0],myrpt->p.tonezone) == -1))
4232 ast_log(LOG_WARNING, "Unable to set tone zone %s\n",myrpt->p.tonezone);
4233 ast_hangup(mychannel);
4234 ast_hangup(genchannel);
4235 myrpt->callmode = 0;
4236 pthread_exit(NULL);
4238 /* start dialtone if patchquiet is 0. Special patch modes don't send dial tone */
4239 if ((!myrpt->patchquiet) && (tone_zone_play_tone(mychannel->fds[0],ZT_TONE_DIALTONE) < 0))
4241 ast_log(LOG_WARNING, "Cannot start dialtone\n");
4242 ast_hangup(mychannel);
4243 ast_hangup(genchannel);
4244 myrpt->callmode = 0;
4245 pthread_exit(NULL);
4247 stopped = 0;
4248 congstarted = 0;
4249 dialtimer = 0;
4250 lastcidx = 0;
4251 aborted = 0;
4254 while ((myrpt->callmode == 1) || (myrpt->callmode == 4))
4257 if((myrpt->patchdialtime)&&(myrpt->callmode == 1)&&(myrpt->cidx != lastcidx)){
4258 dialtimer = 0;
4259 lastcidx = myrpt->cidx;
4262 if((myrpt->patchdialtime)&&(dialtimer >= myrpt->patchdialtime)){
4263 rpt_mutex_lock(&myrpt->lock);
4264 aborted = 1;
4265 myrpt->callmode = 0;
4266 rpt_mutex_unlock(&myrpt->lock);
4267 break;
4270 if ((!myrpt->patchquiet) && (!stopped) && (myrpt->callmode == 1) && (myrpt->cidx > 0))
4272 stopped = 1;
4273 /* stop dial tone */
4274 tone_zone_play_tone(mychannel->fds[0],-1);
4276 if (myrpt->callmode == 4)
4278 if(!congstarted){
4279 congstarted = 1;
4280 /* start congestion tone */
4281 tone_zone_play_tone(mychannel->fds[0],ZT_TONE_CONGESTION);
4284 res = ast_safe_sleep(mychannel, MSWAIT);
4285 if (res < 0)
4287 ast_hangup(mychannel);
4288 ast_hangup(genchannel);
4289 rpt_mutex_lock(&myrpt->lock);
4290 myrpt->callmode = 0;
4291 rpt_mutex_unlock(&myrpt->lock);
4292 pthread_exit(NULL);
4294 dialtimer += MSWAIT;
4296 /* stop any tone generation */
4297 tone_zone_play_tone(mychannel->fds[0],-1);
4298 /* end if done */
4299 if (!myrpt->callmode)
4301 ast_hangup(mychannel);
4302 ast_hangup(genchannel);
4303 rpt_mutex_lock(&myrpt->lock);
4304 myrpt->callmode = 0;
4305 rpt_mutex_unlock(&myrpt->lock);
4306 if((!myrpt->patchquiet) && aborted)
4307 rpt_telemetry(myrpt, TERM, NULL);
4308 pthread_exit(NULL);
4311 if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid){
4312 char *name, *loc, *instr;
4313 instr = strdup(myrpt->p.ourcallerid);
4314 if(instr){
4315 ast_callerid_parse(instr, &name, &loc);
4316 if(loc){
4317 if(mychannel->cid.cid_num)
4318 free(mychannel->cid.cid_num);
4319 mychannel->cid.cid_num = strdup(loc);
4321 if(name){
4322 if(mychannel->cid.cid_name)
4323 free(mychannel->cid.cid_name);
4324 mychannel->cid.cid_name = strdup(name);
4326 free(instr);
4330 ast_copy_string(mychannel->exten, myrpt->exten, sizeof(mychannel->exten) - 1);
4331 ast_copy_string(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context) - 1);
4333 if (myrpt->p.acctcode)
4334 ast_cdr_setaccount(mychannel,myrpt->p.acctcode);
4335 mychannel->priority = 1;
4336 ast_channel_undefer_dtmf(mychannel);
4337 if (ast_pbx_start(mychannel) < 0)
4339 ast_log(LOG_WARNING, "Unable to start PBX!!\n");
4340 ast_hangup(mychannel);
4341 ast_hangup(genchannel);
4342 rpt_mutex_lock(&myrpt->lock);
4343 myrpt->callmode = 0;
4344 rpt_mutex_unlock(&myrpt->lock);
4345 pthread_exit(NULL);
4347 usleep(10000);
4348 rpt_mutex_lock(&myrpt->lock);
4349 myrpt->callmode = 3;
4350 /* set appropriate conference for the pseudo */
4351 ci.chan = 0;
4352 ci.confno = myrpt->conf;
4353 ci.confmode = (myrpt->p.duplex == 2) ? ZT_CONF_CONFANNMON :
4354 (ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
4355 /* first put the channel on the conference in announce mode */
4356 if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
4358 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
4359 ast_hangup(mychannel);
4360 ast_hangup(genchannel);
4361 myrpt->callmode = 0;
4362 pthread_exit(NULL);
4364 while(myrpt->callmode)
4366 if ((!mychannel->pbx) && (myrpt->callmode != 4))
4368 if(myrpt->patchfarenddisconnect){ /* If patch is setup for far end disconnect */
4369 myrpt->callmode = 0;
4370 if(!myrpt->patchquiet){
4371 rpt_mutex_unlock(&myrpt->lock);
4372 rpt_telemetry(myrpt, TERM, NULL);
4373 rpt_mutex_lock(&myrpt->lock);
4376 else{ /* Send congestion until patch is downed by command */
4377 myrpt->callmode = 4;
4378 rpt_mutex_unlock(&myrpt->lock);
4379 /* start congestion tone */
4380 tone_zone_play_tone(genchannel->fds[0],ZT_TONE_CONGESTION);
4381 rpt_mutex_lock(&myrpt->lock);
4384 if (myrpt->mydtmf)
4386 struct ast_frame wf = {AST_FRAME_DTMF, } ;
4387 wf.subclass = myrpt->mydtmf;
4388 rpt_mutex_unlock(&myrpt->lock);
4389 ast_queue_frame(mychannel,&wf);
4390 ast_senddigit(genchannel,myrpt->mydtmf);
4391 rpt_mutex_lock(&myrpt->lock);
4392 myrpt->mydtmf = 0;
4394 rpt_mutex_unlock(&myrpt->lock);
4395 usleep(MSWAIT * 1000);
4396 rpt_mutex_lock(&myrpt->lock);
4398 rpt_mutex_unlock(&myrpt->lock);
4399 tone_zone_play_tone(genchannel->fds[0],-1);
4400 if (mychannel->pbx) ast_softhangup(mychannel,AST_SOFTHANGUP_DEV);
4401 ast_hangup(genchannel);
4402 rpt_mutex_lock(&myrpt->lock);
4403 myrpt->callmode = 0;
4404 rpt_mutex_unlock(&myrpt->lock);
4405 /* set appropriate conference for the pseudo */
4406 ci.chan = 0;
4407 ci.confno = myrpt->conf;
4408 ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? ZT_CONF_CONFANNMON :
4409 (ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
4410 /* first put the channel on the conference in announce mode */
4411 if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
4413 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
4415 pthread_exit(NULL);
4418 static void send_link_dtmf(struct rpt *myrpt,char c)
4420 char str[300];
4421 struct ast_frame wf;
4422 struct rpt_link *l;
4424 snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c);
4425 wf.frametype = AST_FRAME_TEXT;
4426 wf.subclass = 0;
4427 wf.offset = 0;
4428 wf.mallocd = 0;
4429 wf.datalen = strlen(str) + 1;
4430 wf.samples = 0;
4431 l = myrpt->links.next;
4432 /* first, see if our dude is there */
4433 while(l != &myrpt->links)
4435 if (l->name[0] == '0')
4437 l = l->next;
4438 continue;
4440 /* if we found it, write it and were done */
4441 if (!strcmp(l->name,myrpt->cmdnode))
4443 wf.data = str;
4444 if (l->chan) ast_write(l->chan,&wf);
4445 return;
4447 l = l->next;
4449 l = myrpt->links.next;
4450 /* if not, give it to everyone */
4451 while(l != &myrpt->links)
4453 wf.data = str;
4454 if (l->chan) ast_write(l->chan,&wf);
4455 l = l->next;
4457 return;
4461 * Connect a link
4463 * Return values:
4464 * -1: Error
4465 * 0: Success
4466 * 1: No match yet
4467 * 2: Already connected to this node
4470 static int connect_link(struct rpt *myrpt, char* node, int mode, int perma)
4472 char *val, *s, *s1, *s2, *tele;
4473 char lstr[MAXLINKLIST],*strs[MAXLINKLIST];
4474 char tmp[300], deststr[300] = "",modechange = 0;
4475 struct rpt_link *l;
4476 int reconnects = 0;
4477 int i,n;
4478 ZT_CONFINFO ci; /* conference info */
4480 val = node_lookup(myrpt,node);
4481 if (!val){
4482 if(strlen(node) >= myrpt->longestnode)
4483 return -1; /* No such node */
4484 return 1; /* No match yet */
4486 if(debug > 3){
4487 ast_log(LOG_NOTICE,"Connect attempt to node %s\n", node);
4488 ast_log(LOG_NOTICE,"Mode: %s\n",(mode)?"Transceive":"Monitor");
4489 ast_log(LOG_NOTICE,"Connection type: %s\n",(perma)?"Permalink":"Normal");
4492 strncpy(tmp,val,sizeof(tmp) - 1);
4493 s = tmp;
4494 s1 = strsep(&s,",");
4495 s2 = strsep(&s,",");
4496 rpt_mutex_lock(&myrpt->lock);
4497 l = myrpt->links.next;
4498 /* try to find this one in queue */
4499 while(l != &myrpt->links){
4500 if (l->name[0] == '0')
4502 l = l->next;
4503 continue;
4505 /* if found matching string */
4506 if (!strcmp(l->name, node))
4507 break;
4508 l = l->next;
4510 /* if found */
4511 if (l != &myrpt->links){
4512 /* if already in this mode, just ignore */
4513 if ((l->mode) || (!l->chan)) {
4514 rpt_mutex_unlock(&myrpt->lock);
4515 return 2; /* Already linked */
4517 reconnects = l->reconnects;
4518 rpt_mutex_unlock(&myrpt->lock);
4519 if (l->chan) ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
4520 l->retries = l->max_retries + 1;
4521 l->disced = 2;
4522 modechange = 1;
4523 } else
4525 __mklinklist(myrpt,NULL,lstr);
4526 rpt_mutex_unlock(&myrpt->lock);
4527 n = finddelim(lstr,strs,MAXLINKLIST);
4528 for(i = 0; i < n; i++)
4530 if ((*strs[i] < '0') ||
4531 (*strs[i] > '9')) strs[i]++;
4532 if (!strcmp(strs[i],node))
4534 return 2; /* Already linked */
4538 strncpy(myrpt->lastlinknode,node,MAXNODESTR - 1);
4539 /* establish call */
4540 l = malloc(sizeof(struct rpt_link));
4541 if (!l)
4543 ast_log(LOG_WARNING, "Unable to malloc\n");
4544 return -1;
4546 /* zero the silly thing */
4547 memset((char *)l,0,sizeof(struct rpt_link));
4548 l->mode = mode;
4549 l->outbound = 1;
4550 l->thisconnected = 0;
4551 strncpy(l->name, node, MAXNODESTR - 1);
4552 l->isremote = (s && ast_true(s));
4553 if (modechange) l->connected = 1;
4554 l->hasconnected = l->perma = perma;
4555 #ifdef ALLOW_LOCAL_CHANNELS
4556 if ((strncasecmp(s1,"iax2/", 5) == 0) || (strncasecmp(s1, "local/", 6) == 0))
4557 strncpy(deststr, s1, sizeof(deststr));
4558 else
4559 snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
4560 #else
4561 snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
4562 #endif
4563 tele = strchr(deststr, '/');
4564 if (!tele){
4565 ast_log(LOG_WARNING,"link3:Dial number (%s) must be in format tech/number\n",deststr);
4566 free(l);
4567 return -1;
4569 *tele++ = 0;
4570 l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
4571 if (l->chan){
4572 ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
4573 ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
4574 #ifdef AST_CDR_FLAG_POST_DISABLED
4575 ast_set_flag(l->chan->cdr,AST_CDR_FLAG_POST_DISABLED);
4576 #endif
4577 l->chan->whentohangup = 0;
4578 l->chan->appl = "Apprpt";
4579 l->chan->data = "(Remote Rx)";
4580 if (debug > 3)
4581 ast_log(LOG_NOTICE, "rpt (remote) initiating call to %s/%s on %s\n",
4582 deststr, tele, l->chan->name);
4583 if(l->chan->cid.cid_num)
4584 free(l->chan->cid.cid_num);
4585 l->chan->cid.cid_num = strdup(myrpt->name);
4586 ast_call(l->chan,tele,999);
4588 else {
4589 if(debug > 3)
4590 ast_log(LOG_NOTICE, "Unable to place call to %s/%s on %s\n",
4591 deststr,tele,l->chan->name);
4592 if (myrpt->p.archivedir)
4594 char str[100];
4595 sprintf(str,"LINKFAIL,%s",l->name);
4596 donodelog(myrpt,str);
4598 free(l);
4599 return -1;
4601 /* allocate a pseudo-channel thru asterisk */
4602 l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
4603 if (!l->pchan){
4604 ast_log(LOG_WARNING,"rpt connect: Sorry unable to obtain pseudo channel\n");
4605 ast_hangup(l->chan);
4606 free(l);
4607 return -1;
4609 ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
4610 ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
4611 #ifdef AST_CDR_FLAG_POST_DISABLED
4612 ast_set_flag(l->pchan->cdr,AST_CDR_FLAG_POST_DISABLED);
4613 #endif
4614 /* make a conference for the tx */
4615 ci.chan = 0;
4616 ci.confno = myrpt->conf;
4617 ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
4618 /* first put the channel on the conference in proper mode */
4619 if (ioctl(l->pchan->fds[0], ZT_SETCONF, &ci) == -1)
4621 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
4622 ast_hangup(l->chan);
4623 ast_hangup(l->pchan);
4624 free(l);
4625 return -1;
4627 rpt_mutex_lock(&myrpt->lock);
4628 l->reconnects = reconnects;
4629 /* insert at end of queue */
4630 l->max_retries = MAX_RETRIES;
4631 if (perma)
4632 l->max_retries = MAX_RETRIES_PERM;
4633 if (l->isremote) l->retries = l->max_retries + 1;
4634 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
4635 __kickshort(myrpt);
4636 rpt_mutex_unlock(&myrpt->lock);
4637 return 0;
4643 * Internet linking function
4646 static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink)
4649 char *val, *s, *s1, *s2;
4650 char tmp[300];
4651 char digitbuf[MAXNODESTR],*strs[MAXLINKLIST];
4652 char mode,perma;
4653 struct rpt_link *l;
4654 int i,r;
4656 if(!param)
4657 return DC_ERROR;
4660 if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable )
4661 return DC_ERROR;
4663 strncpy(digitbuf,digits,MAXNODESTR - 1);
4665 if(debug > 6)
4666 printf("@@@@ ilink param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
4668 switch(myatoi(param)){
4669 case 11: /* Perm Link off */
4670 case 1: /* Link off */
4671 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
4672 strcpy(digitbuf,myrpt->lastlinknode);
4673 val = node_lookup(myrpt,digitbuf);
4674 if (!val){
4675 if(strlen(digitbuf) >= myrpt->longestnode)
4676 return DC_ERROR;
4677 break;
4679 strncpy(tmp,val,sizeof(tmp) - 1);
4680 s = tmp;
4681 s1 = strsep(&s,",");
4682 s2 = strsep(&s,",");
4683 rpt_mutex_lock(&myrpt->lock);
4684 l = myrpt->links.next;
4685 /* try to find this one in queue */
4686 while(l != &myrpt->links){
4687 if (l->name[0] == '0')
4689 l = l->next;
4690 continue;
4692 /* if found matching string */
4693 if (!strcmp(l->name, digitbuf))
4694 break;
4695 l = l->next;
4697 if (l != &myrpt->links){ /* if found */
4698 struct ast_frame wf;
4700 /* must use perm command on perm link */
4701 if ((myatoi(param) < 10) &&
4702 (l->max_retries > MAX_RETRIES))
4704 rpt_mutex_unlock(&myrpt->lock);
4705 return DC_COMPLETE;
4707 strncpy(myrpt->lastlinknode,digitbuf,MAXNODESTR - 1);
4708 l->retries = l->max_retries + 1;
4709 l->disced = 1;
4710 rpt_mutex_unlock(&myrpt->lock);
4711 wf.frametype = AST_FRAME_TEXT;
4712 wf.subclass = 0;
4713 wf.offset = 0;
4714 wf.mallocd = 0;
4715 wf.datalen = strlen(discstr) + 1;
4716 wf.samples = 0;
4717 wf.data = discstr;
4718 if (l->chan)
4720 ast_write(l->chan,&wf);
4721 if (ast_safe_sleep(l->chan,250) == -1) return DC_ERROR;
4722 ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
4724 rpt_telemetry(myrpt, COMPLETE, NULL);
4725 return DC_COMPLETE;
4727 rpt_mutex_unlock(&myrpt->lock);
4728 return DC_COMPLETE;
4729 case 2: /* Link Monitor */
4730 case 3: /* Link transceive */
4731 case 12: /* Link Monitor permanent */
4732 case 13: /* Link transceive permanent */
4733 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
4734 strcpy(digitbuf,myrpt->lastlinknode);
4735 /* Attempt connection */
4736 perma = (atoi(param) > 10) ? 1 : 0;
4737 mode = (atoi(param) & 1) ? 1 : 0;
4738 r = connect_link(myrpt, digitbuf, mode, perma);
4739 switch(r){
4740 case 0:
4741 rpt_telemetry(myrpt, COMPLETE, NULL);
4742 return DC_COMPLETE;
4744 case 1:
4745 break;
4747 case 2:
4748 rpt_telemetry(myrpt, REMALREADY, NULL);
4749 return DC_COMPLETE;
4751 default:
4752 rpt_telemetry(myrpt, CONNFAIL, NULL);
4753 return DC_COMPLETE;
4755 break;
4757 case 4: /* Enter Command Mode */
4759 /* if doesnt allow link cmd, or no links active, return */
4760 if (((command_source != SOURCE_RPT) &&
4761 (command_source != SOURCE_PHONE) &&
4762 (command_source != SOURCE_DPHONE)) ||
4763 (myrpt->links.next == &myrpt->links))
4764 return DC_COMPLETE;
4766 /* if already in cmd mode, or selected self, fughetabahtit */
4767 if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name, digitbuf))){
4769 rpt_telemetry(myrpt, REMALREADY, NULL);
4770 return DC_COMPLETE;
4772 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
4773 strcpy(digitbuf,myrpt->lastlinknode);
4774 /* node must at least exist in list */
4775 val = node_lookup(myrpt,digitbuf);
4776 if (!val){
4777 if(strlen(digitbuf) >= myrpt->longestnode)
4778 return DC_ERROR;
4779 break;
4782 rpt_mutex_lock(&myrpt->lock);
4783 strcpy(myrpt->lastlinknode,digitbuf);
4784 strncpy(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode) - 1);
4785 rpt_mutex_unlock(&myrpt->lock);
4786 rpt_telemetry(myrpt, REMGO, NULL);
4787 return DC_COMPLETE;
4789 case 5: /* Status */
4790 rpt_telemetry(myrpt, STATUS, NULL);
4791 return DC_COMPLETE;
4793 case 15: /* Full Status */
4794 rpt_telemetry(myrpt, FULLSTATUS, NULL);
4795 return DC_COMPLETE;
4798 case 6: /* All Links Off, including permalinks */
4799 rpt_mutex_lock(&myrpt->lock);
4800 myrpt->savednodes[0] = 0;
4801 l = myrpt->links.next;
4802 /* loop through all links */
4803 while(l != &myrpt->links){
4804 struct ast_frame wf;
4805 if (l->name[0] == '0') /* Skip any IAXRPT monitoring */
4807 l = l->next;
4808 continue;
4810 /* Make a string of disconnected nodes for possible restoration */
4811 sprintf(tmp,"%c%c%s",(l->mode) ? 'X' : 'M',(l->perma) ? 'P':'T',l->name);
4812 if(strlen(tmp) + strlen(myrpt->savednodes) + 1 < MAXNODESTR){
4813 if(myrpt->savednodes[0])
4814 strcat(myrpt->savednodes, ",");
4815 strcat(myrpt->savednodes, tmp);
4817 l->retries = l->max_retries + 1;
4818 l->disced = 2; /* Silently disconnect */
4819 rpt_mutex_unlock(&myrpt->lock);
4820 /* ast_log(LOG_NOTICE,"dumping link %s\n",l->name); */
4822 wf.frametype = AST_FRAME_TEXT;
4823 wf.subclass = 0;
4824 wf.offset = 0;
4825 wf.mallocd = 0;
4826 wf.datalen = strlen(discstr) + 1;
4827 wf.samples = 0;
4828 wf.data = discstr;
4829 if (l->chan)
4831 ast_write(l->chan,&wf);
4832 ast_safe_sleep(l->chan,250); /* It's dead already, why check the return value? */
4833 ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
4835 rpt_mutex_lock(&myrpt->lock);
4836 l = l->next;
4838 rpt_mutex_unlock(&myrpt->lock);
4839 if(debug > 3)
4840 ast_log(LOG_NOTICE,"Nodes disconnected: %s\n",myrpt->savednodes);
4841 rpt_telemetry(myrpt, COMPLETE, NULL);
4842 return DC_COMPLETE;
4844 case 7: /* Identify last node which keyed us up */
4845 rpt_telemetry(myrpt, LASTNODEKEY, NULL);
4846 break;
4849 #ifdef _MDC_DECODE_H_
4850 case 8:
4851 myrpt->lastunit = 0xd00d;
4852 mdc1200_notify(myrpt,NULL,myrpt->lastunit);
4853 mdc1200_send(myrpt,myrpt->lastunit);
4854 break;
4855 #endif
4857 case 16: /* Restore links disconnected with "disconnect all links" command */
4858 strcpy(tmp, myrpt->savednodes); /* Make a copy */
4859 finddelim(tmp, strs, MAXLINKLIST); /* convert into substrings */
4860 for(i = 0; tmp[0] && strs[i] != NULL && i < MAXLINKLIST; i++){
4861 s1 = strs[i];
4862 mode = (s1[0] == 'X') ? 1 : 0;
4863 perma = (s1[1] == 'P') ? 1 : 0;
4864 connect_link(myrpt, s1 + 2, mode, perma); /* Try to reconnect */
4866 rpt_telemetry(myrpt, COMPLETE, NULL);
4867 break;
4869 case 200:
4870 case 201:
4871 case 202:
4872 case 203:
4873 case 204:
4874 case 205:
4875 case 206:
4876 case 207:
4877 case 208:
4878 case 209:
4879 case 210:
4880 case 211:
4881 case 212:
4882 case 213:
4883 case 214:
4884 case 215:
4885 if (((myrpt->p.propagate_dtmf) &&
4886 (command_source == SOURCE_LNK)) ||
4887 ((myrpt->p.propagate_phonedtmf) &&
4888 ((command_source == SOURCE_PHONE) ||
4889 (command_source == SOURCE_DPHONE))))
4890 do_dtmf_local(myrpt,
4891 remdtmfstr[myatoi(param) - 200]);
4892 default:
4893 return DC_ERROR;
4897 return DC_INDETERMINATE;
4901 * Autopatch up
4904 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
4906 pthread_attr_t attr;
4907 int i, index, paramlength;
4908 char *lparam;
4909 char *value = NULL;
4910 char *paramlist[20];
4912 static char *keywords[] = {
4913 "context",
4914 "dialtime",
4915 "farenddisconnect",
4916 "noct",
4917 "quiet",
4918 NULL
4921 if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
4922 return DC_ERROR;
4924 if(debug)
4925 printf("@@@@ Autopatch up\n");
4927 if(!myrpt->callmode){
4928 /* Set defaults */
4929 myrpt->patchnoct = 0;
4930 myrpt->patchdialtime = 0;
4931 myrpt->patchfarenddisconnect = 0;
4932 myrpt->patchquiet = 0;
4933 strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
4935 if(param){
4936 /* Process parameter list */
4937 lparam = ast_strdupa(param);
4938 if(!lparam){
4939 ast_log(LOG_ERROR,"App_rpt out of memory on line %d\n",__LINE__);
4940 return DC_ERROR;
4942 paramlength = finddelim(lparam, paramlist, 20);
4943 for(i = 0; i < paramlength; i++){
4944 index = matchkeyword(paramlist[i], &value, keywords);
4945 if(value)
4946 value = skipchars(value, "= ");
4947 switch(index){
4949 case 1: /* context */
4950 strncpy(myrpt->patchcontext, value, MAXPATCHCONTEXT - 1) ;
4951 break;
4953 case 2: /* dialtime */
4954 myrpt->patchdialtime = atoi(value);
4955 break;
4957 case 3: /* farenddisconnect */
4958 myrpt->patchfarenddisconnect = atoi(value);
4959 break;
4961 case 4: /* noct */
4962 myrpt->patchnoct = atoi(value);
4963 break;
4965 case 5: /* quiet */
4966 myrpt->patchquiet = atoi(value);
4967 break;
4969 default:
4970 break;
4976 rpt_mutex_lock(&myrpt->lock);
4978 /* if on call, force * into current audio stream */
4980 if ((myrpt->callmode == 2) || (myrpt->callmode == 3)){
4981 myrpt->mydtmf = myrpt->p.endchar;
4983 if (myrpt->callmode){
4984 rpt_mutex_unlock(&myrpt->lock);
4985 return DC_COMPLETE;
4987 myrpt->callmode = 1;
4988 myrpt->cidx = 0;
4989 myrpt->exten[myrpt->cidx] = 0;
4990 rpt_mutex_unlock(&myrpt->lock);
4991 pthread_attr_init(&attr);
4992 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
4993 ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *) myrpt);
4994 return DC_COMPLETE;
4998 * Autopatch down
5001 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
5003 if (myrpt->p.s[myrpt->p.sysstate_cur].txdisable || myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable)
5004 return DC_ERROR;
5006 if(debug)
5007 printf("@@@@ Autopatch down\n");
5009 rpt_mutex_lock(&myrpt->lock);
5011 if (!myrpt->callmode){
5012 rpt_mutex_unlock(&myrpt->lock);
5013 return DC_COMPLETE;
5016 myrpt->callmode = 0;
5017 rpt_mutex_unlock(&myrpt->lock);
5018 rpt_telemetry(myrpt, TERM, NULL);
5019 return DC_COMPLETE;
5023 * Status
5026 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
5029 if (!param)
5030 return DC_ERROR;
5032 if ((myrpt->p.s[myrpt->p.sysstate_cur].txdisable) || (myrpt->p.s[myrpt->p.sysstate_cur].userfundisable))
5033 return DC_ERROR;
5035 if(debug)
5036 printf("@@@@ status param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
5038 switch(myatoi(param)){
5039 case 1: /* System ID */
5040 rpt_telemetry(myrpt, ID1, NULL);
5041 return DC_COMPLETE;
5042 case 2: /* System Time */
5043 rpt_telemetry(myrpt, STATS_TIME, NULL);
5044 return DC_COMPLETE;
5045 case 3: /* app_rpt.c version */
5046 rpt_telemetry(myrpt, STATS_VERSION, NULL);
5047 default:
5048 return DC_ERROR;
5050 return DC_INDETERMINATE;
5054 * Macro-oni (without Salami)
5057 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
5060 char *val;
5061 int i;
5062 if (myrpt->remote)
5063 return DC_ERROR;
5065 if(debug)
5066 printf("@@@@ macro-oni param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
5068 if(strlen(digitbuf) < 1) /* needs 1 digit */
5069 return DC_INDETERMINATE;
5071 for(i = 0 ; i < digitbuf[i] ; i++) {
5072 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
5073 return DC_ERROR;
5076 if (*digitbuf == '0') val = myrpt->p.startupmacro;
5077 else val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, digitbuf);
5078 /* param was 1 for local buf */
5079 if (!val){
5080 if (strlen(digitbuf) < myrpt->macro_longest)
5081 return DC_INDETERMINATE;
5082 rpt_telemetry(myrpt, MACRO_NOTFOUND, NULL);
5083 return DC_COMPLETE;
5085 rpt_mutex_lock(&myrpt->lock);
5086 if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val))
5088 rpt_mutex_unlock(&myrpt->lock);
5089 rpt_telemetry(myrpt, MACRO_BUSY, NULL);
5090 return DC_ERROR;
5092 myrpt->macrotimer = MACROTIME;
5093 strncat(myrpt->macrobuf,val,MAXMACRO - 1);
5094 rpt_mutex_unlock(&myrpt->lock);
5095 return DC_COMPLETE;
5099 * COP - Control operator
5102 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
5104 char string[16];
5106 if(!param)
5107 return DC_ERROR;
5109 switch(myatoi(param)){
5110 case 1: /* System reset */
5111 system("killall -9 asterisk");
5112 return DC_COMPLETE;
5114 case 2:
5115 myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 0;
5116 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "RPTENA");
5117 return DC_COMPLETE;
5119 case 3:
5120 myrpt->p.s[myrpt->p.sysstate_cur].txdisable = 1;
5121 return DC_COMPLETE;
5123 case 4: /* test tone on */
5124 if (myrpt->stopgen < 0)
5126 myrpt->stopgen = 1;
5128 else
5130 myrpt->stopgen = 0;
5131 rpt_telemetry(myrpt, TEST_TONE, NULL);
5133 return DC_COMPLETE;
5135 case 5: /* Disgorge variables to log for debug purposes */
5136 myrpt->disgorgetime = time(NULL) + 10; /* Do it 10 seconds later */
5137 return DC_COMPLETE;
5139 case 6: /* Simulate COR being activated (phone only) */
5140 if (command_source != SOURCE_PHONE) return DC_INDETERMINATE;
5141 return DC_DOKEY;
5144 case 7: /* Time out timer enable */
5145 myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 0;
5146 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTENA");
5147 return DC_COMPLETE;
5149 case 8: /* Time out timer disable */
5150 myrpt->p.s[myrpt->p.sysstate_cur].totdisable = 1;
5151 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "TOTDIS");
5152 return DC_COMPLETE;
5154 case 9: /* Autopatch enable */
5155 myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 0;
5156 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APENA");
5157 return DC_COMPLETE;
5159 case 10: /* Autopatch disable */
5160 myrpt->p.s[myrpt->p.sysstate_cur].autopatchdisable = 1;
5161 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "APDIS");
5162 return DC_COMPLETE;
5164 case 11: /* Link Enable */
5165 myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 0;
5166 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKENA");
5167 return DC_COMPLETE;
5169 case 12: /* Link Disable */
5170 myrpt->p.s[myrpt->p.sysstate_cur].linkfundisable = 1;
5171 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "LNKDIS");
5172 return DC_COMPLETE;
5174 case 13: /* Query System State */
5175 string[0] = string[1] = 'S';
5176 string[2] = myrpt->p.sysstate_cur + '0';
5177 string[3] = '\0';
5178 rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
5179 return DC_COMPLETE;
5181 case 14: /* Change System State */
5182 if(strlen(digitbuf) == 0)
5183 break;
5184 if((digitbuf[0] < '0') || (digitbuf[0] > '9'))
5185 return DC_ERROR;
5186 myrpt->p.sysstate_cur = digitbuf[0] - '0';
5187 string[0] = string[1] = 'S';
5188 string[2] = myrpt->p.sysstate_cur + '0';
5189 string[3] = '\0';
5190 rpt_telemetry(myrpt, ARB_ALPHA, (void *) string);
5191 return DC_COMPLETE;
5193 case 15: /* Scheduler Enable */
5194 myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 0;
5195 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKENA");
5196 return DC_COMPLETE;
5198 case 16: /* Scheduler Disable */
5199 myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable = 1;
5200 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "SKDIS");
5201 return DC_COMPLETE;
5203 case 17: /* User functions Enable */
5204 myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 0;
5205 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFENA");
5206 return DC_COMPLETE;
5208 case 18: /* User Functions Disable */
5209 myrpt->p.s[myrpt->p.sysstate_cur].userfundisable = 1;
5210 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "UFDIS");
5211 return DC_COMPLETE;
5213 case 19: /* Alternate Tail Enable */
5214 myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 1;
5215 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATENA");
5216 return DC_COMPLETE;
5218 case 20: /* Alternate Tail Disable */
5219 myrpt->p.s[myrpt->p.sysstate_cur].alternatetail = 0;
5220 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "ATDIS");
5221 return DC_COMPLETE;
5223 return DC_INDETERMINATE;
5227 * Collect digits one by one until something matches
5230 static int collect_function_digits(struct rpt *myrpt, char *digits,
5231 int command_source, struct rpt_link *mylink)
5233 int i;
5234 char *stringp,*action,*param,*functiondigits;
5235 char function_table_name[30] = "";
5236 char workstring[200];
5238 struct ast_variable *vp;
5240 if(debug)
5241 printf("@@@@ Digits collected: %s, source: %d\n", digits, command_source);
5243 if (command_source == SOURCE_DPHONE) {
5244 if (!myrpt->p.dphone_functions) return DC_INDETERMINATE;
5245 strncpy(function_table_name, myrpt->p.dphone_functions, sizeof(function_table_name) - 1);
5247 else if (command_source == SOURCE_PHONE) {
5248 if (!myrpt->p.phone_functions) return DC_INDETERMINATE;
5249 strncpy(function_table_name, myrpt->p.phone_functions, sizeof(function_table_name) - 1);
5251 else if (command_source == SOURCE_LNK)
5252 strncpy(function_table_name, myrpt->p.link_functions, sizeof(function_table_name) - 1);
5253 else
5254 strncpy(function_table_name, myrpt->p.functions, sizeof(function_table_name) - 1);
5255 vp = ast_variable_browse(myrpt->cfg, function_table_name);
5256 while(vp) {
5257 if(!strncasecmp(vp->name, digits, strlen(vp->name)))
5258 break;
5259 vp = vp->next;
5261 if(!vp) {
5262 int n;
5264 n = myrpt->longestfunc;
5265 if (command_source == SOURCE_LNK) n = myrpt->link_longestfunc;
5266 else
5267 if (command_source == SOURCE_PHONE) n = myrpt->phone_longestfunc;
5268 else
5269 if (command_source == SOURCE_DPHONE) n = myrpt->dphone_longestfunc;
5271 if(strlen(digits) >= n)
5272 return DC_ERROR;
5273 else
5274 return DC_INDETERMINATE;
5276 /* Found a match, retrieve value part and parse */
5277 strncpy(workstring, vp->value, sizeof(workstring) - 1 );
5278 stringp = workstring;
5279 action = strsep(&stringp, ",");
5280 param = stringp;
5281 if(debug)
5282 printf("@@@@ action: %s, param = %s\n",action, (param) ? param : "(null)");
5283 /* Look up the action */
5284 for(i = 0 ; i < (sizeof(function_table)/sizeof(struct function_table_tag)); i++){
5285 if(!strncasecmp(action, function_table[i].action, strlen(action)))
5286 break;
5288 if(debug)
5289 printf("@@@@ table index i = %d\n",i);
5290 if(i == (sizeof(function_table)/sizeof(struct function_table_tag))){
5291 /* Error, action not in table */
5292 return DC_ERROR;
5294 if(function_table[i].function == NULL){
5295 /* Error, function undefined */
5296 if(debug)
5297 printf("@@@@ NULL for action: %s\n",action);
5298 return DC_ERROR;
5300 functiondigits = digits + strlen(vp->name);
5301 return (*function_table[i].function)(myrpt, param, functiondigits, command_source, mylink);
5305 static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink,
5306 char *str)
5308 char tmp[512],cmd[300] = "",dest[300],src[300],c;
5309 int seq, res;
5310 struct rpt_link *l;
5311 struct ast_frame wf;
5313 wf.frametype = AST_FRAME_TEXT;
5314 wf.subclass = 0;
5315 wf.offset = 0;
5316 wf.mallocd = 0;
5317 wf.datalen = strlen(str) + 1;
5318 wf.samples = 0;
5319 /* put string in our buffer */
5320 strncpy(tmp,str,sizeof(tmp) - 1);
5322 if (!strcmp(tmp,discstr))
5324 mylink->disced = 1;
5325 mylink->retries = mylink->max_retries + 1;
5326 ast_softhangup(mylink->chan,AST_SOFTHANGUP_DEV);
5327 return;
5329 if (tmp[0] == 'L')
5331 rpt_mutex_lock(&myrpt->lock);
5332 strcpy(mylink->linklist,tmp + 2);
5333 time(&mylink->linklistreceived);
5334 rpt_mutex_unlock(&myrpt->lock);
5335 if (debug > 6) ast_log(LOG_NOTICE,"@@@@ node %s recieved node list %s from node %s\n",
5336 myrpt->name,tmp,mylink->name);
5337 return;
5339 if (tmp[0] == 'I')
5341 if (sscanf(tmp,"%s %s %x",cmd,src,&seq) != 3)
5343 ast_log(LOG_WARNING, "Unable to parse ident string %s\n",str);
5344 return;
5346 mdc1200_notify(myrpt,src,seq);
5347 strcpy(dest,"*");
5349 else
5351 if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
5353 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
5354 return;
5356 if (strcmp(cmd,"D"))
5358 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
5359 return;
5362 if (dest[0] == '0')
5364 strcpy(dest,myrpt->name);
5367 /* if not for me, redistribute to all links */
5368 if (strcmp(dest,myrpt->name))
5370 l = myrpt->links.next;
5371 /* see if this is one in list */
5372 while(l != &myrpt->links)
5374 if (l->name[0] == '0')
5376 l = l->next;
5377 continue;
5379 /* dont send back from where it came */
5380 if ((l == mylink) || (!strcmp(l->name,mylink->name)))
5382 l = l->next;
5383 continue;
5385 /* if it is, send it and we're done */
5386 if (!strcmp(l->name,dest))
5388 /* send, but not to src */
5389 if (strcmp(l->name,src)) {
5390 wf.data = str;
5391 if (l->chan) ast_write(l->chan,&wf);
5393 return;
5395 l = l->next;
5397 l = myrpt->links.next;
5398 /* otherwise, send it to all of em */
5399 while(l != &myrpt->links)
5401 if (l->name[0] == '0')
5403 l = l->next;
5404 continue;
5406 /* dont send back from where it came */
5407 if ((l == mylink) || (!strcmp(l->name,mylink->name)))
5409 l = l->next;
5410 continue;
5412 /* send, but not to src */
5413 if (strcmp(l->name,src)) {
5414 wf.data = str;
5415 if (l->chan) ast_write(l->chan,&wf);
5417 l = l->next;
5419 return;
5421 if (myrpt->p.archivedir)
5423 char str[100];
5425 sprintf(str,"DTMF,%s,%c",mylink->name,c);
5426 donodelog(myrpt,str);
5428 c = func_xlat(myrpt,c,&myrpt->p.outxlat);
5429 if (!c) return;
5430 rpt_mutex_lock(&myrpt->lock);
5431 if (c == myrpt->p.endchar) myrpt->stopgen = 1;
5432 if (myrpt->callmode == 1)
5434 myrpt->exten[myrpt->cidx++] = c;
5435 myrpt->exten[myrpt->cidx] = 0;
5436 /* if this exists */
5437 if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
5439 myrpt->callmode = 2;
5440 if(!myrpt->patchquiet){
5441 rpt_mutex_unlock(&myrpt->lock);
5442 rpt_telemetry(myrpt,PROC,NULL);
5443 rpt_mutex_lock(&myrpt->lock);
5446 /* if can continue, do so */
5447 if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
5449 /* call has failed, inform user */
5450 myrpt->callmode = 4;
5453 if (c == myrpt->p.funcchar)
5455 myrpt->rem_dtmfidx = 0;
5456 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
5457 time(&myrpt->rem_dtmf_time);
5458 rpt_mutex_unlock(&myrpt->lock);
5459 return;
5461 else if (myrpt->rem_dtmfidx < 0)
5463 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
5465 myrpt->mydtmf = c;
5467 if (myrpt->p.propagate_dtmf) do_dtmf_local(myrpt,c);
5468 if (myrpt->p.propagate_phonedtmf) do_dtmf_phone(myrpt,mylink,c);
5469 rpt_mutex_unlock(&myrpt->lock);
5470 return;
5472 else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0))
5474 time(&myrpt->rem_dtmf_time);
5475 if (myrpt->rem_dtmfidx < MAXDTMF)
5477 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
5478 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
5480 rpt_mutex_unlock(&myrpt->lock);
5481 strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
5482 res = collect_function_digits(myrpt, cmd, SOURCE_LNK, mylink);
5483 rpt_mutex_lock(&myrpt->lock);
5485 switch(res){
5487 case DC_INDETERMINATE:
5488 break;
5490 case DC_REQ_FLUSH:
5491 myrpt->rem_dtmfidx = 0;
5492 myrpt->rem_dtmfbuf[0] = 0;
5493 break;
5496 case DC_COMPLETE:
5497 case DC_COMPLETEQUIET:
5498 myrpt->totalexecdcommands++;
5499 myrpt->dailyexecdcommands++;
5500 strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
5501 myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
5502 myrpt->rem_dtmfbuf[0] = 0;
5503 myrpt->rem_dtmfidx = -1;
5504 myrpt->rem_dtmf_time = 0;
5505 break;
5507 case DC_ERROR:
5508 default:
5509 myrpt->rem_dtmfbuf[0] = 0;
5510 myrpt->rem_dtmfidx = -1;
5511 myrpt->rem_dtmf_time = 0;
5512 break;
5517 rpt_mutex_unlock(&myrpt->lock);
5518 return;
5521 static void handle_link_phone_dtmf(struct rpt *myrpt, struct rpt_link *mylink,
5522 char c)
5525 char cmd[300];
5526 int res;
5528 if (myrpt->p.archivedir)
5530 char str[100];
5532 sprintf(str,"DTMF(P),%s,%c",mylink->name,c);
5533 donodelog(myrpt,str);
5535 rpt_mutex_lock(&myrpt->lock);
5536 if (c == myrpt->p.endchar)
5538 if (mylink->lastrx)
5540 mylink->lastrx = 0;
5541 rpt_mutex_unlock(&myrpt->lock);
5542 return;
5544 myrpt->stopgen = 1;
5545 if (myrpt->cmdnode[0])
5547 myrpt->cmdnode[0] = 0;
5548 myrpt->dtmfidx = -1;
5549 myrpt->dtmfbuf[0] = 0;
5550 rpt_mutex_unlock(&myrpt->lock);
5551 rpt_telemetry(myrpt,COMPLETE,NULL);
5552 return;
5555 if (myrpt->cmdnode[0])
5557 rpt_mutex_unlock(&myrpt->lock);
5558 send_link_dtmf(myrpt,c);
5559 return;
5561 if (myrpt->callmode == 1)
5563 myrpt->exten[myrpt->cidx++] = c;
5564 myrpt->exten[myrpt->cidx] = 0;
5565 /* if this exists */
5566 if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
5568 myrpt->callmode = 2;
5569 if(!myrpt->patchquiet){
5570 rpt_mutex_unlock(&myrpt->lock);
5571 rpt_telemetry(myrpt,PROC,NULL);
5572 rpt_mutex_lock(&myrpt->lock);
5575 /* if can continue, do so */
5576 if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
5578 /* call has failed, inform user */
5579 myrpt->callmode = 4;
5582 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
5584 myrpt->mydtmf = c;
5586 if (c == myrpt->p.funcchar)
5588 myrpt->rem_dtmfidx = 0;
5589 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
5590 time(&myrpt->rem_dtmf_time);
5591 rpt_mutex_unlock(&myrpt->lock);
5592 return;
5594 else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0))
5596 time(&myrpt->rem_dtmf_time);
5597 if (myrpt->rem_dtmfidx < MAXDTMF)
5599 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
5600 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
5602 rpt_mutex_unlock(&myrpt->lock);
5603 strncpy(cmd, myrpt->rem_dtmfbuf, sizeof(cmd) - 1);
5604 switch(mylink->phonemode)
5606 case 1:
5607 res = collect_function_digits(myrpt, cmd,
5608 SOURCE_PHONE, mylink);
5609 break;
5610 case 2:
5611 res = collect_function_digits(myrpt, cmd,
5612 SOURCE_DPHONE,mylink);
5613 break;
5614 default:
5615 res = collect_function_digits(myrpt, cmd,
5616 SOURCE_LNK, mylink);
5617 break;
5620 rpt_mutex_lock(&myrpt->lock);
5622 switch(res){
5624 case DC_INDETERMINATE:
5625 break;
5627 case DC_DOKEY:
5628 mylink->lastrx = 1;
5629 break;
5631 case DC_REQ_FLUSH:
5632 myrpt->rem_dtmfidx = 0;
5633 myrpt->rem_dtmfbuf[0] = 0;
5634 break;
5637 case DC_COMPLETE:
5638 case DC_COMPLETEQUIET:
5639 myrpt->totalexecdcommands++;
5640 myrpt->dailyexecdcommands++;
5641 strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
5642 myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
5643 myrpt->rem_dtmfbuf[0] = 0;
5644 myrpt->rem_dtmfidx = -1;
5645 myrpt->rem_dtmf_time = 0;
5646 break;
5648 case DC_ERROR:
5649 default:
5650 myrpt->rem_dtmfbuf[0] = 0;
5651 myrpt->rem_dtmfidx = -1;
5652 myrpt->rem_dtmf_time = 0;
5653 break;
5658 rpt_mutex_unlock(&myrpt->lock);
5659 return;
5662 /* Doug Hall RBI-1 serial data definitions:
5664 * Byte 0: Expansion external outputs
5665 * Byte 1:
5666 * Bits 0-3 are BAND as follows:
5667 * Bits 4-5 are POWER bits as follows:
5668 * 00 - Low Power
5669 * 01 - Hi Power
5670 * 02 - Med Power
5671 * Bits 6-7 are always set
5672 * Byte 2:
5673 * Bits 0-3 MHZ in BCD format
5674 * Bits 4-5 are offset as follows:
5675 * 00 - minus
5676 * 01 - plus
5677 * 02 - simplex
5678 * 03 - minus minus (whatever that is)
5679 * Bit 6 is the 0/5 KHZ bit
5680 * Bit 7 is always set
5681 * Byte 3:
5682 * Bits 0-3 are 10 KHZ in BCD format
5683 * Bits 4-7 are 100 KHZ in BCD format
5684 * Byte 4: PL Tone code and encode/decode enable bits
5685 * Bits 0-5 are PL tone code (comspec binary codes)
5686 * Bit 6 is encode enable/disable
5687 * Bit 7 is decode enable/disable
5690 /* take the frequency from the 10 mhz digits (and up) and convert it
5691 to a band number */
5693 static int rbi_mhztoband(char *str)
5695 int i;
5697 i = atoi(str) / 10; /* get the 10's of mhz */
5698 switch(i)
5700 case 2:
5701 return 10;
5702 case 5:
5703 return 11;
5704 case 14:
5705 return 2;
5706 case 22:
5707 return 3;
5708 case 44:
5709 return 4;
5710 case 124:
5711 return 0;
5712 case 125:
5713 return 1;
5714 case 126:
5715 return 8;
5716 case 127:
5717 return 5;
5718 case 128:
5719 return 6;
5720 case 129:
5721 return 7;
5722 default:
5723 break;
5725 return -1;
5728 /* take a PL frequency and turn it into a code */
5729 static int rbi_pltocode(char *str)
5731 int i;
5732 char *s;
5734 s = strchr(str,'.');
5735 i = 0;
5736 if (s) i = atoi(s + 1);
5737 i += atoi(str) * 10;
5738 switch(i)
5740 case 670:
5741 return 0;
5742 case 719:
5743 return 1;
5744 case 744:
5745 return 2;
5746 case 770:
5747 return 3;
5748 case 797:
5749 return 4;
5750 case 825:
5751 return 5;
5752 case 854:
5753 return 6;
5754 case 885:
5755 return 7;
5756 case 915:
5757 return 8;
5758 case 948:
5759 return 9;
5760 case 974:
5761 return 10;
5762 case 1000:
5763 return 11;
5764 case 1035:
5765 return 12;
5766 case 1072:
5767 return 13;
5768 case 1109:
5769 return 14;
5770 case 1148:
5771 return 15;
5772 case 1188:
5773 return 16;
5774 case 1230:
5775 return 17;
5776 case 1273:
5777 return 18;
5778 case 1318:
5779 return 19;
5780 case 1365:
5781 return 20;
5782 case 1413:
5783 return 21;
5784 case 1462:
5785 return 22;
5786 case 1514:
5787 return 23;
5788 case 1567:
5789 return 24;
5790 case 1622:
5791 return 25;
5792 case 1679:
5793 return 26;
5794 case 1738:
5795 return 27;
5796 case 1799:
5797 return 28;
5798 case 1862:
5799 return 29;
5800 case 1928:
5801 return 30;
5802 case 2035:
5803 return 31;
5804 case 2107:
5805 return 32;
5806 case 2181:
5807 return 33;
5808 case 2257:
5809 return 34;
5810 case 2336:
5811 return 35;
5812 case 2418:
5813 return 36;
5814 case 2503:
5815 return 37;
5817 return -1;
5821 * Shift out a formatted serial bit stream
5824 static void rbi_out_parallel(struct rpt *myrpt,unsigned char *data)
5826 #ifdef __i386__
5827 int i,j;
5828 unsigned char od,d;
5829 static volatile long long delayvar;
5831 for(i = 0 ; i < 5 ; i++){
5832 od = *data++;
5833 for(j = 0 ; j < 8 ; j++){
5834 d = od & 1;
5835 outb(d,myrpt->p.iobase);
5836 /* >= 15 us */
5837 for(delayvar = 1; delayvar < 15000; delayvar++);
5838 od >>= 1;
5839 outb(d | 2,myrpt->p.iobase);
5840 /* >= 30 us */
5841 for(delayvar = 1; delayvar < 30000; delayvar++);
5842 outb(d,myrpt->p.iobase);
5843 /* >= 10 us */
5844 for(delayvar = 1; delayvar < 10000; delayvar++);
5847 /* >= 50 us */
5848 for(delayvar = 1; delayvar < 50000; delayvar++);
5849 #endif
5852 static void rbi_out(struct rpt *myrpt,unsigned char *data)
5854 struct zt_radio_param r;
5856 memset(&r,0,sizeof(struct zt_radio_param));
5857 r.radpar = ZT_RADPAR_REMMODE;
5858 r.data = ZT_RADPAR_REM_RBI1;
5859 /* if setparam ioctl fails, its probably not a pciradio card */
5860 if (ioctl(myrpt->zaprxchannel->fds[0],ZT_RADIO_SETPARAM,&r) == -1)
5862 rbi_out_parallel(myrpt,data);
5863 return;
5865 r.radpar = ZT_RADPAR_REMCOMMAND;
5866 memcpy(&r.data,data,5);
5867 if (ioctl(myrpt->zaprxchannel->fds[0],ZT_RADIO_SETPARAM,&r) == -1)
5869 ast_log(LOG_WARNING,"Cannot send RBI command for channel %s\n",myrpt->zaprxchannel->name);
5870 return;
5874 static int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes,
5875 unsigned char *rxbuf, int rxmaxbytes, int asciiflag)
5877 int i,j,index,oldmode,olddata;
5878 struct zt_radio_param prm;
5879 char c;
5881 if(debug){
5882 printf("String output was: ");
5883 for(i = 0; i < txbytes; i++)
5884 printf("%02X ", (unsigned char ) txbuf[i]);
5885 printf("\n");
5887 if (myrpt->iofd > 0) /* if to do out a serial port */
5889 if (rxmaxbytes && rxbuf) tcflush(myrpt->iofd,TCIFLUSH);
5890 if (write(myrpt->iofd,txbuf,txbytes) != txbytes) return -1;
5891 if ((!rxmaxbytes) || (rxbuf == NULL)) return(0);
5892 memset(rxbuf,0,rxmaxbytes);
5893 for(i = 0; i < rxmaxbytes; i++)
5895 j = read(myrpt->iofd,&c,1);
5896 if (j < 1) return(i);
5897 rxbuf[i] = c;
5898 if (asciiflag & 1)
5900 rxbuf[i + 1] = 0;
5901 if (c == '\r') break;
5904 if(debug){
5905 printf("String returned was: ");
5906 for(j = 0; j < i; j++)
5907 printf("%02X ", (unsigned char ) rxbuf[j]);
5908 printf("\n");
5910 return(i);
5913 /* if not a zap channel, cant use pciradio stuff */
5914 if (myrpt->rxchannel != myrpt->zaprxchannel) return -1;
5916 prm.radpar = ZT_RADPAR_UIOMODE;
5917 if (ioctl(myrpt->zaprxchannel->fds[0],ZT_RADIO_GETPARAM,&prm) == -1) return -1;
5918 oldmode = prm.data;
5919 prm.radpar = ZT_RADPAR_UIODATA;
5920 if (ioctl(myrpt->zaprxchannel->fds[0],ZT_RADIO_GETPARAM,&prm) == -1) return -1;
5921 olddata = prm.data;
5922 prm.radpar = ZT_RADPAR_REMMODE;
5923 if (asciiflag & 1) prm.data = ZT_RADPAR_REM_SERIAL_ASCII;
5924 else prm.data = ZT_RADPAR_REM_SERIAL;
5925 if (ioctl(myrpt->zaprxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
5926 if (asciiflag & 2)
5928 i = ZT_ONHOOK;
5929 if (ioctl(myrpt->zaprxchannel->fds[0],ZT_HOOK,&i) == -1) return -1;
5930 usleep(100000);
5932 prm.radpar = ZT_RADPAR_REMCOMMAND;
5933 prm.data = rxmaxbytes;
5934 memcpy(prm.buf,txbuf,txbytes);
5935 prm.index = txbytes;
5936 if (ioctl(myrpt->zaprxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
5937 if (rxbuf)
5939 *rxbuf = 0;
5940 memcpy(rxbuf,prm.buf,prm.index);
5942 index = prm.index;
5943 prm.radpar = ZT_RADPAR_REMMODE;
5944 prm.data = ZT_RADPAR_REM_NONE;
5945 if (ioctl(myrpt->zaprxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
5946 if (asciiflag & 2)
5948 i = ZT_OFFHOOK;
5949 if (ioctl(myrpt->zaprxchannel->fds[0],ZT_HOOK,&i) == -1) return -1;
5951 prm.radpar = ZT_RADPAR_UIOMODE;
5952 prm.data = oldmode;
5953 if (ioctl(myrpt->zaprxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
5954 prm.radpar = ZT_RADPAR_UIODATA;
5955 prm.data = olddata;
5956 if (ioctl(myrpt->zaprxchannel->fds[0],ZT_RADIO_SETPARAM,&prm) == -1) return -1;
5957 return(index);
5960 static int civ_cmd(struct rpt *myrpt,unsigned char *cmd, int cmdlen)
5962 unsigned char rxbuf[100];
5963 int i,rv ;
5965 rv = serial_remote_io(myrpt,cmd,cmdlen,rxbuf,cmdlen + 6,0);
5966 if (rv == -1) return(-1);
5967 if (rv != (cmdlen + 6)) return(1);
5968 for(i = 0; i < 6; i++)
5969 if (rxbuf[i] != cmd[i]) return(1);
5970 if (rxbuf[cmdlen] != 0xfe) return(1);
5971 if (rxbuf[cmdlen + 1] != 0xfe) return(1);
5972 if (rxbuf[cmdlen + 4] != 0xfb) return(1);
5973 if (rxbuf[cmdlen + 5] != 0xfd) return(1);
5974 return(0);
5977 static int sendkenwood(struct rpt *myrpt,char *txstr, char *rxstr)
5979 int i;
5981 if (debug) printf("Send to kenwood: %s\n",txstr);
5982 i = serial_remote_io(myrpt, (unsigned char *)txstr, strlen(txstr),
5983 (unsigned char *)rxstr,RAD_SERIAL_BUFLEN - 1,3);
5984 if (i < 0) return -1;
5985 if ((i > 0) && (rxstr[i - 1] == '\r'))
5986 rxstr[i-- - 1] = 0;
5987 if (debug) printf("Got from kenwood: %s\n",rxstr);
5988 return(i);
5991 /* take a PL frequency and turn it into a code */
5992 static int kenwood_pltocode(char *str)
5994 int i;
5995 char *s;
5997 s = strchr(str,'.');
5998 i = 0;
5999 if (s) i = atoi(s + 1);
6000 i += atoi(str) * 10;
6001 switch(i)
6003 case 670:
6004 return 1;
6005 case 719:
6006 return 3;
6007 case 744:
6008 return 4;
6009 case 770:
6010 return 5;
6011 case 797:
6012 return 6;
6013 case 825:
6014 return 7;
6015 case 854:
6016 return 8;
6017 case 885:
6018 return 9;
6019 case 915:
6020 return 10;
6021 case 948:
6022 return 11;
6023 case 974:
6024 return 12;
6025 case 1000:
6026 return 13;
6027 case 1035:
6028 return 14;
6029 case 1072:
6030 return 15;
6031 case 1109:
6032 return 16;
6033 case 1148:
6034 return 17;
6035 case 1188:
6036 return 18;
6037 case 1230:
6038 return 19;
6039 case 1273:
6040 return 20;
6041 case 1318:
6042 return 21;
6043 case 1365:
6044 return 22;
6045 case 1413:
6046 return 23;
6047 case 1462:
6048 return 24;
6049 case 1514:
6050 return 25;
6051 case 1567:
6052 return 26;
6053 case 1622:
6054 return 27;
6055 case 1679:
6056 return 28;
6057 case 1738:
6058 return 29;
6059 case 1799:
6060 return 30;
6061 case 1862:
6062 return 31;
6063 case 1928:
6064 return 32;
6065 case 2035:
6066 return 33;
6067 case 2107:
6068 return 34;
6069 case 2181:
6070 return 35;
6071 case 2257:
6072 return 36;
6073 case 2336:
6074 return 37;
6075 case 2418:
6076 return 38;
6077 case 2503:
6078 return 39;
6080 return -1;
6083 static int sendrxkenwood(struct rpt *myrpt, char *txstr, char *rxstr,
6084 char *cmpstr)
6086 int i,j;
6088 for(i = 0;i < KENWOOD_RETRIES;i++)
6090 j = sendkenwood(myrpt,txstr,rxstr);
6091 if (j < 0) return(j);
6092 if (j == 0) continue;
6093 if (!strncmp(rxstr,cmpstr,strlen(cmpstr))) return(0);
6095 return(-1);
6098 static int setkenwood(struct rpt *myrpt)
6100 char rxstr[RAD_SERIAL_BUFLEN],txstr[RAD_SERIAL_BUFLEN],freq[20];
6101 char mhz[MAXREMSTR],offset[20],band,decimals[MAXREMSTR],band1,band2;
6103 int offsets[] = {0,2,1};
6104 int powers[] = {2,1,0};
6106 if (sendrxkenwood(myrpt,"VMC 0,0\r",rxstr,"VMC") < 0) return -1;
6107 split_freq(mhz, decimals, myrpt->freq);
6108 if (atoi(mhz) > 400)
6110 band = '6';
6111 band1 = '1';
6112 band2 = '5';
6113 strcpy(offset,"005000000");
6115 else
6117 band = '2';
6118 band1 = '0';
6119 band2 = '2';
6120 strcpy(offset,"000600000");
6122 strcpy(freq,"000000");
6123 strncpy(freq,decimals,strlen(decimals));
6124 sprintf(txstr,"VW %c,%05d%s,0,%d,0,%d,%d,,%02d,,%02d,%s\r",
6125 band,atoi(mhz),freq,offsets[(int)myrpt->offset],
6126 (myrpt->txplon != 0),(myrpt->rxplon != 0),
6127 kenwood_pltocode(myrpt->txpl),kenwood_pltocode(myrpt->rxpl),
6128 offset);
6129 if (sendrxkenwood(myrpt,txstr,rxstr,"VW") < 0) return -1;
6130 sprintf(txstr,"RBN %c\r",band2);
6131 if (sendrxkenwood(myrpt,txstr,rxstr,"RBN") < 0) return -1;
6132 sprintf(txstr,"PC %c,%d\r",band1,powers[(int)myrpt->powerlevel]);
6133 if (sendrxkenwood(myrpt,txstr,rxstr,"PC") < 0) return -1;
6134 return 0;
6137 static int setrbi(struct rpt *myrpt)
6139 char tmp[MAXREMSTR] = "",*s;
6140 unsigned char rbicmd[5];
6141 int band,txoffset = 0,txpower = 0,rxpl;
6143 /* must be a remote system */
6144 if (!myrpt->remote) return(0);
6145 /* must have rbi hardware */
6146 if (strncmp(myrpt->remote,remote_rig_rbi,3)) return(0);
6147 if (setrbi_check(myrpt) == -1) return(-1);
6148 strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
6149 s = strchr(tmp,'.');
6150 /* if no decimal, is invalid */
6152 if (s == NULL){
6153 if(debug)
6154 printf("@@@@ Frequency needs a decimal\n");
6155 return -1;
6158 *s++ = 0;
6159 if (strlen(tmp) < 2){
6160 if(debug)
6161 printf("@@@@ Bad MHz digits: %s\n", tmp);
6162 return -1;
6165 if (strlen(s) < 3){
6166 if(debug)
6167 printf("@@@@ Bad KHz digits: %s\n", s);
6168 return -1;
6171 if ((s[2] != '0') && (s[2] != '5')){
6172 if(debug)
6173 printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
6174 return -1;
6177 band = rbi_mhztoband(tmp);
6178 if (band == -1){
6179 if(debug)
6180 printf("@@@@ Bad Band: %s\n", tmp);
6181 return -1;
6184 rxpl = rbi_pltocode(myrpt->rxpl);
6186 if (rxpl == -1){
6187 if(debug)
6188 printf("@@@@ Bad TX PL: %s\n", myrpt->rxpl);
6189 return -1;
6193 switch(myrpt->offset)
6195 case REM_MINUS:
6196 txoffset = 0;
6197 break;
6198 case REM_PLUS:
6199 txoffset = 0x10;
6200 break;
6201 case REM_SIMPLEX:
6202 txoffset = 0x20;
6203 break;
6205 switch(myrpt->powerlevel)
6207 case REM_LOWPWR:
6208 txpower = 0;
6209 break;
6210 case REM_MEDPWR:
6211 txpower = 0x20;
6212 break;
6213 case REM_HIPWR:
6214 txpower = 0x10;
6215 break;
6217 rbicmd[0] = 0;
6218 rbicmd[1] = band | txpower | 0xc0;
6219 rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80;
6220 if (s[2] == '5') rbicmd[2] |= 0x40;
6221 rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0');
6222 rbicmd[4] = rxpl;
6223 if (myrpt->txplon) rbicmd[4] |= 0x40;
6224 if (myrpt->rxplon) rbicmd[4] |= 0x80;
6225 rbi_out(myrpt,rbicmd);
6226 return 0;
6229 static int setrbi_check(struct rpt *myrpt)
6231 char tmp[MAXREMSTR] = "",*s;
6232 int band,txpl;
6234 /* must be a remote system */
6235 if (!myrpt->remote) return(0);
6236 /* must have rbi hardware */
6237 if (strncmp(myrpt->remote,remote_rig_rbi,3)) return(0);
6238 strncpy(tmp, myrpt->freq, sizeof(tmp) - 1);
6239 s = strchr(tmp,'.');
6240 /* if no decimal, is invalid */
6242 if (s == NULL){
6243 if(debug)
6244 printf("@@@@ Frequency needs a decimal\n");
6245 return -1;
6248 *s++ = 0;
6249 if (strlen(tmp) < 2){
6250 if(debug)
6251 printf("@@@@ Bad MHz digits: %s\n", tmp);
6252 return -1;
6255 if (strlen(s) < 3){
6256 if(debug)
6257 printf("@@@@ Bad KHz digits: %s\n", s);
6258 return -1;
6261 if ((s[2] != '0') && (s[2] != '5')){
6262 if(debug)
6263 printf("@@@@ KHz must end in 0 or 5: %c\n", s[2]);
6264 return -1;
6267 band = rbi_mhztoband(tmp);
6268 if (band == -1){
6269 if(debug)
6270 printf("@@@@ Bad Band: %s\n", tmp);
6271 return -1;
6274 txpl = rbi_pltocode(myrpt->txpl);
6276 if (txpl == -1){
6277 if(debug)
6278 printf("@@@@ Bad TX PL: %s\n", myrpt->txpl);
6279 return -1;
6281 return 0;
6284 static int check_freq_kenwood(int m, int d, int *defmode)
6286 int dflmd = REM_MODE_FM;
6288 if (m == 144){ /* 2 meters */
6289 if(d < 10100)
6290 return -1;
6292 else if((m >= 145) && (m < 148)){
6295 else if((m >= 430) && (m < 450)){ /* 70 centimeters */
6298 else
6299 return -1;
6301 if(defmode)
6302 *defmode = dflmd;
6305 return 0;
6309 /* Check for valid rbi frequency */
6310 /* Hard coded limits now, configurable later, maybe? */
6312 static int check_freq_rbi(int m, int d, int *defmode)
6314 int dflmd = REM_MODE_FM;
6316 if(m == 50){ /* 6 meters */
6317 if(d < 10100)
6318 return -1;
6320 else if((m >= 51) && ( m < 54)){
6323 else if(m == 144){ /* 2 meters */
6324 if(d < 10100)
6325 return -1;
6327 else if((m >= 145) && (m < 148)){
6330 else if((m >= 222) && (m < 225)){ /* 1.25 meters */
6333 else if((m >= 430) && (m < 450)){ /* 70 centimeters */
6336 else if((m >= 1240) && (m < 1300)){ /* 23 centimeters */
6339 else
6340 return -1;
6342 if(defmode)
6343 *defmode = dflmd;
6346 return 0;
6350 * Convert decimals of frequency to int
6353 static int decimals2int(char *fraction)
6355 int i;
6356 char len = strlen(fraction);
6357 int multiplier = 100000;
6358 int res = 0;
6360 if(!len)
6361 return 0;
6362 for( i = 0 ; i < len ; i++, multiplier /= 10)
6363 res += (fraction[i] - '0') * multiplier;
6364 return res;
6369 * Split frequency into mhz and decimals
6372 static int split_freq(char *mhz, char *decimals, char *freq)
6374 char freq_copy[MAXREMSTR];
6375 char *decp;
6377 decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
6378 if(decp){
6379 *decp++ = 0;
6380 strncpy(mhz, freq_copy, MAXREMSTR);
6381 strcpy(decimals, "00000");
6382 strncpy(decimals, decp, strlen(decp));
6383 decimals[5] = 0;
6384 return 0;
6386 else
6387 return -1;
6392 * Split ctcss frequency into hertz and decimal
6395 static int split_ctcss_freq(char *hertz, char *decimal, char *freq)
6397 char freq_copy[MAXREMSTR];
6398 char *decp;
6400 decp = strchr(strncpy(freq_copy, freq, MAXREMSTR),'.');
6401 if(decp){
6402 *decp++ = 0;
6403 strncpy(hertz, freq_copy, MAXREMSTR);
6404 strncpy(decimal, decp, strlen(decp));
6405 decimal[strlen(decp)] = '\0';
6406 return 0;
6408 else
6409 return -1;
6415 * FT-897 I/O handlers
6418 /* Check to see that the frequency is valid */
6419 /* Hard coded limits now, configurable later, maybe? */
6422 static int check_freq_ft897(int m, int d, int *defmode)
6424 int dflmd = REM_MODE_FM;
6426 if(m == 1){ /* 160 meters */
6427 dflmd = REM_MODE_LSB;
6428 if(d < 80000)
6429 return -1;
6431 else if(m == 3){ /* 80 meters */
6432 dflmd = REM_MODE_LSB;
6433 if(d < 50000)
6434 return -1;
6436 else if(m == 7){ /* 40 meters */
6437 dflmd = REM_MODE_LSB;
6438 if(d > 30000)
6439 return -1;
6441 else if(m == 14){ /* 20 meters */
6442 dflmd = REM_MODE_USB;
6443 if(d > 35000)
6444 return -1;
6446 else if(m == 18){ /* 17 meters */
6447 dflmd = REM_MODE_USB;
6448 if((d < 6800) || (d > 16800))
6449 return -1;
6451 else if(m == 21){ /* 15 meters */
6452 dflmd = REM_MODE_USB;
6453 if((d < 20000) || (d > 45000))
6454 return -1;
6456 else if(m == 24){ /* 12 meters */
6457 dflmd = REM_MODE_USB;
6458 if((d < 89000) || (d > 99000))
6459 return -1;
6461 else if(m == 28){ /* 10 meters */
6462 dflmd = REM_MODE_USB;
6464 else if(m == 29){
6465 if(d >= 51000)
6466 dflmd = REM_MODE_FM;
6467 else
6468 dflmd = REM_MODE_USB;
6469 if(d > 70000)
6470 return -1;
6472 else if(m == 50){ /* 6 meters */
6473 if(d >= 30000)
6474 dflmd = REM_MODE_FM;
6475 else
6476 dflmd = REM_MODE_USB;
6479 else if((m >= 51) && ( m < 54)){
6480 dflmd = REM_MODE_FM;
6482 else if(m == 144){ /* 2 meters */
6483 if(d >= 30000)
6484 dflmd = REM_MODE_FM;
6485 else
6486 dflmd = REM_MODE_USB;
6488 else if((m >= 145) && (m < 148)){
6489 dflmd = REM_MODE_FM;
6491 else if((m >= 430) && (m < 450)){ /* 70 centimeters */
6492 if(m < 438)
6493 dflmd = REM_MODE_USB;
6494 else
6495 dflmd = REM_MODE_FM;
6498 else
6499 return -1;
6501 if(defmode)
6502 *defmode = dflmd;
6504 return 0;
6508 * Set a new frequency for the FT897
6511 static int set_freq_ft897(struct rpt *myrpt, char *newfreq)
6513 unsigned char cmdstr[5];
6514 int fd,m,d;
6515 char mhz[MAXREMSTR];
6516 char decimals[MAXREMSTR];
6518 fd = 0;
6519 if(debug)
6520 printf("New frequency: %s\n",newfreq);
6522 if(split_freq(mhz, decimals, newfreq))
6523 return -1;
6525 m = atoi(mhz);
6526 d = atoi(decimals);
6528 /* The FT-897 likes packed BCD frequencies */
6530 cmdstr[0] = ((m / 100) << 4) + ((m % 100)/10); /* 100MHz 10Mhz */
6531 cmdstr[1] = ((m % 10) << 4) + (d / 10000); /* 1MHz 100KHz */
6532 cmdstr[2] = (((d % 10000)/1000) << 4) + ((d % 1000)/ 100); /* 10KHz 1KHz */
6533 cmdstr[3] = (((d % 100)/10) << 4) + (d % 10); /* 100Hz 10Hz */
6534 cmdstr[4] = 0x01; /* command */
6536 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
6540 /* ft-897 simple commands */
6542 static int simple_command_ft897(struct rpt *myrpt, char command)
6544 unsigned char cmdstr[5];
6546 memset(cmdstr, 0, 5);
6548 cmdstr[4] = command;
6550 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
6554 /* ft-897 offset */
6556 static int set_offset_ft897(struct rpt *myrpt, char offset)
6558 unsigned char cmdstr[5];
6560 memset(cmdstr, 0, 5);
6562 switch(offset){
6563 case REM_SIMPLEX:
6564 cmdstr[0] = 0x89;
6565 break;
6567 case REM_MINUS:
6568 cmdstr[0] = 0x09;
6569 break;
6571 case REM_PLUS:
6572 cmdstr[0] = 0x49;
6573 break;
6575 default:
6576 return -1;
6579 cmdstr[4] = 0x09;
6581 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
6584 /* ft-897 mode */
6586 static int set_mode_ft897(struct rpt *myrpt, char newmode)
6588 unsigned char cmdstr[5];
6590 memset(cmdstr, 0, 5);
6592 switch(newmode){
6593 case REM_MODE_FM:
6594 cmdstr[0] = 0x08;
6595 break;
6597 case REM_MODE_USB:
6598 cmdstr[0] = 0x01;
6599 break;
6601 case REM_MODE_LSB:
6602 cmdstr[0] = 0x00;
6603 break;
6605 case REM_MODE_AM:
6606 cmdstr[0] = 0x04;
6607 break;
6609 default:
6610 return -1;
6612 cmdstr[4] = 0x07;
6614 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
6617 /* Set tone encode and decode modes */
6619 static int set_ctcss_mode_ft897(struct rpt *myrpt, char txplon, char rxplon)
6621 unsigned char cmdstr[5];
6623 memset(cmdstr, 0, 5);
6625 if(rxplon && txplon)
6626 cmdstr[0] = 0x2A; /* Encode and Decode */
6627 else if (!rxplon && txplon)
6628 cmdstr[0] = 0x4A; /* Encode only */
6629 else if (rxplon && !txplon)
6630 cmdstr[0] = 0x3A; /* Encode only */
6631 else
6632 cmdstr[0] = 0x8A; /* OFF */
6634 cmdstr[4] = 0x0A;
6636 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
6640 /* Set transmit and receive ctcss tone frequencies */
6642 static int set_ctcss_freq_ft897(struct rpt *myrpt, char *txtone, char *rxtone)
6644 unsigned char cmdstr[5];
6645 char hertz[MAXREMSTR],decimal[MAXREMSTR];
6646 int h,d;
6648 memset(cmdstr, 0, 5);
6650 if(split_ctcss_freq(hertz, decimal, txtone))
6651 return -1;
6653 h = atoi(hertz);
6654 d = atoi(decimal);
6656 cmdstr[0] = ((h / 100) << 4) + (h % 100)/ 10;
6657 cmdstr[1] = ((h % 10) << 4) + (d % 10);
6659 if(rxtone){
6661 if(split_ctcss_freq(hertz, decimal, rxtone))
6662 return -1;
6664 h = atoi(hertz);
6665 d = atoi(decimal);
6667 cmdstr[2] = ((h / 100) << 4) + (h % 100)/ 10;
6668 cmdstr[3] = ((h % 10) << 4) + (d % 10);
6670 cmdstr[4] = 0x0B;
6672 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
6677 static int set_ft897(struct rpt *myrpt)
6679 int res;
6681 if(debug)
6682 printf("@@@@ lock on\n");
6684 res = simple_command_ft897(myrpt, 0x00); /* LOCK on */
6686 if(debug)
6687 printf("@@@@ ptt off\n");
6689 if(!res)
6690 res = simple_command_ft897(myrpt, 0x88); /* PTT off */
6692 if(debug)
6693 printf("Modulation mode\n");
6695 if(!res)
6696 res = set_mode_ft897(myrpt, myrpt->remmode); /* Modulation mode */
6698 if(debug)
6699 printf("Split off\n");
6701 if(!res)
6702 simple_command_ft897(myrpt, 0x82); /* Split off */
6704 if(debug)
6705 printf("Frequency\n");
6707 if(!res)
6708 res = set_freq_ft897(myrpt, myrpt->freq); /* Frequency */
6709 if((myrpt->remmode == REM_MODE_FM)){
6710 if(debug)
6711 printf("Offset\n");
6712 if(!res)
6713 res = set_offset_ft897(myrpt, myrpt->offset); /* Offset if FM */
6714 if((!res)&&(myrpt->rxplon || myrpt->txplon)){
6715 if(debug)
6716 printf("CTCSS tone freqs.\n");
6717 res = set_ctcss_freq_ft897(myrpt, myrpt->txpl, myrpt->rxpl); /* CTCSS freqs if CTCSS is enabled */
6719 if(!res){
6720 if(debug)
6721 printf("CTCSS mode\n");
6722 res = set_ctcss_mode_ft897(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
6725 if((myrpt->remmode == REM_MODE_USB)||(myrpt->remmode == REM_MODE_LSB)){
6726 if(debug)
6727 printf("Clarifier off\n");
6728 simple_command_ft897(myrpt, 0x85); /* Clarifier off if LSB or USB */
6730 return res;
6733 static int closerem_ft897(struct rpt *myrpt)
6735 simple_command_ft897(myrpt, 0x88); /* PTT off */
6736 return 0;
6740 * Bump frequency up or down by a small amount
6741 * Return 0 if the new frequnecy is valid, or -1 if invalid
6742 * Interval is in Hz, resolution is 10Hz
6745 static int multimode_bump_freq_ft897(struct rpt *myrpt, int interval)
6747 int m,d;
6748 char mhz[MAXREMSTR], decimals[MAXREMSTR];
6750 if(debug)
6751 printf("Before bump: %s\n", myrpt->freq);
6753 if(split_freq(mhz, decimals, myrpt->freq))
6754 return -1;
6756 m = atoi(mhz);
6757 d = atoi(decimals);
6759 d += (interval / 10); /* 10Hz resolution */
6760 if(d < 0){
6761 m--;
6762 d += 100000;
6764 else if(d >= 100000){
6765 m++;
6766 d -= 100000;
6769 if(check_freq_ft897(m, d, NULL)){
6770 if(debug)
6771 printf("Bump freq invalid\n");
6772 return -1;
6775 snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
6777 if(debug)
6778 printf("After bump: %s\n", myrpt->freq);
6780 return set_freq_ft897(myrpt, myrpt->freq);
6786 * IC-706 I/O handlers
6789 /* Check to see that the frequency is valid */
6790 /* Hard coded limits now, configurable later, maybe? */
6793 static int check_freq_ic706(int m, int d, int *defmode)
6795 int dflmd = REM_MODE_FM;
6797 if(m == 1){ /* 160 meters */
6798 dflmd = REM_MODE_LSB;
6799 if(d < 80000)
6800 return -1;
6802 else if(m == 3){ /* 80 meters */
6803 dflmd = REM_MODE_LSB;
6804 if(d < 50000)
6805 return -1;
6807 else if(m == 7){ /* 40 meters */
6808 dflmd = REM_MODE_LSB;
6809 if(d > 30000)
6810 return -1;
6812 else if(m == 14){ /* 20 meters */
6813 dflmd = REM_MODE_USB;
6814 if(d > 35000)
6815 return -1;
6817 else if(m == 18){ /* 17 meters */
6818 dflmd = REM_MODE_USB;
6819 if((d < 6800) || (d > 16800))
6820 return -1;
6822 else if(m == 21){ /* 15 meters */
6823 dflmd = REM_MODE_USB;
6824 if((d < 20000) || (d > 45000))
6825 return -1;
6827 else if(m == 24){ /* 12 meters */
6828 dflmd = REM_MODE_USB;
6829 if((d < 89000) || (d > 99000))
6830 return -1;
6832 else if(m == 28){ /* 10 meters */
6833 dflmd = REM_MODE_USB;
6835 else if(m == 29){
6836 if(d >= 51000)
6837 dflmd = REM_MODE_FM;
6838 else
6839 dflmd = REM_MODE_USB;
6840 if(d > 70000)
6841 return -1;
6843 else if(m == 50){ /* 6 meters */
6844 if(d >= 30000)
6845 dflmd = REM_MODE_FM;
6846 else
6847 dflmd = REM_MODE_USB;
6850 else if((m >= 51) && ( m < 54)){
6851 dflmd = REM_MODE_FM;
6853 else if(m == 144){ /* 2 meters */
6854 if(d >= 30000)
6855 dflmd = REM_MODE_FM;
6856 else
6857 dflmd = REM_MODE_USB;
6859 else if((m >= 145) && (m < 148)){
6860 dflmd = REM_MODE_FM;
6862 else if((m >= 430) && (m < 450)){ /* 70 centimeters */
6863 if(m < 438)
6864 dflmd = REM_MODE_USB;
6865 else
6866 dflmd = REM_MODE_FM;
6869 else
6870 return -1;
6872 if(defmode)
6873 *defmode = dflmd;
6875 return 0;
6878 /* take a PL frequency and turn it into a code */
6879 static int ic706_pltocode(char *str)
6881 int i;
6882 char *s;
6884 s = strchr(str,'.');
6885 i = 0;
6886 if (s) i = atoi(s + 1);
6887 i += atoi(str) * 10;
6888 switch(i)
6890 case 670:
6891 return 0;
6892 case 693:
6893 return 1;
6894 case 719:
6895 return 2;
6896 case 744:
6897 return 3;
6898 case 770:
6899 return 4;
6900 case 797:
6901 return 5;
6902 case 825:
6903 return 6;
6904 case 854:
6905 return 7;
6906 case 885:
6907 return 8;
6908 case 915:
6909 return 9;
6910 case 948:
6911 return 10;
6912 case 974:
6913 return 11;
6914 case 1000:
6915 return 12;
6916 case 1035:
6917 return 13;
6918 case 1072:
6919 return 14;
6920 case 1109:
6921 return 15;
6922 case 1148:
6923 return 16;
6924 case 1188:
6925 return 17;
6926 case 1230:
6927 return 18;
6928 case 1273:
6929 return 19;
6930 case 1318:
6931 return 20;
6932 case 1365:
6933 return 21;
6934 case 1413:
6935 return 22;
6936 case 1462:
6937 return 23;
6938 case 1514:
6939 return 24;
6940 case 1567:
6941 return 25;
6942 case 1598:
6943 return 26;
6944 case 1622:
6945 return 27;
6946 case 1655:
6947 return 28;
6948 case 1679:
6949 return 29;
6950 case 1713:
6951 return 30;
6952 case 1738:
6953 return 31;
6954 case 1773:
6955 return 32;
6956 case 1799:
6957 return 33;
6958 case 1835:
6959 return 34;
6960 case 1862:
6961 return 35;
6962 case 1899:
6963 return 36;
6964 case 1928:
6965 return 37;
6966 case 1966:
6967 return 38;
6968 case 1995:
6969 return 39;
6970 case 2035:
6971 return 40;
6972 case 2065:
6973 return 41;
6974 case 2107:
6975 return 42;
6976 case 2181:
6977 return 43;
6978 case 2257:
6979 return 44;
6980 case 2291:
6981 return 45;
6982 case 2336:
6983 return 46;
6984 case 2418:
6985 return 47;
6986 case 2503:
6987 return 48;
6988 case 2541:
6989 return 49;
6991 return -1;
6994 /* ic-706 simple commands */
6996 static int simple_command_ic706(struct rpt *myrpt, char command, char subcommand)
6998 unsigned char cmdstr[10];
7000 cmdstr[0] = cmdstr[1] = 0xfe;
7001 cmdstr[2] = myrpt->p.civaddr;
7002 cmdstr[3] = 0xe0;
7003 cmdstr[4] = command;
7004 cmdstr[5] = subcommand;
7005 cmdstr[6] = 0xfd;
7007 return(civ_cmd(myrpt,cmdstr,7));
7011 * Set a new frequency for the ic706
7014 static int set_freq_ic706(struct rpt *myrpt, char *newfreq)
7016 unsigned char cmdstr[20];
7017 char mhz[MAXREMSTR], decimals[MAXREMSTR];
7018 int fd,m,d;
7020 fd = 0;
7021 if(debug)
7022 printf("New frequency: %s\n",newfreq);
7024 if(split_freq(mhz, decimals, newfreq))
7025 return -1;
7027 m = atoi(mhz);
7028 d = atoi(decimals);
7030 /* The ic-706 likes packed BCD frequencies */
7032 cmdstr[0] = cmdstr[1] = 0xfe;
7033 cmdstr[2] = myrpt->p.civaddr;
7034 cmdstr[3] = 0xe0;
7035 cmdstr[4] = 5;
7036 cmdstr[5] = ((d % 10) << 4);
7037 cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
7038 cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
7039 cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
7040 cmdstr[9] = (m / 100);
7041 cmdstr[10] = 0xfd;
7043 return(civ_cmd(myrpt,cmdstr,11));
7046 /* ic-706 offset */
7048 static int set_offset_ic706(struct rpt *myrpt, char offset)
7050 unsigned char c;
7052 switch(offset){
7053 case REM_SIMPLEX:
7054 c = 0x10;
7055 break;
7057 case REM_MINUS:
7058 c = 0x11;
7059 break;
7061 case REM_PLUS:
7062 c = 0x12;
7063 break;
7065 default:
7066 return -1;
7069 return simple_command_ic706(myrpt,0x0f,c);
7073 /* ic-706 mode */
7075 static int set_mode_ic706(struct rpt *myrpt, char newmode)
7077 unsigned char c;
7079 switch(newmode){
7080 case REM_MODE_FM:
7081 c = 5;
7082 break;
7084 case REM_MODE_USB:
7085 c = 1;
7086 break;
7088 case REM_MODE_LSB:
7089 c = 0;
7090 break;
7092 case REM_MODE_AM:
7093 c = 2;
7094 break;
7096 default:
7097 return -1;
7099 return simple_command_ic706(myrpt,6,c);
7102 /* Set tone encode and decode modes */
7104 static int set_ctcss_mode_ic706(struct rpt *myrpt, char txplon, char rxplon)
7106 unsigned char cmdstr[10];
7107 int rv;
7109 cmdstr[0] = cmdstr[1] = 0xfe;
7110 cmdstr[2] = myrpt->p.civaddr;
7111 cmdstr[3] = 0xe0;
7112 cmdstr[4] = 0x16;
7113 cmdstr[5] = 0x42;
7114 cmdstr[6] = (txplon != 0);
7115 cmdstr[7] = 0xfd;
7117 rv = civ_cmd(myrpt,cmdstr,8);
7118 if (rv) return(-1);
7120 cmdstr[0] = cmdstr[1] = 0xfe;
7121 cmdstr[2] = myrpt->p.civaddr;
7122 cmdstr[3] = 0xe0;
7123 cmdstr[4] = 0x16;
7124 cmdstr[5] = 0x43;
7125 cmdstr[6] = (rxplon != 0);
7126 cmdstr[7] = 0xfd;
7128 return(civ_cmd(myrpt,cmdstr,8));
7131 #if 0
7132 /* Set transmit and receive ctcss tone frequencies */
7134 static int set_ctcss_freq_ic706(struct rpt *myrpt, char *txtone, char *rxtone)
7136 unsigned char cmdstr[10];
7137 char hertz[MAXREMSTR],decimal[MAXREMSTR];
7138 int h,d,rv;
7140 memset(cmdstr, 0, 5);
7142 if(split_ctcss_freq(hertz, decimal, txtone))
7143 return -1;
7145 h = atoi(hertz);
7146 d = atoi(decimal);
7148 cmdstr[0] = cmdstr[1] = 0xfe;
7149 cmdstr[2] = myrpt->p.civaddr;
7150 cmdstr[3] = 0xe0;
7151 cmdstr[4] = 0x1b;
7152 cmdstr[5] = 0;
7153 cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
7154 cmdstr[7] = ((h % 10) << 4) + (d % 10);
7155 cmdstr[8] = 0xfd;
7157 rv = civ_cmd(myrpt,cmdstr,9);
7158 if (rv) return(-1);
7160 if (!rxtone) return(0);
7162 if(split_ctcss_freq(hertz, decimal, rxtone))
7163 return -1;
7165 h = atoi(hertz);
7166 d = atoi(decimal);
7168 cmdstr[0] = cmdstr[1] = 0xfe;
7169 cmdstr[2] = myrpt->p.civaddr;
7170 cmdstr[3] = 0xe0;
7171 cmdstr[4] = 0x1b;
7172 cmdstr[5] = 1;
7173 cmdstr[6] = ((h / 100) << 4) + (h % 100)/ 10;
7174 cmdstr[7] = ((h % 10) << 4) + (d % 10);
7175 cmdstr[8] = 0xfd;
7176 return(civ_cmd(myrpt,cmdstr,9));
7178 #endif
7180 static int vfo_ic706(struct rpt *myrpt)
7182 unsigned char cmdstr[10];
7184 cmdstr[0] = cmdstr[1] = 0xfe;
7185 cmdstr[2] = myrpt->p.civaddr;
7186 cmdstr[3] = 0xe0;
7187 cmdstr[4] = 7;
7188 cmdstr[5] = 0xfd;
7190 return(civ_cmd(myrpt,cmdstr,6));
7193 static int mem2vfo_ic706(struct rpt *myrpt)
7195 unsigned char cmdstr[10];
7197 cmdstr[0] = cmdstr[1] = 0xfe;
7198 cmdstr[2] = myrpt->p.civaddr;
7199 cmdstr[3] = 0xe0;
7200 cmdstr[4] = 0x0a;
7201 cmdstr[5] = 0xfd;
7203 return(civ_cmd(myrpt,cmdstr,6));
7206 static int select_mem_ic706(struct rpt *myrpt, int slot)
7208 unsigned char cmdstr[10];
7210 cmdstr[0] = cmdstr[1] = 0xfe;
7211 cmdstr[2] = myrpt->p.civaddr;
7212 cmdstr[3] = 0xe0;
7213 cmdstr[4] = 8;
7214 cmdstr[5] = 0;
7215 cmdstr[6] = ((slot / 10) << 4) + (slot % 10);
7216 cmdstr[7] = 0xfd;
7218 return(civ_cmd(myrpt,cmdstr,8));
7221 static int set_ic706(struct rpt *myrpt)
7223 int res = 0,i;
7225 if(debug)
7226 printf("Set to VFO A\n");
7228 if (!res)
7229 res = simple_command_ic706(myrpt,7,0);
7232 if((myrpt->remmode == REM_MODE_FM))
7234 i = ic706_pltocode(myrpt->rxpl);
7235 if (i == -1) return -1;
7236 if(debug)
7237 printf("Select memory number\n");
7238 if (!res)
7239 res = select_mem_ic706(myrpt,i + IC706_PL_MEMORY_OFFSET);
7240 if(debug)
7241 printf("Transfer memory to VFO\n");
7242 if (!res)
7243 res = mem2vfo_ic706(myrpt);
7246 if(debug)
7247 printf("Set to VFO\n");
7249 if (!res)
7250 res = vfo_ic706(myrpt);
7252 if(debug)
7253 printf("Modulation mode\n");
7255 if (!res)
7256 res = set_mode_ic706(myrpt, myrpt->remmode); /* Modulation mode */
7258 if(debug)
7259 printf("Split off\n");
7261 if(!res)
7262 simple_command_ic706(myrpt, 0x82,0); /* Split off */
7264 if(debug)
7265 printf("Frequency\n");
7267 if(!res)
7268 res = set_freq_ic706(myrpt, myrpt->freq); /* Frequency */
7269 if((myrpt->remmode == REM_MODE_FM)){
7270 if(debug)
7271 printf("Offset\n");
7272 if(!res)
7273 res = set_offset_ic706(myrpt, myrpt->offset); /* Offset if FM */
7274 if(!res){
7275 if(debug)
7276 printf("CTCSS mode\n");
7277 res = set_ctcss_mode_ic706(myrpt, myrpt->txplon, myrpt->rxplon); /* CTCSS mode */
7280 return res;
7284 * Bump frequency up or down by a small amount
7285 * Return 0 if the new frequnecy is valid, or -1 if invalid
7286 * Interval is in Hz, resolution is 10Hz
7289 static int multimode_bump_freq_ic706(struct rpt *myrpt, int interval)
7291 int m,d;
7292 char mhz[MAXREMSTR], decimals[MAXREMSTR];
7293 unsigned char cmdstr[20];
7295 if(debug)
7296 printf("Before bump: %s\n", myrpt->freq);
7298 if(split_freq(mhz, decimals, myrpt->freq))
7299 return -1;
7301 m = atoi(mhz);
7302 d = atoi(decimals);
7304 d += (interval / 10); /* 10Hz resolution */
7305 if(d < 0){
7306 m--;
7307 d += 100000;
7309 else if(d >= 100000){
7310 m++;
7311 d -= 100000;
7314 if(check_freq_ic706(m, d, NULL)){
7315 if(debug)
7316 printf("Bump freq invalid\n");
7317 return -1;
7320 snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
7322 if(debug)
7323 printf("After bump: %s\n", myrpt->freq);
7325 /* The ic-706 likes packed BCD frequencies */
7327 cmdstr[0] = cmdstr[1] = 0xfe;
7328 cmdstr[2] = myrpt->p.civaddr;
7329 cmdstr[3] = 0xe0;
7330 cmdstr[4] = 0;
7331 cmdstr[5] = ((d % 10) << 4);
7332 cmdstr[6] = (((d % 1000)/ 100) << 4) + ((d % 100)/10);
7333 cmdstr[7] = ((d / 10000) << 4) + ((d % 10000)/1000);
7334 cmdstr[8] = (((m % 100)/10) << 4) + (m % 10);
7335 cmdstr[9] = (m / 100);
7336 cmdstr[10] = 0xfd;
7338 return(serial_remote_io(myrpt,cmdstr,11,NULL,0,0));
7344 * Dispatch to correct I/O handler
7347 static int setrem(struct rpt *myrpt)
7349 char str[300];
7350 char *offsets[] = {"MINUS","SIMPLEX","PLUS"};
7351 char *powerlevels[] = {"LOW","MEDIUM","HIGH"};
7352 char *modes[] = {"FM","USB","LSB","AM"};
7353 int res = -1;
7355 if (myrpt->p.archivedir)
7357 sprintf(str,"FREQ,%s,%s,%s,%s,%s,%s,%d,%d",myrpt->freq,
7358 modes[(int)myrpt->remmode],
7359 myrpt->txpl,myrpt->rxpl,offsets[(int)myrpt->offset],
7360 powerlevels[(int)myrpt->powerlevel],myrpt->txplon,
7361 myrpt->rxplon);
7362 donodelog(myrpt,str);
7364 if(!strcmp(myrpt->remote, remote_rig_ft897))
7366 rpt_telemetry(myrpt,SETREMOTE,NULL);
7367 res = 0;
7369 if(!strcmp(myrpt->remote, remote_rig_ic706))
7371 rpt_telemetry(myrpt,SETREMOTE,NULL);
7372 res = 0;
7374 else if(!strcmp(myrpt->remote, remote_rig_rbi))
7376 res = setrbi_check(myrpt);
7377 if (!res)
7379 rpt_telemetry(myrpt,SETREMOTE,NULL);
7380 res = 0;
7383 else if(!strcmp(myrpt->remote, remote_rig_kenwood)) {
7384 rpt_telemetry(myrpt,SETREMOTE,NULL);
7385 res = 0;
7387 else
7388 res = 0;
7390 if (res < 0) ast_log(LOG_ERROR,"Unable to send remote command on node %s\n",myrpt->name);
7392 return res;
7395 static int closerem(struct rpt *myrpt)
7397 if(!strcmp(myrpt->remote, remote_rig_ft897))
7398 return closerem_ft897(myrpt);
7399 else
7400 return 0;
7404 * Dispatch to correct RX frequency checker
7407 static int check_freq(struct rpt *myrpt, int m, int d, int *defmode)
7409 if(!strcmp(myrpt->remote, remote_rig_ft897))
7410 return check_freq_ft897(m, d, defmode);
7411 else if(!strcmp(myrpt->remote, remote_rig_ic706))
7412 return check_freq_ic706(m, d, defmode);
7413 else if(!strcmp(myrpt->remote, remote_rig_rbi))
7414 return check_freq_rbi(m, d, defmode);
7415 else if(!strcmp(myrpt->remote, remote_rig_kenwood))
7416 return check_freq_kenwood(m, d, defmode);
7417 else
7418 return -1;
7422 * Check TX frequency before transmitting
7425 static char check_tx_freq(struct rpt *myrpt)
7427 int i;
7428 int radio_mhz, radio_decimals, ulimit_mhz, ulimit_decimals, llimit_mhz, llimit_decimals;
7429 char radio_mhz_char[MAXREMSTR];
7430 char radio_decimals_char[MAXREMSTR];
7431 char limit_mhz_char[MAXREMSTR];
7432 char limit_decimals_char[MAXREMSTR];
7433 char limits[256];
7434 char *limit_ranges[40];
7435 struct ast_variable *limitlist;
7438 /* Must have user logged in and tx_limits defined */
7440 if(!myrpt->p.txlimitsstanzaname || !myrpt->loginuser[0] || !myrpt->loginlevel[0]){
7441 if(debug > 3){
7442 ast_log(LOG_NOTICE, "No tx band table defined, or no user logged in\n");
7444 return 1; /* Assume it's ok otherwise */
7447 /* Retrieve the band table for the loginlevel */
7448 limitlist = ast_variable_browse(myrpt->cfg, myrpt->p.txlimitsstanzaname);
7450 if(!limitlist){
7451 ast_log(LOG_WARNING, "No entries in %s band table stanza\n", myrpt->p.txlimitsstanzaname);
7452 return 0;
7455 split_freq(radio_mhz_char, radio_decimals_char, myrpt->freq);
7456 radio_mhz = atoi(radio_mhz_char);
7457 radio_decimals = decimals2int(radio_decimals_char);
7460 if(debug > 3){
7461 ast_log(LOG_NOTICE, "Login User = %s, login level = %s\n", myrpt->loginuser, myrpt->loginlevel);
7464 /* Find our entry */
7466 for(;limitlist; limitlist=limitlist->next){
7467 if(!strcmp(limitlist->name, myrpt->loginlevel))
7468 break;
7471 if(!limitlist){
7472 ast_log(LOG_WARNING, "Can't find %s entry in band table stanza %s\n", myrpt->loginlevel, myrpt->p.txlimitsstanzaname);
7473 return 0;
7476 if(debug > 3){
7477 ast_log(LOG_NOTICE, "Auth %s = %s\n", limitlist->name, limitlist->value);
7480 /* Parse the limits */
7482 strncpy(limits, limitlist->value, 256);
7483 limits[255] = 0;
7484 finddelim(limits, limit_ranges, 40);
7485 for(i = 0; i < 40 && limit_ranges[i] ; i++){
7486 char range[40];
7487 char *r,*s;
7488 strncpy(range, limit_ranges[i], 40);
7489 range[39] = 0;
7490 if(debug > 3){
7491 ast_log(LOG_NOTICE, "Checking to see if %s is within limits of %s\n", myrpt->freq, range);
7494 r = strchr(range, '-');
7495 if(!r){
7496 ast_log(LOG_WARNING, "Malformed range in %s tx band table entry\n", limitlist->name);
7497 return 0;
7499 *r++ = 0;
7500 s = eatwhite(range);
7501 r = eatwhite(r);
7502 split_freq(limit_mhz_char, limit_decimals_char, s);
7503 llimit_mhz = atoi(limit_mhz_char);
7504 llimit_decimals = decimals2int(limit_decimals_char);
7505 split_freq(limit_mhz_char, limit_decimals_char, r);
7506 ulimit_mhz = atoi(limit_mhz_char);
7507 ulimit_decimals = decimals2int(limit_decimals_char);
7509 if((radio_mhz >= llimit_mhz) && (radio_mhz <= ulimit_mhz)){
7510 if(radio_mhz == llimit_mhz){ /* CASE 1: TX freq is in llimit mhz portion of band */
7511 if(radio_decimals >= llimit_decimals){ /* Cannot be below llimit decimals */
7512 if(llimit_mhz == ulimit_mhz){ /* If bandwidth < 1Mhz, check ulimit decimals */
7513 if(radio_decimals <= ulimit_decimals){
7514 return 1;
7516 else{
7517 if(debug > 3)
7518 ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 1\n");
7519 return 0;
7522 else{
7523 return 1;
7526 else{ /* Is below llimit decimals */
7527 if(debug > 3)
7528 ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 2\n");
7529 return 0;
7532 else if(radio_mhz == ulimit_mhz){ /* CASE 2: TX freq not in llimit mhz portion of band */
7533 if(radio_decimals <= ulimit_decimals){
7534 return 1;
7536 else{ /* Is above ulimit decimals */
7537 if(debug > 3)
7538 ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 3\n");
7539 return 0;
7542 else /* CASE 3: TX freq within a multi-Mhz band and ok */
7543 return 1;
7546 if(debug > 3) /* No match found in TX band table */
7547 ast_log(LOG_NOTICE, "Invalid TX frequency, debug msg 4\n");
7548 return 0;
7553 * Dispatch to correct frequency bumping function
7556 static int multimode_bump_freq(struct rpt *myrpt, int interval)
7558 if(!strcmp(myrpt->remote, remote_rig_ft897))
7559 return multimode_bump_freq_ft897(myrpt, interval);
7560 else if(!strcmp(myrpt->remote, remote_rig_ic706))
7561 return multimode_bump_freq_ic706(myrpt, interval);
7562 else
7563 return -1;
7568 * Queue announcment that scan has been stopped
7571 static void stop_scan(struct rpt *myrpt)
7573 myrpt->hfscanstop = 1;
7574 rpt_telemetry(myrpt,SCAN,0);
7578 * This is called periodically when in scan mode
7582 static int service_scan(struct rpt *myrpt)
7584 int res, interval;
7585 char mhz[MAXREMSTR], decimals[MAXREMSTR], k10=0i, k100=0;
7587 switch(myrpt->hfscanmode){
7589 case HF_SCAN_DOWN_SLOW:
7590 interval = -10; /* 100Hz /sec */
7591 break;
7593 case HF_SCAN_DOWN_QUICK:
7594 interval = -50; /* 500Hz /sec */
7595 break;
7597 case HF_SCAN_DOWN_FAST:
7598 interval = -200; /* 2KHz /sec */
7599 break;
7601 case HF_SCAN_UP_SLOW:
7602 interval = 10; /* 100Hz /sec */
7603 break;
7605 case HF_SCAN_UP_QUICK:
7606 interval = 50; /* 500 Hz/sec */
7607 break;
7609 case HF_SCAN_UP_FAST:
7610 interval = 200; /* 2KHz /sec */
7611 break;
7613 default:
7614 myrpt->hfscanmode = 0; /* Huh? */
7615 return -1;
7618 res = split_freq(mhz, decimals, myrpt->freq);
7620 if(!res){
7621 k100 =decimals[0];
7622 k10 = decimals[1];
7623 res = multimode_bump_freq(myrpt, interval);
7626 if(!res)
7627 res = split_freq(mhz, decimals, myrpt->freq);
7630 if(res){
7631 myrpt->hfscanmode = 0;
7632 myrpt->hfscanstatus = -2;
7633 return -1;
7636 /* Announce 10KHz boundaries */
7637 if(k10 != decimals[1]){
7638 int myhund = (interval < 0) ? k100 : decimals[0];
7639 int myten = (interval < 0) ? k10 : decimals[1];
7640 myrpt->hfscanstatus = (myten == '0') ? (myhund - '0') * 100 : (myten - '0') * 10;
7641 } else myrpt->hfscanstatus = 0;
7642 return res;
7647 * Retrieve a memory channel
7648 * Return 0 if sucessful,
7649 * -1 if channel not found,
7650 * 1 if parse error
7653 static int retreive_memory(struct rpt *myrpt, char *memory)
7655 char tmp[30], *s, *s1, *val;
7657 val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.memory, memory);
7658 if (!val){
7659 return -1;
7661 strncpy(tmp,val,sizeof(tmp) - 1);
7662 tmp[sizeof(tmp)-1] = 0;
7664 s = strchr(tmp,',');
7665 if (!s)
7666 return 1;
7667 *s++ = 0;
7668 s1 = strchr(s,',');
7669 if (!s1)
7670 return 1;
7671 *s1++ = 0;
7672 strncpy(myrpt->freq, tmp, sizeof(myrpt->freq) - 1);
7673 strncpy(myrpt->rxpl, s, sizeof(myrpt->rxpl) - 1);
7674 strncpy(myrpt->txpl, s, sizeof(myrpt->rxpl) - 1);
7675 myrpt->remmode = REM_MODE_FM;
7676 myrpt->offset = REM_SIMPLEX;
7677 myrpt->powerlevel = REM_MEDPWR;
7678 myrpt->txplon = myrpt->rxplon = 0;
7679 while(*s1){
7680 switch(*s1++){
7681 case 'A':
7682 case 'a':
7683 strcpy(myrpt->rxpl, "100.0");
7684 strcpy(myrpt->txpl, "100.0");
7685 myrpt->remmode = REM_MODE_AM;
7686 break;
7687 case 'B':
7688 case 'b':
7689 strcpy(myrpt->rxpl, "100.0");
7690 strcpy(myrpt->txpl, "100.0");
7691 myrpt->remmode = REM_MODE_LSB;
7692 break;
7693 case 'F':
7694 myrpt->remmode = REM_MODE_FM;
7695 break;
7696 case 'L':
7697 case 'l':
7698 myrpt->powerlevel = REM_LOWPWR;
7699 break;
7700 case 'H':
7701 case 'h':
7702 myrpt->powerlevel = REM_HIPWR;
7703 break;
7705 case 'M':
7706 case 'm':
7707 myrpt->powerlevel = REM_MEDPWR;
7708 break;
7710 case '-':
7711 myrpt->offset = REM_MINUS;
7712 break;
7714 case '+':
7715 myrpt->offset = REM_PLUS;
7716 break;
7718 case 'S':
7719 case 's':
7720 myrpt->offset = REM_SIMPLEX;
7721 break;
7723 case 'T':
7724 case 't':
7725 myrpt->txplon = 1;
7726 break;
7728 case 'R':
7729 case 'r':
7730 myrpt->rxplon = 1;
7731 break;
7733 case 'U':
7734 case 'u':
7735 strcpy(myrpt->rxpl, "100.0");
7736 strcpy(myrpt->txpl, "100.0");
7737 myrpt->remmode = REM_MODE_USB;
7738 break;
7739 default:
7740 return 1;
7743 return 0;
7749 * Remote base function
7752 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
7754 char *s,*s1,*s2;
7755 int i,j,p,r,ht,k,l,ls2,m,d,offset,offsave, modesave, defmode;
7756 char multimode = 0;
7757 char oc,*cp,*cp1,*cp2;
7758 char tmp[20], freq[20] = "", savestr[20] = "";
7759 char mhz[MAXREMSTR], decimals[MAXREMSTR];
7761 if((!param) || (command_source == SOURCE_RPT) || (command_source == SOURCE_LNK))
7762 return DC_ERROR;
7764 p = myatoi(param);
7766 if ((p != 99) && (p != 5) && (p != 140) && myrpt->p.authlevel &&
7767 (!myrpt->loginlevel[0])) return DC_ERROR;
7768 multimode = multimode_capable(myrpt);
7770 switch(p){
7772 case 1: /* retrieve memory */
7773 if(strlen(digitbuf) < 2) /* needs 2 digits */
7774 break;
7776 for(i = 0 ; i < 2 ; i++){
7777 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
7778 return DC_ERROR;
7781 r = retreive_memory(myrpt, digitbuf);
7782 if (r < 0){
7783 rpt_telemetry(myrpt,MEMNOTFOUND,NULL);
7784 return DC_COMPLETE;
7786 if (r > 0){
7787 return DC_ERROR;
7789 if (setrem(myrpt) == -1) return DC_ERROR;
7790 return DC_COMPLETE;
7792 case 2: /* set freq and offset */
7795 for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for M+*K+*O or M+*H+* depending on mode */
7796 if(digitbuf[i] == '*'){
7797 j++;
7798 continue;
7800 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
7801 goto invalid_freq;
7802 else{
7803 if(j == 0)
7804 l++; /* # of digits before first * */
7805 if(j == 1)
7806 k++; /* # of digits after first * */
7810 i = strlen(digitbuf) - 1;
7811 if(multimode){
7812 if((j > 2) || (l > 3) || (k > 6))
7813 goto invalid_freq; /* &^@#! */
7815 else{
7816 if((j > 2) || (l > 4) || (k > 3))
7817 goto invalid_freq; /* &^@#! */
7820 /* Wait for M+*K+* */
7822 if(j < 2)
7823 break; /* Not yet */
7825 /* We have a frequency */
7827 strncpy(tmp, digitbuf ,sizeof(tmp) - 1);
7829 s = tmp;
7830 s1 = strsep(&s, "*"); /* Pick off MHz */
7831 s2 = strsep(&s,"*"); /* Pick off KHz and Hz */
7832 ls2 = strlen(s2);
7834 switch(ls2){ /* Allow partial entry of khz and hz digits for laziness support */
7835 case 1:
7836 ht = 0;
7837 k = 100 * atoi(s2);
7838 break;
7840 case 2:
7841 ht = 0;
7842 k = 10 * atoi(s2);
7843 break;
7845 case 3:
7846 if(!multimode){
7847 if((s2[2] != '0')&&(s2[2] != '5'))
7848 goto invalid_freq;
7850 ht = 0;
7851 k = atoi(s2);
7852 break;
7853 case 4:
7854 k = atoi(s2)/10;
7855 ht = 10 * (atoi(s2+(ls2-1)));
7856 break;
7858 case 5:
7859 k = atoi(s2)/100;
7860 ht = (atoi(s2+(ls2-2)));
7861 break;
7863 default:
7864 goto invalid_freq;
7867 /* Check frequency for validity and establish a default mode */
7869 snprintf(freq, sizeof(freq), "%s.%03d%02d",s1, k, ht);
7871 if(debug)
7872 printf("New frequency: %s\n", freq);
7874 split_freq(mhz, decimals, freq);
7875 m = atoi(mhz);
7876 d = atoi(decimals);
7878 if(check_freq(myrpt, m, d, &defmode)) /* Check to see if frequency entered is legit */
7879 goto invalid_freq;
7882 if((defmode == REM_MODE_FM) && (digitbuf[i] == '*')) /* If FM, user must enter and additional offset digit */
7883 break; /* Not yet */
7886 offset = REM_SIMPLEX; /* Assume simplex */
7888 if(defmode == REM_MODE_FM){
7889 oc = *s; /* Pick off offset */
7891 if (oc){
7892 switch(oc){
7893 case '1':
7894 offset = REM_MINUS;
7895 break;
7897 case '2':
7898 offset = REM_SIMPLEX;
7899 break;
7901 case '3':
7902 offset = REM_PLUS;
7903 break;
7905 default:
7906 goto invalid_freq;
7910 offsave = myrpt->offset;
7911 modesave = myrpt->remmode;
7912 strncpy(savestr, myrpt->freq, sizeof(savestr) - 1);
7913 strncpy(myrpt->freq, freq, sizeof(myrpt->freq) - 1);
7914 myrpt->offset = offset;
7915 myrpt->remmode = defmode;
7917 if (setrem(myrpt) == -1){
7918 myrpt->offset = offsave;
7919 myrpt->remmode = modesave;
7920 strncpy(myrpt->freq, savestr, sizeof(myrpt->freq) - 1);
7921 goto invalid_freq;
7924 return DC_COMPLETE;
7926 invalid_freq:
7927 rpt_telemetry(myrpt,INVFREQ,NULL);
7928 return DC_ERROR;
7930 case 3: /* set rx PL tone */
7931 for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
7932 if(digitbuf[i] == '*'){
7933 j++;
7934 continue;
7936 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
7937 return DC_ERROR;
7938 else{
7939 if(j)
7940 l++;
7941 else
7942 k++;
7945 if((j > 1) || (k > 3) || (l > 1))
7946 return DC_ERROR; /* &$@^! */
7947 i = strlen(digitbuf) - 1;
7948 if((j != 1) || (k < 2)|| (l != 1))
7949 break; /* Not yet */
7950 if(debug)
7951 printf("PL digits entered %s\n", digitbuf);
7953 strncpy(tmp, digitbuf, sizeof(tmp) - 1);
7954 /* see if we have at least 1 */
7955 s = strchr(tmp,'*');
7956 if(s)
7957 *s = '.';
7958 strncpy(savestr, myrpt->rxpl, sizeof(savestr) - 1);
7959 strncpy(myrpt->rxpl, tmp, sizeof(myrpt->rxpl) - 1);
7960 if(!strcmp(myrpt->remote, remote_rig_rbi))
7962 strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
7964 if (setrem(myrpt) == -1){
7965 strncpy(myrpt->rxpl, savestr, sizeof(myrpt->rxpl) - 1);
7966 return DC_ERROR;
7970 return DC_COMPLETE;
7972 case 4: /* set tx PL tone */
7973 /* cant set tx tone on RBI (rx tone does both) */
7974 if(!strcmp(myrpt->remote, remote_rig_rbi))
7975 return DC_ERROR;
7976 if(!strcmp(myrpt->remote, remote_rig_ic706))
7977 return DC_ERROR;
7978 for(i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++){ /* look for N+*N */
7979 if(digitbuf[i] == '*'){
7980 j++;
7981 continue;
7983 if((digitbuf[i] < '0') || (digitbuf[i] > '9'))
7984 return DC_ERROR;
7985 else{
7986 if(j)
7987 l++;
7988 else
7989 k++;
7992 if((j > 1) || (k > 3) || (l > 1))
7993 return DC_ERROR; /* &$@^! */
7994 i = strlen(digitbuf) - 1;
7995 if((j != 1) || (k < 2)|| (l != 1))
7996 break; /* Not yet */
7997 if(debug)
7998 printf("PL digits entered %s\n", digitbuf);
8000 strncpy(tmp, digitbuf, sizeof(tmp) - 1);
8001 /* see if we have at least 1 */
8002 s = strchr(tmp,'*');
8003 if(s)
8004 *s = '.';
8005 strncpy(savestr, myrpt->txpl, sizeof(savestr) - 1);
8006 strncpy(myrpt->txpl, tmp, sizeof(myrpt->txpl) - 1);
8008 if (setrem(myrpt) == -1){
8009 strncpy(myrpt->txpl, savestr, sizeof(myrpt->txpl) - 1);
8010 return DC_ERROR;
8014 return DC_COMPLETE;
8017 case 6: /* MODE (FM,USB,LSB,AM) */
8018 if(strlen(digitbuf) < 1)
8019 break;
8021 if(!multimode)
8022 return DC_ERROR; /* Multimode radios only */
8024 switch(*digitbuf){
8025 case '1':
8026 split_freq(mhz, decimals, myrpt->freq);
8027 m=atoi(mhz);
8028 if(m < 29) /* No FM allowed below 29MHz! */
8029 return DC_ERROR;
8030 myrpt->remmode = REM_MODE_FM;
8032 rpt_telemetry(myrpt,REMMODE,NULL);
8033 break;
8035 case '2':
8036 myrpt->remmode = REM_MODE_USB;
8037 rpt_telemetry(myrpt,REMMODE,NULL);
8038 break;
8040 case '3':
8041 myrpt->remmode = REM_MODE_LSB;
8042 rpt_telemetry(myrpt,REMMODE,NULL);
8043 break;
8045 case '4':
8046 myrpt->remmode = REM_MODE_AM;
8047 rpt_telemetry(myrpt,REMMODE,NULL);
8048 break;
8050 default:
8051 return DC_ERROR;
8054 if(setrem(myrpt))
8055 return DC_ERROR;
8056 return DC_COMPLETEQUIET;
8057 case 99:
8058 /* cant log in when logged in */
8059 if (myrpt->loginlevel[0])
8060 return DC_ERROR;
8061 *myrpt->loginuser = 0;
8062 myrpt->loginlevel[0] = 0;
8063 cp = strdup(param);
8064 cp1 = strchr(cp,',');
8065 ast_mutex_lock(&myrpt->lock);
8066 if (cp1)
8068 *cp1 = 0;
8069 cp2 = strchr(cp1 + 1,',');
8070 if (cp2)
8072 *cp2 = 0;
8073 strncpy(myrpt->loginlevel,cp2 + 1,
8074 sizeof(myrpt->loginlevel) - 1);
8076 strncpy(myrpt->loginuser,cp1 + 1,sizeof(myrpt->loginuser));
8077 ast_mutex_unlock(&myrpt->lock);
8078 if (myrpt->p.archivedir)
8080 char str[100];
8082 sprintf(str,"LOGIN,%s,%s",
8083 myrpt->loginuser,myrpt->loginlevel);
8084 donodelog(myrpt,str);
8086 if (debug)
8087 printf("loginuser %s level %s\n",myrpt->loginuser,myrpt->loginlevel);
8088 rpt_telemetry(myrpt,REMLOGIN,NULL);
8090 free(cp);
8091 return DC_COMPLETEQUIET;
8092 case 100: /* RX PL Off */
8093 myrpt->rxplon = 0;
8094 setrem(myrpt);
8095 rpt_telemetry(myrpt,REMXXX,(void *)p);
8096 return DC_COMPLETEQUIET;
8097 case 101: /* RX PL On */
8098 myrpt->rxplon = 1;
8099 setrem(myrpt);
8100 rpt_telemetry(myrpt,REMXXX,(void *)p);
8101 return DC_COMPLETEQUIET;
8102 case 102: /* TX PL Off */
8103 myrpt->txplon = 0;
8104 setrem(myrpt);
8105 rpt_telemetry(myrpt,REMXXX,(void *)p);
8106 return DC_COMPLETEQUIET;
8107 case 103: /* TX PL On */
8108 myrpt->txplon = 1;
8109 setrem(myrpt);
8110 rpt_telemetry(myrpt,REMXXX,(void *)p);
8111 return DC_COMPLETEQUIET;
8112 case 104: /* Low Power */
8113 if(!strcmp(myrpt->remote, remote_rig_ic706))
8114 return DC_ERROR;
8115 myrpt->powerlevel = REM_LOWPWR;
8116 setrem(myrpt);
8117 rpt_telemetry(myrpt,REMXXX,(void *)p);
8118 return DC_COMPLETEQUIET;
8119 case 105: /* Medium Power */
8120 if(!strcmp(myrpt->remote, remote_rig_ic706))
8121 return DC_ERROR;
8122 myrpt->powerlevel = REM_MEDPWR;
8123 setrem(myrpt);
8124 rpt_telemetry(myrpt,REMXXX,(void *)p);
8125 return DC_COMPLETEQUIET;
8126 case 106: /* Hi Power */
8127 if(!strcmp(myrpt->remote, remote_rig_ic706))
8128 return DC_ERROR;
8129 myrpt->powerlevel = REM_HIPWR;
8130 setrem(myrpt);
8131 rpt_telemetry(myrpt,REMXXX,(void *)p);
8132 return DC_COMPLETEQUIET;
8133 case 107: /* Bump down 20Hz */
8134 multimode_bump_freq(myrpt, -20);
8135 return DC_COMPLETE;
8136 case 108: /* Bump down 100Hz */
8137 multimode_bump_freq(myrpt, -100);
8138 return DC_COMPLETE;
8139 case 109: /* Bump down 500Hz */
8140 multimode_bump_freq(myrpt, -500);
8141 return DC_COMPLETE;
8142 case 110: /* Bump up 20Hz */
8143 multimode_bump_freq(myrpt, 20);
8144 return DC_COMPLETE;
8145 case 111: /* Bump up 100Hz */
8146 multimode_bump_freq(myrpt, 100);
8147 return DC_COMPLETE;
8148 case 112: /* Bump up 500Hz */
8149 multimode_bump_freq(myrpt, 500);
8150 return DC_COMPLETE;
8151 case 113: /* Scan down slow */
8152 myrpt->scantimer = REM_SCANTIME;
8153 myrpt->hfscanmode = HF_SCAN_DOWN_SLOW;
8154 rpt_telemetry(myrpt,REMXXX,(void *)p);
8155 return DC_COMPLETEQUIET;
8156 case 114: /* Scan down quick */
8157 myrpt->scantimer = REM_SCANTIME;
8158 myrpt->hfscanmode = HF_SCAN_DOWN_QUICK;
8159 rpt_telemetry(myrpt,REMXXX,(void *)p);
8160 return DC_COMPLETEQUIET;
8161 case 115: /* Scan down fast */
8162 myrpt->scantimer = REM_SCANTIME;
8163 myrpt->hfscanmode = HF_SCAN_DOWN_FAST;
8164 rpt_telemetry(myrpt,REMXXX,(void *)p);
8165 return DC_COMPLETEQUIET;
8166 case 116: /* Scan up slow */
8167 myrpt->scantimer = REM_SCANTIME;
8168 myrpt->hfscanmode = HF_SCAN_UP_SLOW;
8169 rpt_telemetry(myrpt,REMXXX,(void *)p);
8170 return DC_COMPLETEQUIET;
8171 case 117: /* Scan up quick */
8172 myrpt->scantimer = REM_SCANTIME;
8173 myrpt->hfscanmode = HF_SCAN_UP_QUICK;
8174 rpt_telemetry(myrpt,REMXXX,(void *)p);
8175 return DC_COMPLETEQUIET;
8176 case 118: /* Scan up fast */
8177 myrpt->scantimer = REM_SCANTIME;
8178 myrpt->hfscanmode = HF_SCAN_UP_FAST;
8179 rpt_telemetry(myrpt,REMXXX,(void *)p);
8180 return DC_COMPLETEQUIET;
8181 case 119: /* Tune Request */
8182 /* if not currently going, and valid to do */
8183 if((!myrpt->tunerequest) &&
8184 ((!strcmp(myrpt->remote, remote_rig_ft897) ||
8185 !strcmp(myrpt->remote, remote_rig_ic706)) )) {
8186 myrpt->remotetx = 0;
8187 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
8188 myrpt->tunerequest = 1;
8189 rpt_telemetry(myrpt,TUNE,NULL);
8190 return DC_COMPLETEQUIET;
8192 return DC_ERROR;
8193 case 5: /* Long Status */
8194 rpt_telemetry(myrpt,REMLONGSTATUS,NULL);
8195 return DC_COMPLETEQUIET;
8196 case 140: /* Short Status */
8197 rpt_telemetry(myrpt,REMSHORTSTATUS,NULL);
8198 return DC_COMPLETEQUIET;
8199 case 200:
8200 case 201:
8201 case 202:
8202 case 203:
8203 case 204:
8204 case 205:
8205 case 206:
8206 case 207:
8207 case 208:
8208 case 209:
8209 case 210:
8210 case 211:
8211 case 212:
8212 case 213:
8213 case 214:
8214 case 215:
8215 do_dtmf_local(myrpt,remdtmfstr[p - 200]);
8216 return DC_COMPLETEQUIET;
8217 default:
8218 break;
8220 return DC_INDETERMINATE;
8224 static int handle_remote_dtmf_digit(struct rpt *myrpt,char c, char *keyed, int phonemode)
8226 time_t now;
8227 int ret,res = 0,src;
8229 time(&myrpt->last_activity_time);
8230 /* Stop scan mode if in scan mode */
8231 if(myrpt->hfscanmode){
8232 stop_scan(myrpt);
8233 return 0;
8236 time(&now);
8237 /* if timed-out */
8238 if ((myrpt->dtmf_time_rem + DTMF_TIMEOUT) < now)
8240 myrpt->dtmfidx = -1;
8241 myrpt->dtmfbuf[0] = 0;
8242 myrpt->dtmf_time_rem = 0;
8244 /* if decode not active */
8245 if (myrpt->dtmfidx == -1)
8247 /* if not lead-in digit, dont worry */
8248 if (c != myrpt->p.funcchar)
8250 if (!myrpt->p.propagate_dtmf)
8252 rpt_mutex_lock(&myrpt->lock);
8253 do_dtmf_local(myrpt,c);
8254 rpt_mutex_unlock(&myrpt->lock);
8256 return 0;
8258 myrpt->dtmfidx = 0;
8259 myrpt->dtmfbuf[0] = 0;
8260 myrpt->dtmf_time_rem = now;
8261 return 0;
8263 /* if too many in buffer, start over */
8264 if (myrpt->dtmfidx >= MAXDTMF)
8266 myrpt->dtmfidx = 0;
8267 myrpt->dtmfbuf[0] = 0;
8268 myrpt->dtmf_time_rem = now;
8270 if (c == myrpt->p.funcchar)
8272 /* if star at beginning, or 2 together, erase buffer */
8273 if ((myrpt->dtmfidx < 1) ||
8274 (myrpt->dtmfbuf[myrpt->dtmfidx - 1] == myrpt->p.funcchar))
8276 myrpt->dtmfidx = 0;
8277 myrpt->dtmfbuf[0] = 0;
8278 myrpt->dtmf_time_rem = now;
8279 return 0;
8282 myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
8283 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
8284 myrpt->dtmf_time_rem = now;
8287 src = SOURCE_RMT;
8288 if (phonemode > 1) src = SOURCE_DPHONE;
8289 else if (phonemode) src = SOURCE_PHONE;
8290 ret = collect_function_digits(myrpt, myrpt->dtmfbuf, src, NULL);
8292 switch(ret){
8294 case DC_INDETERMINATE:
8295 res = 0;
8296 break;
8298 case DC_DOKEY:
8299 if (keyed) *keyed = 1;
8300 res = 0;
8301 break;
8303 case DC_REQ_FLUSH:
8304 myrpt->dtmfidx = 0;
8305 myrpt->dtmfbuf[0] = 0;
8306 res = 0;
8307 break;
8310 case DC_COMPLETE:
8311 res = 1;
8312 case DC_COMPLETEQUIET:
8313 myrpt->totalexecdcommands++;
8314 myrpt->dailyexecdcommands++;
8315 strncpy(myrpt->lastdtmfcommand, myrpt->dtmfbuf, MAXDTMF-1);
8316 myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
8317 myrpt->dtmfbuf[0] = 0;
8318 myrpt->dtmfidx = -1;
8319 myrpt->dtmf_time_rem = 0;
8320 break;
8322 case DC_ERROR:
8323 default:
8324 myrpt->dtmfbuf[0] = 0;
8325 myrpt->dtmfidx = -1;
8326 myrpt->dtmf_time_rem = 0;
8327 res = 0;
8328 break;
8331 return res;
8334 static int handle_remote_data(struct rpt *myrpt, char *str)
8336 char tmp[300],cmd[300],dest[300],src[300],c;
8337 int seq,res;
8339 /* put string in our buffer */
8340 strncpy(tmp,str,sizeof(tmp) - 1);
8341 if (!strcmp(tmp,discstr)) return 0;
8343 #ifndef DO_NOT_NOTIFY_MDC1200_ON_REMOTE_BASES
8344 if (tmp[0] == 'I')
8346 if (sscanf(tmp,"%s %s %x",cmd,src,&seq) != 3)
8348 ast_log(LOG_WARNING, "Unable to parse ident string %s\n",str);
8349 return 0;
8351 mdc1200_notify(myrpt,src,seq);
8352 return 0;
8354 #endif
8355 if (sscanf(tmp,"%s %s %s %d %c",cmd,dest,src,&seq,&c) != 5)
8357 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
8358 return 0;
8360 if (strcmp(cmd,"D"))
8362 ast_log(LOG_WARNING, "Unable to parse link string %s\n",str);
8363 return 0;
8365 /* if not for me, ignore */
8366 if (strcmp(dest,myrpt->name)) return 0;
8367 if (myrpt->p.archivedir)
8369 char str[100];
8371 sprintf(str,"DTMF,%c",c);
8372 donodelog(myrpt,str);
8374 c = func_xlat(myrpt,c,&myrpt->p.outxlat);
8375 if (!c) return(0);
8376 res = handle_remote_dtmf_digit(myrpt,c, NULL, 0);
8377 if (res != 1)
8378 return res;
8379 rpt_telemetry(myrpt,COMPLETE,NULL);
8380 return 0;
8383 static int handle_remote_phone_dtmf(struct rpt *myrpt, char c, char *keyed, int phonemode)
8385 int res;
8388 if (keyed && *keyed && (c == myrpt->p.endchar))
8390 *keyed = 0;
8391 return DC_INDETERMINATE;
8394 if (myrpt->p.archivedir)
8396 char str[100];
8398 sprintf(str,"DTMF(P),%c",c);
8399 donodelog(myrpt,str);
8401 res = handle_remote_dtmf_digit(myrpt,c,keyed, phonemode);
8402 if (res != 1)
8403 return res;
8404 rpt_telemetry(myrpt,COMPLETE,NULL);
8405 return 0;
8408 static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l)
8410 char *val, *s, *s1, *s2, *tele;
8411 char tmp[300], deststr[300] = "";
8413 val = node_lookup(myrpt,l->name);
8414 if (!val)
8416 fprintf(stderr,"attempt_reconnect: cannot find node %s\n",l->name);
8417 return -1;
8420 rpt_mutex_lock(&myrpt->lock);
8421 /* remove from queue */
8422 remque((struct qelem *) l);
8423 rpt_mutex_unlock(&myrpt->lock);
8424 strncpy(tmp,val,sizeof(tmp) - 1);
8425 s = tmp;
8426 s1 = strsep(&s,",");
8427 s2 = strsep(&s,",");
8428 snprintf(deststr, sizeof(deststr), "IAX2/%s", s1);
8429 tele = strchr(deststr, '/');
8430 if (!tele) {
8431 fprintf(stderr,"attempt_reconnect:Dial number (%s) must be in format tech/number\n",deststr);
8432 return -1;
8434 *tele++ = 0;
8435 l->elaptime = 0;
8436 l->connecttime = 0;
8437 l->thisconnected = 0;
8438 l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele,NULL);
8439 if (l->chan){
8440 ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
8441 ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
8442 l->chan->whentohangup = 0;
8443 l->chan->appl = "Apprpt";
8444 l->chan->data = "(Remote Rx)";
8445 if (option_verbose > 2)
8446 ast_verbose(VERBOSE_PREFIX_3 "rpt (attempt_reconnect) initiating call to %s/%s on %s\n",
8447 deststr, tele, l->chan->name);
8448 if(l->chan->cid.cid_num)
8449 free(l->chan->cid.cid_num);
8450 l->chan->cid.cid_num = strdup(myrpt->name);
8451 ast_call(l->chan,tele,999);
8454 else
8456 if (option_verbose > 2)
8457 ast_verbose(VERBOSE_PREFIX_3 "Unable to place call to %s/%s on %s\n",
8458 deststr,tele,l->chan->name);
8459 return -1;
8461 rpt_mutex_lock(&myrpt->lock);
8462 /* put back in queue */
8463 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
8464 rpt_mutex_unlock(&myrpt->lock);
8465 ast_log(LOG_NOTICE,"Reconnect Attempt to %s in process\n",l->name);
8466 return 0;
8469 /* 0 return=continue, 1 return = break, -1 return = error */
8470 static void local_dtmf_helper(struct rpt *myrpt,char c)
8472 int res;
8473 pthread_attr_t attr;
8474 char cmd[MAXDTMF+1] = "";
8476 if (myrpt->p.archivedir)
8478 char str[100];
8480 sprintf(str,"DTMF,MAIN,%c",c);
8481 donodelog(myrpt,str);
8483 if (c == myrpt->p.endchar)
8485 /* if in simple mode, kill autopatch */
8486 if (myrpt->p.simple && myrpt->callmode)
8488 rpt_mutex_lock(&myrpt->lock);
8489 myrpt->callmode = 0;
8490 rpt_mutex_unlock(&myrpt->lock);
8491 rpt_telemetry(myrpt,TERM,NULL);
8492 return;
8494 rpt_mutex_lock(&myrpt->lock);
8495 myrpt->stopgen = 1;
8496 if (myrpt->cmdnode[0])
8498 myrpt->cmdnode[0] = 0;
8499 myrpt->dtmfidx = -1;
8500 myrpt->dtmfbuf[0] = 0;
8501 rpt_mutex_unlock(&myrpt->lock);
8502 rpt_telemetry(myrpt,COMPLETE,NULL);
8504 else
8506 rpt_mutex_unlock(&myrpt->lock);
8507 if (myrpt->p.propagate_phonedtmf)
8508 do_dtmf_phone(myrpt,NULL,c);
8510 return;
8512 rpt_mutex_lock(&myrpt->lock);
8513 if (myrpt->cmdnode[0])
8515 rpt_mutex_unlock(&myrpt->lock);
8516 send_link_dtmf(myrpt,c);
8517 return;
8519 if (!myrpt->p.simple)
8521 if (c == myrpt->p.funcchar)
8523 myrpt->dtmfidx = 0;
8524 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
8525 rpt_mutex_unlock(&myrpt->lock);
8526 time(&myrpt->dtmf_time);
8527 return;
8529 else if ((c != myrpt->p.endchar) && (myrpt->dtmfidx >= 0))
8531 time(&myrpt->dtmf_time);
8533 if (myrpt->dtmfidx < MAXDTMF)
8535 myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
8536 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
8538 strncpy(cmd, myrpt->dtmfbuf, sizeof(cmd) - 1);
8540 rpt_mutex_unlock(&myrpt->lock);
8541 res = collect_function_digits(myrpt, cmd, SOURCE_RPT, NULL);
8542 rpt_mutex_lock(&myrpt->lock);
8543 switch(res){
8544 case DC_INDETERMINATE:
8545 break;
8546 case DC_REQ_FLUSH:
8547 myrpt->dtmfidx = 0;
8548 myrpt->dtmfbuf[0] = 0;
8549 break;
8550 case DC_COMPLETE:
8551 case DC_COMPLETEQUIET:
8552 myrpt->totalexecdcommands++;
8553 myrpt->dailyexecdcommands++;
8554 strncpy(myrpt->lastdtmfcommand, cmd, MAXDTMF-1);
8555 myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
8556 myrpt->dtmfbuf[0] = 0;
8557 myrpt->dtmfidx = -1;
8558 myrpt->dtmf_time = 0;
8559 break;
8561 case DC_ERROR:
8562 default:
8563 myrpt->dtmfbuf[0] = 0;
8564 myrpt->dtmfidx = -1;
8565 myrpt->dtmf_time = 0;
8566 break;
8568 if(res != DC_INDETERMINATE) {
8569 rpt_mutex_unlock(&myrpt->lock);
8570 return;
8575 else /* if simple */
8577 if ((!myrpt->callmode) && (c == myrpt->p.funcchar))
8579 myrpt->callmode = 1;
8580 myrpt->patchnoct = 0;
8581 myrpt->patchquiet = 0;
8582 myrpt->patchfarenddisconnect = 0;
8583 myrpt->patchdialtime = 0;
8584 strncpy(myrpt->patchcontext, myrpt->p.ourcontext, MAXPATCHCONTEXT);
8585 myrpt->cidx = 0;
8586 myrpt->exten[myrpt->cidx] = 0;
8587 rpt_mutex_unlock(&myrpt->lock);
8588 pthread_attr_init(&attr);
8589 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
8590 ast_pthread_create(&myrpt->rpt_call_thread,&attr,rpt_call,(void *)myrpt);
8591 return;
8594 if (myrpt->callmode == 1)
8596 myrpt->exten[myrpt->cidx++] = c;
8597 myrpt->exten[myrpt->cidx] = 0;
8598 /* if this exists */
8599 if (ast_exists_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
8601 myrpt->callmode = 2;
8602 rpt_mutex_unlock(&myrpt->lock);
8603 if(!myrpt->patchquiet)
8604 rpt_telemetry(myrpt,PROC,NULL);
8605 return;
8607 /* if can continue, do so */
8608 if (!ast_canmatch_extension(myrpt->pchannel,myrpt->patchcontext,myrpt->exten,1,NULL))
8610 /* call has failed, inform user */
8611 myrpt->callmode = 4;
8613 rpt_mutex_unlock(&myrpt->lock);
8614 return;
8616 if ((myrpt->callmode == 2) || (myrpt->callmode == 3))
8618 myrpt->mydtmf = c;
8620 rpt_mutex_unlock(&myrpt->lock);
8621 if ((myrpt->dtmfidx < 0) && myrpt->p.propagate_phonedtmf)
8622 do_dtmf_phone(myrpt,NULL,c);
8623 return;
8627 /* place an ID event in the telemetry queue */
8629 static void queue_id(struct rpt *myrpt)
8631 if(myrpt->p.idtime){ /* ID time must be non-zero */
8632 myrpt->mustid = myrpt->tailid = 0;
8633 myrpt->idtimer = myrpt->p.idtime; /* Reset our ID timer */
8634 rpt_mutex_unlock(&myrpt->lock);
8635 rpt_telemetry(myrpt,ID,NULL);
8636 rpt_mutex_lock(&myrpt->lock);
8640 /* Scheduler */
8641 /* must be called locked */
8643 static void do_scheduler(struct rpt *myrpt)
8645 int i,res;
8646 struct tm tmnow;
8647 struct ast_variable *skedlist;
8648 char *strs[5],*vp,*val,value[100];
8650 memcpy(&myrpt->lasttv, &myrpt->curtv, sizeof(struct timeval));
8652 if( (res = gettimeofday(&myrpt->curtv, NULL)) < 0)
8653 ast_log(LOG_NOTICE, "Scheduler gettime of day returned: %s\n", strerror(res));
8655 /* Try to get close to a 1 second resolution */
8657 if(myrpt->lasttv.tv_sec == myrpt->curtv.tv_sec)
8658 return;
8660 rpt_localtime(&myrpt->curtv.tv_sec, &tmnow);
8662 /* If midnight, then reset all daily statistics */
8664 if((tmnow.tm_hour == 0)&&(tmnow.tm_min == 0)&&(tmnow.tm_sec == 0)){
8665 myrpt->dailykeyups = 0;
8666 myrpt->dailytxtime = 0;
8667 myrpt->dailykerchunks = 0;
8668 myrpt->dailyexecdcommands = 0;
8671 if(tmnow.tm_sec != 0)
8672 return;
8674 /* Code below only executes once per minute */
8677 /* Don't schedule if remote */
8679 if (myrpt->remote)
8680 return;
8682 /* Don't schedule if disabled */
8684 if(myrpt->p.s[myrpt->p.sysstate_cur].schedulerdisable){
8685 if(debug > 6)
8686 ast_log(LOG_NOTICE, "Scheduler disabled\n");
8687 return;
8690 if(!myrpt->p.skedstanzaname){ /* No stanza means we do nothing */
8691 if(debug > 6)
8692 ast_log(LOG_NOTICE,"No stanza for scheduler in rpt.conf\n");
8693 return;
8696 /* get pointer to linked list of scheduler entries */
8697 skedlist = ast_variable_browse(myrpt->cfg, myrpt->p.skedstanzaname);
8699 if(debug > 6){
8700 ast_log(LOG_NOTICE, "Time now: %02d:%02d %02d %02d %02d\n",
8701 tmnow.tm_hour,tmnow.tm_min,tmnow.tm_mday,tmnow.tm_mon + 1, tmnow.tm_wday);
8703 /* walk the list */
8704 for(; skedlist; skedlist = skedlist->next){
8705 if(debug > 6)
8706 ast_log(LOG_NOTICE, "Scheduler entry %s = %s being considered\n",skedlist->name, skedlist->value);
8707 strncpy(value,skedlist->value,99);
8708 value[99] = 0;
8709 /* point to the substrings for minute, hour, dom, month, and dow */
8710 for( i = 0, vp = value ; i < 5; i++){
8711 if(!*vp)
8712 break;
8713 while((*vp == ' ') || (*vp == 0x09)) /* get rid of any leading white space */
8714 vp++;
8715 strs[i] = vp; /* save pointer to beginning of substring */
8716 while((*vp != ' ') && (*vp != 0x09) && (*vp != 0)) /* skip over substring */
8717 vp++;
8718 if(*vp)
8719 *vp++ = 0; /* mark end of substring */
8721 if(debug > 6)
8722 ast_log(LOG_NOTICE, "i = %d, min = %s, hour = %s, mday=%s, mon=%s, wday=%s\n",i,
8723 strs[0], strs[1], strs[2], strs[3], strs[4]);
8724 if(i == 5){
8725 if((*strs[0] != '*')&&(atoi(strs[0]) != tmnow.tm_min))
8726 continue;
8727 if((*strs[1] != '*')&&(atoi(strs[1]) != tmnow.tm_hour))
8728 continue;
8729 if((*strs[2] != '*')&&(atoi(strs[2]) != tmnow.tm_mday))
8730 continue;
8731 if((*strs[3] != '*')&&(atoi(strs[3]) != tmnow.tm_mon + 1))
8732 continue;
8733 if(atoi(strs[4]) == 7)
8734 strs[4] = "0";
8735 if((*strs[4] != '*')&&(atoi(strs[4]) != tmnow.tm_wday))
8736 continue;
8737 if(debug)
8738 ast_log(LOG_NOTICE, "Executing scheduler entry %s = %s\n", skedlist->name, skedlist->value);
8739 if(atoi(skedlist->name) == 0)
8740 return; /* Zero is reserved for the startup macro */
8741 val = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, skedlist->name);
8742 if (!val){
8743 ast_log(LOG_WARNING,"Scheduler could not find macro %s\n",skedlist->name);
8744 return; /* Macro not found */
8746 if ((MAXMACRO - strlen(myrpt->macrobuf)) < strlen(val)){
8747 ast_log(LOG_WARNING, "Scheduler could not execute macro %s: Macro buffer full\n",
8748 skedlist->name);
8749 return; /* Macro buffer full */
8751 myrpt->macrotimer = MACROTIME;
8752 strncat(myrpt->macrobuf,val,MAXMACRO - 1);
8754 else{
8755 ast_log(LOG_WARNING,"Malformed scheduler entry in rpt.conf: %s = %s\n",
8756 skedlist->name, skedlist->value);
8762 /* single thread with one file (request) to dial */
8763 static void *rpt(void *this)
8765 struct rpt *myrpt = (struct rpt *)this;
8766 char *tele,*idtalkover,c;
8767 int ms = MSWAIT,i,lasttx=0,val,remrx=0,identqueued,othertelemqueued;
8768 int tailmessagequeued,ctqueued,dtmfed;
8769 struct ast_channel *who;
8770 ZT_CONFINFO ci; /* conference info */
8771 time_t t;
8772 struct rpt_link *l,*m;
8773 struct rpt_tele *telem;
8774 char tmpstr[300],lstr[MAXLINKLIST];
8777 if (myrpt->p.archivedir) mkdir(myrpt->p.archivedir,0600);
8778 sprintf(tmpstr,"%s/%s",myrpt->p.archivedir,myrpt->name);
8779 mkdir(tmpstr,0600);
8780 rpt_mutex_lock(&myrpt->lock);
8782 telem = myrpt->tele.next;
8783 while(telem != &myrpt->tele)
8785 ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
8786 telem = telem->next;
8788 rpt_mutex_unlock(&myrpt->lock);
8789 /* find our index, and load the vars initially */
8790 for(i = 0; i < nrpts; i++)
8792 if (&rpt_vars[i] == myrpt)
8794 load_rpt_vars(i,0);
8795 break;
8798 rpt_mutex_lock(&myrpt->lock);
8799 strncpy(tmpstr,myrpt->rxchanname,sizeof(tmpstr) - 1);
8800 tele = strchr(tmpstr,'/');
8801 if (!tele)
8803 fprintf(stderr,"rpt:Rxchannel Dial number (%s) must be in format tech/number\n",myrpt->rxchanname);
8804 rpt_mutex_unlock(&myrpt->lock);
8805 myrpt->rpt_thread = AST_PTHREADT_STOP;
8806 pthread_exit(NULL);
8808 *tele++ = 0;
8809 myrpt->rxchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
8810 myrpt->zaprxchannel = NULL;
8811 if (!strcasecmp(tmpstr,"Zap"))
8812 myrpt->zaprxchannel = myrpt->rxchannel;
8813 if (myrpt->rxchannel)
8815 if (myrpt->rxchannel->_state == AST_STATE_BUSY)
8817 fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
8818 rpt_mutex_unlock(&myrpt->lock);
8819 ast_hangup(myrpt->rxchannel);
8820 myrpt->rpt_thread = AST_PTHREADT_STOP;
8821 pthread_exit(NULL);
8823 ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
8824 ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
8825 #ifdef AST_CDR_FLAG_POST_DISABLED
8826 ast_set_flag(myrpt->rxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
8827 #endif
8828 myrpt->rxchannel->whentohangup = 0;
8829 myrpt->rxchannel->appl = "Apprpt";
8830 myrpt->rxchannel->data = "(Repeater Rx)";
8831 if (option_verbose > 2)
8832 ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
8833 tmpstr,tele,myrpt->rxchannel->name);
8834 ast_call(myrpt->rxchannel,tele,999);
8835 if (myrpt->rxchannel->_state != AST_STATE_UP)
8837 rpt_mutex_unlock(&myrpt->lock);
8838 ast_hangup(myrpt->rxchannel);
8839 myrpt->rpt_thread = AST_PTHREADT_STOP;
8840 pthread_exit(NULL);
8843 else
8845 fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
8846 rpt_mutex_unlock(&myrpt->lock);
8847 myrpt->rpt_thread = AST_PTHREADT_STOP;
8848 pthread_exit(NULL);
8850 myrpt->zaptxchannel = NULL;
8851 if (myrpt->txchanname)
8853 strncpy(tmpstr,myrpt->txchanname,sizeof(tmpstr) - 1);
8854 tele = strchr(tmpstr,'/');
8855 if (!tele)
8857 fprintf(stderr,"rpt:Txchannel Dial number (%s) must be in format tech/number\n",myrpt->txchanname);
8858 rpt_mutex_unlock(&myrpt->lock);
8859 ast_hangup(myrpt->rxchannel);
8860 myrpt->rpt_thread = AST_PTHREADT_STOP;
8861 pthread_exit(NULL);
8863 *tele++ = 0;
8864 myrpt->txchannel = ast_request(tmpstr,AST_FORMAT_SLINEAR,tele,NULL);
8865 if (!strcasecmp(tmpstr,"Zap"))
8866 myrpt->zaptxchannel = myrpt->txchannel;
8867 if (myrpt->txchannel)
8869 if (myrpt->txchannel->_state == AST_STATE_BUSY)
8871 fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
8872 rpt_mutex_unlock(&myrpt->lock);
8873 ast_hangup(myrpt->txchannel);
8874 ast_hangup(myrpt->rxchannel);
8875 myrpt->rpt_thread = AST_PTHREADT_STOP;
8876 pthread_exit(NULL);
8878 ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
8879 ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
8880 #ifdef AST_CDR_FLAG_POST_DISABLED
8881 ast_set_flag(myrpt->txchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
8882 #endif
8883 myrpt->txchannel->whentohangup = 0;
8884 myrpt->txchannel->appl = "Apprpt";
8885 myrpt->txchannel->data = "(Repeater Tx)";
8886 if (option_verbose > 2)
8887 ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
8888 tmpstr,tele,myrpt->txchannel->name);
8889 ast_call(myrpt->txchannel,tele,999);
8890 if (myrpt->rxchannel->_state != AST_STATE_UP)
8892 rpt_mutex_unlock(&myrpt->lock);
8893 ast_hangup(myrpt->rxchannel);
8894 ast_hangup(myrpt->txchannel);
8895 myrpt->rpt_thread = AST_PTHREADT_STOP;
8896 pthread_exit(NULL);
8899 else
8901 fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
8902 rpt_mutex_unlock(&myrpt->lock);
8903 ast_hangup(myrpt->rxchannel);
8904 myrpt->rpt_thread = AST_PTHREADT_STOP;
8905 pthread_exit(NULL);
8908 else
8910 myrpt->txchannel = myrpt->rxchannel;
8912 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
8913 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
8914 /* allocate a pseudo-channel thru asterisk */
8915 myrpt->pchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
8916 if (!myrpt->pchannel)
8918 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
8919 rpt_mutex_unlock(&myrpt->lock);
8920 if (myrpt->txchannel != myrpt->rxchannel)
8921 ast_hangup(myrpt->txchannel);
8922 ast_hangup(myrpt->rxchannel);
8923 myrpt->rpt_thread = AST_PTHREADT_STOP;
8924 pthread_exit(NULL);
8926 #ifdef AST_CDR_FLAG_POST_DISABLED
8927 ast_set_flag(myrpt->pchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
8928 #endif
8929 if (!myrpt->zaprxchannel) myrpt->zaprxchannel = myrpt->pchannel;
8930 if (!myrpt->zaptxchannel)
8932 /* allocate a pseudo-channel thru asterisk */
8933 myrpt->zaptxchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
8934 if (!myrpt->zaptxchannel)
8936 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
8937 rpt_mutex_unlock(&myrpt->lock);
8938 if (myrpt->txchannel != myrpt->rxchannel)
8939 ast_hangup(myrpt->txchannel);
8940 ast_hangup(myrpt->rxchannel);
8941 myrpt->rpt_thread = AST_PTHREADT_STOP;
8942 pthread_exit(NULL);
8944 ast_set_read_format(myrpt->zaptxchannel,AST_FORMAT_SLINEAR);
8945 ast_set_write_format(myrpt->zaptxchannel,AST_FORMAT_SLINEAR);
8946 #ifdef AST_CDR_FLAG_POST_DISABLED
8947 ast_set_flag(myrpt->zaptxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
8948 #endif
8950 /* allocate a pseudo-channel thru asterisk */
8951 myrpt->monchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
8952 if (!myrpt->monchannel)
8954 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
8955 rpt_mutex_unlock(&myrpt->lock);
8956 if (myrpt->txchannel != myrpt->rxchannel)
8957 ast_hangup(myrpt->txchannel);
8958 ast_hangup(myrpt->rxchannel);
8959 myrpt->rpt_thread = AST_PTHREADT_STOP;
8960 pthread_exit(NULL);
8962 ast_set_read_format(myrpt->monchannel,AST_FORMAT_SLINEAR);
8963 ast_set_write_format(myrpt->monchannel,AST_FORMAT_SLINEAR);
8964 #ifdef AST_CDR_FLAG_POST_DISABLED
8965 ast_set_flag(myrpt->monchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
8966 #endif
8967 /* make a conference for the tx */
8968 ci.chan = 0;
8969 ci.confno = -1; /* make a new conf */
8970 ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER;
8971 /* first put the channel on the conference in proper mode */
8972 if (ioctl(myrpt->zaptxchannel->fds[0],ZT_SETCONF,&ci) == -1)
8974 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
8975 rpt_mutex_unlock(&myrpt->lock);
8976 ast_hangup(myrpt->pchannel);
8977 ast_hangup(myrpt->monchannel);
8978 if (myrpt->txchannel != myrpt->rxchannel)
8979 ast_hangup(myrpt->txchannel);
8980 ast_hangup(myrpt->rxchannel);
8981 myrpt->rpt_thread = AST_PTHREADT_STOP;
8982 pthread_exit(NULL);
8984 /* save tx conference number */
8985 myrpt->txconf = ci.confno;
8986 /* make a conference for the pseudo */
8987 ci.chan = 0;
8988 ci.confno = -1; /* make a new conf */
8989 ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? ZT_CONF_CONFANNMON :
8990 (ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER);
8991 /* first put the channel on the conference in announce mode */
8992 if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
8994 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
8995 rpt_mutex_unlock(&myrpt->lock);
8996 ast_hangup(myrpt->pchannel);
8997 ast_hangup(myrpt->monchannel);
8998 if (myrpt->txchannel != myrpt->rxchannel)
8999 ast_hangup(myrpt->txchannel);
9000 ast_hangup(myrpt->rxchannel);
9001 myrpt->rpt_thread = AST_PTHREADT_STOP;
9002 pthread_exit(NULL);
9004 /* save pseudo channel conference number */
9005 myrpt->conf = ci.confno;
9006 /* make a conference for the pseudo */
9007 ci.chan = 0;
9008 if ((strstr(myrpt->txchannel->name,"pseudo") == NULL) &&
9009 (myrpt->zaptxchannel == myrpt->txchannel))
9011 /* get tx channel's port number */
9012 if (ioctl(myrpt->txchannel->fds[0],ZT_CHANNO,&ci.confno) == -1)
9014 ast_log(LOG_WARNING, "Unable to set tx channel's chan number\n");
9015 rpt_mutex_unlock(&myrpt->lock);
9016 ast_hangup(myrpt->pchannel);
9017 ast_hangup(myrpt->monchannel);
9018 if (myrpt->txchannel != myrpt->rxchannel)
9019 ast_hangup(myrpt->txchannel);
9020 ast_hangup(myrpt->rxchannel);
9021 myrpt->rpt_thread = AST_PTHREADT_STOP;
9022 pthread_exit(NULL);
9024 ci.confmode = ZT_CONF_MONITORTX;
9026 else
9028 ci.confno = myrpt->txconf;
9029 ci.confmode = ZT_CONF_CONFANNMON;
9031 /* first put the channel on the conference in announce mode */
9032 if (ioctl(myrpt->monchannel->fds[0],ZT_SETCONF,&ci) == -1)
9034 ast_log(LOG_WARNING, "Unable to set conference mode for monitor\n");
9035 rpt_mutex_unlock(&myrpt->lock);
9036 ast_hangup(myrpt->pchannel);
9037 ast_hangup(myrpt->monchannel);
9038 if (myrpt->txchannel != myrpt->rxchannel)
9039 ast_hangup(myrpt->txchannel);
9040 ast_hangup(myrpt->rxchannel);
9041 myrpt->rpt_thread = AST_PTHREADT_STOP;
9042 pthread_exit(NULL);
9044 /* allocate a pseudo-channel thru asterisk */
9045 myrpt->txpchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
9046 if (!myrpt->txpchannel)
9048 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
9049 rpt_mutex_unlock(&myrpt->lock);
9050 ast_hangup(myrpt->pchannel);
9051 ast_hangup(myrpt->monchannel);
9052 if (myrpt->txchannel != myrpt->rxchannel)
9053 ast_hangup(myrpt->txchannel);
9054 ast_hangup(myrpt->rxchannel);
9055 myrpt->rpt_thread = AST_PTHREADT_STOP;
9056 pthread_exit(NULL);
9058 #ifdef AST_CDR_FLAG_POST_DISABLED
9059 ast_set_flag(myrpt->txpchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
9060 #endif
9061 /* make a conference for the tx */
9062 ci.chan = 0;
9063 ci.confno = myrpt->txconf;
9064 ci.confmode = ZT_CONF_CONF | ZT_CONF_TALKER ;
9065 /* first put the channel on the conference in proper mode */
9066 if (ioctl(myrpt->txpchannel->fds[0],ZT_SETCONF,&ci) == -1)
9068 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
9069 rpt_mutex_unlock(&myrpt->lock);
9070 ast_hangup(myrpt->txpchannel);
9071 ast_hangup(myrpt->monchannel);
9072 if (myrpt->txchannel != myrpt->rxchannel)
9073 ast_hangup(myrpt->txchannel);
9074 ast_hangup(myrpt->rxchannel);
9075 myrpt->rpt_thread = AST_PTHREADT_STOP;
9076 pthread_exit(NULL);
9078 /* Now, the idea here is to copy from the physical rx channel buffer
9079 into the pseudo tx buffer, and from the pseudo rx buffer into the
9080 tx channel buffer */
9081 myrpt->links.next = &myrpt->links;
9082 myrpt->links.prev = &myrpt->links;
9083 myrpt->tailtimer = 0;
9084 myrpt->totimer = 0;
9085 myrpt->tmsgtimer = myrpt->p.tailmessagetime;
9086 myrpt->idtimer = myrpt->p.politeid;
9087 myrpt->mustid = myrpt->tailid = 0;
9088 myrpt->callmode = 0;
9089 myrpt->tounkeyed = 0;
9090 myrpt->tonotify = 0;
9091 myrpt->retxtimer = 0;
9092 myrpt->rerxtimer = 0;
9093 myrpt->skedtimer = 0;
9094 myrpt->tailevent = 0;
9095 lasttx = 0;
9096 myrpt->keyed = 0;
9097 idtalkover = (char *) ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover");
9098 myrpt->dtmfidx = -1;
9099 myrpt->dtmfbuf[0] = 0;
9100 myrpt->rem_dtmfidx = -1;
9101 myrpt->rem_dtmfbuf[0] = 0;
9102 myrpt->dtmf_time = 0;
9103 myrpt->rem_dtmf_time = 0;
9104 myrpt->disgorgetime = 0;
9105 myrpt->lastnodewhichkeyedusup[0] = '\0';
9106 myrpt->dailytxtime = 0;
9107 myrpt->totaltxtime = 0;
9108 myrpt->dailykeyups = 0;
9109 myrpt->totalkeyups = 0;
9110 myrpt->dailykerchunks = 0;
9111 myrpt->totalkerchunks = 0;
9112 myrpt->dailyexecdcommands = 0;
9113 myrpt->totalexecdcommands = 0;
9114 myrpt->timeouts = 0;
9115 myrpt->exten[0] = '\0';
9116 myrpt->lastdtmfcommand[0] = '\0';
9117 if (myrpt->p.startupmacro)
9119 snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
9121 rpt_mutex_unlock(&myrpt->lock);
9122 val = 1;
9123 ast_channel_setoption(myrpt->rxchannel,AST_OPTION_RELAXDTMF,&val,sizeof(char),0);
9124 val = 1;
9125 ast_channel_setoption(myrpt->rxchannel,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
9126 if (myrpt->p.archivedir) donodelog(myrpt,"STARTUP");
9127 dtmfed = 0;
9128 while (ms >= 0)
9130 struct ast_frame *f,*f1,*f2;
9131 struct ast_channel *cs[300],*cs1[300];
9132 int totx=0,elap=0,n,x,toexit=0;
9134 /* DEBUG Dump */
9135 if((myrpt->disgorgetime) && (time(NULL) >= myrpt->disgorgetime)){
9136 struct rpt_link *zl;
9137 struct rpt_tele *zt;
9139 myrpt->disgorgetime = 0;
9140 ast_log(LOG_NOTICE,"********** Variable Dump Start (app_rpt) **********\n");
9141 ast_log(LOG_NOTICE,"totx = %d\n",totx);
9142 ast_log(LOG_NOTICE,"remrx = %d\n",remrx);
9143 ast_log(LOG_NOTICE,"lasttx = %d\n",lasttx);
9144 ast_log(LOG_NOTICE,"elap = %d\n",elap);
9145 ast_log(LOG_NOTICE,"toexit = %d\n",toexit);
9147 ast_log(LOG_NOTICE,"myrpt->keyed = %d\n",myrpt->keyed);
9148 ast_log(LOG_NOTICE,"myrpt->localtx = %d\n",myrpt->localtx);
9149 ast_log(LOG_NOTICE,"myrpt->callmode = %d\n",myrpt->callmode);
9150 ast_log(LOG_NOTICE,"myrpt->mustid = %d\n",myrpt->mustid);
9151 ast_log(LOG_NOTICE,"myrpt->tounkeyed = %d\n",myrpt->tounkeyed);
9152 ast_log(LOG_NOTICE,"myrpt->tonotify = %d\n",myrpt->tonotify);
9153 ast_log(LOG_NOTICE,"myrpt->retxtimer = %ld\n",myrpt->retxtimer);
9154 ast_log(LOG_NOTICE,"myrpt->totimer = %d\n",myrpt->totimer);
9155 ast_log(LOG_NOTICE,"myrpt->tailtimer = %d\n",myrpt->tailtimer);
9156 ast_log(LOG_NOTICE,"myrpt->tailevent = %d\n",myrpt->tailevent);
9158 zl = myrpt->links.next;
9159 while(zl != &myrpt->links){
9160 ast_log(LOG_NOTICE,"*** Link Name: %s ***\n",zl->name);
9161 ast_log(LOG_NOTICE," link->lasttx %d\n",zl->lasttx);
9162 ast_log(LOG_NOTICE," link->lastrx %d\n",zl->lastrx);
9163 ast_log(LOG_NOTICE," link->connected %d\n",zl->connected);
9164 ast_log(LOG_NOTICE," link->hasconnected %d\n",zl->hasconnected);
9165 ast_log(LOG_NOTICE," link->outbound %d\n",zl->outbound);
9166 ast_log(LOG_NOTICE," link->disced %d\n",zl->disced);
9167 ast_log(LOG_NOTICE," link->killme %d\n",zl->killme);
9168 ast_log(LOG_NOTICE," link->disctime %ld\n",zl->disctime);
9169 ast_log(LOG_NOTICE," link->retrytimer %ld\n",zl->retrytimer);
9170 ast_log(LOG_NOTICE," link->retries = %d\n",zl->retries);
9171 ast_log(LOG_NOTICE," link->reconnects = %d\n",zl->reconnects);
9172 zl = zl->next;
9175 zt = myrpt->tele.next;
9176 if(zt != &myrpt->tele)
9177 ast_log(LOG_NOTICE,"*** Telemetry Queue ***\n");
9178 while(zt != &myrpt->tele){
9179 ast_log(LOG_NOTICE," Telemetry mode: %d\n",zt->mode);
9180 zt = zt->next;
9182 ast_log(LOG_NOTICE,"******* Variable Dump End (app_rpt) *******\n");
9187 if (myrpt->reload)
9189 struct rpt_tele *telem;
9191 rpt_mutex_lock(&myrpt->lock);
9192 telem = myrpt->tele.next;
9193 while(telem != &myrpt->tele)
9195 ast_softhangup(telem->chan,AST_SOFTHANGUP_DEV);
9196 telem = telem->next;
9198 myrpt->reload = 0;
9199 rpt_mutex_unlock(&myrpt->lock);
9200 usleep(10000);
9201 /* find our index, and load the vars */
9202 for(i = 0; i < nrpts; i++)
9204 if (&rpt_vars[i] == myrpt)
9206 load_rpt_vars(i,0);
9207 break;
9212 rpt_mutex_lock(&myrpt->lock);
9213 if (ast_check_hangup(myrpt->rxchannel)) break;
9214 if (ast_check_hangup(myrpt->txchannel)) break;
9215 if (ast_check_hangup(myrpt->pchannel)) break;
9216 if (ast_check_hangup(myrpt->monchannel)) break;
9217 if (ast_check_hangup(myrpt->txpchannel)) break;
9218 if (myrpt->zaptxchannel && ast_check_hangup(myrpt->zaptxchannel)) break;
9220 /* Set local tx with keyed */
9221 myrpt->localtx = myrpt->keyed;
9222 /* If someone's connected, and they're transmitting from their end to us, set remrx true */
9223 l = myrpt->links.next;
9224 remrx = 0;
9225 while(l != &myrpt->links)
9227 if (l->lastrx){
9228 remrx = 1;
9229 if(l->name[0] != '0') /* Ignore '0' nodes */
9230 strcpy(myrpt->lastnodewhichkeyedusup, l->name); /* Note the node which is doing the key up */
9232 l = l->next;
9234 /* Create a "must_id" flag for the cleanup ID */
9235 if(myrpt->p.idtime) /* ID time must be non-zero */
9236 myrpt->mustid |= (myrpt->idtimer) && (myrpt->keyed || remrx) ;
9237 /* Build a fresh totx from myrpt->keyed and autopatch activated */
9238 totx = myrpt->callmode;
9239 /* If full duplex, add local tx to totx */
9240 if (myrpt->p.duplex > 1)
9242 totx = totx || myrpt->localtx;
9244 /* Traverse the telemetry list to see what's queued */
9245 identqueued = 0;
9246 othertelemqueued = 0;
9247 tailmessagequeued = 0;
9248 ctqueued = 0;
9249 telem = myrpt->tele.next;
9250 while(telem != &myrpt->tele)
9252 if((telem->mode == ID) || (telem->mode == IDTALKOVER)){
9253 identqueued = 1; /* Identification telemetry */
9255 else if(telem->mode == TAILMSG)
9257 tailmessagequeued = 1; /* Tail message telemetry */
9259 else
9261 if ((telem->mode != UNKEY) && (telem->mode != LINKUNKEY))
9262 othertelemqueued = 1; /* Other telemetry */
9263 else
9264 ctqueued = 1; /* Courtesy tone telemetry */
9266 telem = telem->next;
9269 /* Add in any "other" telemetry, unless specified otherwise */
9270 if (!myrpt->p.notelemtx) totx = totx || othertelemqueued;
9271 /* Update external (to links) transmitter PTT state with everything but ID, CT, and tailmessage telemetry */
9272 myrpt->exttx = totx;
9273 totx = totx || myrpt->dtmf_local_timer;
9274 /* If half or 3/4 duplex, add localtx to external link tx */
9275 if (myrpt->p.duplex < 2) myrpt->exttx = myrpt->exttx || myrpt->localtx;
9276 /* Add in ID telemetry to local transmitter */
9277 totx = totx || remrx;
9278 /* If 3/4 or full duplex, add in ident and CT telemetry */
9279 if (myrpt->p.duplex > 0)
9280 totx = totx || identqueued || ctqueued;
9281 /* If full duplex, add local dtmf stuff active */
9282 if (myrpt->p.duplex > 1)
9284 totx = totx || (myrpt->dtmfidx > -1) ||
9285 myrpt->cmdnode[0];
9287 /* Reset time out timer variables if there is no activity */
9288 if (!totx)
9290 myrpt->totimer = myrpt->p.totime;
9291 myrpt->tounkeyed = 0;
9292 myrpt->tonotify = 0;
9294 else{
9295 myrpt->tailtimer = myrpt->p.s[myrpt->p.sysstate_cur].alternatetail ?
9296 myrpt->p.althangtime : /* Initialize tail timer */
9297 myrpt->p.hangtime;
9299 /* Disable the local transmitter if we are timed out */
9300 totx = totx && myrpt->totimer;
9301 /* if timed-out and not said already, say it */
9302 if ((!myrpt->totimer) && (!myrpt->tonotify))
9304 myrpt->tonotify = 1;
9305 myrpt->timeouts++;
9306 rpt_mutex_unlock(&myrpt->lock);
9307 rpt_telemetry(myrpt,TIMEOUT,NULL);
9308 rpt_mutex_lock(&myrpt->lock);
9311 /* If unkey and re-key, reset time out timer */
9312 if ((!totx) && (!myrpt->totimer) && (!myrpt->tounkeyed) && (!myrpt->keyed))
9314 myrpt->tounkeyed = 1;
9316 if ((!totx) && (!myrpt->totimer) && myrpt->tounkeyed && myrpt->keyed)
9318 myrpt->totimer = myrpt->p.totime;
9319 myrpt->tounkeyed = 0;
9320 myrpt->tonotify = 0;
9321 rpt_mutex_unlock(&myrpt->lock);
9322 continue;
9324 /* if timed-out and in circuit busy after call */
9325 if ((!totx) && (!myrpt->totimer) && (myrpt->callmode == 4))
9327 myrpt->callmode = 0;
9329 /* get rid of tail if timed out */
9330 if (!myrpt->totimer) myrpt->tailtimer = 0;
9331 /* if not timed-out, add in tail */
9332 if (myrpt->totimer) totx = totx || myrpt->tailtimer;
9333 /* If user or links key up or are keyed up over standard ID, switch to talkover ID, if one is defined */
9334 /* If tail message, kill the message if someone keys up over it */
9335 if ((myrpt->keyed || remrx) && ((identqueued && idtalkover) || (tailmessagequeued))) {
9336 int hasid = 0,hastalkover = 0;
9338 telem = myrpt->tele.next;
9339 while(telem != &myrpt->tele){
9340 if(telem->mode == ID){
9341 if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
9342 hasid = 1;
9344 if(telem->mode == TAILMSG){
9345 if (telem->chan) ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV); /* Whoosh! */
9347 if (telem->mode == IDTALKOVER) hastalkover = 1;
9348 telem = telem->next;
9350 rpt_mutex_unlock(&myrpt->lock);
9351 if (hasid && (!hastalkover)) rpt_telemetry(myrpt, IDTALKOVER, NULL); /* Start Talkover ID */
9352 rpt_mutex_lock(&myrpt->lock);
9354 /* Try to be polite */
9355 /* If the repeater has been inactive for longer than the ID time, do an initial ID in the tail*/
9356 /* If within 30 seconds of the time to ID, try do it in the tail */
9357 /* else if at ID time limit, do it right over the top of them */
9358 /* Lastly, if the repeater has been keyed, and the ID timer is expired, do a clean up ID */
9359 if(myrpt->mustid && (!myrpt->idtimer))
9360 queue_id(myrpt);
9362 if ((myrpt->p.idtime && totx && (!myrpt->exttx) &&
9363 (myrpt->idtimer <= myrpt->p.politeid) && myrpt->tailtimer)) /* ID time must be non-zero */
9365 myrpt->tailid = 1;
9368 /* If tail timer expires, then check for tail messages */
9370 if(myrpt->tailevent){
9371 myrpt->tailevent = 0;
9372 if(myrpt->tailid){
9373 totx = 1;
9374 queue_id(myrpt);
9376 else if ((myrpt->p.tailmessages[0]) &&
9377 (myrpt->p.tailmessagetime) && (myrpt->tmsgtimer == 0)){
9378 totx = 1;
9379 myrpt->tmsgtimer = myrpt->p.tailmessagetime;
9380 rpt_mutex_unlock(&myrpt->lock);
9381 rpt_telemetry(myrpt, TAILMSG, NULL);
9382 rpt_mutex_lock(&myrpt->lock);
9386 /* Main TX control */
9388 /* let telemetry transmit anyway (regardless of timeout) */
9389 if (myrpt->p.duplex > 0) totx = totx || (myrpt->tele.next != &myrpt->tele);
9390 if (totx && (!lasttx))
9392 char mydate[100],myfname[100];
9393 time_t myt;
9395 if (myrpt->monstream) ast_closestream(myrpt->monstream);
9396 if (myrpt->p.archivedir)
9398 long blocksleft;
9400 time(&myt);
9401 strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
9402 localtime(&myt));
9403 sprintf(myfname,"%s/%s/%s",myrpt->p.archivedir,
9404 myrpt->name,mydate);
9405 myrpt->monstream = ast_writefile(myfname,"wav49",
9406 "app_rpt Air Archive",O_CREAT | O_APPEND,0,0600);
9407 if (myrpt->p.monminblocks)
9409 blocksleft = diskavail(myrpt);
9410 if (blocksleft >= myrpt->p.monminblocks)
9411 donodelog(myrpt,"TXKEY,MAIN");
9412 } else donodelog(myrpt,"TXKEY,MAIN");
9414 lasttx = 1;
9415 myrpt->dailykeyups++;
9416 myrpt->totalkeyups++;
9417 rpt_mutex_unlock(&myrpt->lock);
9418 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
9419 rpt_mutex_lock(&myrpt->lock);
9421 totx = totx && !myrpt->p.s[myrpt->p.sysstate_cur].txdisable;
9422 if ((!totx) && lasttx)
9424 if (myrpt->monstream) ast_closestream(myrpt->monstream);
9425 myrpt->monstream = NULL;
9427 lasttx = 0;
9428 rpt_mutex_unlock(&myrpt->lock);
9429 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
9430 rpt_mutex_lock(&myrpt->lock);
9431 donodelog(myrpt,"TXUNKEY,MAIN");
9433 time(&t);
9434 /* if DTMF timeout */
9435 if ((!myrpt->cmdnode[0]) && (myrpt->dtmfidx >= 0) && ((myrpt->dtmf_time + DTMF_TIMEOUT) < t))
9437 myrpt->dtmfidx = -1;
9438 myrpt->dtmfbuf[0] = 0;
9440 /* if remote DTMF timeout */
9441 if ((myrpt->rem_dtmfidx >= 0) && ((myrpt->rem_dtmf_time + DTMF_TIMEOUT) < t))
9443 myrpt->rem_dtmfidx = -1;
9444 myrpt->rem_dtmfbuf[0] = 0;
9447 /* Reconnect */
9449 l = myrpt->links.next;
9450 while(l != &myrpt->links)
9452 if (l->killme)
9454 /* remove from queue */
9455 remque((struct qelem *) l);
9456 if (!strcmp(myrpt->cmdnode,l->name))
9457 myrpt->cmdnode[0] = 0;
9458 rpt_mutex_unlock(&myrpt->lock);
9459 /* hang-up on call to device */
9460 if (l->chan) ast_hangup(l->chan);
9461 ast_hangup(l->pchan);
9462 free(l);
9463 rpt_mutex_lock(&myrpt->lock);
9464 /* re-start link traversal */
9465 l = myrpt->links.next;
9466 continue;
9468 l = l->next;
9470 n = 0;
9471 cs[n++] = myrpt->rxchannel;
9472 cs[n++] = myrpt->pchannel;
9473 cs[n++] = myrpt->monchannel;
9474 cs[n++] = myrpt->txpchannel;
9475 if (myrpt->txchannel != myrpt->rxchannel) cs[n++] = myrpt->txchannel;
9476 if (myrpt->zaptxchannel != myrpt->txchannel)
9477 cs[n++] = myrpt->zaptxchannel;
9478 l = myrpt->links.next;
9479 while(l != &myrpt->links)
9481 if ((!l->killme) && (!l->disctime) && l->chan)
9483 cs[n++] = l->chan;
9484 cs[n++] = l->pchan;
9486 l = l->next;
9488 rpt_mutex_unlock(&myrpt->lock);
9489 ms = MSWAIT;
9490 for(x = 0; x < n; x++)
9492 int s = -(-x - myrpt->scram - 1) % n;
9493 cs1[x] = cs[s];
9495 myrpt->scram++;
9496 who = ast_waitfor_n(cs1,n,&ms);
9497 if (who == NULL) ms = 0;
9498 elap = MSWAIT - ms;
9499 rpt_mutex_lock(&myrpt->lock);
9500 l = myrpt->links.next;
9501 while(l != &myrpt->links)
9503 if (l->linklisttimer)
9505 l->linklisttimer -= elap;
9506 if (l->linklisttimer < 0) l->linklisttimer = 0;
9508 if ((!l->linklisttimer) && (l->name[0] != '0') && (!l->isremote))
9510 struct ast_frame lf;
9512 memset(&lf,0,sizeof(lf));
9513 lf.frametype = AST_FRAME_TEXT;
9514 lf.subclass = 0;
9515 lf.offset = 0;
9516 lf.mallocd = 0;
9517 lf.samples = 0;
9518 l->linklisttimer = LINKLISTTIME;
9519 strcpy(lstr,"L ");
9520 __mklinklist(myrpt,l,lstr + 2);
9521 if (l->chan)
9523 lf.datalen = strlen(lstr) + 1;
9524 lf.data = lstr;
9525 ast_write(l->chan,&lf);
9526 if (debug > 6) ast_log(LOG_NOTICE,
9527 "@@@@ node %s sent node string %s to node %s\n",
9528 myrpt->name,lstr,l->name);
9531 #ifndef OLDKEY
9532 if ((l->retxtimer += elap) >= REDUNDANT_TX_TIME)
9534 l->retxtimer = 0;
9535 if (l->chan && l->phonemode == 0)
9537 if (l->lasttx)
9538 ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
9539 else
9540 ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
9543 if ((l->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 5))
9545 if (debug == 7) printf("@@@@ rx un-key\n");
9546 l->lastrx = 0;
9547 l->rerxtimer = 0;
9548 if(myrpt->p.duplex)
9549 rpt_telemetry(myrpt,LINKUNKEY,l);
9550 if (myrpt->p.archivedir)
9552 char str[100];
9554 l->lastrx1 = 0;
9555 sprintf(str,"RXUNKEY(T),%s",l->name);
9556 donodelog(myrpt,str);
9559 #endif
9560 if (l->disctime) /* Disconnect timer active on a channel ? */
9562 l->disctime -= elap;
9563 if (l->disctime <= 0) /* Disconnect timer expired on inbound channel ? */
9564 l->disctime = 0; /* Yep */
9567 if (l->retrytimer)
9569 l->retrytimer -= elap;
9570 if (l->retrytimer < 0) l->retrytimer = 0;
9573 /* Tally connect time */
9574 l->connecttime += elap;
9576 /* ignore non-timing channels */
9577 if (l->elaptime < 0)
9579 l = l->next;
9580 continue;
9582 l->elaptime += elap;
9583 /* if connection has taken too long */
9584 if ((l->elaptime > MAXCONNECTTIME) &&
9585 ((!l->chan) || (l->chan->_state != AST_STATE_UP)))
9587 l->elaptime = 0;
9588 rpt_mutex_unlock(&myrpt->lock);
9589 if (l->chan) ast_softhangup(l->chan,AST_SOFTHANGUP_DEV);
9590 rpt_mutex_lock(&myrpt->lock);
9591 break;
9593 if ((!l->chan) && (!l->retrytimer) && l->outbound &&
9594 (l->retries++ < l->max_retries) && (l->hasconnected))
9596 if (l->chan) ast_hangup(l->chan);
9597 l->chan = 0;
9598 rpt_mutex_unlock(&myrpt->lock);
9599 if ((l->name[0] != '0') && (!l->isremote))
9601 if (attempt_reconnect(myrpt,l) == -1)
9603 l->retrytimer = RETRY_TIMER_MS;
9606 else
9608 l->retrytimer = l->max_retries + 1;
9611 rpt_mutex_lock(&myrpt->lock);
9612 break;
9614 if ((!l->chan) && (!l->retrytimer) && l->outbound &&
9615 (l->retries >= l->max_retries))
9617 /* remove from queue */
9618 remque((struct qelem *) l);
9619 if (!strcmp(myrpt->cmdnode,l->name))
9620 myrpt->cmdnode[0] = 0;
9621 rpt_mutex_unlock(&myrpt->lock);
9622 if (l->name[0] != '0')
9624 if (!l->hasconnected)
9625 rpt_telemetry(myrpt,CONNFAIL,l);
9626 else rpt_telemetry(myrpt,REMDISC,l);
9628 if (myrpt->p.archivedir)
9630 char str[100];
9632 if (!l->hasconnected)
9633 sprintf(str,"LINKFAIL,%s",l->name);
9634 else
9635 sprintf(str,"LINKDISC,%s",l->name);
9636 donodelog(myrpt,str);
9638 /* hang-up on call to device */
9639 ast_hangup(l->pchan);
9640 free(l);
9641 rpt_mutex_lock(&myrpt->lock);
9642 break;
9644 if ((!l->chan) && (!l->disctime) && (!l->outbound))
9646 /* remove from queue */
9647 remque((struct qelem *) l);
9648 if (!strcmp(myrpt->cmdnode,l->name))
9649 myrpt->cmdnode[0] = 0;
9650 rpt_mutex_unlock(&myrpt->lock);
9651 if (l->name[0] != '0')
9653 rpt_telemetry(myrpt,REMDISC,l);
9655 if (myrpt->p.archivedir)
9657 char str[100];
9659 sprintf(str,"LINKDISC,%s",l->name);
9660 donodelog(myrpt,str);
9662 /* hang-up on call to device */
9663 ast_hangup(l->pchan);
9664 free(l);
9665 rpt_mutex_lock(&myrpt->lock);
9666 break;
9668 l = l->next;
9670 if(totx){
9671 myrpt->dailytxtime += elap;
9672 myrpt->totaltxtime += elap;
9674 i = myrpt->tailtimer;
9675 if (myrpt->tailtimer) myrpt->tailtimer -= elap;
9676 if (myrpt->tailtimer < 0) myrpt->tailtimer = 0;
9677 if((i) && (myrpt->tailtimer == 0))
9678 myrpt->tailevent = 1;
9679 if ((!myrpt->p.s[myrpt->p.sysstate_cur].totdisable) && myrpt->totimer) myrpt->totimer -= elap;
9680 if (myrpt->totimer < 0) myrpt->totimer = 0;
9681 if (myrpt->idtimer) myrpt->idtimer -= elap;
9682 if (myrpt->idtimer < 0) myrpt->idtimer = 0;
9683 if (myrpt->tmsgtimer) myrpt->tmsgtimer -= elap;
9684 if (myrpt->tmsgtimer < 0) myrpt->tmsgtimer = 0;
9685 /* do macro timers */
9686 if (myrpt->macrotimer) myrpt->macrotimer -= elap;
9687 if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
9688 /* do local dtmf timer */
9689 if (myrpt->dtmf_local_timer)
9691 if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
9692 if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
9694 do_dtmf_local(myrpt,0);
9695 /* Execute scheduler appx. every 2 tenths of a second */
9696 if (myrpt->skedtimer <= 0){
9697 myrpt->skedtimer = 200;
9698 do_scheduler(myrpt);
9700 else
9701 myrpt->skedtimer -=elap;
9702 if (!ms)
9704 rpt_mutex_unlock(&myrpt->lock);
9705 continue;
9707 c = myrpt->macrobuf[0];
9708 time(&t);
9709 if (c && (!myrpt->macrotimer) &&
9710 starttime && (t > (starttime + START_DELAY)))
9712 myrpt->macrotimer = MACROTIME;
9713 memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
9714 if ((c == 'p') || (c == 'P'))
9715 myrpt->macrotimer = MACROPTIME;
9716 rpt_mutex_unlock(&myrpt->lock);
9717 if (myrpt->p.archivedir)
9719 char str[100];
9721 sprintf(str,"DTMF(M),MAIN,%c",c);
9722 donodelog(myrpt,str);
9724 local_dtmf_helper(myrpt,c);
9725 } else rpt_mutex_unlock(&myrpt->lock);
9726 if (who == myrpt->rxchannel) /* if it was a read from rx */
9728 int ismuted;
9730 f = ast_read(myrpt->rxchannel);
9731 if (!f)
9733 if (debug) printf("@@@@ rpt:Hung Up\n");
9734 break;
9736 if (f->frametype == AST_FRAME_VOICE)
9738 #ifdef _MDC_DECODE_H_
9739 unsigned char ubuf[2560];
9740 short *sp;
9741 int n;
9742 #endif
9744 if ((!myrpt->localtx) && (!myrpt->p.linktolink)) {
9745 memset(f->data,0,f->datalen);
9748 #ifdef _MDC_DECODE_H_
9749 sp = (short *) f->data;
9750 /* convert block to unsigned char */
9751 for(n = 0; n < f->datalen / 2; n++)
9753 ubuf[n] = (*sp++ >> 8) + 128;
9755 n = mdc_decoder_process_samples(myrpt->mdc,ubuf,f->datalen / 2);
9756 if (n == 1)
9758 unsigned char op,arg;
9759 unsigned short unitID;
9761 mdc_decoder_get_packet(myrpt->mdc,&op,&arg,&unitID);
9762 if (debug > 2)
9764 ast_log(LOG_NOTICE,"Got (single-length) packet:\n");
9765 ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
9766 op & 255,arg & 255,unitID);
9768 if ((op == 1) && (arg == 0))
9770 myrpt->lastunit = unitID;
9771 mdc1200_notify(myrpt,NULL,myrpt->lastunit);
9772 mdc1200_send(myrpt,myrpt->lastunit);
9775 if ((debug > 2) && (i == 2))
9777 unsigned char op,arg,ex1,ex2,ex3,ex4;
9778 unsigned short unitID;
9780 mdc_decoder_get_double_packet(myrpt->mdc,&op,&arg,&unitID,
9781 &ex1,&ex2,&ex3,&ex4);
9782 ast_log(LOG_NOTICE,"Got (double-length) packet:\n");
9783 ast_log(LOG_NOTICE,"op: %02x, arg: %02x, UnitID: %04x\n",
9784 op & 255,arg & 255,unitID);
9785 ast_log(LOG_NOTICE,"ex1: %02x, ex2: %02x, ex3: %02x, ex4: %02x\n",
9786 ex1 & 255, ex2 & 255, ex3 & 255, ex4 & 255);
9788 #endif
9789 #ifdef __RPT_NOTCH
9790 /* apply inbound filters, if any */
9791 rpt_filter(myrpt,f->data,f->datalen / 2);
9792 #endif
9793 if (ioctl(myrpt->zaprxchannel->fds[0], ZT_GETCONFMUTE, &ismuted) == -1)
9795 ismuted = 0;
9797 if (dtmfed) ismuted = 1;
9798 dtmfed = 0;
9799 if (ismuted)
9801 memset(f->data,0,f->datalen);
9802 if (myrpt->lastf1)
9803 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
9804 if (myrpt->lastf2)
9805 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
9807 if (f) f2 = ast_frdup(f);
9808 else f2 = NULL;
9809 f1 = myrpt->lastf2;
9810 myrpt->lastf2 = myrpt->lastf1;
9811 myrpt->lastf1 = f2;
9812 if (ismuted)
9814 if (myrpt->lastf1)
9815 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
9816 if (myrpt->lastf2)
9817 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
9819 if (f1)
9821 ast_write(myrpt->pchannel,f1);
9822 ast_frfree(f1);
9825 #ifndef OLD_ASTERISK
9826 else if (f->frametype == AST_FRAME_DTMF_BEGIN)
9828 if (myrpt->lastf1)
9829 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
9830 if (myrpt->lastf2)
9831 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
9832 dtmfed = 1;
9834 #endif
9835 else if (f->frametype == AST_FRAME_DTMF)
9837 c = (char) f->subclass; /* get DTMF char */
9838 ast_frfree(f);
9839 if (myrpt->lastf1)
9840 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
9841 if (myrpt->lastf2)
9842 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
9843 dtmfed = 1;
9844 if (!myrpt->keyed) continue;
9845 c = func_xlat(myrpt,c,&myrpt->p.inxlat);
9846 if (c) local_dtmf_helper(myrpt,c);
9847 continue;
9849 else if (f->frametype == AST_FRAME_CONTROL)
9851 if (f->subclass == AST_CONTROL_HANGUP)
9853 if (debug) printf("@@@@ rpt:Hung Up\n");
9854 ast_frfree(f);
9855 break;
9857 /* if RX key */
9858 if (f->subclass == AST_CONTROL_RADIO_KEY)
9860 if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink))
9862 if (debug == 7) printf("@@@@ rx key\n");
9863 myrpt->keyed = 1;
9865 if (myrpt->p.archivedir)
9867 donodelog(myrpt,"RXKEY,MAIN");
9870 /* if RX un-key */
9871 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
9873 if ((!lasttx) || (myrpt->p.duplex > 1) || (myrpt->p.linktolink))
9875 if (debug == 7) printf("@@@@ rx un-key\n");
9876 if(myrpt->p.duplex && myrpt->keyed) {
9877 rpt_telemetry(myrpt,UNKEY,NULL);
9880 myrpt->keyed = 0;
9881 if (myrpt->p.archivedir)
9883 donodelog(myrpt,"RXUNKEY,MAIN");
9887 ast_frfree(f);
9888 continue;
9890 if (who == myrpt->pchannel) /* if it was a read from pseudo */
9892 f = ast_read(myrpt->pchannel);
9893 if (!f)
9895 if (debug) printf("@@@@ rpt:Hung Up\n");
9896 break;
9898 if (f->frametype == AST_FRAME_VOICE)
9900 ast_write(myrpt->txpchannel,f);
9902 if (f->frametype == AST_FRAME_CONTROL)
9904 if (f->subclass == AST_CONTROL_HANGUP)
9906 if (debug) printf("@@@@ rpt:Hung Up\n");
9907 ast_frfree(f);
9908 break;
9911 ast_frfree(f);
9912 continue;
9914 if (who == myrpt->txchannel) /* if it was a read from tx */
9916 f = ast_read(myrpt->txchannel);
9917 if (!f)
9919 if (debug) printf("@@@@ rpt:Hung Up\n");
9920 break;
9922 if (f->frametype == AST_FRAME_CONTROL)
9924 if (f->subclass == AST_CONTROL_HANGUP)
9926 if (debug) printf("@@@@ rpt:Hung Up\n");
9927 ast_frfree(f);
9928 break;
9931 ast_frfree(f);
9932 continue;
9934 if (who == myrpt->zaptxchannel) /* if it was a read from pseudo-tx */
9936 f = ast_read(myrpt->zaptxchannel);
9937 if (!f)
9939 if (debug) printf("@@@@ rpt:Hung Up\n");
9940 break;
9942 if (f->frametype == AST_FRAME_VOICE)
9944 ast_write(myrpt->txchannel,f);
9946 if (f->frametype == AST_FRAME_CONTROL)
9948 if (f->subclass == AST_CONTROL_HANGUP)
9950 if (debug) printf("@@@@ rpt:Hung Up\n");
9951 ast_frfree(f);
9952 break;
9955 ast_frfree(f);
9956 continue;
9958 toexit = 0;
9959 rpt_mutex_lock(&myrpt->lock);
9960 l = myrpt->links.next;
9961 while(l != &myrpt->links)
9963 if (l->disctime)
9965 l = l->next;
9966 continue;
9968 if (who == l->chan) /* if it was a read from rx */
9970 int remnomute;
9972 remrx = 0;
9973 /* see if any other links are receiving */
9974 m = myrpt->links.next;
9975 while(m != &myrpt->links)
9977 /* if not us, count it */
9978 if ((m != l) && (m->lastrx)) remrx = 1;
9979 m = m->next;
9981 rpt_mutex_unlock(&myrpt->lock);
9982 remnomute = myrpt->localtx &&
9983 (!(myrpt->cmdnode[0] ||
9984 (myrpt->dtmfidx > -1)));
9985 totx = (((l->isremote) ? (remnomute) :
9986 myrpt->exttx) || remrx) && l->mode;
9987 if (l->phonemode == 0 && l->chan && (l->lasttx != totx))
9989 if (totx)
9991 ast_indicate(l->chan,AST_CONTROL_RADIO_KEY);
9993 else
9995 ast_indicate(l->chan,AST_CONTROL_RADIO_UNKEY);
9997 if (myrpt->p.archivedir)
9999 char str[100];
10001 if (totx)
10002 sprintf(str,"TXKEY,%s",l->name);
10003 else
10004 sprintf(str,"TXUNKEY,%s",l->name);
10005 donodelog(myrpt,str);
10008 l->lasttx = totx;
10009 f = ast_read(l->chan);
10010 if (!f)
10012 rpt_mutex_lock(&myrpt->lock);
10013 __kickshort(myrpt);
10014 rpt_mutex_unlock(&myrpt->lock);
10015 if ((!l->disced) && (!l->outbound))
10017 if ((l->name[0] == '0') || l->isremote)
10018 l->disctime = 1;
10019 else
10020 l->disctime = DISC_TIME;
10021 rpt_mutex_lock(&myrpt->lock);
10022 ast_hangup(l->chan);
10023 l->chan = 0;
10024 break;
10027 if (l->retrytimer)
10029 ast_hangup(l->chan);
10030 l->chan = 0;
10031 rpt_mutex_lock(&myrpt->lock);
10032 break;
10034 if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
10036 rpt_mutex_lock(&myrpt->lock);
10037 if (l->chan) ast_hangup(l->chan);
10038 l->chan = 0;
10039 l->hasconnected = 1;
10040 l->retrytimer = RETRY_TIMER_MS;
10041 l->elaptime = 0;
10042 l->connecttime = 0;
10043 l->thisconnected = 0;
10044 break;
10046 rpt_mutex_lock(&myrpt->lock);
10047 /* remove from queue */
10048 remque((struct qelem *) l);
10049 if (!strcmp(myrpt->cmdnode,l->name))
10050 myrpt->cmdnode[0] = 0;
10051 __kickshort(myrpt);
10052 rpt_mutex_unlock(&myrpt->lock);
10053 if (!l->hasconnected)
10054 rpt_telemetry(myrpt,CONNFAIL,l);
10055 else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
10056 if (myrpt->p.archivedir)
10058 char str[100];
10060 if (!l->hasconnected)
10061 sprintf(str,"LINKFAIL,%s",l->name);
10062 else
10063 sprintf(str,"LINKDISC,%s",l->name);
10064 donodelog(myrpt,str);
10066 if (l->lastf1) ast_frfree(l->lastf1);
10067 l->lastf1 = NULL;
10068 if (l->lastf2) ast_frfree(l->lastf2);
10069 l->lastf2 = NULL;
10070 /* hang-up on call to device */
10071 ast_hangup(l->chan);
10072 ast_hangup(l->pchan);
10073 free(l);
10074 rpt_mutex_lock(&myrpt->lock);
10075 break;
10077 if (f->frametype == AST_FRAME_VOICE)
10079 int ismuted;
10081 if (l->phonemode)
10083 if (ioctl(l->chan->fds[0], ZT_GETCONFMUTE, &ismuted) == -1)
10085 ismuted = 0;
10087 /* if not receiving, zero-out audio */
10088 ismuted |= (!l->lastrx);
10089 if (l->dtmfed && l->phonemode) ismuted = 1;
10090 l->dtmfed = 0;
10091 if (ismuted)
10093 memset(f->data,0,f->datalen);
10094 if (l->lastf1)
10095 memset(l->lastf1->data,0,l->lastf1->datalen);
10096 if (l->lastf2)
10097 memset(l->lastf2->data,0,l->lastf2->datalen);
10099 if (f) f2 = ast_frdup(f);
10100 else f2 = NULL;
10101 f1 = l->lastf2;
10102 l->lastf2 = l->lastf1;
10103 l->lastf1 = f2;
10104 if (ismuted)
10106 if (l->lastf1)
10107 memset(l->lastf1->data,0,l->lastf1->datalen);
10108 if (l->lastf2)
10109 memset(l->lastf2->data,0,l->lastf2->datalen);
10111 if (f1)
10113 ast_write(l->pchan,f1);
10114 ast_frfree(f1);
10117 else
10119 if (!l->lastrx)
10120 memset(f->data,0,f->datalen);
10121 ast_write(l->pchan,f);
10124 #ifndef OLD_ASTERISK
10125 else if (f->frametype == AST_FRAME_DTMF_BEGIN)
10127 if (l->lastf1)
10128 memset(l->lastf1->data,0,l->lastf1->datalen);
10129 if (l->lastf2)
10130 memset(l->lastf2->data,0,l->lastf2->datalen);
10131 l->dtmfed = 1;
10133 #endif
10135 if (f->frametype == AST_FRAME_TEXT)
10137 handle_link_data(myrpt,l,f->data);
10139 if (f->frametype == AST_FRAME_DTMF)
10141 if (l->lastf1)
10142 memset(l->lastf1->data,0,l->lastf1->datalen);
10143 if (l->lastf2)
10144 memset(l->lastf2->data,0,l->lastf2->datalen);
10145 l->dtmfed = 1;
10146 handle_link_phone_dtmf(myrpt,l,f->subclass);
10148 if (f->frametype == AST_FRAME_CONTROL)
10150 if (f->subclass == AST_CONTROL_ANSWER)
10152 char lconnected = l->connected;
10154 __kickshort(myrpt);
10155 l->connected = 1;
10156 l->hasconnected = 1;
10157 l->thisconnected = 1;
10158 l->elaptime = -1;
10159 if (!l->isremote) l->retries = 0;
10160 if (!lconnected)
10162 rpt_telemetry(myrpt,CONNECTED,l);
10163 if (myrpt->p.archivedir)
10165 char str[100];
10167 if (l->mode)
10168 sprintf(str,"LINKTRX,%s",l->name);
10169 else
10170 sprintf(str,"LINKMONITOR,%s",l->name);
10171 donodelog(myrpt,str);
10174 else
10175 l->reconnects++;
10177 /* if RX key */
10178 if (f->subclass == AST_CONTROL_RADIO_KEY)
10180 if (debug == 7 ) printf("@@@@ rx key\n");
10181 l->lastrx = 1;
10182 l->rerxtimer = 0;
10183 if (myrpt->p.archivedir && (!l->lastrx1))
10185 char str[100];
10187 l->lastrx1 = 1;
10188 sprintf(str,"RXKEY,%s",l->name);
10189 donodelog(myrpt,str);
10192 /* if RX un-key */
10193 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
10195 if (debug == 7) printf("@@@@ rx un-key\n");
10196 l->lastrx = 0;
10197 l->rerxtimer = 0;
10198 if(myrpt->p.duplex)
10199 rpt_telemetry(myrpt,LINKUNKEY,l);
10200 if (myrpt->p.archivedir && (l->lastrx1))
10202 char str[100];
10204 l->lastrx1 = 0;
10205 sprintf(str,"RXUNKEY,%s",l->name);
10206 donodelog(myrpt,str);
10209 if (f->subclass == AST_CONTROL_HANGUP)
10211 ast_frfree(f);
10212 rpt_mutex_lock(&myrpt->lock);
10213 __kickshort(myrpt);
10214 rpt_mutex_unlock(&myrpt->lock);
10215 if ((!l->outbound) && (!l->disced))
10217 if ((l->name[0] == '0') || l->isremote)
10218 l->disctime = 1;
10219 else
10220 l->disctime = DISC_TIME;
10221 rpt_mutex_lock(&myrpt->lock);
10222 ast_hangup(l->chan);
10223 l->chan = 0;
10224 break;
10226 if (l->retrytimer)
10228 if (l->chan) ast_hangup(l->chan);
10229 l->chan = 0;
10230 rpt_mutex_lock(&myrpt->lock);
10231 break;
10233 if (l->outbound && (l->retries++ < l->max_retries) && (l->hasconnected))
10235 rpt_mutex_lock(&myrpt->lock);
10236 if (l->chan) ast_hangup(l->chan);
10237 l->chan = 0;
10238 l->hasconnected = 1;
10239 l->elaptime = 0;
10240 l->retrytimer = RETRY_TIMER_MS;
10241 l->connecttime = 0;
10242 l->thisconnected = 0;
10243 break;
10245 rpt_mutex_lock(&myrpt->lock);
10246 /* remove from queue */
10247 remque((struct qelem *) l);
10248 if (!strcmp(myrpt->cmdnode,l->name))
10249 myrpt->cmdnode[0] = 0;
10250 __kickshort(myrpt);
10251 rpt_mutex_unlock(&myrpt->lock);
10252 if (!l->hasconnected)
10253 rpt_telemetry(myrpt,CONNFAIL,l);
10254 else if (l->disced != 2) rpt_telemetry(myrpt,REMDISC,l);
10255 if (myrpt->p.archivedir)
10257 char str[100];
10259 if (!l->hasconnected)
10260 sprintf(str,"LINKFAIL,%s",l->name);
10261 else
10262 sprintf(str,"LINKDISC,%s",l->name);
10263 donodelog(myrpt,str);
10265 if (l->lastf1) ast_frfree(l->lastf1);
10266 l->lastf1 = NULL;
10267 if (l->lastf2) ast_frfree(l->lastf2);
10268 l->lastf2 = NULL;
10269 /* hang-up on call to device */
10270 ast_hangup(l->chan);
10271 ast_hangup(l->pchan);
10272 free(l);
10273 rpt_mutex_lock(&myrpt->lock);
10274 break;
10277 ast_frfree(f);
10278 rpt_mutex_lock(&myrpt->lock);
10279 break;
10281 if (who == l->pchan)
10283 rpt_mutex_unlock(&myrpt->lock);
10284 f = ast_read(l->pchan);
10285 if (!f)
10287 if (debug) printf("@@@@ rpt:Hung Up\n");
10288 toexit = 1;
10289 rpt_mutex_lock(&myrpt->lock);
10290 break;
10292 if (f->frametype == AST_FRAME_VOICE)
10294 if (l->chan) ast_write(l->chan,f);
10296 if (f->frametype == AST_FRAME_CONTROL)
10298 if (f->subclass == AST_CONTROL_HANGUP)
10300 if (debug) printf("@@@@ rpt:Hung Up\n");
10301 ast_frfree(f);
10302 toexit = 1;
10303 rpt_mutex_lock(&myrpt->lock);
10304 break;
10307 ast_frfree(f);
10308 rpt_mutex_lock(&myrpt->lock);
10309 break;
10311 l = l->next;
10313 rpt_mutex_unlock(&myrpt->lock);
10314 if (toexit) break;
10315 if (who == myrpt->monchannel)
10317 f = ast_read(myrpt->monchannel);
10318 if (!f)
10320 if (debug) printf("@@@@ rpt:Hung Up\n");
10321 break;
10323 if (f->frametype == AST_FRAME_VOICE)
10325 if (myrpt->monstream)
10326 ast_writestream(myrpt->monstream,f);
10328 if (f->frametype == AST_FRAME_CONTROL)
10330 if (f->subclass == AST_CONTROL_HANGUP)
10332 if (debug) printf("@@@@ rpt:Hung Up\n");
10333 ast_frfree(f);
10334 break;
10337 ast_frfree(f);
10338 continue;
10340 if (who == myrpt->txpchannel) /* if it was a read from remote tx */
10342 f = ast_read(myrpt->txpchannel);
10343 if (!f)
10345 if (debug) printf("@@@@ rpt:Hung Up\n");
10346 break;
10348 if (f->frametype == AST_FRAME_CONTROL)
10350 if (f->subclass == AST_CONTROL_HANGUP)
10352 if (debug) printf("@@@@ rpt:Hung Up\n");
10353 ast_frfree(f);
10354 break;
10357 ast_frfree(f);
10358 continue;
10361 usleep(100000);
10362 ast_hangup(myrpt->pchannel);
10363 ast_hangup(myrpt->monchannel);
10364 ast_hangup(myrpt->txpchannel);
10365 if (myrpt->txchannel != myrpt->rxchannel) ast_hangup(myrpt->txchannel);
10366 if (myrpt->zaptxchannel != myrpt->txchannel) ast_hangup(myrpt->zaptxchannel);
10367 if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
10368 myrpt->lastf1 = NULL;
10369 if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
10370 myrpt->lastf2 = NULL;
10371 ast_hangup(myrpt->rxchannel);
10372 rpt_mutex_lock(&myrpt->lock);
10373 l = myrpt->links.next;
10374 while(l != &myrpt->links)
10376 struct rpt_link *ll = l;
10377 /* remove from queue */
10378 remque((struct qelem *) l);
10379 /* hang-up on call to device */
10380 if (l->chan) ast_hangup(l->chan);
10381 ast_hangup(l->pchan);
10382 l = l->next;
10383 free(ll);
10385 rpt_mutex_unlock(&myrpt->lock);
10386 if (debug) printf("@@@@ rpt:Hung up channel\n");
10387 myrpt->rpt_thread = AST_PTHREADT_STOP;
10388 pthread_exit(NULL);
10389 return NULL;
10393 static void *rpt_master(void *ignore)
10395 int i,n;
10396 pthread_attr_t attr;
10397 struct ast_config *cfg;
10398 char *this,*val;
10400 /* init nodelog queue */
10401 nodelog.next = nodelog.prev = &nodelog;
10402 /* go thru all the specified repeaters */
10403 this = NULL;
10404 n = 0;
10405 /* wait until asterisk starts */
10406 while(!ast_test_flag(&ast_options,AST_OPT_FLAG_FULLY_BOOTED))
10407 usleep(250000);
10408 rpt_vars[n].cfg = ast_config_load("rpt.conf");
10409 cfg = rpt_vars[n].cfg;
10410 if (!cfg) {
10411 ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf. Radio Repeater disabled.\n");
10412 pthread_exit(NULL);
10414 while((this = ast_category_browse(cfg,this)) != NULL)
10416 for(i = 0 ; i < strlen(this) ; i++){
10417 if((this[i] < '0') || (this[i] > '9'))
10418 break;
10420 if(i != strlen(this)) continue; /* Not a node defn */
10421 memset(&rpt_vars[n],0,sizeof(rpt_vars[n]));
10422 rpt_vars[n].name = strdup(this);
10423 val = (char *) ast_variable_retrieve(cfg,this,"rxchannel");
10424 if (val) rpt_vars[n].rxchanname = strdup(val);
10425 val = (char *) ast_variable_retrieve(cfg,this,"txchannel");
10426 if (val) rpt_vars[n].txchanname = strdup(val);
10427 val = (char *) ast_variable_retrieve(cfg,this,"remote");
10428 if (val) rpt_vars[n].remote = strdup(val);
10429 ast_mutex_init(&rpt_vars[n].lock);
10430 ast_mutex_init(&rpt_vars[n].remlock);
10431 rpt_vars[n].tele.next = &rpt_vars[n].tele;
10432 rpt_vars[n].tele.prev = &rpt_vars[n].tele;
10433 rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
10434 rpt_vars[n].tailmessagen = 0;
10435 #ifdef _MDC_DECODE_H_
10436 rpt_vars[n].mdc = mdc_decoder_new(8000);
10437 #endif
10438 n++;
10440 nrpts = n;
10441 ast_config_destroy(cfg);
10443 /* start em all */
10444 for(i = 0; i < n; i++)
10446 load_rpt_vars(i,1);
10448 /* if is a remote, dont start one for it */
10449 if (rpt_vars[i].remote)
10451 if(retreive_memory(&rpt_vars[i],"init")){ /* Try to retreive initial memory channel */
10452 strncpy(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq) - 1);
10453 strncpy(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl) - 1);
10455 strncpy(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl) - 1);
10456 rpt_vars[i].remmode = REM_MODE_FM;
10457 rpt_vars[i].offset = REM_SIMPLEX;
10458 rpt_vars[i].powerlevel = REM_MEDPWR;
10460 continue;
10462 if (!rpt_vars[i].p.ident)
10464 ast_log(LOG_WARNING,"Did not specify ident for node %s\n",rpt_vars[i].name);
10465 ast_config_destroy(cfg);
10466 pthread_exit(NULL);
10468 pthread_attr_init(&attr);
10469 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
10470 ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
10472 usleep(500000);
10473 time(&starttime);
10474 for(;;)
10476 /* Now monitor each thread, and restart it if necessary */
10477 for(i = 0; i < n; i++)
10479 int rv;
10480 if (rpt_vars[i].remote) continue;
10481 if (rpt_vars[i].rpt_thread == AST_PTHREADT_STOP)
10482 rv = -1;
10483 else
10484 rv = pthread_kill(rpt_vars[i].rpt_thread,0);
10485 if (rv)
10487 if(time(NULL) - rpt_vars[i].lastthreadrestarttime <= 15)
10489 if(rpt_vars[i].threadrestarts >= 5)
10491 ast_log(LOG_ERROR,"Continual RPT thread restarts, killing Asterisk\n");
10492 exit(1); /* Stuck in a restart loop, kill Asterisk and start over */
10494 else
10496 ast_log(LOG_NOTICE,"RPT thread restarted on %s\n",rpt_vars[i].name);
10497 rpt_vars[i].threadrestarts++;
10500 else
10501 rpt_vars[i].threadrestarts = 0;
10503 rpt_vars[i].lastthreadrestarttime = time(NULL);
10504 pthread_attr_init(&attr);
10505 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
10506 ast_pthread_create(&rpt_vars[i].rpt_thread,&attr,rpt,(void *) &rpt_vars[i]);
10507 ast_log(LOG_WARNING, "rpt_thread restarted on node %s\n", rpt_vars[i].name);
10511 for(;;)
10513 struct nodelog *nodep;
10514 char *space,datestr[100],fname[300];
10515 int fd;
10517 ast_mutex_lock(&nodeloglock);
10518 nodep = nodelog.next;
10519 if(nodep == &nodelog) /* if nothing in queue */
10521 ast_mutex_unlock(&nodeloglock);
10522 break;
10524 remque((struct qelem *)nodep);
10525 ast_mutex_unlock(&nodeloglock);
10526 space = strchr(nodep->str,' ');
10527 if (!space)
10529 free(nodep);
10530 continue;
10532 *space = 0;
10533 strftime(datestr,sizeof(datestr) - 1,"%Y%m%d",
10534 localtime(&nodep->timestamp));
10535 sprintf(fname,"%s/%s/%s.txt",nodep->archivedir,
10536 nodep->str,datestr);
10537 fd = open(fname,O_WRONLY | O_CREAT | O_APPEND,0600);
10538 if (fd == -1)
10540 ast_log(LOG_ERROR,"Cannot open node log file %s for write",space + 1);
10541 free(nodep);
10542 continue;
10544 if (write(fd,space + 1,strlen(space + 1)) !=
10545 strlen(space + 1))
10547 ast_log(LOG_ERROR,"Cannot write node log file %s for write",space + 1);
10548 free(nodep);
10549 continue;
10551 close(fd);
10552 free(nodep);
10554 usleep(2000000);
10556 ast_config_destroy(cfg);
10557 pthread_exit(NULL);
10560 static int rpt_exec(struct ast_channel *chan, void *data)
10562 int res=-1,i,rem_totx,rem_rx,remkeyed,n,phone_mode = 0;
10563 int iskenwood_pci4,authtold,authreq,setting,notremming,reming;
10564 int ismuted,dtmfed;
10565 #ifdef OLD_ASTERISK
10566 struct localuser *u;
10567 #endif
10568 char tmp[256], keyed = 0,keyed1 = 0;
10569 char *options,*stringp,*tele,c;
10570 struct rpt *myrpt;
10571 struct ast_frame *f,*f1,*f2;
10572 struct ast_channel *who;
10573 struct ast_channel *cs[20];
10574 struct rpt_link *l;
10575 ZT_CONFINFO ci; /* conference info */
10576 ZT_PARAMS par;
10577 int ms,elap,nullfd;
10578 time_t t,last_timeout_warning;
10579 struct zt_radio_param z;
10580 struct rpt_tele *telem;
10582 nullfd = open("/dev/null",O_RDWR);
10583 if (ast_strlen_zero(data)) {
10584 ast_log(LOG_WARNING, "Rpt requires an argument (system node)\n");
10585 return -1;
10588 strncpy(tmp, (char *)data, sizeof(tmp)-1);
10589 time(&t);
10590 /* if time has externally shifted negative, screw it */
10591 if (t < starttime) t = starttime + START_DELAY;
10592 if ((!starttime) || (t < (starttime + START_DELAY)))
10594 ast_log(LOG_NOTICE,"Node %s rejecting call: too soon!\n",tmp);
10595 ast_safe_sleep(chan,3000);
10596 return -1;
10598 stringp=tmp;
10599 strsep(&stringp, "|");
10600 options = stringp;
10601 myrpt = NULL;
10602 /* see if we can find our specified one */
10603 for(i = 0; i < nrpts; i++)
10605 /* if name matches, assign it and exit loop */
10606 if (!strcmp(tmp,rpt_vars[i].name))
10608 myrpt = &rpt_vars[i];
10609 break;
10612 if (myrpt == NULL)
10614 ast_log(LOG_WARNING, "Cannot find specified system node %s\n",tmp);
10615 return -1;
10618 if(myrpt->p.s[myrpt->p.sysstate_cur].txdisable){ /* Do not allow incoming connections if disabled */
10619 ast_log(LOG_NOTICE, "Connect attempt to node %s with tx disabled", myrpt->name);
10620 return -1;
10623 /* if not phone access, must be an IAX connection */
10624 if (options && ((*options == 'P') || (*options == 'D') || (*options == 'R')))
10626 int val;
10628 phone_mode = 1;
10629 if (*options == 'D') phone_mode = 2;
10630 ast_set_callerid(chan,"0","app_rpt user","0");
10631 val = 1;
10632 ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&val,sizeof(char),0);
10634 else
10636 #ifdef ALLOW_LOCAL_CHANNELS
10637 /* Check to insure the connection is IAX2 or Local*/
10638 if ( (strncmp(chan->name,"IAX2",4)) && (strncmp(chan->name,"Local",5)) ) {
10639 ast_log(LOG_WARNING, "We only accept links via IAX2 or Local!!\n");
10640 return -1;
10642 #else
10643 if (strncmp(chan->name,"IAX2",4))
10645 ast_log(LOG_WARNING, "We only accept links via IAX2!!\n");
10646 return -1;
10648 #endif
10650 if (options && (*options == 'R'))
10653 /* Parts of this section taken from app_parkandannounce */
10654 char *return_context;
10655 int l, m, lot, timeout = 0;
10656 char tmp[256],*template;
10657 char *working, *context, *exten, *priority;
10658 char *s,*orig_s;
10661 rpt_mutex_lock(&myrpt->lock);
10662 m = myrpt->callmode;
10663 rpt_mutex_unlock(&myrpt->lock);
10665 if ((!myrpt->p.nobusyout) && m)
10667 if (chan->_state != AST_STATE_UP)
10669 ast_indicate(chan,AST_CONTROL_BUSY);
10671 while(ast_safe_sleep(chan,10000) != -1);
10672 return -1;
10675 if (chan->_state != AST_STATE_UP)
10677 ast_answer(chan);
10680 l=strlen(options)+2;
10681 orig_s=malloc(l);
10682 if(!orig_s) {
10683 ast_log(LOG_WARNING, "Out of memory\n");
10684 return -1;
10686 s=orig_s;
10687 strncpy(s,options,l);
10689 template=strsep(&s,"|");
10690 if(!template) {
10691 ast_log(LOG_WARNING, "An announce template must be defined\n");
10692 free(orig_s);
10693 return -1;
10696 if(s) {
10697 timeout = atoi(strsep(&s, "|"));
10698 timeout *= 1000;
10701 return_context = s;
10703 if(return_context != NULL) {
10704 /* set the return context. Code borrowed from the Goto builtin */
10706 working = return_context;
10707 context = strsep(&working, "|");
10708 exten = strsep(&working, "|");
10709 if(!exten) {
10710 /* Only a priority in this one */
10711 priority = context;
10712 exten = NULL;
10713 context = NULL;
10714 } else {
10715 priority = strsep(&working, "|");
10716 if(!priority) {
10717 /* Only an extension and priority in this one */
10718 priority = exten;
10719 exten = context;
10720 context = NULL;
10723 if(atoi(priority) < 0) {
10724 ast_log(LOG_WARNING, "Priority '%s' must be a number > 0\n", priority);
10725 free(orig_s);
10726 return -1;
10728 /* At this point we have a priority and maybe an extension and a context */
10729 chan->priority = atoi(priority);
10730 #ifdef OLD_ASTERISK
10731 if(exten && strcasecmp(exten, "BYEXTENSION"))
10732 #else
10733 if(exten)
10734 #endif
10735 strncpy(chan->exten, exten, sizeof(chan->exten)-1);
10736 if(context)
10737 strncpy(chan->context, context, sizeof(chan->context)-1);
10738 } else { /* increment the priority by default*/
10739 chan->priority++;
10742 if(option_verbose > 2) {
10743 ast_verbose( VERBOSE_PREFIX_3 "Return Context: (%s,%s,%d) ID: %s\n", chan->context,chan->exten, chan->priority, chan->cid.cid_num);
10744 if(!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
10745 ast_verbose( VERBOSE_PREFIX_3 "Warning: Return Context Invalid, call will return to default|s\n");
10749 /* we are using masq_park here to protect * from touching the channel once we park it. If the channel comes out of timeout
10750 before we are done announcing and the channel is messed with, Kablooeee. So we use Masq to prevent this. */
10752 ast_masq_park_call(chan, NULL, timeout, &lot);
10754 if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, return_context);
10756 snprintf(tmp,sizeof(tmp) - 1,"%d,%s",lot,template + 1);
10758 rpt_telemetry(myrpt,REV_PATCH,tmp);
10760 free(orig_s);
10762 return 0;
10766 if (!options)
10768 struct ast_hostent ahp;
10769 struct hostent *hp;
10770 struct in_addr ia;
10771 char hisip[100],nodeip[100],*val, *s, *s1, *s2, *b,*b1;
10773 /* look at callerid to see what node this comes from */
10774 if (!chan->cid.cid_num) /* if doesn't have caller id */
10776 ast_log(LOG_WARNING, "Doesnt have callerid on %s\n",tmp);
10777 return -1;
10780 /* get his IP from IAX2 module */
10781 memset(hisip,0,sizeof(hisip));
10782 #ifdef ALLOW_LOCAL_CHANNELS
10783 /* set IP address if this is a local connection*/
10784 if (strncmp(chan->name,"Local",5)==0) {
10785 strcpy(hisip,"127.0.0.1");
10786 } else {
10787 pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
10789 #else
10790 pbx_substitute_variables_helper(chan,"${IAXPEER(CURRENTCHANNEL)}",hisip,sizeof(hisip) - 1);
10791 #endif
10793 if (!hisip[0])
10795 ast_log(LOG_WARNING, "Link IP address cannot be determined!!\n");
10796 return -1;
10799 ast_callerid_parse(chan->cid.cid_num,&b,&b1);
10800 ast_shrink_phone_number(b1);
10801 if (!strcmp(myrpt->name,b1))
10803 ast_log(LOG_WARNING, "Trying to link to self!!\n");
10804 return -1;
10807 if (*b1 < '1')
10809 ast_log(LOG_WARNING, "Node %s Invalid for connection here!!\n",b1);
10810 return -1;
10814 /* look for his reported node string */
10815 val = node_lookup(myrpt,b1);
10816 if (!val)
10818 ast_log(LOG_WARNING, "Reported node %s cannot be found!!\n",b1);
10819 return -1;
10821 strncpy(tmp,val,sizeof(tmp) - 1);
10822 s = tmp;
10823 s1 = strsep(&s,",");
10824 s2 = strsep(&s,",");
10825 if (!s2)
10827 ast_log(LOG_WARNING, "Reported node %s not in correct format!!\n",b1);
10828 return -1;
10830 if (strcmp(s2,"NONE")) {
10831 hp = ast_gethostbyname(s2, &ahp);
10832 if (!hp)
10834 ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s2);
10835 return -1;
10837 memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
10838 #ifdef OLD_ASTERISK
10839 ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
10840 #else
10841 strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
10842 #endif
10843 if (strcmp(hisip,nodeip))
10845 char *s3 = strchr(s1,'@');
10846 if (s3) s1 = s3 + 1;
10847 s3 = strchr(s1,'/');
10848 if (s3) *s3 = 0;
10849 hp = ast_gethostbyname(s1, &ahp);
10850 if (!hp)
10852 ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n",b1,s1);
10853 return -1;
10855 memcpy(&ia,hp->h_addr,sizeof(in_addr_t));
10856 #ifdef OLD_ASTERISK
10857 ast_inet_ntoa(nodeip,sizeof(nodeip) - 1,ia);
10858 #else
10859 strncpy(nodeip,ast_inet_ntoa(ia),sizeof(nodeip) - 1);
10860 #endif
10861 if (strcmp(hisip,nodeip))
10863 ast_log(LOG_WARNING, "Node %s IP %s does not match link IP %s!!\n",b1,nodeip,hisip);
10864 return -1;
10870 /* if is not a remote */
10871 if (!myrpt->remote)
10874 char *b,*b1;
10875 int reconnects = 0;
10877 /* look at callerid to see what node this comes from */
10878 if (!chan->cid.cid_num) /* if doesn't have caller id */
10880 ast_log(LOG_WARNING, "Doesnt have callerid on %s\n",tmp);
10881 return -1;
10884 ast_callerid_parse(chan->cid.cid_num,&b,&b1);
10885 ast_shrink_phone_number(b1);
10886 if (!strcmp(myrpt->name,b1))
10888 ast_log(LOG_WARNING, "Trying to link to self!!\n");
10889 return -1;
10891 rpt_mutex_lock(&myrpt->lock);
10892 l = myrpt->links.next;
10893 /* try to find this one in queue */
10894 while(l != &myrpt->links)
10896 if (l->name[0] == '0')
10898 l = l->next;
10899 continue;
10901 /* if found matching string */
10902 if (!strcmp(l->name,b1)) break;
10903 l = l->next;
10905 /* if found */
10906 if (l != &myrpt->links)
10908 l->killme = 1;
10909 l->retries = l->max_retries + 1;
10910 l->disced = 2;
10911 reconnects = l->reconnects;
10912 reconnects++;
10913 rpt_mutex_unlock(&myrpt->lock);
10914 usleep(500000);
10915 } else
10916 rpt_mutex_unlock(&myrpt->lock);
10917 /* establish call in tranceive mode */
10918 l = malloc(sizeof(struct rpt_link));
10919 if (!l)
10921 ast_log(LOG_WARNING, "Unable to malloc\n");
10922 pthread_exit(NULL);
10924 /* zero the silly thing */
10925 memset((char *)l,0,sizeof(struct rpt_link));
10926 l->mode = 1;
10927 strncpy(l->name,b1,MAXNODESTR - 1);
10928 l->isremote = 0;
10929 l->chan = chan;
10930 l->connected = 1;
10931 l->thisconnected = 1;
10932 l->hasconnected = 1;
10933 l->reconnects = reconnects;
10934 l->phonemode = phone_mode;
10935 l->lastf1 = NULL;
10936 l->lastf2 = NULL;
10937 l->dtmfed = 0;
10938 ast_set_read_format(l->chan,AST_FORMAT_SLINEAR);
10939 ast_set_write_format(l->chan,AST_FORMAT_SLINEAR);
10940 /* allocate a pseudo-channel thru asterisk */
10941 l->pchan = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
10942 if (!l->pchan)
10944 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
10945 pthread_exit(NULL);
10947 ast_set_read_format(l->pchan,AST_FORMAT_SLINEAR);
10948 ast_set_write_format(l->pchan,AST_FORMAT_SLINEAR);
10949 #ifdef AST_CDR_FLAG_POST_DISABLED
10950 ast_set_flag(l->pchan->cdr,AST_CDR_FLAG_POST_DISABLED);
10951 #endif
10952 /* make a conference for the tx */
10953 ci.chan = 0;
10954 ci.confno = myrpt->conf;
10955 ci.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER | ZT_CONF_TALKER;
10956 /* first put the channel on the conference in proper mode */
10957 if (ioctl(l->pchan->fds[0],ZT_SETCONF,&ci) == -1)
10959 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
10960 pthread_exit(NULL);
10962 rpt_mutex_lock(&myrpt->lock);
10963 if (phone_mode > 1) l->lastrx = 1;
10964 l->max_retries = MAX_RETRIES;
10965 /* insert at end of queue */
10966 insque((struct qelem *)l,(struct qelem *)myrpt->links.next);
10967 __kickshort(myrpt);
10968 rpt_mutex_unlock(&myrpt->lock);
10969 if (chan->_state != AST_STATE_UP) {
10970 ast_answer(chan);
10972 if (myrpt->p.archivedir)
10974 char str[100];
10976 if (l->phonemode)
10977 sprintf(str,"LINK(P),%s",l->name);
10978 else
10979 sprintf(str,"LINK,%s",l->name);
10980 donodelog(myrpt,str);
10982 return AST_PBX_KEEPALIVE;
10984 /* well, then it is a remote */
10985 rpt_mutex_lock(&myrpt->lock);
10986 /* if remote, error if anyone else already linked */
10987 if (myrpt->remoteon)
10989 rpt_mutex_unlock(&myrpt->lock);
10990 usleep(500000);
10991 if (myrpt->remoteon)
10993 ast_log(LOG_WARNING, "Trying to use busy link on %s\n",tmp);
10994 return -1;
10996 rpt_mutex_lock(&myrpt->lock);
10998 if ((!strcmp(myrpt->remote, remote_rig_rbi)) &&
10999 (ioperm(myrpt->p.iobase,1,1) == -1))
11001 rpt_mutex_unlock(&myrpt->lock);
11002 ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n",myrpt->p.iobase);
11003 return -1;
11005 myrpt->remoteon = 1;
11006 #ifdef OLD_ASTERISK
11007 LOCAL_USER_ADD(u);
11008 #endif
11009 rpt_mutex_unlock(&myrpt->lock);
11010 /* find our index, and load the vars initially */
11011 for(i = 0; i < nrpts; i++)
11013 if (&rpt_vars[i] == myrpt)
11015 load_rpt_vars(i,0);
11016 break;
11019 rpt_mutex_lock(&myrpt->lock);
11020 tele = strchr(myrpt->rxchanname,'/');
11021 if (!tele)
11023 fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
11024 rpt_mutex_unlock(&myrpt->lock);
11025 pthread_exit(NULL);
11027 *tele++ = 0;
11028 myrpt->rxchannel = ast_request(myrpt->rxchanname,AST_FORMAT_SLINEAR,tele,NULL);
11029 myrpt->zaprxchannel = NULL;
11030 if (!strcasecmp(myrpt->rxchanname,"Zap"))
11031 myrpt->zaprxchannel = myrpt->rxchannel;
11032 if (myrpt->rxchannel)
11034 ast_set_read_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
11035 ast_set_write_format(myrpt->rxchannel,AST_FORMAT_SLINEAR);
11036 #ifdef AST_CDR_FLAG_POST_DISABLED
11037 ast_set_flag(myrpt->rxchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11038 #endif
11039 myrpt->rxchannel->whentohangup = 0;
11040 myrpt->rxchannel->appl = "Apprpt";
11041 myrpt->rxchannel->data = "(Link Rx)";
11042 if (option_verbose > 2)
11043 ast_verbose(VERBOSE_PREFIX_3 "rpt (Rx) initiating call to %s/%s on %s\n",
11044 myrpt->rxchanname,tele,myrpt->rxchannel->name);
11045 rpt_mutex_unlock(&myrpt->lock);
11046 ast_call(myrpt->rxchannel,tele,999);
11047 rpt_mutex_lock(&myrpt->lock);
11049 else
11051 fprintf(stderr,"rpt:Sorry unable to obtain Rx channel\n");
11052 rpt_mutex_unlock(&myrpt->lock);
11053 pthread_exit(NULL);
11055 *--tele = '/';
11056 myrpt->zaptxchannel = NULL;
11057 if (myrpt->txchanname)
11059 tele = strchr(myrpt->txchanname,'/');
11060 if (!tele)
11062 fprintf(stderr,"rpt:Dial number must be in format tech/number\n");
11063 rpt_mutex_unlock(&myrpt->lock);
11064 ast_hangup(myrpt->rxchannel);
11065 pthread_exit(NULL);
11067 *tele++ = 0;
11068 myrpt->txchannel = ast_request(myrpt->txchanname,AST_FORMAT_SLINEAR,tele,NULL);
11069 if (!strcasecmp(myrpt->txchanname,"Zap"))
11070 myrpt->zaptxchannel = myrpt->txchannel;
11071 if (myrpt->txchannel)
11073 ast_set_read_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
11074 ast_set_write_format(myrpt->txchannel,AST_FORMAT_SLINEAR);
11075 #ifdef AST_CDR_FLAG_POST_DISABLED
11076 ast_set_flag(myrpt->txchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11077 #endif
11078 myrpt->txchannel->whentohangup = 0;
11079 myrpt->txchannel->appl = "Apprpt";
11080 myrpt->txchannel->data = "(Link Tx)";
11081 if (option_verbose > 2)
11082 ast_verbose(VERBOSE_PREFIX_3 "rpt (Tx) initiating call to %s/%s on %s\n",
11083 myrpt->txchanname,tele,myrpt->txchannel->name);
11084 rpt_mutex_unlock(&myrpt->lock);
11085 ast_call(myrpt->txchannel,tele,999);
11086 rpt_mutex_lock(&myrpt->lock);
11088 else
11090 fprintf(stderr,"rpt:Sorry unable to obtain Tx channel\n");
11091 rpt_mutex_unlock(&myrpt->lock);
11092 ast_hangup(myrpt->rxchannel);
11093 pthread_exit(NULL);
11095 *--tele = '/';
11097 else
11099 myrpt->txchannel = myrpt->rxchannel;
11101 /* allocate a pseudo-channel thru asterisk */
11102 myrpt->pchannel = ast_request("zap",AST_FORMAT_SLINEAR,"pseudo",NULL);
11103 if (!myrpt->pchannel)
11105 fprintf(stderr,"rpt:Sorry unable to obtain pseudo channel\n");
11106 rpt_mutex_unlock(&myrpt->lock);
11107 if (myrpt->txchannel != myrpt->rxchannel)
11108 ast_hangup(myrpt->txchannel);
11109 ast_hangup(myrpt->rxchannel);
11110 pthread_exit(NULL);
11112 ast_set_read_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
11113 ast_set_write_format(myrpt->pchannel,AST_FORMAT_SLINEAR);
11114 #ifdef AST_CDR_FLAG_POST_DISABLED
11115 ast_set_flag(myrpt->pchannel->cdr,AST_CDR_FLAG_POST_DISABLED);
11116 #endif
11117 if (!myrpt->zaprxchannel) myrpt->zaprxchannel = myrpt->pchannel;
11118 if (!myrpt->zaptxchannel) myrpt->zaptxchannel = myrpt->pchannel;
11119 /* make a conference for the pseudo */
11120 ci.chan = 0;
11121 ci.confno = -1; /* make a new conf */
11122 ci.confmode = ZT_CONF_CONFANNMON ;
11123 /* first put the channel on the conference in announce/monitor mode */
11124 if (ioctl(myrpt->pchannel->fds[0],ZT_SETCONF,&ci) == -1)
11126 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
11127 rpt_mutex_unlock(&myrpt->lock);
11128 ast_hangup(myrpt->pchannel);
11129 if (myrpt->txchannel != myrpt->rxchannel)
11130 ast_hangup(myrpt->txchannel);
11131 ast_hangup(myrpt->rxchannel);
11132 pthread_exit(NULL);
11134 /* save pseudo channel conference number */
11135 myrpt->conf = myrpt->txconf = ci.confno;
11136 /* if serial io port, open it */
11137 myrpt->iofd = -1;
11138 if (myrpt->p.ioport && ((myrpt->iofd = openserial(myrpt->p.ioport)) == -1))
11140 rpt_mutex_unlock(&myrpt->lock);
11141 ast_hangup(myrpt->pchannel);
11142 if (myrpt->txchannel != myrpt->rxchannel)
11143 ast_hangup(myrpt->txchannel);
11144 ast_hangup(myrpt->rxchannel);
11145 pthread_exit(NULL);
11147 iskenwood_pci4 = 0;
11148 memset(&z,0,sizeof(z));
11149 if ((myrpt->iofd < 1) && (myrpt->txchannel == myrpt->zaptxchannel))
11151 z.radpar = ZT_RADPAR_REMMODE;
11152 z.data = ZT_RADPAR_REM_NONE;
11153 res = ioctl(myrpt->zaptxchannel->fds[0],ZT_RADIO_SETPARAM,&z);
11154 /* if PCIRADIO and kenwood selected */
11155 if ((!res) && (!strcmp(myrpt->remote,remote_rig_kenwood)))
11157 z.radpar = ZT_RADPAR_UIOMODE;
11158 z.data = 1;
11159 if (ioctl(myrpt->zaptxchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
11161 ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
11162 return -1;
11164 z.radpar = ZT_RADPAR_UIODATA;
11165 z.data = 3;
11166 if (ioctl(myrpt->zaptxchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
11168 ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11169 return -1;
11171 i = ZT_OFFHOOK;
11172 if (ioctl(myrpt->zaptxchannel->fds[0],ZT_HOOK,&i) == -1)
11174 ast_log(LOG_ERROR,"Cannot set hook\n");
11175 return -1;
11177 iskenwood_pci4 = 1;
11180 if (myrpt->txchannel == myrpt->zaptxchannel)
11182 i = ZT_ONHOOK;
11183 ioctl(myrpt->zaptxchannel->fds[0],ZT_HOOK,&i);
11184 /* if PCIRADIO and Yaesu ft897/ICOM IC-706 selected */
11185 if ((myrpt->iofd < 1) && (!res) &&
11186 (!strcmp(myrpt->remote,remote_rig_ft897) ||
11187 (!strcmp(myrpt->remote,remote_rig_ic706))))
11189 z.radpar = ZT_RADPAR_UIOMODE;
11190 z.data = 1;
11191 if (ioctl(myrpt->zaptxchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
11193 ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
11194 return -1;
11196 z.radpar = ZT_RADPAR_UIODATA;
11197 z.data = 3;
11198 if (ioctl(myrpt->zaptxchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
11200 ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11201 return -1;
11205 myrpt->remoterx = 0;
11206 myrpt->remotetx = 0;
11207 myrpt->retxtimer = 0;
11208 myrpt->rerxtimer = 0;
11209 myrpt->remoteon = 1;
11210 myrpt->dtmfidx = -1;
11211 myrpt->dtmfbuf[0] = 0;
11212 myrpt->dtmf_time_rem = 0;
11213 myrpt->hfscanmode = 0;
11214 myrpt->hfscanstatus = 0;
11215 if (myrpt->p.startupmacro)
11217 snprintf(myrpt->macrobuf,MAXMACRO - 1,"PPPP%s",myrpt->p.startupmacro);
11219 time(&myrpt->start_time);
11220 myrpt->last_activity_time = myrpt->start_time;
11221 last_timeout_warning = 0;
11222 myrpt->reload = 0;
11223 myrpt->tele.next = &myrpt->tele;
11224 myrpt->tele.prev = &myrpt->tele;
11225 rpt_mutex_unlock(&myrpt->lock);
11226 ast_set_write_format(chan, AST_FORMAT_SLINEAR);
11227 ast_set_read_format(chan, AST_FORMAT_SLINEAR);
11228 rem_rx = 0;
11229 remkeyed = 0;
11230 /* if we are on 2w loop and are a remote, turn EC on */
11231 if (myrpt->remote && (myrpt->rxchannel == myrpt->txchannel))
11233 i = 128;
11234 ioctl(myrpt->zaprxchannel->fds[0],ZT_ECHOCANCEL,&i);
11236 if (chan->_state != AST_STATE_UP) {
11237 ast_answer(chan);
11240 if (myrpt->rxchannel == myrpt->zaprxchannel)
11242 if (ioctl(myrpt->zaprxchannel->fds[0],ZT_GET_PARAMS,&par) != -1)
11244 if (par.rxisoffhook)
11246 ast_indicate(chan,AST_CONTROL_RADIO_KEY);
11247 myrpt->remoterx = 1;
11248 remkeyed = 1;
11252 if (myrpt->p.archivedir)
11254 char mycmd[100],mydate[100],*b,*b1;
11255 time_t myt;
11256 long blocksleft;
11259 mkdir(myrpt->p.archivedir,0600);
11260 sprintf(mycmd,"%s/%s",myrpt->p.archivedir,myrpt->name);
11261 mkdir(mycmd,0600);
11262 time(&myt);
11263 strftime(mydate,sizeof(mydate) - 1,"%Y%m%d%H%M%S",
11264 localtime(&myt));
11265 sprintf(mycmd,"mixmonitor start %s %s/%s/%s.wav49 a",chan->name,
11266 myrpt->p.archivedir,myrpt->name,mydate);
11267 if (myrpt->p.monminblocks)
11269 blocksleft = diskavail(myrpt);
11270 if (myrpt->p.remotetimeout)
11272 blocksleft -= (myrpt->p.remotetimeout *
11273 MONITOR_DISK_BLOCKS_PER_MINUTE) / 60;
11275 if (blocksleft >= myrpt->p.monminblocks)
11276 ast_cli_command(nullfd,mycmd);
11277 } else ast_cli_command(nullfd,mycmd);
11278 /* look at callerid to see what node this comes from */
11279 if (!chan->cid.cid_num) /* if doesn't have caller id */
11281 b1 = "0";
11282 } else {
11283 ast_callerid_parse(chan->cid.cid_num,&b,&b1);
11284 ast_shrink_phone_number(b1);
11286 sprintf(mycmd,"CONNECT,%s",b1);
11287 donodelog(myrpt,mycmd);
11289 myrpt->loginuser[0] = 0;
11290 myrpt->loginlevel[0] = 0;
11291 myrpt->authtelltimer = 0;
11292 myrpt->authtimer = 0;
11293 authtold = 0;
11294 authreq = 0;
11295 if (myrpt->p.authlevel > 1) authreq = 1;
11296 setrem(myrpt);
11297 n = 0;
11298 dtmfed = 0;
11299 cs[n++] = chan;
11300 cs[n++] = myrpt->rxchannel;
11301 cs[n++] = myrpt->pchannel;
11302 if (myrpt->rxchannel != myrpt->txchannel)
11303 cs[n++] = myrpt->txchannel;
11304 /* start un-locked */
11305 for(;;)
11307 if (ast_check_hangup(chan)) break;
11308 if (ast_check_hangup(myrpt->rxchannel)) break;
11309 notremming = 0;
11310 setting = 0;
11311 reming = 0;
11312 telem = myrpt->tele.next;
11313 while(telem != &myrpt->tele)
11315 if (telem->mode == SETREMOTE) setting = 1;
11316 if ((telem->mode == SETREMOTE) ||
11317 (telem->mode == SCAN) ||
11318 (telem->mode == TUNE)) reming = 1;
11319 else notremming = 1;
11320 telem = telem->next;
11322 if (myrpt->reload)
11324 myrpt->reload = 0;
11325 /* find our index, and load the vars */
11326 for(i = 0; i < nrpts; i++)
11328 if (&rpt_vars[i] == myrpt)
11330 load_rpt_vars(i,0);
11331 break;
11335 time(&t);
11336 if (myrpt->p.remotetimeout)
11338 time_t r;
11340 r = (t - myrpt->start_time);
11341 if (r >= myrpt->p.remotetimeout)
11343 sayfile(chan,"rpt/node");
11344 ast_say_character_str(chan,myrpt->name,NULL,chan->language);
11345 sayfile(chan,"rpt/timeout");
11346 ast_safe_sleep(chan,1000);
11347 break;
11349 if ((myrpt->p.remotetimeoutwarning) &&
11350 (r >= (myrpt->p.remotetimeout -
11351 myrpt->p.remotetimeoutwarning)) &&
11352 (r <= (myrpt->p.remotetimeout -
11353 myrpt->p.remotetimeoutwarningfreq)))
11355 if (myrpt->p.remotetimeoutwarningfreq)
11357 if ((t - last_timeout_warning) >=
11358 myrpt->p.remotetimeoutwarningfreq)
11360 time(&last_timeout_warning);
11361 rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
11364 else
11366 if (!last_timeout_warning)
11368 time(&last_timeout_warning);
11369 rpt_telemetry(myrpt,TIMEOUT_WARNING,0);
11374 if (myrpt->p.remoteinacttimeout && myrpt->last_activity_time)
11376 time_t r;
11378 r = (t - myrpt->last_activity_time);
11379 if (r >= myrpt->p.remoteinacttimeout)
11381 sayfile(chan,"rpt/node");
11382 ast_say_character_str(chan,myrpt->name,NULL,chan->language);
11383 sayfile(chan,"rpt/timeout");
11384 ast_safe_sleep(chan,1000);
11385 break;
11387 if ((myrpt->p.remotetimeoutwarning) &&
11388 (r >= (myrpt->p.remoteinacttimeout -
11389 myrpt->p.remotetimeoutwarning)) &&
11390 (r <= (myrpt->p.remoteinacttimeout -
11391 myrpt->p.remotetimeoutwarningfreq)))
11393 if (myrpt->p.remotetimeoutwarningfreq)
11395 if ((t - last_timeout_warning) >=
11396 myrpt->p.remotetimeoutwarningfreq)
11398 time(&last_timeout_warning);
11399 rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
11402 else
11404 if (!last_timeout_warning)
11406 time(&last_timeout_warning);
11407 rpt_telemetry(myrpt,ACT_TIMEOUT_WARNING,0);
11412 ms = MSWAIT;
11413 who = ast_waitfor_n(cs,n,&ms);
11414 if (who == NULL) ms = 0;
11415 elap = MSWAIT - ms;
11416 if (myrpt->macrotimer) myrpt->macrotimer -= elap;
11417 if (myrpt->macrotimer < 0) myrpt->macrotimer = 0;
11418 if (!ms) continue;
11419 /* do local dtmf timer */
11420 if (myrpt->dtmf_local_timer)
11422 if (myrpt->dtmf_local_timer > 1) myrpt->dtmf_local_timer -= elap;
11423 if (myrpt->dtmf_local_timer < 1) myrpt->dtmf_local_timer = 1;
11425 rpt_mutex_lock(&myrpt->lock);
11426 do_dtmf_local(myrpt,0);
11427 rpt_mutex_unlock(&myrpt->lock);
11428 rem_totx = myrpt->dtmf_local_timer && (!phone_mode);
11429 rem_totx |= keyed && (!myrpt->tunerequest);
11430 rem_rx = (remkeyed && (!setting)) || (myrpt->tele.next != &myrpt->tele);
11431 if(!strcmp(myrpt->remote, remote_rig_ic706))
11432 rem_totx |= myrpt->tunerequest;
11433 if (keyed && (!keyed1))
11435 keyed1 = 1;
11438 if (!keyed && (keyed1))
11440 time_t myt;
11442 keyed1 = 0;
11443 time(&myt);
11444 /* if login necessary, and not too soon */
11445 if ((myrpt->p.authlevel) &&
11446 (!myrpt->loginlevel[0]) &&
11447 (myt > (t + 3)))
11449 authreq = 1;
11450 authtold = 0;
11451 myrpt->authtelltimer = AUTHTELLTIME - AUTHTXTIME;
11456 if (rem_rx && (!myrpt->remoterx))
11458 myrpt->remoterx = 1;
11459 ast_indicate(chan,AST_CONTROL_RADIO_KEY);
11461 if ((!rem_rx) && (myrpt->remoterx))
11463 myrpt->remoterx = 0;
11464 ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
11466 /* if auth requested, and not authed yet */
11467 if (authreq && (!myrpt->loginlevel[0]))
11469 if ((!authtold) && ((myrpt->authtelltimer += elap)
11470 >= AUTHTELLTIME))
11472 authtold = 1;
11473 rpt_telemetry(myrpt,LOGINREQ,NULL);
11475 if ((myrpt->authtimer += elap) >= AUTHLOGOUTTIME)
11477 break; /* if not logged in, hang up after a time */
11480 #ifndef OLDKEY
11481 if ((myrpt->retxtimer += elap) >= REDUNDANT_TX_TIME)
11483 myrpt->retxtimer = 0;
11484 if ((myrpt->remoterx) && (!myrpt->remotetx))
11485 ast_indicate(chan,AST_CONTROL_RADIO_KEY);
11486 else
11487 ast_indicate(chan,AST_CONTROL_RADIO_UNKEY);
11490 if ((myrpt->rerxtimer += elap) >= (REDUNDANT_TX_TIME * 2))
11492 keyed = 0;
11493 myrpt->rerxtimer = 0;
11495 #endif
11496 if (rem_totx && (!myrpt->remotetx))
11498 /* if not authed, and needed, dont transmit */
11499 if ((!myrpt->p.authlevel) || myrpt->loginlevel[0])
11501 myrpt->remotetx = 1;
11502 if((myrpt->remtxfreqok = check_tx_freq(myrpt)))
11504 time(&myrpt->last_activity_time);
11505 if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->zaptxchannel))
11507 z.radpar = ZT_RADPAR_UIODATA;
11508 z.data = 1;
11509 if (ioctl(myrpt->zaptxchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
11511 ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11512 return -1;
11515 else
11517 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_KEY);
11519 if (myrpt->p.archivedir) donodelog(myrpt,"TXKEY");
11523 if ((!rem_totx) && myrpt->remotetx) /* Remote base radio TX unkey */
11525 myrpt->remotetx = 0;
11526 if(!myrpt->remtxfreqok){
11527 rpt_telemetry(myrpt,UNAUTHTX,NULL);
11529 if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->zaptxchannel))
11531 z.radpar = ZT_RADPAR_UIODATA;
11532 z.data = 3;
11533 if (ioctl(myrpt->zaptxchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
11535 ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11536 return -1;
11539 else
11541 ast_indicate(myrpt->txchannel,AST_CONTROL_RADIO_UNKEY);
11543 if (myrpt->p.archivedir) donodelog(myrpt,"TXUNKEY");
11545 if (myrpt->hfscanmode){
11546 myrpt->scantimer -= elap;
11547 if(myrpt->scantimer <= 0){
11548 if (!reming)
11550 myrpt->scantimer = REM_SCANTIME;
11551 rpt_telemetry(myrpt,SCAN,0);
11552 } else myrpt->scantimer = 1;
11555 rpt_mutex_lock(&myrpt->lock);
11556 c = myrpt->macrobuf[0];
11557 if (c && (!myrpt->macrotimer))
11559 myrpt->macrotimer = MACROTIME;
11560 memmove(myrpt->macrobuf,myrpt->macrobuf + 1,MAXMACRO - 1);
11561 if ((c == 'p') || (c == 'P'))
11562 myrpt->macrotimer = MACROPTIME;
11563 rpt_mutex_unlock(&myrpt->lock);
11564 if (myrpt->p.archivedir)
11566 char str[100];
11567 sprintf(str,"DTMF(M),%c",c);
11568 donodelog(myrpt,str);
11570 if (handle_remote_dtmf_digit(myrpt,c,&keyed,0) == -1) break;
11571 continue;
11572 } else rpt_mutex_unlock(&myrpt->lock);
11573 if (who == chan) /* if it was a read from incomming */
11575 f = ast_read(chan);
11576 if (!f)
11578 if (debug) printf("@@@@ link:Hung Up\n");
11579 break;
11581 if (f->frametype == AST_FRAME_VOICE)
11583 if (ioctl(chan->fds[0], ZT_GETCONFMUTE, &ismuted) == -1)
11585 ismuted = 0;
11587 /* if not transmitting, zero-out audio */
11588 ismuted |= (!myrpt->remotetx);
11589 if (dtmfed && phone_mode) ismuted = 1;
11590 dtmfed = 0;
11591 if (ismuted)
11593 memset(f->data,0,f->datalen);
11594 if (myrpt->lastf1)
11595 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11596 if (myrpt->lastf2)
11597 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11599 if (f) f2 = ast_frdup(f);
11600 else f2 = NULL;
11601 f1 = myrpt->lastf2;
11602 myrpt->lastf2 = myrpt->lastf1;
11603 myrpt->lastf1 = f2;
11604 if (ismuted)
11606 if (myrpt->lastf1)
11607 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11608 if (myrpt->lastf2)
11609 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11611 if (f1)
11613 if (phone_mode)
11614 ast_write(myrpt->txchannel,f1);
11615 else
11616 ast_write(myrpt->txchannel,f);
11617 ast_frfree(f1);
11620 #ifndef OLD_ASTERISK
11621 else if (f->frametype == AST_FRAME_DTMF_BEGIN)
11623 if (myrpt->lastf1)
11624 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11625 if (myrpt->lastf2)
11626 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11627 dtmfed = 1;
11629 #endif
11630 if (f->frametype == AST_FRAME_DTMF)
11632 if (myrpt->lastf1)
11633 memset(myrpt->lastf1->data,0,myrpt->lastf1->datalen);
11634 if (myrpt->lastf2)
11635 memset(myrpt->lastf2->data,0,myrpt->lastf2->datalen);
11636 dtmfed = 1;
11637 if (handle_remote_phone_dtmf(myrpt,f->subclass,&keyed,phone_mode) == -1)
11639 if (debug) printf("@@@@ rpt:Hung Up\n");
11640 ast_frfree(f);
11641 break;
11644 if (f->frametype == AST_FRAME_TEXT)
11646 if (handle_remote_data(myrpt,f->data) == -1)
11648 if (debug) printf("@@@@ rpt:Hung Up\n");
11649 ast_frfree(f);
11650 break;
11653 if (f->frametype == AST_FRAME_CONTROL)
11655 if (f->subclass == AST_CONTROL_HANGUP)
11657 if (debug) printf("@@@@ rpt:Hung Up\n");
11658 ast_frfree(f);
11659 break;
11661 /* if RX key */
11662 if (f->subclass == AST_CONTROL_RADIO_KEY)
11664 if (debug == 7) printf("@@@@ rx key\n");
11665 keyed = 1;
11666 myrpt->rerxtimer = 0;
11668 /* if RX un-key */
11669 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
11671 myrpt->rerxtimer = 0;
11672 if (debug == 7) printf("@@@@ rx un-key\n");
11673 keyed = 0;
11676 ast_frfree(f);
11677 continue;
11679 if (who == myrpt->rxchannel) /* if it was a read from radio */
11681 f = ast_read(myrpt->rxchannel);
11682 if (!f)
11684 if (debug) printf("@@@@ link:Hung Up\n");
11685 break;
11687 if (f->frametype == AST_FRAME_VOICE)
11689 int myreming = 0;
11691 if(!strcmp(myrpt->remote, remote_rig_kenwood))
11692 myreming = reming;
11694 if (myreming || (!remkeyed) ||
11695 ((myrpt->remote) && (myrpt->remotetx)) ||
11696 ((myrpt->remmode != REM_MODE_FM) &&
11697 notremming))
11698 memset(f->data,0,f->datalen);
11699 ast_write(myrpt->pchannel,f);
11701 else if (f->frametype == AST_FRAME_CONTROL)
11703 if (f->subclass == AST_CONTROL_HANGUP)
11705 if (debug) printf("@@@@ rpt:Hung Up\n");
11706 ast_frfree(f);
11707 break;
11709 /* if RX key */
11710 if (f->subclass == AST_CONTROL_RADIO_KEY)
11712 if (debug == 7) printf("@@@@ remote rx key\n");
11713 if (!myrpt->remotetx)
11715 remkeyed = 1;
11718 /* if RX un-key */
11719 if (f->subclass == AST_CONTROL_RADIO_UNKEY)
11721 if (debug == 7) printf("@@@@ remote rx un-key\n");
11722 if (!myrpt->remotetx)
11724 remkeyed = 0;
11728 ast_frfree(f);
11729 continue;
11731 if (who == myrpt->pchannel) /* if is remote mix output */
11733 f = ast_read(myrpt->pchannel);
11734 if (!f)
11736 if (debug) printf("@@@@ link:Hung Up\n");
11737 break;
11739 if (f->frametype == AST_FRAME_VOICE)
11741 ast_write(chan,f);
11743 if (f->frametype == AST_FRAME_CONTROL)
11745 if (f->subclass == AST_CONTROL_HANGUP)
11747 if (debug) printf("@@@@ rpt:Hung Up\n");
11748 ast_frfree(f);
11749 break;
11752 ast_frfree(f);
11753 continue;
11755 if ((myrpt->rxchannel != myrpt->txchannel) &&
11756 (who == myrpt->txchannel)) /* do this cuz you have to */
11758 f = ast_read(myrpt->txchannel);
11759 if (!f)
11761 if (debug) printf("@@@@ link:Hung Up\n");
11762 break;
11764 if (f->frametype == AST_FRAME_CONTROL)
11766 if (f->subclass == AST_CONTROL_HANGUP)
11768 if (debug) printf("@@@@ rpt:Hung Up\n");
11769 ast_frfree(f);
11770 break;
11773 ast_frfree(f);
11774 continue;
11777 if (myrpt->p.archivedir)
11779 char mycmd[100],*b,*b1;
11781 /* look at callerid to see what node this comes from */
11782 if (!chan->cid.cid_num) /* if doesn't have caller id */
11784 b1 = "0";
11785 } else {
11786 ast_callerid_parse(chan->cid.cid_num,&b,&b1);
11787 ast_shrink_phone_number(b1);
11789 sprintf(mycmd,"DISCONNECT,%s",b1);
11790 donodelog(myrpt,mycmd);
11792 /* wait for telem to be done */
11793 while(myrpt->tele.next != &myrpt->tele) usleep(100000);
11794 sprintf(tmp,"mixmonitor stop %s",chan->name);
11795 ast_cli_command(nullfd,tmp);
11796 close(nullfd);
11797 rpt_mutex_lock(&myrpt->lock);
11798 myrpt->hfscanmode = 0;
11799 myrpt->hfscanstatus = 0;
11800 myrpt->remoteon = 0;
11801 rpt_mutex_unlock(&myrpt->lock);
11802 if (myrpt->lastf1) ast_frfree(myrpt->lastf1);
11803 myrpt->lastf1 = NULL;
11804 if (myrpt->lastf2) ast_frfree(myrpt->lastf2);
11805 myrpt->lastf2 = NULL;
11806 if ((iskenwood_pci4) && (myrpt->txchannel == myrpt->zaptxchannel))
11808 z.radpar = ZT_RADPAR_UIOMODE;
11809 z.data = 3;
11810 if (ioctl(myrpt->zaptxchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
11812 ast_log(LOG_ERROR,"Cannot set UIOMODE\n");
11813 return -1;
11815 z.radpar = ZT_RADPAR_UIODATA;
11816 z.data = 3;
11817 if (ioctl(myrpt->zaptxchannel->fds[0],ZT_RADIO_SETPARAM,&z) == -1)
11819 ast_log(LOG_ERROR,"Cannot set UIODATA\n");
11820 return -1;
11822 i = ZT_OFFHOOK;
11823 if (ioctl(myrpt->zaptxchannel->fds[0],ZT_HOOK,&i) == -1)
11825 ast_log(LOG_ERROR,"Cannot set hook\n");
11826 return -1;
11829 if (myrpt->iofd) close(myrpt->iofd);
11830 myrpt->iofd = -1;
11831 ast_hangup(myrpt->pchannel);
11832 if (myrpt->rxchannel != myrpt->txchannel) ast_hangup(myrpt->txchannel);
11833 ast_hangup(myrpt->rxchannel);
11834 closerem(myrpt);
11835 #ifdef OLD_ASTERISK
11836 LOCAL_USER_REMOVE(u);
11837 #endif
11838 return res;
11841 #ifdef OLD_ASTERISK
11842 int unload_module()
11843 #else
11844 static int unload_module(void)
11845 #endif
11847 int i;
11849 #ifdef OLD_ASTERISK
11850 STANDARD_HANGUP_LOCALUSERS;
11851 #endif
11852 for(i = 0; i < nrpts; i++) {
11853 if (!strcmp(rpt_vars[i].name,rpt_vars[i].p.nodes)) continue;
11854 ast_mutex_destroy(&rpt_vars[i].lock);
11855 ast_mutex_destroy(&rpt_vars[i].remlock);
11857 i = ast_unregister_application(app);
11859 /* Unregister cli extensions */
11860 ast_cli_unregister(&cli_debug);
11861 ast_cli_unregister(&cli_dump);
11862 ast_cli_unregister(&cli_stats);
11863 ast_cli_unregister(&cli_lstats);
11864 ast_cli_unregister(&cli_nodes);
11865 ast_cli_unregister(&cli_reload);
11866 ast_cli_unregister(&cli_restart);
11867 ast_cli_unregister(&cli_fun);
11869 return i;
11872 #ifdef OLD_ASTERISK
11873 int load_module()
11874 #else
11875 static int load_module(void)
11876 #endif
11878 ast_pthread_create(&rpt_master_thread,NULL,rpt_master,NULL);
11880 /* Register cli extensions */
11881 ast_cli_register(&cli_debug);
11882 ast_cli_register(&cli_dump);
11883 ast_cli_register(&cli_stats);
11884 ast_cli_register(&cli_lstats);
11885 ast_cli_register(&cli_nodes);
11886 ast_cli_register(&cli_reload);
11887 ast_cli_register(&cli_restart);
11888 ast_cli_register(&cli_fun);
11890 return ast_register_application(app, rpt_exec, synopsis, descrip);
11893 #ifdef OLD_ASTERISK
11894 char *description()
11896 return tdesc;
11898 int usecount(void)
11900 int res;
11901 STANDARD_USECOUNT(res);
11902 return res;
11905 char *key()
11907 return ASTERISK_GPL_KEY;
11909 #endif
11911 #ifdef OLD_ASTERISK
11912 int reload()
11913 #else
11914 static int reload(void)
11915 #endif
11917 int n;
11919 for(n = 0; n < nrpts; n++) rpt_vars[n].reload = 1;
11920 return(0);
11923 #ifndef OLD_ASTERISK
11924 /* STD_MOD(MOD_1, reload, NULL, NULL); */
11925 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Radio Repeater/Remote Base Application",
11926 .load = load_module,
11927 .unload = unload_module,
11928 .reload = reload,
11931 #endif