00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134 #define MAXDTMF 32
00135 #define MAXMACRO 2048
00136 #define MAXGOSUB 2048
00137 #define MACROTIME 100
00138 #define GOSUBTIME 100
00139 #define MACROPTIME 500
00140 #define GOSUBPTIME 500
00141 #define DTMF_TIMEOUT 3
00142
00143 #ifdef __RPT_NOTCH
00144 #define MAXFILTERS 10
00145 #endif
00146
00147 #define DISC_TIME 10000
00148 #define MAX_RETRIES 5
00149
00150 #define REDUNDANT_TX_TIME 2000
00151
00152 #define RETRY_TIMER_MS 5000
00153
00154 #define MAXPEERSTR 31
00155 #define MAXREMSTR 15
00156
00157 #define DELIMCHR ','
00158 #define QUOTECHR 34
00159
00160 #define NODES "nodes"
00161 #define MEMORY "memory"
00162 #define MACRO "macro"
00163 #define GOSUB "gosub"
00164 #define FUNCTIONS "functions"
00165 #define TELEMETRY "telemetry"
00166 #define MORSE "morse"
00167 #define FUNCCHAR '*'
00168 #define ENDCHAR '#'
00169
00170 #define DEFAULT_IOBASE 0x378
00171
00172 #define MAXCONNECTTIME 5000
00173
00174 #define MAXNODESTR 300
00175
00176 #define MAXPATCHCONTEXT 100
00177
00178 #define ACTIONSIZE 32
00179
00180 #define TELEPARAMSIZE 256
00181
00182 #define REM_SCANTIME 100
00183
00184
00185 enum {REM_OFF, REM_MONITOR, REM_TX};
00186
00187 enum {ID, PROC, TERM, COMPLETE, UNKEY, REMDISC, REMALREADY, REMNOTFOUND, REMGO,
00188 CONNECTED, CONNFAIL, STATUS, TIMEOUT, ID1, STATS_TIME,
00189 STATS_VERSION, IDTALKOVER, ARB_ALPHA, TEST_TONE, REV_PATCH,
00190 TAILMSG, MACRO_NOTFOUND, GOSUB_NOTFOUND, MACRO_BUSY, GOSUB_BUSY, LASTNODEKEY};
00191
00192 enum {REM_SIMPLEX, REM_MINUS, REM_PLUS};
00193
00194 enum {REM_LOWPWR, REM_MEDPWR, REM_HIPWR};
00195
00196 enum {DC_INDETERMINATE, DC_REQ_FLUSH, DC_ERROR, DC_COMPLETE, DC_DOKEY};
00197
00198 enum {SOURCE_RPT, SOURCE_LNK, SOURCE_RMT, SOURCE_PHONE, SOURCE_DPHONE};
00199
00200 enum {DLY_TELEM, DLY_ID, DLY_UNKEY, DLY_CALLTERM};
00201
00202 enum {REM_MODE_FM, REM_MODE_USB, REM_MODE_LSB, REM_MODE_AM};
00203
00204 enum {HF_SCAN_OFF, HF_SCAN_DOWN_SLOW, HF_SCAN_DOWN_QUICK,
00205 HF_SCAN_DOWN_FAST, HF_SCAN_UP_SLOW, HF_SCAN_UP_QUICK, HF_SCAN_UP_FAST};
00206
00207 #include "asterisk.h"
00208
00209 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 174439 $")
00210
00211 #include <signal.h>
00212 #include <search.h>
00213 #include <sys/stat.h>
00214 #include <dirent.h>
00215 #include <ctype.h>
00216 #include <sys/time.h>
00217 #include <sys/file.h>
00218 #include <sys/ioctl.h>
00219 #include <sys/io.h>
00220 #include <math.h>
00221 #include <dahdi/user.h>
00222 #include <dahdi/tonezone.h>
00223 #include <netinet/in.h>
00224 #include <arpa/inet.h>
00225
00226 #include "asterisk/utils.h"
00227 #include "asterisk/lock.h"
00228 #include "asterisk/file.h"
00229 #include "asterisk/channel.h"
00230 #include "asterisk/callerid.h"
00231 #include "asterisk/pbx.h"
00232 #include "asterisk/module.h"
00233 #include "asterisk/translate.h"
00234 #include "asterisk/features.h"
00235 #include "asterisk/cli.h"
00236 #include "asterisk/config.h"
00237 #include "asterisk/say.h"
00238 #include "asterisk/localtime.h"
00239 #include "asterisk/app.h"
00240
00241 static char *app = "Rpt";
00242
00243 static char *synopsis = "Radio Repeater/Remote Base Control System";
00244
00245 static char *descrip =
00246 " Rpt(nodename[,options]): Radio Remote Link or Remote Base Link Endpoint Process.\n"
00247 "\n"
00248 " Not specifying an option puts it in normal endpoint mode (where source\n"
00249 " IP and nodename are verified).\n"
00250 "\n"
00251 " Options are as follows:\n"
00252 "\n"
00253 " X - Normal endpoint mode WITHOUT security check. Only specify\n"
00254 " this if you have checked security already (like with an IAX2\n"
00255 " user/password or something).\n"
00256 "\n"
00257 " Rannounce-string[,timeout[,timeout-destination]] - Amateur Radio\n"
00258 " Reverse Autopatch. Caller is put on hold, and announcement (as\n"
00259 " specified by the 'announce-string') is played on radio system.\n"
00260 " Users of radio system can access autopatch, dial specified\n"
00261 " code, and pick up call. Announce-string is list of names of\n"
00262 " recordings, or \"PARKED\" to substitute code for un-parking,\n"
00263 " or \"NODE\" to substitute node number.\n"
00264 "\n"
00265 " P - Phone Control mode. This allows a regular phone user to have\n"
00266 " full control and audio access to the radio system. For the\n"
00267 " user to have DTMF control, the 'phone_functions' parameter\n"
00268 " must be specified for the node in 'rpt.conf'. An additional\n"
00269 " function (cop,6) must be listed so that PTT control is available.\n"
00270 "\n"
00271 " D - Dumb Phone Control mode. This allows a regular phone user to\n"
00272 " have full control and audio access to the radio system. In this\n"
00273 " mode, the PTT is activated for the entire length of the call.\n"
00274 " For the user to have DTMF control (not generally recomended in\n"
00275 " this mode), the 'dphone_functions' parameter must be specified\n"
00276 " for the node in 'rpt.conf'. Otherwise no DTMF control will be\n"
00277 " available to the phone user.\n"
00278 "\n";
00279
00280 static unsigned int vmajor = 0;
00281 static unsigned int vminor = 47;
00282
00283 static int debug = 0;
00284 static int nrpts = 0;
00285
00286 char *discstr = "!!DISCONNECT!!";
00287 static char *remote_rig_ft897 = "ft897";
00288 static char *remote_rig_rbi = "rbi";
00289
00290 #define MSWAIT 200
00291 #define HANGTIME 5000
00292 #define TOTIME 180000
00293 #define IDTIME 300000
00294 #define MAXRPTS 20
00295 #define MAX_STAT_LINKS 32
00296 #define POLITEID 30000
00297 #define FUNCTDELAY 1500
00298
00299 static pthread_t rpt_master_thread;
00300
00301 struct rpt;
00302
00303 struct rpt_link
00304 {
00305 struct rpt_link *next;
00306 struct rpt_link *prev;
00307 char mode;
00308 char isremote;
00309 char phonemode;
00310 char name[MAXNODESTR];
00311 char lasttx;
00312 char lastrx;
00313 char connected;
00314 char hasconnected;
00315 char outbound;
00316 char disced;
00317 char killme;
00318 long elaptime;
00319 long disctime;
00320 long retrytimer;
00321 long retxtimer;
00322 int retries;
00323 int reconnects;
00324 long long connecttime;
00325 struct ast_channel *chan;
00326 struct ast_channel *pchan;
00327 } ;
00328
00329 struct rpt_lstat
00330 {
00331 struct rpt_lstat *next;
00332 struct rpt_lstat *prev;
00333 char peer[MAXPEERSTR];
00334 char name[MAXNODESTR];
00335 char mode;
00336 char outbound;
00337 char reconnects;
00338 long long connecttime;
00339 } ;
00340
00341 struct rpt_tele
00342 {
00343 struct rpt_tele *next;
00344 struct rpt_tele *prev;
00345 struct rpt *rpt;
00346 struct ast_channel *chan;
00347 int mode;
00348 struct rpt_link mylink;
00349 char param[TELEPARAMSIZE];
00350 pthread_t threadid;
00351 } ;
00352
00353 struct function_table_tag
00354 {
00355 char action[ACTIONSIZE];
00356 int (*function)(struct rpt *myrpt, char *param, char *digitbuf,
00357 int command_source, struct rpt_link *mylink);
00358 } ;
00359
00360
00361
00362 struct morse_bits
00363 {
00364 int len;
00365 int ddcomb;
00366 } ;
00367
00368 struct telem_defaults
00369 {
00370 char name[20];
00371 char value[80];
00372 } ;
00373
00374
00375 static struct rpt
00376 {
00377 ast_mutex_t lock;
00378 struct ast_config *cfg;
00379 char reload;
00380
00381 char *name;
00382 char *rxchanname;
00383 char *txchanname;
00384 char *remote;
00385
00386 struct {
00387 char ourcontext[80];
00388 char ourcallerid[80];
00389 char acctcode[21];
00390 char ident[80];
00391 char tonezone[80];
00392 char simple;
00393 char functions[80];
00394 char link_functions[80];
00395 char phone_functions[80];
00396 char dphone_functions[80];
00397 char nodes[80];
00398 int hangtime;
00399 int totime;
00400 int idtime;
00401 int tailmessagetime;
00402 int tailsquashedtime;
00403 int duplex;
00404 int politeid;
00405 char *tailmsgbuf;
00406 AST_DECLARE_APP_ARGS(tailmsg,
00407 AST_APP_ARG(msgs)[100];
00408 );
00409 char memory[80];
00410 char macro[80];
00411 char gosub[80];
00412 char startupmacro[80];
00413 char startupgosub[80];
00414 int iobase;
00415 char funcchar;
00416 char endchar;
00417 char nobusyout;
00418 } p;
00419 struct rpt_link links;
00420 int unkeytocttimer;
00421 char keyed;
00422 char exttx;
00423 char localtx;
00424 char remoterx;
00425 char remotetx;
00426 char remoteon;
00427 char tounkeyed;
00428 char tonotify;
00429 char enable;
00430 char dtmfbuf[MAXDTMF];
00431 char macrobuf[MAXMACRO];
00432 char gosubbuf[MAXGOSUB];
00433 char rem_dtmfbuf[MAXDTMF];
00434 char lastdtmfcommand[MAXDTMF];
00435 char cmdnode[50];
00436 struct ast_channel *rxchannel, *txchannel;
00437 struct ast_channel *pchannel, *txpchannel, *remchannel;
00438 struct rpt_tele tele;
00439 struct timeval lasttv, curtv;
00440 pthread_t rpt_call_thread, rpt_thread;
00441 time_t dtmf_time, rem_dtmf_time, dtmf_time_rem;
00442 int tailtimer, totimer, idtimer, txconf, conf, callmode, cidx, scantimer, tmsgtimer, skedtimer;
00443 int mustid, tailid;
00444 int tailevent;
00445 int telemrefcount;
00446 int dtmfidx, rem_dtmfidx;
00447 int dailytxtime, dailykerchunks, totalkerchunks, dailykeyups, totalkeyups, timeouts;
00448 int totalexecdcommands, dailyexecdcommands;
00449 long retxtimer;
00450 long long totaltxtime;
00451 char mydtmf;
00452 char exten[AST_MAX_EXTENSION];
00453 char freq[MAXREMSTR], rxpl[MAXREMSTR], txpl[MAXREMSTR];
00454 char offset;
00455 char powerlevel;
00456 char txplon;
00457 char rxplon;
00458 char remmode;
00459 char tunerequest;
00460 char hfscanmode;
00461 int hfscanstatus;
00462 char lastlinknode[MAXNODESTR];
00463 char stopgen;
00464 char patchfarenddisconnect;
00465 char patchnoct;
00466 char patchquiet;
00467 char patchcontext[MAXPATCHCONTEXT];
00468 int patchdialtime;
00469 int macro_longest;
00470 int gosub_longest;
00471 int phone_longestfunc;
00472 int dphone_longestfunc;
00473 int link_longestfunc;
00474 int longestfunc;
00475 int longestnode;
00476 int threadrestarts;
00477 int tailmessagen;
00478 time_t disgorgetime;
00479 time_t lastthreadrestarttime;
00480 long macrotimer;
00481 long gosubtimer;
00482 char lastnodewhichkeyedusup[MAXNODESTR];
00483 #ifdef __RPT_NOTCH
00484 struct rptfilter
00485 {
00486 char desc[100];
00487 float x0;
00488 float x1;
00489 float x2;
00490 float y0;
00491 float y1;
00492 float y2;
00493 float gain;
00494 float const0;
00495 float const1;
00496 float const2;
00497 } filters[MAXFILTERS];
00498 #endif
00499 #ifdef _MDC_DECODE_H_
00500 mdc_decoder_t *mdc;
00501 unsigned short lastunit;
00502 #endif
00503 } rpt_vars[MAXRPTS];
00504
00505
00506 #ifdef APP_RPT_LOCK_DEBUG
00507
00508 #warning COMPILING WITH LOCK-DEBUGGING ENABLED!!
00509
00510 #define MAXLOCKTHREAD 100
00511
00512 #define rpt_mutex_lock(x) _rpt_mutex_lock(x, myrpt, __LINE__)
00513 #define rpt_mutex_unlock(x) _rpt_mutex_unlock(x, myrpt, __LINE__)
00514
00515 struct lockthread
00516 {
00517 pthread_t id;
00518 int lockcount;
00519 int lastlock;
00520 int lastunlock;
00521 } lockthreads[MAXLOCKTHREAD];
00522
00523
00524 struct by_lightning
00525 {
00526 int line;
00527 struct timeval tv;
00528 struct rpt *rpt;
00529 struct lockthread lockthread;
00530 } lock_ring[32];
00531
00532
00533 int lock_ring_index = 0;
00534
00535 AST_MUTEX_DEFINE_STATIC(locklock);
00536
00537 static struct lockthread *get_lockthread(pthread_t id)
00538 {
00539 int i;
00540
00541 for (i = 0; i < MAXLOCKTHREAD; i++) {
00542 if (lockthreads[i].id == id)
00543 return(&lockthreads[i]);
00544 }
00545 return NULL;
00546 }
00547
00548 static struct lockthread *put_lockthread(pthread_t id)
00549 {
00550 int i;
00551
00552 for (i = 0; i < MAXLOCKTHREAD; i++) {
00553 if (lockthreads[i].id == id)
00554 return(&lockthreads[i]);
00555 }
00556 for (i = 0; i < MAXLOCKTHREAD; i++) {
00557 if (!lockthreads[i].id) {
00558 lockthreads[i].lockcount = 0;
00559 lockthreads[i].lastlock = 0;
00560 lockthreads[i].lastunlock = 0;
00561 lockthreads[i].id = id;
00562 return &lockthreads[i];
00563 }
00564 }
00565 return NULL;
00566 }
00567
00568
00569 static void rpt_mutex_spew(void)
00570 {
00571 struct by_lightning lock_ring_copy[32];
00572 int lock_ring_index_copy;
00573 int i, j;
00574 long long diff;
00575 char a[100] = "";
00576 struct ast_tm tm;
00577 struct timeval lasttv;
00578
00579 ast_mutex_lock(&locklock);
00580 memcpy(&lock_ring_copy, &lock_ring, sizeof(lock_ring_copy));
00581 lock_ring_index_copy = lock_ring_index;
00582 ast_mutex_unlock(&locklock);
00583
00584 lasttv.tv_sec = lasttv.tv_usec = 0;
00585 for (i = 0; i < 32; i++) {
00586 j = (i + lock_ring_index_copy) % 32;
00587 ast_strftime(a, sizeof(a) - 1, "%m/%d/%Y %H:%M:%S",
00588 ast_localtime(&lock_ring_copy[j].tv, &tm, NULL));
00589 diff = 0;
00590 if (lasttv.tv_sec) {
00591 diff = (lock_ring_copy[j].tv.tv_sec - lasttv.tv_sec) * 1000000;
00592 diff += (lock_ring_copy[j].tv.tv_usec - lasttv.tv_usec);
00593 }
00594 lasttv.tv_sec = lock_ring_copy[j].tv.tv_sec;
00595 lasttv.tv_usec = lock_ring_copy[j].tv.tv_usec;
00596 if (!lock_ring_copy[j].tv.tv_sec)
00597 continue;
00598 if (lock_ring_copy[j].line < 0) {
00599 ast_log(LOG_NOTICE, "LOCKDEBUG [#%d] UNLOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
00600 i - 31, -lock_ring_copy[j].line, lock_ring_copy[j].rpt->name,
00601 (int) lock_ring_copy[j].lockthread.id, diff, a, (int)lock_ring_copy[j].tv.tv_usec);
00602 } else {
00603 ast_log(LOG_NOTICE, "LOCKDEBUG [#%d] LOCK app_rpt.c:%d node %s pid %x diff %lld us at %s.%06d\n",
00604 i - 31, lock_ring_copy[j].line, lock_ring_copy[j].rpt->name,
00605 (int) lock_ring_copy[j].lockthread.id, diff, a, (int)lock_ring_copy[j].tv.tv_usec);
00606 }
00607 }
00608 }
00609
00610
00611 static void _rpt_mutex_lock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
00612 {
00613 struct lockthread *t;
00614 pthread_t id;
00615
00616 id = pthread_self();
00617 ast_mutex_lock(&locklock);
00618 t = put_lockthread(id);
00619 if (!t) {
00620 ast_mutex_unlock(&locklock);
00621 return;
00622 }
00623 if (t->lockcount) {
00624 int lastline = t->lastlock;
00625 ast_mutex_unlock(&locklock);
00626 ast_log(LOG_NOTICE, "rpt_mutex_lock: Double lock request line %d node %s pid %x, last lock was line %d\n",
00627 line, myrpt->name, (int) t->id, lastline);
00628 rpt_mutex_spew();
00629 return;
00630 }
00631 t->lastlock = line;
00632 t->lockcount = 1;
00633 gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
00634 lock_ring[lock_ring_index].rpt = myrpt;
00635 memcpy(&lock_ring[lock_ring_index].lockthread, t, sizeof(struct lockthread));
00636 lock_ring[lock_ring_index++].line = line;
00637 if (lock_ring_index == 32)
00638 lock_ring_index = 0;
00639 ast_mutex_unlock(&locklock);
00640 ast_mutex_lock(lockp);
00641 }
00642
00643
00644 static void _rpt_mutex_unlock(ast_mutex_t *lockp, struct rpt *myrpt, int line)
00645 {
00646 struct lockthread *t;
00647 pthread_t id;
00648
00649 id = pthread_self();
00650 ast_mutex_lock(&locklock);
00651 t = put_lockthread(id);
00652 if (!t) {
00653 ast_mutex_unlock(&locklock);
00654 return;
00655 }
00656 if (!t->lockcount) {
00657 int lastline = t->lastunlock;
00658 ast_mutex_unlock(&locklock);
00659 ast_log(LOG_NOTICE, "rpt_mutex_lock: Double un-lock request line %d node %s pid %x, last un-lock was line %d\n",
00660 line, myrpt->name, (int) t->id, lastline);
00661 rpt_mutex_spew();
00662 return;
00663 }
00664 t->lastunlock = line;
00665 t->lockcount = 0;
00666 gettimeofday(&lock_ring[lock_ring_index].tv, NULL);
00667 lock_ring[lock_ring_index].rpt = myrpt;
00668 memcpy(&lock_ring[lock_ring_index].lockthread, t, sizeof(struct lockthread));
00669 lock_ring[lock_ring_index++].line = -line;
00670 if (lock_ring_index == 32)
00671 lock_ring_index = 0;
00672 ast_mutex_unlock(&locklock);
00673 ast_mutex_unlock(lockp);
00674 }
00675
00676 #else
00677
00678 #define rpt_mutex_lock(x) ast_mutex_lock(x)
00679 #define rpt_mutex_unlock(x) ast_mutex_unlock(x)
00680
00681 #endif
00682
00683
00684
00685
00686
00687
00688 static char *handle_cli_rpt_debug_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
00689 static char *handle_cli_rpt_dump(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
00690 static char *handle_cli_rpt_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
00691 static char *handle_cli_rpt_lstats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
00692 static char *handle_cli_rpt_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
00693 static char *handle_cli_rpt_restart(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
00694
00695 static struct ast_cli_entry cli_rpt[] = {
00696 AST_CLI_DEFINE(handle_cli_rpt_debug_level, "Enable app_rpt debuggin"),
00697 AST_CLI_DEFINE(handle_cli_rpt_dump, "Dump app_rpt structs for debugging"),
00698 AST_CLI_DEFINE(handle_cli_rpt_stats, "Dump node statistics"),
00699 AST_CLI_DEFINE(handle_cli_rpt_lstats, "Dump link statistics"),
00700 AST_CLI_DEFINE(handle_cli_rpt_reload, "Reload app_rpt config"),
00701 AST_CLI_DEFINE(handle_cli_rpt_restart, "Restart app_rpt")
00702 };
00703
00704
00705
00706
00707
00708
00709 static struct telem_defaults tele_defs[] = {
00710 {"ct1", "|t(350,0,100,3072)(500,0,100,3072)(660,0,100,3072)"},
00711 {"ct2", "|t(660,880,150,3072)"},
00712 {"ct3", "|t(440,0,150,3072)"},
00713 {"ct4", "|t(550,0,150,3072)"},
00714 {"ct5", "|t(660,0,150,3072)"},
00715 {"ct6", "|t(880,0,150,3072)"},
00716 {"ct7", "|t(660,440,150,3072)"},
00717 {"ct8", "|t(700,1100,150,3072)"},
00718 {"remotemon", "|t(1600,0,75,2048)"},
00719 {"remotetx", "|t(2000,0,75,2048)(0,0,75,0)(1600,0,75,2048)"},
00720 {"cmdmode", "|t(900,904,200,2048)"},
00721 {"functcomplete", "|t(1000,0,100,2048)(0,0,100,0)(1000,0,100,2048)"}
00722 } ;
00723
00724
00725
00726
00727
00728 static int setrbi(struct rpt *myrpt);
00729
00730
00731
00732
00733
00734
00735
00736 static int function_ilink(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
00737 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
00738 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
00739 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
00740 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
00741 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
00742 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
00743 static int function_gosub(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink);
00744
00745
00746
00747
00748 static struct function_table_tag function_table[] = {
00749 {"cop", function_cop},
00750 {"autopatchup", function_autopatchup},
00751 {"autopatchdn", function_autopatchdn},
00752 {"ilink", function_ilink},
00753 {"status", function_status},
00754 {"remote", function_remote},
00755 {"macro", function_macro},
00756 {"gosub", function_gosub},
00757 } ;
00758
00759
00760
00761
00762
00763
00764 static int matchkeyword(char *string, char **param, char *keywords[])
00765 {
00766 int i, ls;
00767 for (i = 0; keywords[i]; i++) {
00768 ls = strlen(keywords[i]);
00769 if (!ls) {
00770 *param = NULL;
00771 return 0;
00772 }
00773 if (!strncmp(string, keywords[i], ls)) {
00774 if (param)
00775 *param = string + ls;
00776 return i + 1;
00777 }
00778 }
00779 param = NULL;
00780 return 0;
00781 }
00782
00783
00784
00785
00786
00787
00788 static char *skipchars(char *string, char *charlist)
00789 {
00790 int i;
00791 while (*string) {
00792 for (i = 0; charlist[i] ; i++) {
00793 if (*string == charlist[i]) {
00794 string++;
00795 break;
00796 }
00797 }
00798 if (!charlist[i])
00799 return string;
00800 }
00801 return string;
00802 }
00803
00804
00805
00806 static int myatoi(const char *str)
00807 {
00808 int ret;
00809
00810 if (str == NULL)
00811 return -1;
00812
00813 if (sscanf(str, "%i", &ret) != 1)
00814 return -1;
00815 return ret;
00816 }
00817
00818
00819 #ifdef __RPT_NOTCH
00820
00821
00822 static void rpt_filter(struct rpt *myrpt, volatile short *buf, int len)
00823 {
00824 int i, j;
00825 struct rptfilter *f;
00826
00827 for (i = 0; i < len; i++) {
00828 for (j = 0; j < MAXFILTERS; j++) {
00829 f = &myrpt->filters[j];
00830 if (!*f->desc)
00831 continue;
00832 f->x0 = f->x1; f->x1 = f->x2;
00833 f->x2 = ((float)buf[i]) / f->gain;
00834 f->y0 = f->y1; f->y1 = f->y2;
00835 f->y2 = (f->x0 + f->x2) + f->const0 * f->x1
00836 + (f->const1 * f->y0) + (f->const2 * f->y1);
00837 buf[i] = (short)f->y2;
00838 }
00839 }
00840 }
00841
00842 #endif
00843
00844
00845 static int retrieve_astcfgint(struct rpt *myrpt, const char *category, const char *name, int min, int max, int defl)
00846 {
00847 const char *var = ast_variable_retrieve(myrpt->cfg, category, name);
00848 int ret;
00849
00850 if (var) {
00851 ret = myatoi(var);
00852 if (ret < min)
00853 ret = min;
00854 else if (ret > max)
00855 ret = max;
00856 } else
00857 ret = defl;
00858 return ret;
00859 }
00860
00861
00862 static void load_rpt_vars(int n, int init)
00863 {
00864 int j;
00865 struct ast_variable *vp, *var;
00866 struct ast_config *cfg;
00867 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
00868 #ifdef __RPT_NOTCH
00869 AST_DECLARE_APP_ARGS(strs,
00870 AST_APP_ARG(str)[100];
00871 );
00872 #endif
00873
00874 ast_verb(3, "%s config for repeater %s\n",
00875 (init) ? "Loading initial" : "Re-Loading", rpt_vars[n].name);
00876 ast_mutex_lock(&rpt_vars[n].lock);
00877 if (rpt_vars[n].cfg)
00878 ast_config_destroy(rpt_vars[n].cfg);
00879 cfg = ast_config_load("rpt.conf", config_flags);
00880 if (!cfg) {
00881 ast_mutex_unlock(&rpt_vars[n].lock);
00882 ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf. Radio Repeater disabled.\n");
00883 pthread_exit(NULL);
00884 }
00885 rpt_vars[n].cfg = cfg;
00886
00887 if (!init && rpt_vars[n].p.tailmsgbuf)
00888 ast_free(rpt_vars[n].p.tailmsgbuf);
00889 memset(&rpt_vars[n].p, 0, sizeof(rpt_vars[n].p));
00890 if (init) {
00891
00892 memset(&rpt_vars[n].p + sizeof(rpt_vars[0].p), 0, sizeof(rpt_vars[0]) - sizeof(rpt_vars[0].p) - offsetof(typeof(rpt_vars[0]), p));
00893 rpt_vars[n].tele.next = &rpt_vars[n].tele;
00894 rpt_vars[n].tele.prev = &rpt_vars[n].tele;
00895 rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
00896 rpt_vars[n].tailmessagen = 0;
00897 }
00898 #ifdef __RPT_NOTCH
00899
00900 memset(&rpt_vars[n].filters, 0, sizeof(rpt_vars[n].filters));
00901 #endif
00902
00903
00904 ast_copy_string(rpt_vars[n].p.ourcontext, rpt_vars[n].name, sizeof(rpt_vars[n].p.ourcontext));
00905 rpt_vars[n].p.hangtime = HANGTIME;
00906 rpt_vars[n].p.totime = TOTIME;
00907 rpt_vars[n].p.duplex = 2;
00908 rpt_vars[n].p.idtime = IDTIME;
00909 rpt_vars[n].p.politeid = POLITEID;
00910 ast_copy_string(rpt_vars[n].p.memory, MEMORY, sizeof(rpt_vars[n].p.memory));
00911 ast_copy_string(rpt_vars[n].p.macro, MACRO, sizeof(rpt_vars[n].p.macro));
00912 ast_copy_string(rpt_vars[n].p.gosub, GOSUB, sizeof(rpt_vars[n].p.gosub));
00913 rpt_vars[n].p.iobase = DEFAULT_IOBASE;
00914 ast_copy_string(rpt_vars[n].p.functions, FUNCTIONS, sizeof(rpt_vars[n].p.functions));
00915 rpt_vars[n].p.simple = 1;
00916 rpt_vars[n].p.funcchar = FUNCCHAR;
00917 rpt_vars[n].p.endchar = ENDCHAR;
00918 ast_copy_string(rpt_vars[n].p.nodes, NODES, sizeof(rpt_vars[n].p.nodes));
00919
00920 for (var = ast_variable_browse(cfg, rpt_vars[n].name); var; var = var->next) {
00921 if (!strcmp(var->name, "context")) {
00922 ast_copy_string(rpt_vars[n].p.ourcontext, var->value, sizeof(rpt_vars[n].p.ourcontext));
00923 } else if (!strcmp(var->name, "callerid")) {
00924 ast_copy_string(rpt_vars[n].p.ourcallerid, var->value, sizeof(rpt_vars[n].p.ourcallerid));
00925 } else if (!strcmp(var->name, "accountcode")) {
00926 ast_copy_string(rpt_vars[n].p.acctcode, var->value, sizeof(rpt_vars[n].p.acctcode));
00927 } else if (!strcmp(var->name, "idrecording")) {
00928 ast_copy_string(rpt_vars[n].p.ident, var->value, sizeof(rpt_vars[n].p.ident));
00929 } else if (!strcmp(var->name, "hangtime")) {
00930 rpt_vars[n].p.hangtime = atoi(var->value);
00931 } else if (!strcmp(var->name, "totime")) {
00932 rpt_vars[n].p.totime = atoi(var->value);
00933 } else if (!strcmp(var->name, "tailmessagetime")) {
00934 rpt_vars[n].p.tailmessagetime = atoi(var->value);
00935 if (rpt_vars[n].p.tailmessagetime < 0)
00936 rpt_vars[n].p.tailmessagetime = 0;
00937 else if (rpt_vars[n].p.tailmessagetime > 2400000)
00938 rpt_vars[n].p.tailmessagetime = 2400000;
00939 } else if (!strcmp(var->name, "tailsquashedtime")) {
00940 rpt_vars[n].p.tailsquashedtime = atoi(var->value);
00941 if (rpt_vars[n].p.tailsquashedtime < 0)
00942 rpt_vars[n].p.tailsquashedtime = 0;
00943 else if (rpt_vars[n].p.tailsquashedtime > 2400000)
00944 rpt_vars[n].p.tailsquashedtime = 2400000;
00945 } else if (!strcmp(var->name, "duplex")) {
00946 rpt_vars[n].p.duplex = atoi(var->value);
00947 if (rpt_vars[n].p.duplex < 0)
00948 rpt_vars[n].p.duplex = 0;
00949 else if (rpt_vars[n].p.duplex > 4)
00950 rpt_vars[n].p.duplex = 4;
00951 } else if (!strcmp(var->name, "idtime")) {
00952 rpt_vars[n].p.idtime = atoi(var->value);
00953 if (rpt_vars[n].p.idtime < 60000)
00954 rpt_vars[n].p.idtime = 60000;
00955 else if (rpt_vars[n].p.idtime > 2400000)
00956 rpt_vars[n].p.idtime = 2400000;
00957 } else if (!strcmp(var->name, "politeid")) {
00958 rpt_vars[n].p.politeid = atoi(var->value);
00959 if (rpt_vars[n].p.politeid < 30000)
00960 rpt_vars[n].p.politeid = 30000;
00961 else if (rpt_vars[n].p.politeid > 300000)
00962 rpt_vars[n].p.politeid = 300000;
00963 } else if (!strcmp(var->name, "tonezone")) {
00964 ast_copy_string(rpt_vars[n].p.tonezone, var->value, sizeof(rpt_vars[n].p.tonezone));
00965 } else if (!strcmp(var->name, "tailmessagelist")) {
00966 rpt_vars[n].p.tailmsgbuf = ast_strdup(var->value);
00967 AST_STANDARD_APP_ARGS(rpt_vars[n].p.tailmsg, rpt_vars[n].p.tailmsgbuf);
00968 } else if (!strcmp(var->name, "memory")) {
00969 ast_copy_string(rpt_vars[n].p.memory, var->value, sizeof(rpt_vars[n].p.memory));
00970 } else if (!strcmp(var->name, "macro")) {
00971 ast_copy_string(rpt_vars[n].p.macro, var->value, sizeof(rpt_vars[n].p.macro));
00972 } else if (!strcmp(var->name, "gosub")) {
00973 ast_copy_string(rpt_vars[n].p.gosub, var->value, sizeof(rpt_vars[n].p.gosub));
00974 } else if (!strcmp(var->name, "startup_macro")) {
00975 ast_copy_string(rpt_vars[n].p.startupmacro, var->value, sizeof(rpt_vars[n].p.startupmacro));
00976 } else if (!strcmp(var->name, "startup_gosub")) {
00977 ast_copy_string(rpt_vars[n].p.startupgosub, var->value, sizeof(rpt_vars[n].p.startupgosub));
00978 } else if (!strcmp(var->name, "iobase")) {
00979
00980
00981
00982 if (sscanf(var->value, "%i", &rpt_vars[n].p.iobase) != 1)
00983 rpt_vars[n].p.iobase = DEFAULT_IOBASE;
00984 } else if (!strcmp(var->name, "functions")) {
00985 rpt_vars[n].p.simple = 0;
00986 ast_copy_string(rpt_vars[n].p.functions, var->value, sizeof(rpt_vars[n].p.functions));
00987 } else if (!strcmp(var->name, "link_functions")) {
00988 ast_copy_string(rpt_vars[n].p.link_functions, var->value, sizeof(rpt_vars[n].p.link_functions));
00989 } else if (!strcmp(var->name, "phone_functions")) {
00990 ast_copy_string(rpt_vars[n].p.phone_functions, var->value, sizeof(rpt_vars[n].p.phone_functions));
00991 } else if (!strcmp(var->name, "dphone_functions")) {
00992 ast_copy_string(rpt_vars[n].p.dphone_functions, var->value, sizeof(rpt_vars[n].p.dphone_functions));
00993 } else if (!strcmp(var->name, "funcchar")) {
00994 rpt_vars[n].p.funcchar = *var->value;
00995 } else if (!strcmp(var->name, "endchar")) {
00996 rpt_vars[n].p.endchar = *var->value;
00997 } else if (!strcmp(var->name, "nobusyout")) {
00998 rpt_vars[n].p.nobusyout = ast_true(var->value);
00999 } else if (!strcmp(var->name, "nodes")) {
01000 ast_copy_string(rpt_vars[n].p.nodes, var->value, sizeof(rpt_vars[n].p.nodes));
01001 #ifdef __RPT_NOTCH
01002 } else if (!strcmp(var->name, "rxnotch")) {
01003 char *tmp = ast_strdupa(val);
01004 AST_STANDARD_APP_ARGS(strs, tmp);
01005 strs.argc &= ~1;
01006 if (strs.argc >= 2) {
01007 for (j = 0; j < strs.argc; j += 2) {
01008 rpt_mknotch(atof(strs.str[j]), atof(strs.str[j + 1]),
01009 &rpt_vars[n].filters[j >> 1].gain,
01010 &rpt_vars[n].filters[j >> 1].const0,
01011 &rpt_vars[n].filters[j >> 1].const1,
01012 &rpt_vars[n].filters[j >> 1].const2);
01013 sprintf(rpt_vars[n].filters[j >> 1].desc, "%s Hz, BW = %s",
01014 strs.str[j], strs.str[j + 1]);
01015 }
01016 }
01017 #endif
01018 }
01019 }
01020
01021
01022 if (ast_strlen_zero(rpt_vars[n].p.link_functions))
01023 ast_copy_string(rpt_vars[n].p.link_functions, rpt_vars[n].p.functions, sizeof(rpt_vars[n].p.link_functions));
01024
01025 rpt_vars[n].longestnode = 0;
01026 for (vp = ast_variable_browse(cfg, rpt_vars[n].p.nodes); vp; vp = vp->next) {
01027 if ((j = strlen(vp->name)) > rpt_vars[n].longestnode)
01028 rpt_vars[n].longestnode = j;
01029 }
01030
01031
01032
01033
01034 rpt_vars[n].longestfunc = 0;
01035 for (vp = ast_variable_browse(cfg, rpt_vars[n].p.functions); vp; vp = vp->next) {
01036 if ((j = strlen(vp->name)) > rpt_vars[n].longestfunc)
01037 rpt_vars[n].longestfunc = j;
01038 }
01039
01040 rpt_vars[n].link_longestfunc = 0;
01041 for (vp = ast_variable_browse(cfg, rpt_vars[n].p.link_functions); vp; vp = vp->next) {
01042 if ((j = strlen(vp->name)) > rpt_vars[n].link_longestfunc)
01043 rpt_vars[n].link_longestfunc = j;
01044 }
01045
01046 rpt_vars[n].phone_longestfunc = 0;
01047 for (vp = ast_variable_browse(cfg, rpt_vars[n].p.phone_functions); vp; vp = vp->next) {
01048 if ((j = strlen(vp->name)) > rpt_vars[n].phone_longestfunc)
01049 rpt_vars[n].phone_longestfunc = j;
01050 }
01051
01052 rpt_vars[n].dphone_longestfunc = 0;
01053 for (vp = ast_variable_browse(cfg, rpt_vars[n].p.dphone_functions); vp; vp = vp->next) {
01054 if ((j = strlen(vp->name)) > rpt_vars[n].dphone_longestfunc)
01055 rpt_vars[n].dphone_longestfunc = j;
01056 }
01057
01058 rpt_vars[n].macro_longest = 1;
01059 for (vp = ast_variable_browse(cfg, rpt_vars[n].p.macro); vp; vp = vp->next) {
01060 if ((j = strlen(vp->name)) > rpt_vars[n].macro_longest)
01061 rpt_vars[n].macro_longest = j;
01062 }
01063
01064 rpt_vars[n].gosub_longest = 1;
01065 for (vp = ast_variable_browse(cfg, rpt_vars[n].p.gosub); vp; vp = vp->next) {
01066 if ((j = strlen(vp->name)) > rpt_vars[n].gosub_longest)
01067 rpt_vars[n].gosub_longest = j;
01068 }
01069 ast_mutex_unlock(&rpt_vars[n].lock);
01070 }
01071
01072
01073
01074
01075 static char *handle_cli_rpt_debug_level(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01076 {
01077 int newlevel;
01078
01079 switch (cmd) {
01080 case CLI_INIT:
01081 e->command = "rpt debug level";
01082 e->usage =
01083 "Usage: rpt debug level {0-7}\n"
01084 " Enables debug messages in app_rpt\n";
01085 return NULL;
01086 case CLI_GENERATE:
01087 return NULL;
01088 }
01089 if (a->argc != e->args)
01090 return CLI_SHOWUSAGE;
01091 newlevel = myatoi(a->argv[3]);
01092 if ((newlevel < 0) || (newlevel > 7))
01093 return CLI_SHOWUSAGE;
01094 if (newlevel)
01095 ast_cli(a->fd, "app_rpt Debugging enabled, previous level: %d, new level: %d\n", debug, newlevel);
01096 else
01097 ast_cli(a->fd, "app_rpt Debugging disabled\n");
01098
01099 debug = newlevel;
01100
01101 return CLI_SUCCESS;
01102 }
01103
01104
01105
01106
01107 static char *handle_cli_rpt_dump(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01108 {
01109 int i;
01110
01111 switch (cmd) {
01112 case CLI_INIT:
01113 e->command = "rpt dump";
01114 e->usage =
01115 "Usage: rpt dump <nodename>\n"
01116 " Dumps struct debug info to log\n";
01117 return NULL;
01118 case CLI_GENERATE:
01119 return NULL;
01120 }
01121
01122 if (a->argc != 3)
01123 return CLI_SHOWUSAGE;
01124
01125 for (i = 0; i < nrpts; i++) {
01126 if (!strcmp(a->argv[2], rpt_vars[i].name)) {
01127 rpt_vars[i].disgorgetime = time(NULL) + 10;
01128 ast_cli(a->fd, "app_rpt struct dump requested for node %s\n", a->argv[2]);
01129 return CLI_SUCCESS;
01130 }
01131 }
01132 return CLI_FAILURE;
01133 }
01134
01135
01136
01137
01138 static char *handle_cli_rpt_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01139 {
01140 int i, j;
01141 int dailytxtime, dailykerchunks;
01142 int totalkerchunks, dailykeyups, totalkeyups, timeouts;
01143 int totalexecdcommands, dailyexecdcommands, hours, minutes, seconds;
01144 long long totaltxtime;
01145 struct rpt_link *l;
01146 char *listoflinks[MAX_STAT_LINKS];
01147 char *lastnodewhichkeyedusup, *lastdtmfcommand;
01148 char *tot_state, *ider_state, *patch_state;
01149 char *reverse_patch_state, *enable_state, *input_signal, *called_number;
01150 struct rpt *myrpt;
01151
01152 static char *not_applicable = "N/A";
01153
01154 switch (cmd) {
01155 case CLI_INIT:
01156 e->command = "rpt stats";
01157 e->usage =
01158 "Usage: rpt stats <nodename>\n"
01159 " Dumps node statistics to console\n";
01160 return NULL;
01161 case CLI_GENERATE:
01162 return NULL;
01163 }
01164
01165 if (a->argc != 3)
01166 return CLI_SHOWUSAGE;
01167
01168 for (i = 0 ; i <= MAX_STAT_LINKS; i++)
01169 listoflinks[i] = NULL;
01170
01171 tot_state = ider_state =
01172 patch_state = reverse_patch_state =
01173 input_signal = called_number =
01174 lastdtmfcommand = not_applicable;
01175
01176 for (i = 0; i < nrpts; i++) {
01177 if (!strcmp(a->argv[2], rpt_vars[i].name)) {
01178
01179 myrpt = &rpt_vars[i];
01180 rpt_mutex_lock(&myrpt->lock);
01181
01182 dailytxtime = myrpt->dailytxtime;
01183 totaltxtime = myrpt->totaltxtime;
01184 dailykeyups = myrpt->dailykeyups;
01185 totalkeyups = myrpt->totalkeyups;
01186 dailykerchunks = myrpt->dailykerchunks;
01187 totalkerchunks = myrpt->totalkerchunks;
01188 dailyexecdcommands = myrpt->dailyexecdcommands;
01189 totalexecdcommands = myrpt->totalexecdcommands;
01190 timeouts = myrpt->timeouts;
01191
01192
01193 reverse_patch_state = "DOWN";
01194 j = 0;
01195 l = myrpt->links.next;
01196 while (l != &myrpt->links) {
01197 if (l->name[0] == '0') {
01198 reverse_patch_state = "UP";
01199 l = l->next;
01200 continue;
01201 }
01202 listoflinks[j] = ast_strdupa(l->name);
01203 if (listoflinks[j])
01204 j++;
01205 l = l->next;
01206 }
01207
01208 lastnodewhichkeyedusup = ast_strdupa(myrpt->lastnodewhichkeyedusup);
01209 if ((!lastnodewhichkeyedusup) || (ast_strlen_zero(lastnodewhichkeyedusup)))
01210 lastnodewhichkeyedusup = not_applicable;
01211
01212 if (myrpt->keyed)
01213 input_signal = "YES";
01214 else
01215 input_signal = "NO";
01216
01217 if (myrpt->enable)
01218 enable_state = "YES";
01219 else
01220 enable_state = "NO";
01221
01222 if (!myrpt->totimer)
01223 tot_state = "TIMED OUT!";
01224 else if (myrpt->totimer != myrpt->p.totime)
01225 tot_state = "ARMED";
01226 else
01227 tot_state = "RESET";
01228
01229 if (myrpt->tailid)
01230 ider_state = "QUEUED IN TAIL";
01231 else if (myrpt->mustid)
01232 ider_state = "QUEUED FOR CLEANUP";
01233 else
01234 ider_state = "CLEAN";
01235
01236 switch (myrpt->callmode) {
01237 case 1:
01238 patch_state = "DIALING";
01239 break;
01240 case 2:
01241 patch_state = "CONNECTING";
01242 break;
01243 case 3:
01244 patch_state = "UP";
01245 break;
01246 case 4:
01247 patch_state = "CALL FAILED";
01248 break;
01249 default:
01250 patch_state = "DOWN";
01251 }
01252
01253 if (!ast_strlen_zero(myrpt->exten))
01254 called_number = ast_strdupa(myrpt->exten);
01255
01256 if (!ast_strlen_zero(myrpt->lastdtmfcommand))
01257 lastdtmfcommand = ast_strdupa(myrpt->lastdtmfcommand);
01258
01259 rpt_mutex_unlock(&myrpt->lock);
01260
01261 ast_cli(a->fd, "************************ NODE %s STATISTICS *************************\n\n", myrpt->name);
01262 ast_cli(a->fd, "Signal on input..................................: %s\n", input_signal);
01263 ast_cli(a->fd, "Transmitter enabled..............................: %s\n", enable_state);
01264 ast_cli(a->fd, "Time out timer state.............................: %s\n", tot_state);
01265 ast_cli(a->fd, "Time outs since system initialization............: %d\n", timeouts);
01266 ast_cli(a->fd, "Identifier state.................................: %s\n", ider_state);
01267 ast_cli(a->fd, "Kerchunks today..................................: %d\n", dailykerchunks);
01268 ast_cli(a->fd, "Kerchunks since system initialization............: %d\n", totalkerchunks);
01269 ast_cli(a->fd, "Keyups today.....................................: %d\n", dailykeyups);
01270 ast_cli(a->fd, "Keyups since system initialization...............: %d\n", totalkeyups);
01271 ast_cli(a->fd, "DTMF commands today..............................: %d\n", dailyexecdcommands);
01272 ast_cli(a->fd, "DTMF commands since system initialization........: %d\n", totalexecdcommands);
01273 ast_cli(a->fd, "Last DTMF command executed.......................: %s\n", lastdtmfcommand);
01274
01275 hours = dailytxtime / 3600000;
01276 dailytxtime %= 3600000;
01277 minutes = dailytxtime / 60000;
01278 dailytxtime %= 60000;
01279 seconds = dailytxtime / 1000;
01280 dailytxtime %= 1000;
01281
01282 ast_cli(a->fd, "TX time today ...................................: %02d:%02d:%02d.%d\n",
01283 hours, minutes, seconds, dailytxtime);
01284
01285 hours = (int) totaltxtime / 3600000;
01286 totaltxtime %= 3600000;
01287 minutes = (int) totaltxtime / 60000;
01288 totaltxtime %= 60000;
01289 seconds = (int) totaltxtime / 1000;
01290 totaltxtime %= 1000;
01291
01292 ast_cli(a->fd, "TX time since system initialization..............: %02d:%02d:%02d.%d\n",
01293 hours, minutes, seconds, (int) totaltxtime);
01294 ast_cli(a->fd, "Nodes currently connected to us..................: ");
01295 for (j = 0;; j++) {
01296 if (!listoflinks[j]) {
01297 if (!j) {
01298 ast_cli(a->fd, "<NONE>");
01299 }
01300 break;
01301 }
01302 ast_cli(a->fd, "%s", listoflinks[j]);
01303 if (j % 4 == 3) {
01304 ast_cli(a->fd, "\n");
01305 ast_cli(a->fd, " : ");
01306 } else {
01307 if (listoflinks[j + 1])
01308 ast_cli(a->fd, ", ");
01309 }
01310 }
01311 ast_cli(a->fd, "\n");
01312
01313 ast_cli(a->fd, "Last node which transmitted to us................: %s\n", lastnodewhichkeyedusup);
01314 ast_cli(a->fd, "Autopatch state..................................: %s\n", patch_state);
01315 ast_cli(a->fd, "Autopatch called number..........................: %s\n", called_number);
01316 ast_cli(a->fd, "Reverse patch/IAXRPT connected...................: %s\n\n", reverse_patch_state);
01317
01318 return CLI_SUCCESS;
01319 }
01320 }
01321 return CLI_FAILURE;
01322 }
01323
01324
01325
01326
01327 static char *handle_cli_rpt_lstats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01328 {
01329 int i, j;
01330 struct rpt *myrpt;
01331 struct rpt_link *l;
01332 struct rpt_lstat *s, *t;
01333 struct rpt_lstat s_head;
01334
01335 switch (cmd) {
01336 case CLI_INIT:
01337 e->command = "rpt lstats";
01338 e->usage =
01339 "Usage: rpt lstats <nodename>\n"
01340 " Dumps link statistics to console\n";
01341 return NULL;
01342 case CLI_GENERATE:
01343 return NULL;
01344 }
01345
01346 if (a->argc != 3)
01347 return CLI_SHOWUSAGE;
01348
01349 s = NULL;
01350 s_head.next = &s_head;
01351 s_head.prev = &s_head;
01352
01353 for (i = 0; i < nrpts; i++) {
01354 if (!strcmp(a->argv[2], rpt_vars[i].name)) {
01355
01356 myrpt = &rpt_vars[i];
01357 rpt_mutex_lock(&myrpt->lock);
01358
01359 j = 0;
01360 l = myrpt->links.next;
01361 while (l != &myrpt->links) {
01362 if (l->name[0] == '0') {
01363 l = l->next;
01364 continue;
01365 }
01366 if ((s = ast_calloc(1, sizeof(*s))) == NULL) {
01367 ast_log(LOG_ERROR, "Malloc failed in rpt_do_lstats\n");
01368 rpt_mutex_unlock(&myrpt->lock);
01369 return CLI_FAILURE;
01370 }
01371 ast_copy_string(s->name, l->name, MAXREMSTR);
01372 pbx_substitute_variables_helper(l->chan, "${IAXPEER(CURRENTCHANNEL)}", s->peer, MAXPEERSTR - 1);
01373 s->mode = l->mode;
01374 s->outbound = l->outbound;
01375 s->reconnects = l->reconnects;
01376 s->connecttime = l->connecttime;
01377 insque((struct qelem *) s, (struct qelem *) s_head.next);
01378 l = l->next;
01379 }
01380 rpt_mutex_unlock(&myrpt->lock);
01381 ast_cli(a->fd, "NODE PEER RECONNECTS DIRECTION CONNECT TIME\n");
01382 ast_cli(a->fd, "---- ---- ---------- --------- ------------\n");
01383
01384 for (s = s_head.next; s != &s_head; s = s->next) {
01385 int hours, minutes, seconds;
01386 long long connecttime = s->connecttime;
01387 char conntime[31];
01388 hours = (int) connecttime/3600000;
01389 connecttime %= 3600000;
01390 minutes = (int) connecttime/60000;
01391 connecttime %= 60000;
01392 seconds = (int) connecttime/1000;
01393 connecttime %= 1000;
01394 snprintf(conntime, sizeof(conntime), "%02d:%02d:%02d.%d",
01395 hours, minutes, seconds, (int) connecttime);
01396 ast_cli(a->fd, "%-10s%-20s%-12d%-11s%-30s\n",
01397 s->name, s->peer, s->reconnects, (s->outbound)? "OUT":"IN", conntime);
01398 }
01399
01400 s = s_head.next;
01401 while (s != &s_head) {
01402 t = s;
01403 s = s->next;
01404 remque((struct qelem *)t);
01405 ast_free(t);
01406 }
01407 return CLI_SUCCESS;
01408 }
01409 }
01410
01411 return CLI_FAILURE;
01412 }
01413
01414
01415
01416
01417 static char *handle_cli_rpt_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01418 {
01419 int n;
01420
01421 switch (cmd) {
01422 case CLI_INIT:
01423 e->command = "rpt reload";
01424 e->usage =
01425 "Usage: rpt reload\n"
01426 " Reloads app_rpt running config parameters\n";
01427 return NULL;
01428 case CLI_GENERATE:
01429 return NULL;
01430 }
01431
01432 if (a->argc > 2)
01433 return CLI_SHOWUSAGE;
01434
01435 for (n = 0; n < nrpts; n++)
01436 rpt_vars[n].reload = 1;
01437
01438 return CLI_SUCCESS;
01439 }
01440
01441
01442
01443
01444 static char *handle_cli_rpt_restart(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01445 {
01446 int i;
01447
01448 switch (cmd) {
01449 case CLI_INIT:
01450 e->command = "rpt restart";
01451 e->usage =
01452 "Usage: rpt restart\n"
01453 " Restarts app_rpt\n";
01454 return NULL;
01455 case CLI_GENERATE:
01456 return NULL;
01457 }
01458
01459 if (a->argc > 2)
01460 return CLI_SHOWUSAGE;
01461 for (i = 0; i < nrpts; i++) {
01462 if (rpt_vars[i].rxchannel)
01463 ast_softhangup(rpt_vars[i].rxchannel, AST_SOFTHANGUP_DEV);
01464 }
01465 return CLI_SUCCESS;
01466 }
01467
01468 static int play_tone_pair(struct ast_channel *chan, int f1, int f2, int duration, int amplitude)
01469 {
01470 int res;
01471
01472 if ((res = ast_tonepair_start(chan, f1, f2, duration, amplitude)))
01473 return res;
01474
01475 while (chan->generatordata) {
01476 if (ast_safe_sleep(chan, 1))
01477 return -1;
01478 }
01479
01480 return 0;
01481 }
01482
01483 static int play_tone(struct ast_channel *chan, int freq, int duration, int amplitude)
01484 {
01485 return play_tone_pair(chan, freq, 0, duration, amplitude);
01486 }
01487
01488 static int play_silence(struct ast_channel *chan, int duration)
01489 {
01490 return play_tone_pair(chan, 0, 0, duration, 0);
01491 }
01492
01493
01494 static int send_morse(struct ast_channel *chan, const char *string, int speed, int freq, int amplitude)
01495 {
01496
01497 static struct morse_bits mbits[] = {
01498 {0, 0},
01499 {0, 0},
01500 {6, 18},
01501 {0, 0},
01502 {7, 72},
01503 {0, 0},
01504 {0, 0},
01505 {6, 30},
01506 {5, 13},
01507 {6, 29},
01508 {0, 0},
01509 {5, 10},
01510 {6, 51},
01511 {6, 33},
01512 {6, 42},
01513 {5, 9},
01514 {5, 31},
01515 {5, 30},
01516 {5, 28},
01517 {5, 24},
01518 {5, 16},
01519 {5, 0},
01520 {5, 1},
01521 {5, 3},
01522 {5, 7},
01523 {5, 15},
01524 {6, 7},
01525 {6, 21},
01526 {0, 0},
01527 {5, 33},
01528 {0, 0},
01529 {6, 12},
01530 {0, 0},
01531 {2, 2},
01532 {4, 1},
01533 {4, 5},
01534 {3, 1},
01535 {1, 0},
01536 {4, 4},
01537 {3, 3},
01538 {4, 0},
01539 {2, 0},
01540 {4, 14},
01541 {3, 5},
01542 {4, 2},
01543 {2, 3},
01544 {2, 1},
01545 {3, 7},
01546 {4, 6},
01547 {4, 11},
01548 {3, 2},
01549 {3, 0},
01550 {1, 1},
01551 {3, 4},
01552 {4, 8},
01553 {3, 6},
01554 {4, 9},
01555 {4, 13},
01556 {4, 3}
01557 };
01558
01559 int dottime;
01560 int dashtime;
01561 int intralettertime;
01562 int interlettertime;
01563 int interwordtime;
01564 int len, ddcomb;
01565 int res;
01566 int c;
01567 int i;
01568 int flags;
01569
01570 res = 0;
01571
01572
01573
01574 dottime = 900 / speed;
01575
01576
01577
01578 dashtime = 3 * dottime;
01579 intralettertime = dottime;
01580 interlettertime = dottime * 4 ;
01581 interwordtime = dottime * 7;
01582
01583 for (; (*string) && (!res); string++) {
01584
01585 c = *string;
01586
01587
01588
01589 if ((c >= 'a') && (c <= 'z'))
01590 c -= 0x20;
01591
01592
01593
01594 if (c > 'Z')
01595 continue;
01596
01597
01598
01599 if (c == ' ') {
01600 if (!res)
01601 res = play_silence(chan, interwordtime);
01602 continue;
01603 }
01604
01605
01606
01607 c -= 0x20;
01608
01609
01610
01611 len = mbits[c].len;
01612 ddcomb = mbits[c].ddcomb;
01613
01614
01615
01616 for (; len ; len--) {
01617 if (!res)
01618 res = play_tone(chan, freq, (ddcomb & 1) ? dashtime : dottime, amplitude);
01619 if (!res)
01620 res = play_silence(chan, intralettertime);
01621 ddcomb >>= 1;
01622 }
01623
01624
01625
01626 if (!res)
01627 res = play_silence(chan, interlettertime - intralettertime);
01628 }
01629
01630
01631
01632 if (!res)
01633 res = ast_waitstream(chan, "");
01634 ast_stopstream(chan);
01635
01636
01637
01638
01639
01640 for (i = 0; i < 20 ; i++) {
01641 flags = DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT;
01642 res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
01643 if (flags & DAHDI_IOMUX_WRITEEMPTY)
01644 break;
01645 if ( ast_safe_sleep(chan, 50)) {
01646 res = -1;
01647 break;
01648 }
01649 }
01650
01651
01652 return res;
01653 }
01654
01655 static int send_tone_telemetry(struct ast_channel *chan, const char *tonestring)
01656 {
01657 char *stringp;
01658 char *tonesubset;
01659 int f1, f2;
01660 int duration;
01661 int amplitude;
01662 int res;
01663 int i;
01664 int flags;
01665
01666 res = 0;
01667
01668 stringp = ast_strdupa(tonestring);
01669
01670 for (;tonestring;) {
01671 tonesubset = strsep(&stringp, ")");
01672 if (!tonesubset)
01673 break;
01674 if (sscanf(tonesubset, "(%d,%d,%d,%d", &f1, &f2, &duration, &litude) != 4)
01675 break;
01676 res = play_tone_pair(chan, f1, f2, duration, amplitude);
01677 if (res)
01678 break;
01679 }
01680 if (!res)
01681 res = play_tone_pair(chan, 0, 0, 100, 0);
01682
01683 if (!res)
01684 res = ast_waitstream(chan, "");
01685 ast_stopstream(chan);
01686
01687
01688
01689
01690
01691 for (i = 0; i < 20 ; i++) {
01692 flags = DAHDI_IOMUX_WRITEEMPTY | DAHDI_IOMUX_NOWAIT;
01693 res = ioctl(chan->fds[0], DAHDI_IOMUX, &flags);
01694 if (flags & DAHDI_IOMUX_WRITEEMPTY)
01695 break;
01696 if (ast_safe_sleep(chan, 50)) {
01697 res = -1;
01698 break;
01699 }
01700 }
01701
01702 return res;
01703 }
01704
01705
01706 static int sayfile(struct ast_channel *mychannel, const char *fname)
01707 {
01708 int res;
01709
01710 res = ast_streamfile(mychannel, fname, mychannel->language);
01711 if (!res)
01712 res = ast_waitstream(mychannel, "");
01713 else
01714 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
01715 ast_stopstream(mychannel);
01716 return res;
01717 }
01718
01719 static int saycharstr(struct ast_channel *mychannel, char *str)
01720 {
01721 int res;
01722
01723 res = ast_say_character_str(mychannel, str, NULL, mychannel->language);
01724 if (!res)
01725 res = ast_waitstream(mychannel, "");
01726 else
01727 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
01728 ast_stopstream(mychannel);
01729 return res;
01730 }
01731
01732 static int saynum(struct ast_channel *mychannel, int num)
01733 {
01734 int res;
01735 res = ast_say_number(mychannel, num, NULL, mychannel->language, NULL);
01736 if (!res)
01737 res = ast_waitstream(mychannel, "");
01738 else
01739 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
01740 ast_stopstream(mychannel);
01741 return res;
01742 }
01743
01744 static int saydigits(struct ast_channel *mychannel, int num)
01745 {
01746 int res;
01747 res = ast_say_digits(mychannel, num, NULL, mychannel->language);
01748 if (!res)
01749 res = ast_waitstream(mychannel, "");
01750 else
01751 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
01752 ast_stopstream(mychannel);
01753 return res;
01754 }
01755
01756
01757 static int telem_any(struct rpt *myrpt, struct ast_channel *chan, const char *entry)
01758 {
01759 int res;
01760 char c;
01761
01762 static int morsespeed;
01763 static int morsefreq;
01764 static int morseampl;
01765 static int morseidfreq = 0;
01766 static int morseidampl;
01767 static char mcat[] = MORSE;
01768
01769 res = 0;
01770
01771 if (!morseidfreq) {
01772 morsespeed = retrieve_astcfgint(myrpt, mcat, "speed", 5, 20, 20);
01773 morsefreq = retrieve_astcfgint(myrpt, mcat, "frequency", 300, 3000, 800);
01774 morseampl = retrieve_astcfgint(myrpt, mcat, "amplitude", 200, 8192, 4096);
01775 morseidampl = retrieve_astcfgint(myrpt, mcat, "idamplitude", 200, 8192, 2048);
01776 morseidfreq = retrieve_astcfgint(myrpt, mcat, "idfrequency", 300, 3000, 330);
01777 }
01778
01779
01780
01781 if (entry[0] == '|') {
01782 c = entry[1];
01783 if ((c >= 'a') && (c <= 'z'))
01784 c -= 0x20;
01785
01786 switch (c) {
01787 case 'I':
01788 res = send_morse(chan, entry + 2, morsespeed, morseidfreq, morseidampl);
01789 break;
01790 case 'M':
01791 res = send_morse(chan, entry + 2, morsespeed, morsefreq, morseampl);
01792 break;
01793 case 'T':
01794 res = send_tone_telemetry(chan, entry + 2);
01795 break;
01796 default:
01797 res = -1;
01798 }
01799 } else
01800 res = sayfile(chan, entry);
01801 return res;
01802 }
01803
01804
01805
01806
01807
01808
01809
01810 static int telem_lookup(struct rpt *myrpt, struct ast_channel *chan, const char *node, const char *name)
01811 {
01812 int res = 0;
01813 int i;
01814 const char *entry = NULL;
01815 const char *telemetry;
01816
01817
01818 if ((telemetry = ast_variable_retrieve(myrpt->cfg, node, TELEMETRY)))
01819 entry = ast_variable_retrieve(myrpt->cfg, telemetry, name);
01820
01821
01822
01823 if (!entry) {
01824
01825 for (i = 0; i < sizeof(tele_defs) / sizeof(struct telem_defaults); i++) {
01826 if (!strcasecmp(tele_defs[i].name, name))
01827 entry = tele_defs[i].value;
01828 }
01829 }
01830 if (entry) {
01831 if (!ast_strlen_zero(entry))
01832 telem_any(myrpt, chan, entry);
01833 } else {
01834 res = -1;
01835 }
01836 return res;
01837 }
01838
01839
01840
01841
01842
01843 static int get_wait_interval(struct rpt *myrpt, int type)
01844 {
01845 int interval = 1000;
01846 const char *wait_times = ast_variable_retrieve(myrpt->cfg, myrpt->name, "wait_times");
01847
01848 switch (type) {
01849 case DLY_TELEM:
01850 if (wait_times)
01851 interval = retrieve_astcfgint(myrpt, wait_times, "telemwait", 500, 5000, 1000);
01852 break;
01853 case DLY_ID:
01854 if (wait_times)
01855 interval = retrieve_astcfgint(myrpt, wait_times, "idwait", 250, 5000, 500);
01856 else
01857 interval = 500;
01858 break;
01859 case DLY_UNKEY:
01860 if (wait_times)
01861 interval = retrieve_astcfgint(myrpt, wait_times, "unkeywait", 500, 5000, 1000);
01862 break;
01863 case DLY_CALLTERM:
01864 if (wait_times)
01865 interval = retrieve_astcfgint(myrpt, wait_times, "calltermwait", 500, 5000, 1500);
01866 break;
01867 default:
01868 return 0;
01869 }
01870 return interval;
01871 }
01872
01873
01874
01875
01876
01877
01878
01879 static void wait_interval(struct rpt *myrpt, int type, struct ast_channel *chan)
01880 {
01881 int interval;
01882 interval = get_wait_interval(myrpt, type);
01883 if (debug)
01884 ast_log(LOG_NOTICE, " Delay interval = %d\n", interval);
01885 if (interval)
01886 ast_safe_sleep(chan, interval);
01887 if (debug)
01888 ast_log(LOG_NOTICE, "Delay complete\n");
01889 return;
01890 }
01891
01892
01893 static void *rpt_tele_thread(void *this)
01894 {
01895 struct dahdi_confinfo ci;
01896 int res = 0, haslink, hastx, hasremote, imdone = 0, unkeys_queued, x;
01897 struct rpt_tele *mytele = (struct rpt_tele *)this;
01898 struct rpt_tele *tlist;
01899 struct rpt *myrpt;
01900 struct rpt_link *l, *m, linkbase;
01901 struct ast_channel *mychannel;
01902 const char *p, *ct;
01903 struct timeval tv;
01904 struct ast_tm localtm;
01905 #ifdef APP_RPT_LOCK_DEBUG
01906 struct lockthread *t;
01907 #endif
01908
01909
01910 myrpt = mytele->rpt;
01911
01912
01913 rpt_mutex_lock(&myrpt->lock);
01914 rpt_mutex_unlock(&myrpt->lock);
01915
01916
01917 mychannel = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
01918 if (!mychannel) {
01919 ast_log(LOG_WARNING, "rpt: unable to obtain pseudo channel\n");
01920 rpt_mutex_lock(&myrpt->lock);
01921 remque((struct qelem *)mytele);
01922 ast_log(LOG_NOTICE, "Telemetry thread aborted at line %d, mode: %d\n", __LINE__, mytele->mode);
01923 rpt_mutex_unlock(&myrpt->lock);
01924 ast_free(mytele);
01925 pthread_exit(NULL);
01926 }
01927 rpt_mutex_lock(&myrpt->lock);
01928 mytele->chan = mychannel;
01929 rpt_mutex_unlock(&myrpt->lock);
01930
01931
01932 ci.chan = 0;
01933
01934
01935
01936 ci.confno = (((mytele->mode == ID) || (mytele->mode == IDTALKOVER) || (mytele->mode == UNKEY) ||
01937 (mytele->mode == TAILMSG)) ?
01938 myrpt->txconf : myrpt->conf);
01939 ci.confmode = DAHDI_CONF_CONFANN;
01940
01941 if (ioctl(mychannel->fds[0], DAHDI_SETCONF, &ci) == -1) {
01942 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
01943 rpt_mutex_lock(&myrpt->lock);
01944 remque((struct qelem *)mytele);
01945 rpt_mutex_unlock(&myrpt->lock);
01946 ast_log(LOG_NOTICE, "Telemetry thread aborted at line %d, mode: %d\n", __LINE__, mytele->mode);
01947 ast_free(mytele);
01948 ast_hangup(mychannel);
01949 pthread_exit(NULL);
01950 }
01951 ast_stopstream(mychannel);
01952 switch (mytele->mode) {
01953 case ID:
01954 case ID1:
01955
01956 wait_interval(myrpt, (mytele->mode == ID) ? DLY_ID : DLY_TELEM, mychannel);
01957 res = telem_any(myrpt, mychannel, myrpt->p.ident);
01958 imdone=1;
01959 break;
01960
01961 case TAILMSG:
01962 res = ast_streamfile(mychannel, myrpt->p.tailmsg.msgs[myrpt->tailmessagen], mychannel->language);
01963 break;
01964
01965 case IDTALKOVER:
01966 p = ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover");
01967 if (p)
01968 res = telem_any(myrpt, mychannel, p);
01969 imdone = 1;
01970 break;
01971 case PROC:
01972
01973 wait_interval(myrpt, DLY_TELEM, mychannel);
01974 res = telem_lookup(myrpt, mychannel, myrpt->name, "patchup");
01975 if (res < 0) {
01976 res = ast_streamfile(mychannel, "rpt/callproceeding", mychannel->language);
01977 }
01978 break;
01979 case TERM:
01980
01981 wait_interval(myrpt, DLY_CALLTERM, mychannel);
01982 res = telem_lookup(myrpt, mychannel, myrpt->name, "patchdown");
01983 if (res < 0) {
01984 res = ast_streamfile(mychannel, "rpt/callterminated", mychannel->language);
01985 }
01986 break;
01987 case COMPLETE:
01988
01989 wait_interval(myrpt, DLY_TELEM, mychannel);
01990 res = telem_lookup(myrpt, mychannel, myrpt->name, "functcomplete");
01991 break;
01992 case MACRO_NOTFOUND:
01993
01994 wait_interval(myrpt, DLY_TELEM, mychannel);
01995 res = ast_streamfile(mychannel, "rpt/macro_notfound", mychannel->language);
01996 break;
01997 case GOSUB_NOTFOUND:
01998
01999 wait_interval(myrpt, DLY_TELEM, mychannel);
02000 res = ast_streamfile(mychannel, "rpt/gosub_notfound", mychannel->language);
02001 break;
02002 case MACRO_BUSY:
02003
02004 wait_interval(myrpt, DLY_TELEM, mychannel);
02005 res = ast_streamfile(mychannel, "rpt/macro_busy", mychannel->language);
02006 break;
02007 case GOSUB_BUSY:
02008
02009 wait_interval(myrpt, DLY_TELEM, mychannel);
02010 res = ast_streamfile(mychannel, "rpt/gosub_busy", mychannel->language);
02011 break;
02012 case UNKEY:
02013 if (myrpt->patchnoct && myrpt->callmode) {
02014 imdone = 1;
02015 break;
02016 }
02017
02018
02019
02020
02021
02022 x = get_wait_interval(myrpt, DLY_UNKEY);
02023 rpt_mutex_lock(&myrpt->lock);
02024 myrpt->unkeytocttimer = x;
02025 rpt_mutex_unlock(&myrpt->lock);
02026
02027
02028
02029
02030
02031 tlist = myrpt->tele.next;
02032 unkeys_queued = 0;
02033 if (tlist != &myrpt->tele) {
02034 rpt_mutex_lock(&myrpt->lock);
02035 while (tlist != &myrpt->tele) {
02036 if (tlist->mode == UNKEY)
02037 unkeys_queued++;
02038 tlist = tlist->next;
02039 }
02040 rpt_mutex_unlock(&myrpt->lock);
02041 }
02042 if (unkeys_queued > 1) {
02043 imdone = 1;
02044 break;
02045 }
02046
02047
02048
02049 while (myrpt->unkeytocttimer) {
02050 int ctint;
02051 if (myrpt->unkeytocttimer > 100)
02052 ctint = 100;
02053 else
02054 ctint = myrpt->unkeytocttimer;
02055 ast_safe_sleep(mychannel, ctint);
02056 rpt_mutex_lock(&myrpt->lock);
02057 if (myrpt->unkeytocttimer < ctint)
02058 myrpt->unkeytocttimer = 0;
02059 else
02060 myrpt->unkeytocttimer -= ctint;
02061 rpt_mutex_unlock(&myrpt->lock);
02062 }
02063
02064
02065
02066
02067
02068 if (myrpt->keyed) {
02069 imdone = 1;
02070 break;
02071 }
02072
02073 rpt_mutex_lock(&myrpt->lock);
02074 myrpt->dailykerchunks++;
02075 myrpt->totalkerchunks++;
02076 rpt_mutex_unlock(&myrpt->lock);
02077
02078 haslink = 0;
02079 hastx = 0;
02080 hasremote = 0;
02081 l = myrpt->links.next;
02082 if (l != &myrpt->links) {
02083 rpt_mutex_lock(&myrpt->lock);
02084 while (l != &myrpt->links) {
02085 if (l->name[0] == '0') {
02086 l = l->next;
02087 continue;
02088 }
02089 haslink = 1;
02090 if (l->mode) {
02091 hastx++;
02092 if (l->isremote)
02093 hasremote++;
02094 }
02095 l = l->next;
02096 }
02097 rpt_mutex_unlock(&myrpt->lock);
02098 }
02099 if (haslink) {
02100 res = telem_lookup(myrpt, mychannel, myrpt->name, (!hastx) ? "remotemon" : "remotetx");
02101 if (res)
02102 ast_log(LOG_WARNING, "telem_lookup:remotexx failed on %s\n", mychannel->name);
02103
02104
02105 if (myrpt->cmdnode[0]) {
02106 ast_safe_sleep(mychannel, 200);
02107 res = telem_lookup(myrpt, mychannel, myrpt->name, "cmdmode");
02108 if (res)
02109 ast_log(LOG_WARNING, "telem_lookup:cmdmode failed on %s\n", mychannel->name);
02110 ast_stopstream(mychannel);
02111 }
02112 } else if ((ct = ast_variable_retrieve(myrpt->cfg, myrpt->name, "unlinkedct"))) {
02113 res = telem_lookup(myrpt, mychannel, myrpt->name, ct);
02114 if (res)
02115 ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);
02116 }
02117 if (hasremote && (!myrpt->cmdnode[0])) {
02118
02119 ci.chan = 0;
02120 ci.confno = myrpt->conf;
02121 ci.confmode = DAHDI_CONF_CONFANN;
02122
02123 if (ioctl(mychannel->fds[0], DAHDI_SETCONF, &ci) == -1) {
02124 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02125 rpt_mutex_lock(&myrpt->lock);
02126 remque((struct qelem *)mytele);
02127 rpt_mutex_unlock(&myrpt->lock);
02128 ast_log(LOG_NOTICE, "Telemetry thread aborted at line %d, mode: %d\n", __LINE__, mytele->mode);
02129 ast_free(mytele);
02130 ast_hangup(mychannel);
02131 pthread_exit(NULL);
02132 }
02133 if ((ct = ast_variable_retrieve(myrpt->cfg, myrpt->name, "remotect"))) {
02134 ast_safe_sleep(mychannel, 200);
02135 res = telem_lookup(myrpt, mychannel, myrpt->name, ct);
02136 if (res)
02137 ast_log(LOG_WARNING, "telem_lookup:ctx failed on %s\n", mychannel->name);
02138 }
02139 }
02140 #ifdef _MDC_DECODE_H_
02141 if (myrpt->lastunit) {
02142 char mystr[10];
02143
02144 ast_safe_sleep(mychannel, 200);
02145
02146 ci.chan = 0;
02147 ci.confno = myrpt->txconf;
02148 ci.confmode = DAHDI_CONF_CONFANN;
02149
02150 if (ioctl(mychannel->fds[0], DAHDI_SETCONF, &ci) == -1) {
02151 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02152 rpt_mutex_lock(&myrpt->lock);
02153 remque((struct qelem *)mytele);
02154 rpt_mutex_unlock(&myrpt->lock);
02155 ast_log(LOG_NOTICE, "Telemetry thread aborted at line %d, mode: %d\n", __LINE__, mytele->mode);
02156 ast_free(mytele);
02157 ast_hangup(mychannel);
02158 pthread_exit(NULL);
02159 }
02160 snprintf(mystr, sizeof(mystr), "%04x", myrpt->lastunit);
02161 myrpt->lastunit = 0;
02162 ast_say_character_str(mychannel, mystr, NULL, mychannel->language);
02163 break;
02164 }
02165 #endif
02166 imdone = 1;
02167 break;
02168 case REMDISC:
02169
02170 wait_interval(myrpt, DLY_TELEM, mychannel);
02171 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
02172 if (!res)
02173 res = ast_waitstream(mychannel, "");
02174 else
02175 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02176 ast_stopstream(mychannel);
02177 ast_say_character_str(mychannel, mytele->mylink.name, NULL, mychannel->language);
02178 res = ast_streamfile(mychannel, ((mytele->mylink.connected) ?
02179 "rpt/remote_disc" : "rpt/remote_busy"), mychannel->language);
02180 break;
02181 case REMALREADY:
02182
02183 wait_interval(myrpt, DLY_TELEM, mychannel);
02184 res = ast_streamfile(mychannel, "rpt/remote_already", mychannel->language);
02185 break;
02186 case REMNOTFOUND:
02187
02188 wait_interval(myrpt, DLY_TELEM, mychannel);
02189 res = ast_streamfile(mychannel, "rpt/remote_notfound", mychannel->language);
02190 break;
02191 case REMGO:
02192
02193 wait_interval(myrpt, DLY_TELEM, mychannel);
02194 res = ast_streamfile(mychannel, "rpt/remote_go", mychannel->language);
02195 break;
02196 case CONNECTED:
02197
02198 wait_interval(myrpt, DLY_TELEM, mychannel);
02199 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
02200 if (!res)
02201 res = ast_waitstream(mychannel, "");
02202 else
02203 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02204 ast_stopstream(mychannel);
02205 ast_say_character_str(mychannel, mytele->mylink.name, NULL, mychannel->language);
02206 res = ast_streamfile(mychannel, "rpt/connected", mychannel->language);
02207 break;
02208 case CONNFAIL:
02209 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
02210 if (!res)
02211 res = ast_waitstream(mychannel, "");
02212 else
02213 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02214 ast_stopstream(mychannel);
02215 ast_say_character_str(mychannel, mytele->mylink.name, NULL, mychannel->language);
02216 res = ast_streamfile(mychannel, "rpt/connection_failed", mychannel->language);
02217 break;
02218 case STATUS:
02219
02220 wait_interval(myrpt, DLY_TELEM, mychannel);
02221 hastx = 0;
02222 linkbase.next = &linkbase;
02223 linkbase.prev = &linkbase;
02224 rpt_mutex_lock(&myrpt->lock);
02225
02226 l = myrpt->links.next;
02227 while (l != &myrpt->links) {
02228 if (l->name[0] == '0') {
02229 l = l->next;
02230 continue;
02231 }
02232 m = ast_malloc(sizeof(*m));
02233 if (!m) {
02234 ast_log(LOG_WARNING, "Cannot alloc memory on %s\n", mychannel->name);
02235 remque((struct qelem *)mytele);
02236 rpt_mutex_unlock(&myrpt->lock);
02237 ast_log(LOG_NOTICE, "Telemetry thread aborted at line %d, mode: %d\n", __LINE__, mytele->mode);
02238 ast_free(mytele);
02239 ast_hangup(mychannel);
02240 pthread_exit(NULL);
02241 }
02242 memcpy(m, l, sizeof(struct rpt_link));
02243 m->next = m->prev = NULL;
02244 insque((struct qelem *)m, (struct qelem *)linkbase.next);
02245 l = l->next;
02246 }
02247 rpt_mutex_unlock(&myrpt->lock);
02248 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
02249 if (!res)
02250 res = ast_waitstream(mychannel, "");
02251 else
02252 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02253 ast_stopstream(mychannel);
02254 ast_say_character_str(mychannel, myrpt->name, NULL, mychannel->language);
02255 if (!res)
02256 res = ast_waitstream(mychannel, "");
02257 else
02258 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02259 ast_stopstream(mychannel);
02260 if (myrpt->callmode) {
02261 hastx = 1;
02262 res = ast_streamfile(mychannel, "rpt/autopatch_on", mychannel->language);
02263 if (!res)
02264 res = ast_waitstream(mychannel, "");
02265 else
02266 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02267 ast_stopstream(mychannel);
02268 }
02269 l = linkbase.next;
02270 while (l != &linkbase) {
02271 hastx = 1;
02272 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
02273 if (!res)
02274 res = ast_waitstream(mychannel, "");
02275 else
02276 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02277 ast_stopstream(mychannel);
02278 ast_say_character_str(mychannel, l->name, NULL, mychannel->language);
02279 if (!res)
02280 res = ast_waitstream(mychannel, "");
02281 else
02282 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02283 ast_stopstream(mychannel);
02284 res = ast_streamfile(mychannel, ((l->mode) ?
02285 "rpt/tranceive" : "rpt/monitor"), mychannel->language);
02286 if (!res)
02287 res = ast_waitstream(mychannel, "");
02288 else
02289 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02290 ast_stopstream(mychannel);
02291 l = l->next;
02292 }
02293 if (!hastx) {
02294 res = ast_streamfile(mychannel, "rpt/repeat_only", mychannel->language);
02295 if (!res)
02296 res = ast_waitstream(mychannel, "");
02297 else
02298 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02299 ast_stopstream(mychannel);
02300 }
02301
02302 l = linkbase.next;
02303 while (l != &linkbase) {
02304 m = l;
02305 l = l->next;
02306 remque((struct qelem *)m);
02307 ast_free(m);
02308 }
02309 imdone = 1;
02310 break;
02311
02312 case LASTNODEKEY:
02313 rpt_mutex_lock(&myrpt->lock);
02314 if (myrpt->lastnodewhichkeyedusup)
02315 p = ast_strdupa(myrpt->lastnodewhichkeyedusup);
02316 else
02317 p = NULL;
02318 rpt_mutex_unlock(&myrpt->lock);
02319 if (!p) {
02320 imdone = 1;
02321 break;
02322 }
02323 wait_interval(myrpt, DLY_TELEM, mychannel);
02324 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
02325 if (!res)
02326 res = ast_waitstream(mychannel, "");
02327 else
02328 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02329 ast_stopstream(mychannel);
02330 ast_say_character_str(mychannel, p, NULL, mychannel->language);
02331 if (!res)
02332 res = ast_waitstream(mychannel, "");
02333 else
02334 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02335 ast_stopstream(mychannel);
02336 imdone = 1;
02337 break;
02338
02339 case TIMEOUT:
02340 res = ast_streamfile(mychannel, "rpt/node", mychannel->language);
02341 if (!res)
02342 res = ast_waitstream(mychannel, "");
02343 else
02344 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02345 ast_stopstream(mychannel);
02346 ast_say_character_str(mychannel, myrpt->name, NULL, mychannel->language);
02347 res = ast_streamfile(mychannel, "rpt/timeout", mychannel->language);
02348 break;
02349
02350 case STATS_TIME:
02351 wait_interval(myrpt, DLY_TELEM, mychannel);
02352 tv = ast_tvnow();
02353 ast_localtime(&tv, &localtm, NULL);
02354
02355 if ((localtm.tm_hour >= 0) && (localtm.tm_hour < 12))
02356 p = "rpt/goodmorning";
02357 else if ((localtm.tm_hour >= 12) && (localtm.tm_hour < 18))
02358 p = "rpt/goodafternoon";
02359 else
02360 p = "rpt/goodevening";
02361 if (sayfile(mychannel, p) == -1) {
02362 imdone = 1;
02363 break;
02364 }
02365
02366 if (sayfile(mychannel, "rpt/thetimeis") == -1) {
02367 imdone = 1;
02368 break;
02369 }
02370
02371 res = ast_say_time(mychannel, tv.tv_sec, "", mychannel->language);
02372 if (!res)
02373 res = ast_waitstream(mychannel, "");
02374 ast_stopstream(mychannel);
02375 imdone = 1;
02376 break;
02377 case STATS_VERSION:
02378 wait_interval(myrpt, DLY_TELEM, mychannel);
02379
02380 if (sayfile(mychannel, "rpt/version") == -1) {
02381 imdone = 1;
02382 break;
02383 }
02384 if (!res)
02385 ast_say_number(mychannel, vmajor, "", mychannel->language, (char *) NULL);
02386 if (!res)
02387 res = ast_waitstream(mychannel, "");
02388 ast_stopstream(mychannel);
02389 if (saycharstr(mychannel, ".") == -1) {
02390 imdone = 1;
02391 break;
02392 }
02393 if (!res)
02394 ast_say_number(mychannel, vminor, "", mychannel->language, (char *) NULL);
02395 if (!res) {
02396 res = ast_waitstream(mychannel, "");
02397 ast_stopstream(mychannel);
02398 } else
02399 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02400 imdone = 1;
02401 break;
02402 case ARB_ALPHA:
02403 wait_interval(myrpt, DLY_TELEM, mychannel);
02404 if (mytele->param)
02405 saycharstr(mychannel, mytele->param);
02406 imdone = 1;
02407 break;
02408 case REV_PATCH:
02409 wait_interval(myrpt, DLY_TELEM, mychannel);
02410 if (mytele->param) {
02411
02412 char *tpl_working, *tpl_current;
02413 char *tmp[100], *myparm;
02414 int looptemp=0, i = 0, dres = 0;
02415
02416 tpl_working = ast_strdupa(mytele->param);
02417 myparm = strsep(&tpl_working, ",");
02418 tpl_current = strsep(&tpl_working, ":");
02419
02420 while (tpl_current && looptemp < sizeof(tmp)) {
02421 tmp[looptemp] = tpl_current;
02422 looptemp++;
02423 tpl_current = strsep(&tpl_working, ":");
02424 }
02425
02426 for (i = 0; i < looptemp; i++) {
02427 if (!strcmp(tmp[i], "PARKED")) {
02428 ast_say_digits(mychannel, atoi(myparm), "", mychannel->language);
02429 } else if (!strcmp(tmp[i], "NODE")) {
02430 ast_say_digits(mychannel, atoi(myrpt->name), "", mychannel->language);
02431 } else {
02432 dres = ast_streamfile(mychannel, tmp[i], mychannel->language);
02433 if (!dres) {
02434 dres = ast_waitstream(mychannel, "");
02435 } else {
02436 ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", tmp[i], mychannel->name);
02437 dres = 0;
02438 }
02439 }
02440 }
02441 }
02442 imdone = 1;
02443 break;
02444 case TEST_TONE:
02445 imdone = 1;
02446 myrpt->stopgen = 0;
02447 if ((res = ast_tonepair_start(mychannel, 1004.0, 0, 99999999, 7200.0)))
02448 break;
02449 while (mychannel->generatordata && (!myrpt->stopgen)) {
02450 if (ast_safe_sleep(mychannel, 1)) break;
02451 imdone = 1;
02452 }
02453 break;
02454 default:
02455 break;
02456 }
02457
02458 myrpt->stopgen = 0;
02459 if (!imdone) {
02460 if (!res)
02461 res = ast_waitstream(mychannel, "");
02462 else {
02463 ast_log(LOG_WARNING, "ast_streamfile failed on %s\n", mychannel->name);
02464 res = 0;
02465 }
02466 }
02467 ast_stopstream(mychannel);
02468 rpt_mutex_lock(&myrpt->lock);
02469 if (mytele->mode == TAILMSG) {
02470 if (!res) {
02471 myrpt->tailmessagen++;
02472 if (myrpt->tailmessagen >= myrpt->p.tailmsg.argc)
02473 myrpt->tailmessagen = 0;
02474 } else {
02475 myrpt->tmsgtimer = myrpt->p.tailsquashedtime;
02476 }
02477 }
02478 remque((struct qelem *)mytele);
02479 rpt_mutex_unlock(&myrpt->lock);
02480 ast_free(mytele);
02481 ast_hangup(mychannel);
02482 #ifdef APP_RPT_LOCK_DEBUG
02483 sleep(5);
02484 ast_mutex_lock(&locklock);
02485 t = get_lockthread(pthread_self());
02486 if (t)
02487 memset(t, 0, sizeof(struct lockthread));
02488 ast_mutex_unlock(&locklock);
02489 #endif
02490 pthread_exit(NULL);
02491 }
02492
02493 static void rpt_telemetry(struct rpt *myrpt, int mode, void *data)
02494 {
02495 struct rpt_tele *tele;
02496 struct rpt_link *mylink = (struct rpt_link *) data;
02497 int res;
02498
02499 tele = ast_calloc(1, sizeof(*tele));
02500 if (!tele) {
02501 ast_log(LOG_WARNING, "Unable to allocate memory\n");
02502 pthread_exit(NULL);
02503 }
02504 tele->rpt = myrpt;
02505 tele->mode = mode;
02506 rpt_mutex_lock(&myrpt->lock);
02507 if ((mode == CONNFAIL) || (mode == REMDISC) || (mode == CONNECTED)) {
02508 if (mylink) {
02509 memcpy(&tele->mylink, mylink, sizeof(struct rpt_link));
02510 }
02511 } else if ((mode == ARB_ALPHA) || (mode == REV_PATCH)) {
02512 ast_copy_string(tele->param, (char *) data, sizeof(tele->param));
02513 }
02514 insque((struct qelem *)tele, (struct qelem *)myrpt->tele.next);
02515 rpt_mutex_unlock(&myrpt->lock);
02516 res = ast_pthread_create_detached(&tele->threadid, NULL, rpt_tele_thread, (void *) tele);
02517 if (res != 0) {
02518 rpt_mutex_lock(&myrpt->lock);
02519 remque((struct qlem *) tele);
02520 rpt_mutex_unlock(&myrpt->lock);
02521 ast_log(LOG_WARNING, "Could not create telemetry thread: %s\n", strerror(res));
02522 }
02523 return;
02524 }
02525
02526 static void *rpt_call(void *this)
02527 {
02528 struct dahdi_confinfo ci;
02529 struct rpt *myrpt = (struct rpt *)this;
02530 int res;
02531 struct ast_frame wf;
02532 int stopped, congstarted, dialtimer, lastcidx, aborted;
02533 struct ast_channel *mychannel, *genchannel;
02534
02535 myrpt->mydtmf = 0;
02536
02537 mychannel = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
02538 if (!mychannel) {
02539 ast_log(LOG_ERROR, "rpt: unable to obtain pseudo channel\n");
02540 pthread_exit(NULL);
02541 }
02542 ci.chan = 0;
02543 ci.confno = myrpt->conf;
02544 ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
02545 | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER;
02546
02547 if (ioctl(mychannel->fds[0], DAHDI_SETCONF, &ci) == -1) {
02548 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02549 ast_hangup(mychannel);
02550 myrpt->callmode = 0;
02551 pthread_exit(NULL);
02552 }
02553
02554 genchannel = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
02555 if (!genchannel) {
02556 ast_log(LOG_ERROR, "rpt: unable to obtain pseudo channel\n");
02557 ast_hangup(mychannel);
02558 pthread_exit(NULL);
02559 }
02560 ci.chan = 0;
02561 ci.confno = myrpt->conf;
02562 ci.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER
02563 | DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER;
02564
02565 if (ioctl(genchannel->fds[0], DAHDI_SETCONF, &ci) == -1) {
02566 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02567 ast_hangup(mychannel);
02568 ast_hangup(genchannel);
02569 myrpt->callmode = 0;
02570 pthread_exit(NULL);
02571 }
02572 if (myrpt->p.tonezone && (tone_zone_set_zone(mychannel->fds[0], myrpt->p.tonezone) == -1)) {
02573 ast_log(LOG_WARNING, "Unable to set tone zone %s\n", myrpt->p.tonezone);
02574 ast_hangup(mychannel);
02575 ast_hangup(genchannel);
02576 myrpt->callmode = 0;
02577 pthread_exit(NULL);
02578 }
02579 if (myrpt->p.tonezone && (tone_zone_set_zone(genchannel->fds[0], myrpt->p.tonezone) == -1)) {
02580 ast_log(LOG_WARNING, "Unable to set tone zone %s\n", myrpt->p.tonezone);
02581 ast_hangup(mychannel);
02582 ast_hangup(genchannel);
02583 myrpt->callmode = 0;
02584 pthread_exit(NULL);
02585 }
02586
02587 if ((!myrpt->patchquiet) && (tone_zone_play_tone(mychannel->fds[0], DAHDI_TONE_DIALTONE) < 0)) {
02588 ast_log(LOG_WARNING, "Cannot start dialtone\n");
02589 ast_hangup(mychannel);
02590 ast_hangup(genchannel);
02591 myrpt->callmode = 0;
02592 pthread_exit(NULL);
02593 }
02594 stopped = 0;
02595 congstarted = 0;
02596 dialtimer = 0;
02597 lastcidx = 0;
02598 aborted = 0;
02599
02600 while ((myrpt->callmode == 1) || (myrpt->callmode == 4)) {
02601 if ((myrpt->patchdialtime) && (myrpt->callmode == 1) && (myrpt->cidx != lastcidx)) {
02602 dialtimer = 0;
02603 lastcidx = myrpt->cidx;
02604 }
02605
02606 if ((myrpt->patchdialtime) && (dialtimer >= myrpt->patchdialtime)) {
02607 rpt_mutex_lock(&myrpt->lock);
02608 aborted = 1;
02609 myrpt->callmode = 0;
02610 rpt_mutex_unlock(&myrpt->lock);
02611 break;
02612 }
02613
02614 if ((!myrpt->patchquiet) && (!stopped) && (myrpt->callmode == 1) && (myrpt->cidx > 0)) {
02615 stopped = 1;
02616
02617 tone_zone_play_tone(mychannel->fds[0], -1);
02618 }
02619 if (myrpt->callmode == 4) {
02620 if (!congstarted) {
02621 congstarted = 1;
02622
02623 tone_zone_play_tone(mychannel->fds[0], DAHDI_TONE_CONGESTION);
02624 }
02625 }
02626 res = ast_safe_sleep(mychannel, MSWAIT);
02627 if (res < 0) {
02628 ast_hangup(mychannel);
02629 ast_hangup(genchannel);
02630 rpt_mutex_lock(&myrpt->lock);
02631 myrpt->callmode = 0;
02632 rpt_mutex_unlock(&myrpt->lock);
02633 pthread_exit(NULL);
02634 }
02635 dialtimer += MSWAIT;
02636 }
02637
02638 tone_zone_play_tone(mychannel->fds[0], -1);
02639
02640 if (!myrpt->callmode) {
02641 ast_hangup(mychannel);
02642 ast_hangup(genchannel);
02643 rpt_mutex_lock(&myrpt->lock);
02644 myrpt->callmode = 0;
02645 rpt_mutex_unlock(&myrpt->lock);
02646 if ((!myrpt->patchquiet) && aborted)
02647 rpt_telemetry(myrpt, TERM, NULL);
02648 pthread_exit(NULL);
02649 }
02650
02651 if (myrpt->p.ourcallerid && *myrpt->p.ourcallerid) {
02652 char *name, *loc, *instr;
02653 instr = ast_strdup(myrpt->p.ourcallerid);
02654 if (instr) {
02655 ast_callerid_parse(instr, &name, &loc);
02656 if (loc) {
02657 if (mychannel->cid.cid_num)
02658 ast_free(mychannel->cid.cid_num);
02659 mychannel->cid.cid_num = ast_strdup(loc);
02660 }
02661 if (name) {
02662 if (mychannel->cid.cid_name)
02663 ast_free(mychannel->cid.cid_name);
02664 mychannel->cid.cid_name = ast_strdup(name);
02665 }
02666 ast_free(instr);
02667 }
02668 }
02669
02670 ast_copy_string(mychannel->exten, myrpt->exten, sizeof(mychannel->exten));
02671 ast_copy_string(mychannel->context, myrpt->patchcontext, sizeof(mychannel->context));
02672
02673 if (myrpt->p.acctcode)
02674 ast_string_field_set(mychannel, accountcode, myrpt->p.acctcode);
02675 mychannel->priority = 1;
02676 ast_channel_undefer_dtmf(mychannel);
02677 if (ast_pbx_start(mychannel) < 0) {
02678 ast_log(LOG_WARNING, "Unable to start PBX!!\n");
02679 ast_hangup(mychannel);
02680 ast_hangup(genchannel);
02681 rpt_mutex_lock(&myrpt->lock);
02682 myrpt->callmode = 0;
02683 rpt_mutex_unlock(&myrpt->lock);
02684 pthread_exit(NULL);
02685 }
02686 usleep(10000);
02687 rpt_mutex_lock(&myrpt->lock);
02688 myrpt->callmode = 3;
02689
02690 ci.chan = 0;
02691 ci.confno = myrpt->conf;
02692 ci.confmode = (myrpt->p.duplex == 2) ? DAHDI_CONF_CONFANNMON :
02693 (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
02694
02695 if (ioctl(myrpt->pchannel->fds[0], DAHDI_SETCONF, &ci) == -1) {
02696 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02697 ast_hangup(mychannel);
02698 ast_hangup(genchannel);
02699 myrpt->callmode = 0;
02700 pthread_exit(NULL);
02701 }
02702 while (myrpt->callmode) {
02703 if ((!mychannel->pbx) && (myrpt->callmode != 4)) {
02704 if (myrpt->patchfarenddisconnect) {
02705 myrpt->callmode = 0;
02706 if (!myrpt->patchquiet) {
02707 rpt_mutex_unlock(&myrpt->lock);
02708 rpt_telemetry(myrpt, TERM, NULL);
02709 rpt_mutex_lock(&myrpt->lock);
02710 }
02711 } else {
02712 myrpt->callmode = 4;
02713 rpt_mutex_unlock(&myrpt->lock);
02714
02715 tone_zone_play_tone(genchannel->fds[0], DAHDI_TONE_CONGESTION);
02716 rpt_mutex_lock(&myrpt->lock);
02717 }
02718 }
02719 if (myrpt->mydtmf) {
02720 wf.frametype = AST_FRAME_DTMF;
02721 wf.subclass = myrpt->mydtmf;
02722 wf.offset = 0;
02723 wf.mallocd = 0;
02724 wf.data = NULL;
02725 wf.datalen = 0;
02726 wf.samples = 0;
02727 rpt_mutex_unlock(&myrpt->lock);
02728 ast_write(genchannel, &wf);
02729 rpt_mutex_lock(&myrpt->lock);
02730 myrpt->mydtmf = 0;
02731 }
02732 rpt_mutex_unlock(&myrpt->lock);
02733 usleep(MSWAIT * 1000);
02734 rpt_mutex_lock(&myrpt->lock);
02735 }
02736 rpt_mutex_unlock(&myrpt->lock);
02737 tone_zone_play_tone(genchannel->fds[0], -1);
02738 if (mychannel->pbx)
02739 ast_softhangup(mychannel, AST_SOFTHANGUP_DEV);
02740 ast_hangup(genchannel);
02741 rpt_mutex_lock(&myrpt->lock);
02742 myrpt->callmode = 0;
02743 rpt_mutex_unlock(&myrpt->lock);
02744
02745 ci.chan = 0;
02746 ci.confno = myrpt->conf;
02747 ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
02748 (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
02749
02750 if (ioctl(myrpt->pchannel->fds[0], DAHDI_SETCONF, &ci) == -1) {
02751 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02752 }
02753 pthread_exit(NULL);
02754 }
02755
02756 static void send_link_dtmf(struct rpt *myrpt, char c)
02757 {
02758 char str[300];
02759 struct ast_frame wf;
02760 struct rpt_link *l;
02761
02762 snprintf(str, sizeof(str), "D %s %s %d %c", myrpt->cmdnode, myrpt->name, ++(myrpt->dtmfidx), c);
02763 wf.frametype = AST_FRAME_TEXT;
02764 wf.subclass = 0;
02765 wf.offset = 0;
02766 wf.mallocd = 1;
02767 wf.datalen = strlen(str) + 1;
02768 wf.samples = 0;
02769 l = myrpt->links.next;
02770
02771 while (l != &myrpt->links) {
02772 if (l->name[0] == '0') {
02773 l = l->next;
02774 continue;
02775 }
02776
02777 if (!strcmp(l->name, myrpt->cmdnode)) {
02778 wf.data = ast_strdup(str);
02779 if (l->chan)
02780 ast_write(l->chan, &wf);
02781 return;
02782 }
02783 l = l->next;
02784 }
02785 l = myrpt->links.next;
02786
02787 while (l != &myrpt->links) {
02788 wf.data = ast_strdup(str);
02789 if (l->chan)
02790 ast_write(l->chan, &wf);
02791 l = l->next;
02792 }
02793 return;
02794 }
02795
02796
02797
02798
02799
02800 static int function_ilink(struct rpt *myrpt, char *param, char *digits, int command_source, struct rpt_link *mylink)
02801 {
02802 const char *val;
02803 char *s, *tele;
02804 char deststr[300] = "", modechange = 0;
02805 char digitbuf[MAXNODESTR];
02806 struct rpt_link *l;
02807 int reconnects = 0;
02808 struct dahdi_confinfo ci;
02809 AST_DECLARE_APP_ARGS(args,
02810 AST_APP_ARG(s1);
02811 AST_APP_ARG(s2);
02812 );
02813
02814 if (!param)
02815 return DC_ERROR;
02816
02817 if (!myrpt->enable)
02818 return DC_ERROR;
02819
02820 ast_copy_string(digitbuf, digits, sizeof(digitbuf));
02821 ast_debug(1, "@@@@ ilink param = %s, digitbuf = %s\n", S_OR(param, "(null)"), digitbuf);
02822
02823 switch (myatoi(param)) {
02824 case 1:
02825 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
02826 strcpy(digitbuf, myrpt->lastlinknode);
02827 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
02828 if (!val) {
02829 if (strlen(digitbuf) >= myrpt->longestnode)
02830 return DC_ERROR;
02831 break;
02832 }
02833 rpt_mutex_lock(&myrpt->lock);
02834 l = myrpt->links.next;
02835
02836 while (l != &myrpt->links) {
02837 if (l->name[0] == '0') {
02838 l = l->next;
02839 continue;
02840 }
02841
02842 if (!strcmp(l->name, digitbuf))
02843 break;
02844 l = l->next;
02845 }
02846 if (l != &myrpt->links) {
02847 struct ast_frame wf;
02848 ast_copy_string(myrpt->lastlinknode, digitbuf, MAXNODESTR);
02849 l->retries = MAX_RETRIES + 1;
02850 l->disced = 1;
02851 rpt_mutex_unlock(&myrpt->lock);
02852 wf.frametype = AST_FRAME_TEXT;
02853 wf.subclass = 0;
02854 wf.offset = 0;
02855 wf.mallocd = 1;
02856 wf.datalen = strlen(discstr) + 1;
02857 wf.samples = 0;
02858 wf.data = ast_strdup(discstr);
02859 if (l->chan) {
02860 ast_write(l->chan, &wf);
02861 if (ast_safe_sleep(l->chan, 250) == -1)
02862 return DC_ERROR;
02863 ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
02864 }
02865 rpt_telemetry(myrpt, COMPLETE, NULL);
02866 return DC_COMPLETE;
02867 }
02868 rpt_mutex_unlock(&myrpt->lock);
02869 return DC_COMPLETE;
02870 case 2:
02871 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
02872 strcpy(digitbuf, myrpt->lastlinknode);
02873 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
02874 if (!val) {
02875 if (strlen(digitbuf) >= myrpt->longestnode)
02876 return DC_ERROR;
02877 break;
02878 }
02879 s = ast_strdupa(val);
02880 AST_STANDARD_APP_ARGS(args, s);
02881 rpt_mutex_lock(&myrpt->lock);
02882 l = myrpt->links.next;
02883
02884 while (l != &myrpt->links) {
02885 if (l->name[0] == '0') {
02886 l = l->next;
02887 continue;
02888 }
02889
02890 if (!strcmp(l->name, digitbuf))
02891 break;
02892 l = l->next;
02893 }
02894
02895 if (l != &myrpt->links) {
02896
02897 if ((!l->mode) || (!l->chan)) {
02898 rpt_mutex_unlock(&myrpt->lock);
02899 rpt_telemetry(myrpt, REMALREADY, NULL);
02900 return DC_COMPLETE;
02901 }
02902 reconnects = l->reconnects;
02903 rpt_mutex_unlock(&myrpt->lock);
02904 if (l->chan)
02905 ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
02906 l->retries = MAX_RETRIES + 1;
02907 l->disced = 2;
02908 modechange = 1;
02909 } else
02910 rpt_mutex_unlock(&myrpt->lock);
02911 ast_copy_string(myrpt->lastlinknode, digitbuf, MAXNODESTR);
02912
02913 l = ast_calloc(1, sizeof(*l));
02914 if (!l) {
02915 ast_log(LOG_WARNING, "Unable to malloc\n");
02916 return DC_ERROR;
02917 }
02918 snprintf(deststr, sizeof(deststr), "IAX2/%s", args.s1);
02919 tele = strchr(deststr, '/');
02920 if (!tele) {
02921 ast_log(LOG_ERROR, "link2:Dial number (%s) must be in format tech/number\n", deststr);
02922 return DC_ERROR;
02923 }
02924 *tele++ = 0;
02925 l->isremote = (s && ast_true(s));
02926 ast_copy_string(l->name, digitbuf, MAXNODESTR);
02927 l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele, NULL);
02928 if (modechange)
02929 l->connected = 1;
02930 if (l->chan) {
02931 ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
02932 ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
02933 l->chan->whentohangup = 0;
02934 l->chan->appl = "Apprpt";
02935 l->chan->data = "(Remote Rx)";
02936 ast_verb(3, "rpt (remote) initiating call to %s/%s on %s\n",
02937 deststr, tele, l->chan->name);
02938 if (l->chan->cid.cid_num)
02939 ast_free(l->chan->cid.cid_num);
02940 l->chan->cid.cid_num = ast_strdup(myrpt->name);
02941 ast_call(l->chan, tele, 0);
02942 } else {
02943 rpt_telemetry(myrpt, CONNFAIL, l);
02944 ast_free(l);
02945 ast_verb(3, "Unable to place call to %s/%s on %s\n",
02946 deststr, tele, l->chan->name);
02947 return DC_ERROR;
02948 }
02949
02950 l->pchan = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
02951 if (!l->pchan) {
02952 ast_log(LOG_ERROR, "rpt:Sorry unable to obtain pseudo channel\n");
02953 ast_hangup(l->chan);
02954 ast_free(l);
02955 return DC_ERROR;
02956 }
02957 ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
02958 ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
02959
02960 ci.chan = 0;
02961 ci.confno = myrpt->conf;
02962 ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
02963
02964 if (ioctl(l->pchan->fds[0], DAHDI_SETCONF, &ci) == -1) {
02965 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
02966 ast_hangup(l->chan);
02967 ast_hangup(l->pchan);
02968 ast_free(l);
02969 return DC_ERROR;
02970 }
02971 rpt_mutex_lock(&myrpt->lock);
02972 l->reconnects = reconnects;
02973
02974 insque((struct qelem *)l, (struct qelem *)myrpt->links.next);
02975 rpt_mutex_unlock(&myrpt->lock);
02976 rpt_telemetry(myrpt, COMPLETE, NULL);
02977 return DC_COMPLETE;
02978 case 3:
02979 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
02980 strcpy(digitbuf, myrpt->lastlinknode);
02981 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
02982 if (!val) {
02983 if (strlen(digitbuf) >= myrpt->longestnode)
02984 return DC_ERROR;
02985 break;
02986 }
02987 s = ast_strdupa(val);
02988 AST_STANDARD_APP_ARGS(args, s);
02989 rpt_mutex_lock(&myrpt->lock);
02990 l = myrpt->links.next;
02991
02992 while (l != &myrpt->links) {
02993 if (l->name[0] == '0') {
02994 l = l->next;
02995 continue;
02996 }
02997
02998 if (!strcmp(l->name, digitbuf))
02999 break;
03000 l = l->next;
03001 }
03002
03003 if (l != &myrpt->links) {
03004
03005 if ((l->mode) || (!l->chan)) {
03006 rpt_mutex_unlock(&myrpt->lock);
03007 rpt_telemetry(myrpt, REMALREADY, NULL);
03008 return DC_COMPLETE;
03009 }
03010 reconnects = l->reconnects;
03011 rpt_mutex_unlock(&myrpt->lock);
03012 if (l->chan)
03013 ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
03014 l->retries = MAX_RETRIES + 1;
03015 l->disced = 2;
03016 modechange = 1;
03017 } else
03018 rpt_mutex_unlock(&myrpt->lock);
03019 ast_copy_string(myrpt->lastlinknode, digitbuf, MAXNODESTR);
03020
03021 l = ast_calloc(1, sizeof(*l));
03022 if (!l) {
03023 ast_log(LOG_WARNING, "Unable to malloc\n");
03024 return DC_ERROR;
03025 }
03026 l->mode = 1;
03027 l->outbound = 1;
03028 ast_copy_string(l->name, digitbuf, MAXNODESTR);
03029 l->isremote = (s && ast_true(s));
03030 if (modechange)
03031 l->connected = 1;
03032 snprintf(deststr, sizeof(deststr), "IAX2/%s", args.s1);
03033 tele = strchr(deststr, '/');
03034 if (!tele) {
03035 ast_log(LOG_ERROR, "link3:Dial number (%s) must be in format tech/number\n", deststr);
03036 ast_free(l);
03037 return DC_ERROR;
03038 }
03039 *tele++ = 0;
03040 l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele, NULL);
03041 if (l->chan) {
03042 ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
03043 ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
03044 l->chan->whentohangup = 0;
03045 l->chan->appl = "Apprpt";
03046 l->chan->data = "(Remote Rx)";
03047 ast_verb(3, "rpt (remote) initiating call to %s/%s on %s\n",
03048 deststr, tele, l->chan->name);
03049 if (l->chan->cid.cid_num)
03050 ast_free(l->chan->cid.cid_num);
03051 l->chan->cid.cid_num = ast_strdup(myrpt->name);
03052 ast_call(l->chan, tele, 999);
03053 } else {
03054 rpt_telemetry(myrpt, CONNFAIL, l);
03055 ast_free(l);
03056 ast_verb(3, "Unable to place call to %s/%s on %s\n",
03057 deststr, tele, l->chan->name);
03058 return DC_ERROR;
03059 }
03060
03061 l->pchan = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
03062 if (!l->pchan) {
03063 ast_log(LOG_ERROR, "rpt:Sorry unable to obtain pseudo channel\n");
03064 ast_hangup(l->chan);
03065 ast_free(l);
03066 return DC_ERROR;
03067 }
03068 ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
03069 ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
03070
03071 ci.chan = 0;
03072 ci.confno = myrpt->conf;
03073 ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
03074
03075 if (ioctl(l->pchan->fds[0], DAHDI_SETCONF, &ci) == -1) {
03076 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
03077 ast_hangup(l->chan);
03078 ast_hangup(l->pchan);
03079 ast_free(l);
03080 return DC_ERROR;
03081 }
03082 rpt_mutex_lock(&myrpt->lock);
03083 l->reconnects = reconnects;
03084
03085 insque((struct qelem *)l, (struct qelem *)myrpt->links.next);
03086 rpt_mutex_unlock(&myrpt->lock);
03087 rpt_telemetry(myrpt, COMPLETE, NULL);
03088 return DC_COMPLETE;
03089 case 4:
03090
03091 if (((command_source != SOURCE_RPT) &&
03092 (command_source != SOURCE_PHONE) &&
03093 (command_source != SOURCE_DPHONE)) ||
03094 (myrpt->links.next == &myrpt->links))
03095 return DC_COMPLETE;
03096
03097 if ((myrpt->cmdnode[0]) || (!strcmp(myrpt->name, digitbuf))) {
03098 rpt_telemetry(myrpt, REMALREADY, NULL);
03099 return DC_COMPLETE;
03100 }
03101 if ((digitbuf[0] == '0') && (myrpt->lastlinknode[0]))
03102 strcpy(digitbuf, myrpt->lastlinknode);
03103
03104 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, digitbuf);
03105 if (!val) {
03106 if (strlen(digitbuf) >= myrpt->longestnode)
03107 return DC_ERROR;
03108 break;
03109 }
03110 rpt_mutex_lock(&myrpt->lock);
03111 strcpy(myrpt->lastlinknode, digitbuf);
03112 ast_copy_string(myrpt->cmdnode, digitbuf, sizeof(myrpt->cmdnode));
03113 rpt_mutex_unlock(&myrpt->lock);
03114 rpt_telemetry(myrpt, REMGO, NULL);
03115 return DC_COMPLETE;
03116 case 5:
03117 rpt_telemetry(myrpt, STATUS, NULL);
03118 return DC_COMPLETE;
03119 case 6:
03120 l = myrpt->links.next;
03121 while (l != &myrpt->links) {
03122 if (l->chan)
03123 ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
03124 l = l->next;
03125 }
03126 rpt_telemetry(myrpt, COMPLETE, NULL);
03127 break;
03128 case 7:
03129 rpt_telemetry(myrpt, LASTNODEKEY, NULL);
03130 break;
03131 default:
03132 return DC_ERROR;
03133 }
03134
03135 return DC_INDETERMINATE;
03136 }
03137
03138
03139
03140
03141
03142 static int function_autopatchup(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
03143 {
03144 int i, index;
03145 char *value = NULL;
03146 AST_DECLARE_APP_ARGS(params,
03147 AST_APP_ARG(list)[20];
03148 );
03149
03150 static char *keywords[] = {
03151 "context",
03152 "dialtime",
03153 "farenddisconnect",
03154 "noct",
03155 "quiet",
03156 NULL
03157 };
03158
03159 if (!myrpt->enable)
03160 return DC_ERROR;
03161
03162 ast_debug(1, "@@@@ Autopatch up\n");
03163
03164 if (!myrpt->callmode) {
03165
03166 myrpt->patchnoct = 0;
03167 myrpt->patchdialtime = 0;
03168 myrpt->patchfarenddisconnect = 0;
03169 myrpt->patchquiet = 0;
03170 ast_copy_string(myrpt->patchcontext, myrpt->p.ourcontext, sizeof(myrpt->patchcontext));
03171
03172 if (param) {
03173
03174 char *tmp = ast_strdupa(param);
03175 AST_STANDARD_APP_ARGS(params, tmp);
03176 for (i = 0; i < params.argc; i++) {
03177 index = matchkeyword(params.list[i], &value, keywords);
03178 if (value)
03179 value = skipchars(value, "= ");
03180 switch (index) {
03181 case 1:
03182 ast_copy_string(myrpt->patchcontext, value, sizeof(myrpt->patchcontext)) ;
03183 break;
03184 case 2:
03185 myrpt->patchdialtime = atoi(value);
03186 break;
03187 case 3:
03188 myrpt->patchfarenddisconnect = atoi(value);
03189 break;
03190 case 4:
03191 myrpt->patchnoct = atoi(value);
03192 break;
03193 case 5:
03194 myrpt->patchquiet = atoi(value);
03195 break;
03196 default:
03197 break;
03198 }
03199 }
03200 }
03201 }
03202
03203 rpt_mutex_lock(&myrpt->lock);
03204
03205
03206
03207 if ((myrpt->callmode == 2) || (myrpt->callmode == 3)) {
03208 myrpt->mydtmf = myrpt->p.funcchar;
03209 }
03210 if (myrpt->callmode) {
03211 rpt_mutex_unlock(&myrpt->lock);
03212 return DC_COMPLETE;
03213 }
03214 myrpt->callmode = 1;
03215 myrpt->cidx = 0;
03216 myrpt->exten[myrpt->cidx] = 0;
03217 rpt_mutex_unlock(&myrpt->lock);
03218 ast_pthread_create_detached(&myrpt->rpt_call_thread, NULL, rpt_call, (void *) myrpt);
03219 return DC_COMPLETE;
03220 }
03221
03222
03223
03224
03225
03226 static int function_autopatchdn(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
03227 {
03228 if (!myrpt->enable)
03229 return DC_ERROR;
03230
03231 ast_debug(1, "@@@@ Autopatch down\n");
03232
03233 rpt_mutex_lock(&myrpt->lock);
03234
03235 if (!myrpt->callmode) {
03236 rpt_mutex_unlock(&myrpt->lock);
03237 return DC_COMPLETE;
03238 }
03239
03240 myrpt->callmode = 0;
03241 rpt_mutex_unlock(&myrpt->lock);
03242 rpt_telemetry(myrpt, TERM, NULL);
03243 return DC_COMPLETE;
03244 }
03245
03246
03247
03248
03249
03250 static int function_status(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
03251 {
03252
03253 if (!param)
03254 return DC_ERROR;
03255
03256 if (!myrpt->enable)
03257 return DC_ERROR;
03258
03259 ast_debug(1, "@@@@ status param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
03260
03261 switch (myatoi(param)) {
03262 case 1:
03263 rpt_telemetry(myrpt, ID1, NULL);
03264 return DC_COMPLETE;
03265 case 2:
03266 rpt_telemetry(myrpt, STATS_TIME, NULL);
03267 return DC_COMPLETE;
03268 case 3:
03269 rpt_telemetry(myrpt, STATS_VERSION, NULL);
03270 default:
03271 return DC_ERROR;
03272 }
03273
03274
03275 return DC_INDETERMINATE;
03276 }
03277
03278
03279
03280
03281
03282 static int function_macro(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
03283 {
03284
03285 const char *val;
03286 int i;
03287 struct ast_channel *mychannel;
03288
03289 if ((!myrpt->remote) && (!myrpt->enable))
03290 return DC_ERROR;
03291
03292 ast_debug(1, "@@@@ macro-oni param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
03293
03294 mychannel = myrpt->remchannel;
03295
03296 if (ast_strlen_zero(digitbuf))
03297 return DC_INDETERMINATE;
03298
03299 for (i = 0; i < digitbuf[i]; i++) {
03300 if ((digitbuf[i] < '0') || (digitbuf[i] > '9'))
03301 return DC_ERROR;
03302 }
03303
03304 if (*digitbuf == '0')
03305 val = myrpt->p.startupmacro;
03306 else
03307 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.macro, digitbuf);
03308
03309 if (!val) {
03310 rpt_telemetry(myrpt, MACRO_NOTFOUND, NULL);
03311 return DC_COMPLETE;
03312 }
03313 rpt_mutex_lock(&myrpt->lock);
03314 if ((sizeof(myrpt->macrobuf) - strlen(myrpt->macrobuf)) < strlen(val)) {
03315 rpt_mutex_unlock(&myrpt->lock);
03316 rpt_telemetry(myrpt, MACRO_BUSY, NULL);
03317 return DC_ERROR;
03318 }
03319 myrpt->macrotimer = MACROTIME;
03320 strncat(myrpt->macrobuf, val, sizeof(myrpt->macrobuf) - strlen(myrpt->macrobuf) - 1);
03321 rpt_mutex_unlock(&myrpt->lock);
03322 return DC_COMPLETE;
03323 }
03324
03325
03326
03327
03328
03329 static int function_gosub(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
03330 {
03331
03332 const char *val;
03333 int i;
03334 struct ast_channel *mychannel;
03335
03336 if ((!myrpt->remote) && (!myrpt->enable))
03337 return DC_ERROR;
03338
03339 if (debug)
03340 ast_log(LOG_DEBUG, "@@@@ gosub param = %s, digitbuf = %s\n", (param)? param : "(null)", digitbuf);
03341
03342 mychannel = myrpt->remchannel;
03343
03344 if (ast_strlen_zero(digitbuf))
03345 return DC_INDETERMINATE;
03346
03347 for (i = 0; i < digitbuf[i]; i++) {
03348 if ((digitbuf[i] < '0') || (digitbuf[i] > '9'))
03349 return DC_ERROR;
03350 }
03351
03352 if (*digitbuf == '0')
03353 val = myrpt->p.startupgosub;
03354 else
03355 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.gosub, digitbuf);
03356
03357 if (!val) {
03358 rpt_telemetry(myrpt, GOSUB_NOTFOUND, NULL);
03359 return DC_COMPLETE;
03360 }
03361 rpt_mutex_lock(&myrpt->lock);
03362 if ((sizeof(myrpt->gosubbuf) - strlen(myrpt->gosubbuf)) < strlen(val)) {
03363 rpt_mutex_unlock(&myrpt->lock);
03364 rpt_telemetry(myrpt, GOSUB_BUSY, NULL);
03365 return DC_ERROR;
03366 }
03367 myrpt->gosubtimer = GOSUBTIME;
03368 strncat(myrpt->gosubbuf, val, sizeof(myrpt->gosubbuf) - strlen(myrpt->gosubbuf) - 1);
03369 rpt_mutex_unlock(&myrpt->lock);
03370 return DC_COMPLETE;
03371 }
03372
03373
03374
03375
03376
03377 static int function_cop(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
03378 {
03379 if (!param)
03380 return DC_ERROR;
03381
03382 switch(myatoi(param)) {
03383 case 1:
03384 ast_cli_command(STDERR_FILENO, "restart now");
03385 return DC_COMPLETE;
03386 case 2:
03387 myrpt->enable = 1;
03388 rpt_telemetry(myrpt, ARB_ALPHA, (void *) "RPTENA");
03389 return DC_COMPLETE;
03390 case 3:
03391 myrpt->enable = 0;
03392 return DC_COMPLETE;
03393 case 4:
03394 rpt_telemetry(myrpt, TEST_TONE, NULL);
03395 return DC_COMPLETE;
03396 case 5:
03397 myrpt->disgorgetime = time(NULL) + 10;
03398 return DC_COMPLETE;
03399 case 6:
03400 if (command_source != SOURCE_PHONE)
03401 return DC_INDETERMINATE;
03402 return DC_DOKEY;
03403 }
03404 return DC_INDETERMINATE;
03405 }
03406
03407
03408
03409
03410
03411 static int collect_function_digits(struct rpt *myrpt, char *digits, int command_source, struct rpt_link *mylink)
03412 {
03413 int i;
03414 char *stringp, *functiondigits;
03415 char function_table_name[30] = "";
03416 struct ast_variable *vp;
03417 AST_DECLARE_APP_ARGS(args,
03418 AST_APP_ARG(action);
03419 AST_APP_ARG(param);
03420 );
03421
03422 ast_debug(1, "@@@@ Digits collected: %s, source: %d\n", digits, command_source);
03423
03424 if (command_source == SOURCE_DPHONE) {
03425 if (!myrpt->p.dphone_functions)
03426 return DC_INDETERMINATE;
03427 ast_copy_string(function_table_name, myrpt->p.dphone_functions, sizeof(function_table_name));
03428 } else if (command_source == SOURCE_PHONE) {
03429 if (!myrpt->p.phone_functions)
03430 return DC_INDETERMINATE;
03431 ast_copy_string(function_table_name, myrpt->p.phone_functions, sizeof(function_table_name));
03432 } else if (command_source == SOURCE_LNK)
03433 ast_copy_string(function_table_name, myrpt->p.link_functions, sizeof(function_table_name));
03434 else
03435 ast_copy_string(function_table_name, myrpt->p.functions, sizeof(function_table_name));
03436
03437 for (vp = ast_variable_browse(myrpt->cfg, function_table_name); vp; vp = vp->next) {
03438 if (!strncasecmp(vp->name, digits, strlen(vp->name)))
03439 break;
03440 }
03441 if (!vp) {
03442 int n;
03443
03444 n = myrpt->longestfunc;
03445 if (command_source == SOURCE_LNK)
03446 n = myrpt->link_longestfunc;
03447 else if (command_source == SOURCE_PHONE)
03448 n = myrpt->phone_longestfunc;
03449 else if (command_source == SOURCE_DPHONE)
03450 n = myrpt->dphone_longestfunc;
03451
03452 if (strlen(digits) >= n)
03453 return DC_ERROR;
03454 else
03455 return DC_INDETERMINATE;
03456 }
03457
03458
03459 stringp = ast_strdupa(vp->value);
03460 AST_STANDARD_APP_ARGS(args, stringp);
03461
03462 ast_debug(1, "@@@@ action: %s, param = %s\n", args.action, S_OR(args.param, "(null)"));
03463
03464 for (i = 0; i < (sizeof(function_table) / sizeof(struct function_table_tag)); i++) {
03465 if (!strncasecmp(args.action, function_table[i].action, strlen(args.action)))
03466 break;
03467 }
03468 ast_debug(1, "@@@@ table index i = %d\n", i);
03469 if (i == (sizeof(function_table) / sizeof(struct function_table_tag))) {
03470
03471 return DC_ERROR;
03472 }
03473 if (function_table[i].function == NULL) {
03474
03475 ast_debug(1, "@@@@ NULL for action: %s\n", args.action);
03476 return DC_ERROR;
03477 }
03478 functiondigits = digits + strlen(vp->name);
03479 return (*function_table[i].function)(myrpt, args.param, functiondigits, command_source, mylink);
03480 }
03481
03482
03483 static void handle_link_data(struct rpt *myrpt, struct rpt_link *mylink, char *str)
03484 {
03485 char cmd[300] = "", dest[300], src[300], c;
03486 int seq, res;
03487 struct rpt_link *l;
03488 struct ast_frame wf;
03489
03490 wf.frametype = AST_FRAME_TEXT;
03491 wf.subclass = 0;
03492 wf.offset = 0;
03493 wf.mallocd = 1;
03494 wf.datalen = strlen(str) + 1;
03495 wf.samples = 0;
03496 if (!strcmp(str, discstr)) {
03497 mylink->disced = 1;
03498 mylink->retries = MAX_RETRIES + 1;
03499 ast_softhangup(mylink->chan, AST_SOFTHANGUP_DEV);
03500 return;
03501 }
03502 if (sscanf(str, "%s %s %s %d %c", cmd, dest, src, &seq, &c) != 5) {
03503 ast_log(LOG_WARNING, "Unable to parse link string %s\n", str);
03504 return;
03505 }
03506 if (strcmp(cmd, "D")) {
03507 ast_log(LOG_WARNING, "Unable to parse link string %s\n", str);
03508 return;
03509 }
03510
03511 if (dest[0] == '0') {
03512 strcpy(dest, myrpt->name);
03513 }
03514
03515
03516 if (strcmp(dest, myrpt->name)) {
03517 l = myrpt->links.next;
03518
03519 while (l != &myrpt->links) {
03520 if (l->name[0] == '0') {
03521 l = l->next;
03522 continue;
03523 }
03524
03525 if ((l == mylink) || (!strcmp(l->name, mylink->name))) {
03526 l = l->next;
03527 continue;
03528 }
03529
03530 if (!strcmp(l->name, dest)) {
03531
03532 if (strcmp(l->name, src)) {
03533 wf.data = ast_strdup(str);
03534 if (l->chan)
03535 ast_write(l->chan, &wf);
03536 }
03537 return;
03538 }
03539 l = l->next;
03540 }
03541 l = myrpt->links.next;
03542
03543 while (l != &myrpt->links) {
03544 if (l->name[0] == '0') {
03545 l = l->next;
03546 continue;
03547 }
03548
03549 if ((l == mylink) || (!strcmp(l->name, mylink->name))) {
03550 l = l->next;
03551 continue;
03552 }
03553
03554 if (strcmp(l->name, src)) {
03555 wf.data = ast_strdup(str);
03556 if (l->chan)
03557 ast_write(l->chan, &wf);
03558 }
03559 l = l->next;
03560 }
03561 return;
03562 }
03563 rpt_mutex_lock(&myrpt->lock);
03564 if (c == myrpt->p.endchar)
03565 myrpt->stopgen = 1;
03566 if (myrpt->callmode == 1) {
03567 myrpt->exten[myrpt->cidx++] = c;
03568 myrpt->exten[myrpt->cidx] = 0;
03569
03570 if (ast_exists_extension(myrpt->pchannel, myrpt->patchcontext, myrpt->exten, 1, NULL)) {
03571 myrpt->callmode = 2;
03572 if (!myrpt->patchquiet) {
03573 rpt_mutex_unlock(&myrpt->lock);
03574 rpt_telemetry(myrpt, PROC, NULL);
03575 rpt_mutex_lock(&myrpt->lock);
03576 }
03577 }
03578
03579 if (!ast_canmatch_extension(myrpt->pchannel, myrpt->patchcontext, myrpt->exten, 1, NULL)) {
03580
03581 myrpt->callmode = 4;
03582 }
03583 }
03584 if ((myrpt->callmode == 2) || (myrpt->callmode == 3)) {
03585 myrpt->mydtmf = c;
03586 }
03587 if (c == myrpt->p.funcchar) {
03588 myrpt->rem_dtmfidx = 0;
03589 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
03590 time(&myrpt->rem_dtmf_time);
03591 rpt_mutex_unlock(&myrpt->lock);
03592 return;
03593 } else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0)) {
03594 time(&myrpt->rem_dtmf_time);
03595 if (myrpt->rem_dtmfidx < MAXDTMF) {
03596 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
03597 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
03598
03599 rpt_mutex_unlock(&myrpt->lock);
03600 ast_copy_string(cmd, myrpt->rem_dtmfbuf, sizeof(cmd));
03601 res = collect_function_digits(myrpt, cmd, SOURCE_LNK, mylink);
03602 rpt_mutex_lock(&myrpt->lock);
03603
03604 switch (res) {
03605 case DC_INDETERMINATE:
03606 break;
03607 case DC_REQ_FLUSH:
03608 myrpt->rem_dtmfidx = 0;
03609 myrpt->rem_dtmfbuf[0] = 0;
03610 break;
03611 case DC_COMPLETE:
03612 myrpt->totalexecdcommands++;
03613 myrpt->dailyexecdcommands++;
03614 ast_copy_string(myrpt->lastdtmfcommand, cmd, MAXDTMF);
03615 myrpt->lastdtmfcommand[MAXDTMF-1] = '\0';
03616 myrpt->rem_dtmfbuf[0] = 0;
03617 myrpt->rem_dtmfidx = -1;
03618 myrpt->rem_dtmf_time = 0;
03619 break;
03620 case DC_ERROR:
03621 default:
03622 myrpt->rem_dtmfbuf[0] = 0;
03623 myrpt->rem_dtmfidx = -1;
03624 myrpt->rem_dtmf_time = 0;
03625 break;
03626 }
03627 }
03628
03629 }
03630 rpt_mutex_unlock(&myrpt->lock);
03631 return;
03632 }
03633
03634 static void handle_link_phone_dtmf(struct rpt *myrpt, struct rpt_link *mylink, char c)
03635 {
03636 char cmd[300];
03637 int res;
03638
03639 rpt_mutex_lock(&myrpt->lock);
03640 if (c == myrpt->p.endchar) {
03641 if (mylink->lastrx) {
03642 mylink->lastrx = 0;
03643 rpt_mutex_unlock(&myrpt->lock);
03644 return;
03645 }
03646 myrpt->stopgen = 1;
03647 if (myrpt->cmdnode[0]) {
03648 myrpt->cmdnode[0] = 0;
03649 myrpt->dtmfidx = -1;
03650 myrpt->dtmfbuf[0] = 0;
03651 rpt_mutex_unlock(&myrpt->lock);
03652 rpt_telemetry(myrpt, COMPLETE, NULL);
03653 return;
03654 }
03655 }
03656 if (myrpt->cmdnode[0]) {
03657 rpt_mutex_unlock(&myrpt->lock);
03658 send_link_dtmf(myrpt, c);
03659 return;
03660 }
03661 if (myrpt->callmode == 1) {
03662 myrpt->exten[myrpt->cidx++] = c;
03663 myrpt->exten[myrpt->cidx] = 0;
03664
03665 if (ast_exists_extension(myrpt->pchannel, myrpt->patchcontext, myrpt->exten, 1, NULL)) {
03666 myrpt->callmode = 2;
03667 if (!myrpt->patchquiet) {
03668 rpt_mutex_unlock(&myrpt->lock);
03669 rpt_telemetry(myrpt, PROC, NULL);
03670 rpt_mutex_lock(&myrpt->lock);
03671 }
03672 }
03673
03674 if (!ast_canmatch_extension(myrpt->pchannel, myrpt->patchcontext, myrpt->exten, 1, NULL)) {
03675
03676 myrpt->callmode = 4;
03677 }
03678 }
03679 if ((myrpt->callmode == 2) || (myrpt->callmode == 3)) {
03680 myrpt->mydtmf = c;
03681 }
03682 if (c == myrpt->p.funcchar) {
03683 myrpt->rem_dtmfidx = 0;
03684 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
03685 time(&myrpt->rem_dtmf_time);
03686 rpt_mutex_unlock(&myrpt->lock);
03687 return;
03688 } else if ((c != myrpt->p.endchar) && (myrpt->rem_dtmfidx >= 0)) {
03689 time(&myrpt->rem_dtmf_time);
03690 if (myrpt->rem_dtmfidx < MAXDTMF) {
03691 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx++] = c;
03692 myrpt->rem_dtmfbuf[myrpt->rem_dtmfidx] = 0;
03693
03694 rpt_mutex_unlock(&myrpt->lock);
03695 ast_copy_string(cmd, myrpt->rem_dtmfbuf, sizeof(cmd));
03696 switch(mylink->phonemode) {
03697 case 1:
03698 res = collect_function_digits(myrpt, cmd,
03699 SOURCE_PHONE, mylink);
03700 break;
03701 case 2:
03702 res = collect_function_digits(myrpt, cmd,
03703 SOURCE_DPHONE, mylink);
03704 break;
03705 default:
03706 res = collect_function_digits(myrpt, cmd,
03707 SOURCE_LNK, mylink);
03708 break;
03709 }
03710
03711 rpt_mutex_lock(&myrpt->lock);
03712
03713 switch(res) {
03714 case DC_INDETERMINATE:
03715 break;
03716 case DC_DOKEY:
03717 mylink->lastrx = 1;
03718 break;
03719 case DC_REQ_FLUSH:
03720 myrpt->rem_dtmfidx = 0;
03721 myrpt->rem_dtmfbuf[0] = 0;
03722 break;
03723 case DC_COMPLETE:
03724 myrpt->totalexecdcommands++;
03725 myrpt->dailyexecdcommands++;
03726 ast_copy_string(myrpt->lastdtmfcommand, cmd, MAXDTMF);
03727 myrpt->rem_dtmfbuf[0] = 0;
03728 myrpt->rem_dtmfidx = -1;
03729 myrpt->rem_dtmf_time = 0;
03730 break;
03731 case DC_ERROR:
03732 default:
03733 myrpt->rem_dtmfbuf[0] = 0;
03734 myrpt->rem_dtmfidx = -1;
03735 myrpt->rem_dtmf_time = 0;
03736 break;
03737 }
03738 }
03739
03740 }
03741 rpt_mutex_unlock(&myrpt->lock);
03742 return;
03743 }
03744
03745
03746
03747
03748
03749
03750
03751
03752
03753
03754
03755
03756
03757
03758
03759
03760
03761
03762
03763
03764
03765
03766
03767
03768
03769
03770
03771
03772
03773
03774
03775
03776 static int rbi_mhztoband(char *str)
03777 {
03778 int i;
03779
03780 i = atoi(str) / 10;
03781 switch (i) {
03782 case 2:
03783 return 10;
03784 case 5:
03785 return 11;
03786 case 14:
03787 return 2;
03788 case 22:
03789 return 3;
03790 case 44:
03791 return 4;
03792 case 124:
03793 return 0;
03794 case 125:
03795 return 1;
03796 case 126:
03797 return 8;
03798 case 127:
03799 return 5;
03800 case 128:
03801 return 6;
03802 case 129:
03803 return 7;
03804 default:
03805 break;
03806 }
03807 return -1;
03808 }
03809
03810
03811 static int rbi_pltocode(char *str)
03812 {
03813 int i;
03814 char *s;
03815
03816 s = strchr(str, '.');
03817 i = 0;
03818 if (s)
03819 i = atoi(s + 1);
03820 i += atoi(str) * 10;
03821 switch(i) {
03822 case 670:
03823 return 0;
03824 case 719:
03825 return 1;
03826 case 744:
03827 return 2;
03828 case 770:
03829 return 3;
03830 case 797:
03831 return 4;
03832 case 825:
03833 return 5;
03834 case 854:
03835 return 6;
03836 case 885:
03837 return 7;
03838 case 915:
03839 return 8;
03840 case 948:
03841 return 9;
03842 case 974:
03843 return 10;
03844 case 1000:
03845 return 11;
03846 case 1035:
03847 return 12;
03848 case 1072:
03849 return 13;
03850 case 1109:
03851 return 14;
03852 case 1148:
03853 return 15;
03854 case 1188:
03855 return 16;
03856 case 1230:
03857 return 17;
03858 case 1273:
03859 return 18;
03860 case 1318:
03861 return 19;
03862 case 1365:
03863 return 20;
03864 case 1413:
03865 return 21;
03866 case 1462:
03867 return 22;
03868 case 1514:
03869 return 23;
03870 case 1567:
03871 return 24;
03872 case 1622:
03873 return 25;
03874 case 1679:
03875 return 26;
03876 case 1738:
03877 return 27;
03878 case 1799:
03879 return 28;
03880 case 1862:
03881 return 29;
03882 case 1928:
03883 return 30;
03884 case 2035:
03885 return 31;
03886 case 2107:
03887 return 32;
03888 case 2181:
03889 return 33;
03890 case 2257:
03891 return 34;
03892 case 2336:
03893 return 35;
03894 case 2418:
03895 return 36;
03896 case 2503:
03897 return 37;
03898 }
03899 return -1;
03900 }
03901
03902
03903
03904
03905
03906 static void rbi_out_parallel(struct rpt *myrpt, unsigned char *data)
03907 {
03908 int i, j;
03909 unsigned char od, d;
03910
03911 for (i = 0; i < 5; i++) {
03912 od = *data++;
03913 for (j = 0; j < 8; j++) {
03914 d = od & 1;
03915 outb(d, myrpt->p.iobase);
03916 usleep(15);
03917 od >>= 1;
03918 outb(d | 2, myrpt->p.iobase);
03919 usleep(30);
03920 outb(d, myrpt->p.iobase);
03921 usleep(10);
03922 }
03923 }
03924
03925 usleep(50);
03926 }
03927
03928 static void rbi_out(struct rpt *myrpt, unsigned char *data)
03929 {
03930 struct dahdi_radio_param r = { 0, };
03931
03932 r.radpar = DAHDI_RADPAR_REMMODE;
03933 r.data = DAHDI_RADPAR_REM_RBI1;
03934
03935 if (ioctl(myrpt->rxchannel->fds[0], DAHDI_RADIO_SETPARAM, &r) == -1) {
03936 rbi_out_parallel(myrpt, data);
03937 return;
03938 }
03939 r.radpar = DAHDI_RADPAR_REMCOMMAND;
03940 memcpy(&r.data, data, 5);
03941 if (ioctl(myrpt->rxchannel->fds[0], DAHDI_RADIO_SETPARAM, &r) == -1) {
03942 ast_log(LOG_WARNING, "Cannot send RBI command for channel %s\n", myrpt->rxchannel->name);
03943 return;
03944 }
03945 }
03946
03947 static int serial_remote_io(struct rpt *myrpt, unsigned char *txbuf, int txbytes, char *rxbuf, int rxmaxbytes, int asciiflag)
03948 {
03949 int i;
03950 struct dahdi_radio_param prm;
03951
03952 char *buf = alloca(30 + txbytes * 3);
03953 int len;
03954 ast_copy_string(buf, "String output was: ", 30 + txbytes * 3);
03955 len = strlen(buf);
03956 for (i = 0; i < txbytes; i++)
03957 len += snprintf(buf + len, 30 + txbytes * 3 - len, "%02X ", (unsigned char) txbuf[i]);
03958 strcat(buf + len, "\n");
03959 ast_debug(1, "%s", buf);
03960
03961 prm.radpar = DAHDI_RADPAR_REMMODE;
03962 if (asciiflag)
03963 prm.data = DAHDI_RADPAR_REM_SERIAL_ASCII;
03964 else
03965 prm.data = DAHDI_RADPAR_REM_SERIAL;
03966 if (ioctl(myrpt->rxchannel->fds[0], DAHDI_RADIO_SETPARAM, &prm) == -1)
03967 return -1;
03968 prm.radpar = DAHDI_RADPAR_REMCOMMAND;
03969 prm.data = rxmaxbytes;
03970 memcpy(prm.buf, txbuf, txbytes);
03971 prm.index = txbytes;
03972 if (ioctl(myrpt->rxchannel->fds[0], DAHDI_RADIO_SETPARAM, &prm) == -1)
03973 return -1;
03974 if (rxbuf) {
03975 *rxbuf = 0;
03976 memcpy(rxbuf, prm.buf, prm.index);
03977 }
03978 return(prm.index);
03979 }
03980
03981 static int setrbi(struct rpt *myrpt)
03982 {
03983 char tmp[MAXREMSTR] = "", *s;
03984 unsigned char rbicmd[5];
03985 int band, txoffset = 0, txpower = 0, txpl;
03986
03987
03988 if (!myrpt->remote)
03989 return(0);
03990
03991 if (strncmp(myrpt->remote, remote_rig_rbi, 3))
03992 return(0);
03993 ast_copy_string(tmp, myrpt->freq, sizeof(tmp));
03994 s = strchr(tmp, '.');
03995
03996
03997 if (s == NULL) {
03998 ast_debug(1, "@@@@ Frequency needs a decimal\n");
03999 return -1;
04000 }
04001
04002 *s++ = 0;
04003 if (strlen(tmp) < 2) {
04004 ast_debug(1, "@@@@ Bad MHz digits: %s\n", tmp);
04005 return -1;
04006 }
04007
04008 if (strlen(s) < 3) {
04009 ast_debug(1, "@@@@ Bad KHz digits: %s\n", s);
04010 return -1;
04011 }
04012
04013 if ((s[2] != '0') && (s[2] != '5')) {
04014 ast_debug(1, "@@@@ KHz must end in 0 or 5: %c\n", s[2]);
04015 return -1;
04016 }
04017
04018 band = rbi_mhztoband(tmp);
04019 if (band == -1) {
04020 ast_debug(1, "@@@@ Bad Band: %s\n", tmp);
04021 return -1;
04022 }
04023
04024 txpl = rbi_pltocode(myrpt->txpl);
04025
04026 if (txpl == -1) {
04027 ast_debug(1, "@@@@ Bad TX PL: %s\n", myrpt->txpl);
04028 return -1;
04029 }
04030
04031
04032 switch (myrpt->offset) {
04033 case REM_MINUS:
04034 txoffset = 0;
04035 break;
04036 case REM_PLUS:
04037 txoffset = 0x10;
04038 break;
04039 case REM_SIMPLEX:
04040 txoffset = 0x20;
04041 break;
04042 }
04043 switch(myrpt->powerlevel) {
04044 case REM_LOWPWR:
04045 txpower = 0;
04046 break;
04047 case REM_MEDPWR:
04048 txpower = 0x20;
04049 break;
04050 case REM_HIPWR:
04051 txpower = 0x10;
04052 break;
04053 }
04054 rbicmd[0] = 0;
04055 rbicmd[1] = band | txpower | 0xc0;
04056 rbicmd[2] = (*(s - 2) - '0') | txoffset | 0x80;
04057 if (s[2] == '5')
04058 rbicmd[2] |= 0x40;
04059 rbicmd[3] = ((*s - '0') << 4) + (s[1] - '0');
04060 rbicmd[4] = txpl;
04061 if (myrpt->txplon)
04062 rbicmd[4] |= 0x40;
04063 if (myrpt->rxplon)
04064 rbicmd[4] |= 0x80;
04065 rbi_out(myrpt, rbicmd);
04066 return 0;
04067 }
04068
04069
04070
04071
04072
04073 static int check_freq_rbi(int m, int d, int *defmode)
04074 {
04075 int dflmd = REM_MODE_FM;
04076
04077 if (m == 50) {
04078 if (d < 10100)
04079 return -1;
04080 } else if ((m >= 51) && ( m < 54)) {
04081
04082 } else if (m == 144) {
04083 if (d < 10100)
04084 return -1;
04085 } else if ((m >= 145) && (m < 148)) {
04086
04087 } else if ((m >= 222) && (m < 225)) {
04088
04089 } else if ((m >= 430) && (m < 450)) {
04090
04091 } else if ((m >= 1240) && (m < 1300)) {
04092
04093 } else
04094 return -1;
04095
04096 if (defmode)
04097 *defmode = dflmd;
04098
04099 return 0;
04100 }
04101
04102 static int split_decimal(char *input, int *ints, int *decs, int places)
04103 {
04104 double input2 = 0.0;
04105 long long modifier = (long long)pow(10.0, (double)places);
04106 if (sscanf(input, "%lf", &input2) == 1) {
04107 long long input3 = input2 * modifier;
04108 *ints = input3 / modifier;
04109 *decs = input3 % modifier;
04110 return 0;
04111 } else
04112 return -1;
04113 }
04114
04115
04116
04117
04118
04119 #define split_freq(mhz, decimal, freq) split_decimal(freq, mhz, decimal, 5)
04120
04121
04122
04123
04124
04125 #define split_ctcss_freq(hertz, decimal, freq) split_decimal(freq, hertz, decimal, 1)
04126
04127
04128
04129
04130
04131
04132
04133
04134 static int check_freq_ft897(int m, int d, int *defmode)
04135 {
04136 int dflmd = REM_MODE_FM;
04137
04138 if (m == 1) {
04139 dflmd = REM_MODE_LSB;
04140 if (d < 80001)
04141 return -1;
04142 } else if (m == 3) {
04143 dflmd = REM_MODE_LSB;
04144 if (d < 75001)
04145 return -1;
04146 } else if (m == 7) {
04147 dflmd = REM_MODE_LSB;
04148 if ((d < 15001) || (d > 29999))
04149 return -1;
04150 } else if (m == 14) {
04151 dflmd = REM_MODE_USB;
04152 if ((d < 15001) || (d > 34999))
04153 return -1;
04154 } else if (m == 18) {
04155 dflmd = REM_MODE_USB;
04156 if ((d < 11001) || (d > 16797))
04157 return -1;
04158 } else if (m == 21) {
04159 dflmd = REM_MODE_USB;
04160 if ((d < 20001) || (d > 44999))
04161 return -1;
04162 } else if (m == 24) {
04163 dflmd = REM_MODE_USB;
04164 if ((d < 93001) || (d > 98999))
04165 return -1;
04166 } else if (m == 28) {
04167 dflmd = REM_MODE_USB;
04168 if (d < 30001)
04169 return -1;
04170 } else if (m == 29) {
04171 if (d >= 51000)
04172 dflmd = REM_MODE_FM;
04173 else
04174 dflmd = REM_MODE_USB;
04175 if (d > 69999)
04176 return -1;
04177 } else if (m == 50) {
04178 if (d < 10100)
04179 return -1;
04180 if (d >= 30000)
04181 dflmd = REM_MODE_FM;
04182 else
04183 dflmd = REM_MODE_USB;
04184 } else if ((m >= 51) && ( m < 54)) {
04185 dflmd = REM_MODE_FM;
04186 } else if (m == 144) {
04187 if (d < 10100)
04188 return -1;
04189 if (d >= 30000)
04190 dflmd = REM_MODE_FM;
04191 else
04192 dflmd = REM_MODE_USB;
04193 } else if ((m >= 145) && (m < 148)) {
04194 dflmd = REM_MODE_FM;
04195 } else if ((m >= 430) && (m < 450)) {
04196 if (m < 438)
04197 dflmd = REM_MODE_USB;
04198 else
04199 dflmd = REM_MODE_FM;
04200 ;
04201 } else
04202 return -1;
04203
04204 if (defmode)
04205 *defmode = dflmd;
04206
04207 return 0;
04208 }
04209
04210
04211
04212
04213
04214 static int set_freq_ft897(struct rpt *myrpt, char *newfreq)
04215 {
04216 unsigned char cmdstr[5];
04217 int fd, m, d;
04218
04219 fd = 0;
04220 ast_debug(1, "New frequency: %s\n", newfreq);
04221
04222 if (split_freq(&m, &d, newfreq))
04223 return -1;
04224
04225
04226
04227 cmdstr[0] = ((m / 100) << 4) + ((m % 100) / 10);
04228 cmdstr[1] = ((m % 10) << 4) + (d / 10000);
04229 cmdstr[2] = (((d % 10000) / 1000) << 4) + ((d % 1000) / 100);
04230 cmdstr[3] = (((d % 100) / 10) << 4) + (d % 10);
04231 cmdstr[4] = 0x01;
04232
04233 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
04234 }
04235
04236
04237
04238 static int simple_command_ft897(struct rpt *myrpt, char command)
04239 {
04240 unsigned char cmdstr[5] = { 0, 0, 0, 0, command };
04241
04242 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
04243 }
04244
04245
04246
04247 static int set_offset_ft897(struct rpt *myrpt, char offset)
04248 {
04249 unsigned char cmdstr[5] = "";
04250
04251 switch (offset) {
04252 case REM_SIMPLEX:
04253 cmdstr[0] = 0x89;
04254 break;
04255 case REM_MINUS:
04256 cmdstr[0] = 0x09;
04257 break;
04258 case REM_PLUS:
04259 cmdstr[0] = 0x49;
04260 break;
04261 default:
04262 return -1;
04263 }
04264
04265 cmdstr[4] = 0x09;
04266
04267 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
04268 }
04269
04270
04271
04272 static int set_mode_ft897(struct rpt *myrpt, char newmode)
04273 {
04274 unsigned char cmdstr[5] = { 0, 0, 0, 0, 0x07 };
04275
04276 switch (newmode) {
04277 case REM_MODE_FM:
04278 cmdstr[0] = 0x08;
04279 break;
04280 case REM_MODE_USB:
04281 cmdstr[0] = 0x01;
04282 break;
04283 case REM_MODE_LSB:
04284 cmdstr[0] = 0x00;
04285 break;
04286 case REM_MODE_AM:
04287 cmdstr[0] = 0x04;
04288 break;
04289 default:
04290 return -1;
04291 }
04292
04293 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
04294 }
04295
04296
04297
04298 static int set_ctcss_mode_ft897(struct rpt *myrpt, char txplon, char rxplon)
04299 {
04300 unsigned char cmdstr[5] = { 0, 0, 0, 0, 0x0A };
04301
04302 if (rxplon && txplon)
04303 cmdstr[0] = 0x2A;
04304 else if (!rxplon && txplon)
04305 cmdstr[0] = 0x4A;
04306 else if (rxplon && !txplon)
04307 cmdstr[0] = 0x3A;
04308 else
04309 cmdstr[0] = 0x8A;
04310
04311 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
04312 }
04313
04314
04315
04316
04317 static int set_ctcss_freq_ft897(struct rpt *myrpt, char *txtone, char *rxtone)
04318 {
04319 unsigned char cmdstr[5] = { 0, 0, 0, 0, 0x0B };
04320 int hertz, decimal;
04321
04322 if (split_ctcss_freq(&hertz, &decimal, txtone))
04323 return -1;
04324
04325 cmdstr[0] = ((hertz / 100) << 4) + (hertz % 100) / 10;
04326 cmdstr[1] = ((hertz % 10) << 4) + (decimal % 10);
04327
04328 if (rxtone) {
04329 if (split_ctcss_freq(&hertz, &decimal, rxtone))
04330 return -1;
04331
04332 cmdstr[2] = ((hertz / 100) << 4) + (hertz % 100)/ 10;
04333 cmdstr[3] = ((hertz % 10) << 4) + (decimal % 10);
04334 }
04335
04336 return serial_remote_io(myrpt, cmdstr, 5, NULL, 0, 0);
04337 }
04338
04339
04340
04341 static int set_ft897(struct rpt *myrpt)
04342 {
04343 int res;
04344
04345 ast_debug(1, "@@@@ lock on\n");
04346
04347 res = simple_command_ft897(myrpt, 0x00);
04348
04349 ast_debug(1, "@@@@ ptt off\n");
04350
04351 if (!res)
04352 res = simple_command_ft897(myrpt, 0x88);
04353
04354 ast_debug(1, "Modulation mode\n");
04355
04356 if (!res)
04357 res = set_mode_ft897(myrpt, myrpt->remmode);
04358
04359 ast_debug(1, "Split off\n");
04360
04361 if (!res)
04362 simple_command_ft897(myrpt, 0x82);
04363
04364 ast_debug(1, "Frequency\n");
04365
04366 if (!res)
04367 res = set_freq_ft897(myrpt, myrpt->freq);
04368 if ((myrpt->remmode == REM_MODE_FM)) {
04369 ast_debug(1, "Offset\n");
04370 if (!res)
04371 res = set_offset_ft897(myrpt, myrpt->offset);
04372 if ((!res)&&(myrpt->rxplon || myrpt->txplon)) {
04373 ast_debug(1, "CTCSS tone freqs.\n");
04374 res = set_ctcss_freq_ft897(myrpt, myrpt->txpl, myrpt->rxpl);
04375 }
04376 if (!res) {
04377 ast_debug(1, "CTCSS mode\n");
04378 res = set_ctcss_mode_ft897(myrpt, myrpt->txplon, myrpt->rxplon);
04379 }
04380 }
04381 if ((myrpt->remmode == REM_MODE_USB)||(myrpt->remmode == REM_MODE_LSB)) {
04382 ast_debug(1, "Clarifier off\n");
04383 simple_command_ft897(myrpt, 0x85);
04384 }
04385 return res;
04386 }
04387
04388 static int closerem_ft897(struct rpt *myrpt)
04389 {
04390 simple_command_ft897(myrpt, 0x88);
04391 return 0;
04392 }
04393
04394
04395
04396
04397
04398
04399
04400 static int multimode_bump_freq_ft897(struct rpt *myrpt, int interval)
04401 {
04402 int m, d;
04403
04404 ast_debug(1, "Before bump: %s\n", myrpt->freq);
04405
04406 if (split_freq(&m, &d, myrpt->freq))
04407 return -1;
04408
04409 d += (interval / 10);
04410 if (d < 0) {
04411 m--;
04412 d += 100000;
04413 } else if (d >= 100000) {
04414 m++;
04415 d -= 100000;
04416 }
04417
04418 if (check_freq_ft897(m, d, NULL)) {
04419 ast_debug(1, "Bump freq invalid\n");
04420 return -1;
04421 }
04422
04423 snprintf(myrpt->freq, MAXREMSTR, "%d.%05d", m, d);
04424 ast_debug(1, "After bump: %s\n", myrpt->freq);
04425
04426 return set_freq_ft897(myrpt, myrpt->freq);
04427 }
04428
04429
04430
04431
04432
04433
04434
04435 static int setrem(struct rpt *myrpt)
04436 {
04437 return 0;
04438 if (!strcmp(myrpt->remote, remote_rig_ft897))
04439 return set_ft897(myrpt);
04440 else if (!strcmp(myrpt->remote, remote_rig_rbi))
04441 return setrbi(myrpt);
04442 else
04443 return -1;
04444 }
04445
04446 static int closerem(struct rpt *myrpt)
04447 {
04448 return 0;
04449 if (!strcmp(myrpt->remote, remote_rig_ft897))
04450 return closerem_ft897(myrpt);
04451 else
04452 return 0;
04453 }
04454
04455
04456
04457
04458
04459 static int check_freq(struct rpt *myrpt, int m, int d, int *defmode)
04460 {
04461 if (!strcmp(myrpt->remote, remote_rig_ft897))
04462 return check_freq_ft897(m, d, defmode);
04463 else if (!strcmp(myrpt->remote, remote_rig_rbi))
04464 return check_freq_rbi(m, d, defmode);
04465 else
04466 return -1;
04467 }
04468
04469
04470
04471
04472
04473 static int multimode_capable(struct rpt *myrpt)
04474 {
04475 if (!strcmp(myrpt->remote, remote_rig_ft897))
04476 return 1;
04477 return 0;
04478 }
04479
04480
04481
04482
04483
04484 static int multimode_bump_freq(struct rpt *myrpt, int interval)
04485 {
04486 if (!strcmp(myrpt->remote, remote_rig_ft897))
04487 return multimode_bump_freq_ft897(myrpt, interval);
04488 else
04489 return -1;
04490 }
04491
04492
04493
04494
04495
04496
04497 static void stop_scan(struct rpt *myrpt, int flag)
04498 {
04499 myrpt->hfscanmode = 0;
04500 myrpt->hfscanstatus = ((flag) ? -2 : -1);
04501 }
04502
04503
04504
04505
04506
04507 static int service_scan(struct rpt *myrpt)
04508 {
04509 int res, interval, mhz, decimals;
04510 char k10=0, k100=0;
04511
04512 switch (myrpt->hfscanmode) {
04513
04514 case HF_SCAN_DOWN_SLOW:
04515 interval = -10;
04516 break;
04517
04518 case HF_SCAN_DOWN_QUICK:
04519 interval = -50;
04520 break;
04521
04522 case HF_SCAN_DOWN_FAST:
04523 interval = -200;
04524 break;
04525
04526 case HF_SCAN_UP_SLOW:
04527 interval = 10;
04528 break;
04529
04530 case HF_SCAN_UP_QUICK:
04531 interval = 50;
04532 break;
04533
04534 case HF_SCAN_UP_FAST:
04535 interval = 200;
04536 break;
04537
04538 default:
04539 myrpt->hfscanmode = 0;
04540 return -1;
04541 }
04542
04543 res = split_freq(&mhz, &decimals, myrpt->freq);
04544
04545 if (!res) {
04546 k100 = decimals / 10000;
04547 k10 = (decimals / 1000) % 10;
04548 res = multimode_bump_freq(myrpt, interval);
04549 }
04550
04551 if (!res)
04552 res = split_freq(&mhz, &decimals, myrpt->freq);
04553
04554 if (res) {
04555 stop_scan(myrpt, 1);
04556 return -1;
04557 }
04558
04559
04560 if (k10 != (decimals / 1000) % 10) {
04561 int myhund = (interval < 0) ? k100 : decimals / 10000;
04562 int myten = (interval < 0) ? k10 : (decimals / 1000) % 10;
04563 myrpt->hfscanstatus = (myten == 0) ? (myhund) * 100 : (myten) * 10;
04564 }
04565 return res;
04566
04567 }
04568
04569
04570 static int rmt_telem_start(struct rpt *myrpt, struct ast_channel *chan, int delay)
04571 {
04572 myrpt->remotetx = 0;
04573 ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_UNKEY);
04574 if (!myrpt->remoterx)
04575 ast_indicate(chan, AST_CONTROL_RADIO_KEY);
04576 if (ast_safe_sleep(chan, delay) == -1)
04577 return -1;
04578 return 0;
04579 }
04580
04581
04582 static int rmt_telem_finish(struct rpt *myrpt, struct ast_channel *chan)
04583 {
04584 struct dahdi_params par;
04585
04586 if (ioctl(myrpt->txchannel->fds[0], DAHDI_GET_PARAMS, &par) == -1) {
04587 return -1;
04588
04589 }
04590 if (!par.rxisoffhook) {
04591 ast_indicate(myrpt->remchannel, AST_CONTROL_RADIO_UNKEY);
04592 myrpt->remoterx = 0;
04593 } else {
04594 myrpt->remoterx = 1;
04595 }
04596 return 0;
04597 }
04598
04599
04600 static int rmt_sayfile(struct rpt *myrpt, struct ast_channel *chan, int delay, char *filename)
04601 {
04602 int res;
04603
04604 res = rmt_telem_start(myrpt, chan, delay);
04605
04606 if (!res)
04607 res = sayfile(chan, filename);
04608
04609 if (!res)
04610 res = rmt_telem_finish(myrpt, chan);
04611 return res;
04612 }
04613
04614 static int rmt_saycharstr(struct rpt *myrpt, struct ast_channel *chan, int delay, char *charstr)
04615 {
04616 int res;
04617
04618 res = rmt_telem_start(myrpt, chan, delay);
04619
04620 if (!res)
04621 res = saycharstr(chan, charstr);
04622
04623 if (!res)
04624 res = rmt_telem_finish(myrpt, chan);
04625 return res;
04626 }
04627
04628
04629
04630
04631
04632 static int function_remote(struct rpt *myrpt, char *param, char *digitbuf, int command_source, struct rpt_link *mylink)
04633 {
04634 char *s, *modestr;
04635 const char *val;
04636 int i, j, ht, k, l, ls2, res, offset, offsave, modesave, defmode = 0;
04637 char multimode = 0;
04638 char oc;
04639 char tmp[20], freq[20] = "", savestr[20] = "";
04640 int mhz = 0, decimals = 0;
04641 struct ast_channel *mychannel;
04642 AST_DECLARE_APP_ARGS(args1,
04643 AST_APP_ARG(freq);
04644 AST_APP_ARG(xpl);
04645 AST_APP_ARG(mode);
04646 );
04647 AST_DECLARE_APP_ARGS(args,
04648 AST_APP_ARG(s1);
04649 AST_APP_ARG(s2);
04650 );
04651
04652 if ((!param) || (command_source == SOURCE_RPT) || (command_source == SOURCE_LNK))
04653 return DC_ERROR;
04654
04655 multimode = multimode_capable(myrpt);
04656 mychannel = myrpt->remchannel;
04657
04658 switch (myatoi(param)) {
04659 case 1:
04660 if (strlen(digitbuf) < 2)
04661 break;
04662
04663 for (i = 0 ; i < 2 ; i++) {
04664 if ((digitbuf[i] < '0') || (digitbuf[i] > '9'))
04665 return DC_ERROR;
04666 }
04667
04668 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.memory, digitbuf);
04669 if (!val) {
04670 if (ast_safe_sleep(mychannel, 1000) == -1)
04671 return DC_ERROR;
04672 sayfile(mychannel, "rpt/memory_notfound");
04673 return DC_COMPLETE;
04674 }
04675 s = ast_strdupa(val);
04676 AST_STANDARD_APP_ARGS(args1, s);
04677 if (args1.argc < 3)
04678 return DC_ERROR;
04679 ast_copy_string(myrpt->freq, args1.freq, sizeof(myrpt->freq));
04680 ast_copy_string(myrpt->rxpl, args1.xpl, sizeof(myrpt->rxpl));
04681 ast_copy_string(myrpt->txpl, args1.xpl, sizeof(myrpt->rxpl));
04682 myrpt->remmode = REM_MODE_FM;
04683 myrpt->offset = REM_SIMPLEX;
04684 myrpt->powerlevel = REM_MEDPWR;
04685 myrpt->txplon = myrpt->rxplon = 0;
04686 modestr = args1.mode;
04687 while (*modestr) {
04688 switch (*modestr++) {
04689 case 'A':
04690 case 'a':
04691 strcpy(myrpt->rxpl, "100.0");
04692 strcpy(myrpt->txpl, "100.0");
04693 myrpt->remmode = REM_MODE_AM;
04694 break;
04695
04696 case 'B':
04697 case 'b':
04698 strcpy(myrpt->rxpl, "100.0");
04699 strcpy(myrpt->txpl, "100.0");
04700 myrpt->remmode = REM_MODE_LSB;
04701 break;
04702
04703 case 'F':
04704 myrpt->remmode = REM_MODE_FM;
04705 break;
04706
04707 case 'L':
04708 case 'l':
04709 myrpt->powerlevel = REM_LOWPWR;
04710 break;
04711 case 'H':
04712 case 'h':
04713 myrpt->powerlevel = REM_HIPWR;
04714 break;
04715
04716 case 'M':
04717 case 'm':
04718 myrpt->powerlevel = REM_MEDPWR;
04719 break;
04720
04721 case '-':
04722 myrpt->offset = REM_MINUS;
04723 break;
04724
04725 case '+':
04726 myrpt->offset = REM_PLUS;
04727 break;
04728
04729 case 'S':
04730 case 's':
04731 myrpt->offset = REM_SIMPLEX;
04732 break;
04733
04734 case 'T':
04735 case 't':
04736 myrpt->txplon = 1;
04737 break;
04738
04739 case 'R':
04740 case 'r':
04741 myrpt->rxplon = 1;
04742 break;
04743
04744 case 'U':
04745 case 'u':
04746 strcpy(myrpt->rxpl, "100.0");
04747 strcpy(myrpt->txpl, "100.0");
04748 myrpt->remmode = REM_MODE_USB;
04749 break;
04750 }
04751 }
04752
04753 if (setrem(myrpt) == -1)
04754 return DC_ERROR;
04755
04756 return DC_COMPLETE;
04757
04758 case 2:
04759 for (i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++) {
04760 if (digitbuf[i] == '*') {
04761 j++;
04762 continue;
04763 }
04764 if ((digitbuf[i] < '0') || (digitbuf[i] > '9'))
04765 goto invalid_freq;
04766 else {
04767 if (j == 0)
04768 l++;
04769 if (j == 1)
04770 k++;
04771 }
04772 }
04773
04774 i = strlen(digitbuf) - 1;
04775 if (multimode) {
04776 if ((j > 2) || (l > 3) || (k > 6))
04777 goto invalid_freq;
04778 } else {
04779 if ((j > 2) || (l > 4) || (k > 3))
04780 goto invalid_freq;
04781 }
04782
04783
04784
04785 if (j < 2)
04786 break;
04787
04788
04789
04790 s = ast_strdupa(digitbuf);
04791 AST_NONSTANDARD_APP_ARGS(args, s, '*');
04792 ls2 = strlen(args.s2);
04793
04794 switch (ls2) {
04795 case 1:
04796 ht = 0;
04797 k = 100 * atoi(args.s2);
04798 break;
04799 case 2:
04800 ht = 0;
04801 k = 10 * atoi(args.s2);
04802 break;
04803 case 3:
04804 if (!multimode) {
04805 if ((args.s2[2] != '0') && (args.s2[2] != '5'))
04806 goto invalid_freq;
04807 }
04808 ht = 0;
04809 k = atoi(args.s2);
04810 break;
04811 case 4:
04812 k = atoi(args.s2) / 10;
04813 ht = 10 * (atoi(args.s2 + (ls2 - 1)));
04814 break;
04815 case 5:
04816 k = atoi(args.s2) / 100;
04817 ht = (atoi(args.s2 + (ls2 - 2)));
04818 break;
04819 default:
04820 goto invalid_freq;
04821 }
04822
04823
04824
04825 snprintf(freq, sizeof(freq), "%s.%03d%02d", args.s1, k, ht);
04826 ast_debug(1, "New frequency: %s\n", freq);
04827
04828 split_freq(&mhz, &decimals, freq);
04829
04830 if (check_freq(myrpt, mhz, decimals, &defmode))
04831 goto invalid_freq;
04832
04833 if ((defmode == REM_MODE_FM) && (digitbuf[i] == '*'))
04834 break;
04835
04836 offset = REM_SIMPLEX;
04837
04838 if (defmode == REM_MODE_FM) {
04839 oc = *s;
04840 if (oc) {
04841 switch (oc) {
04842 case '1':
04843 offset = REM_MINUS;
04844 break;
04845 case '2':
04846 offset = REM_SIMPLEX;
04847 break;
04848 case '3':
04849 offset = REM_PLUS;
04850 break;
04851 default:
04852 goto invalid_freq;
04853 }
04854 }
04855 }
04856 offsave = myrpt->offset;
04857 modesave = myrpt->remmode;
04858 ast_copy_string(savestr, myrpt->freq, sizeof(savestr));
04859 ast_copy_string(myrpt->freq, freq, sizeof(myrpt->freq));
04860 myrpt->offset = offset;
04861 myrpt->remmode = defmode;
04862
04863 if (setrem(myrpt) == -1) {
04864 myrpt->offset = offsave;
04865 myrpt->remmode = modesave;
04866 ast_copy_string(myrpt->freq, savestr, sizeof(myrpt->freq));
04867 goto invalid_freq;
04868 }
04869
04870 return DC_COMPLETE;
04871
04872 invalid_freq:
04873 rmt_sayfile(myrpt, mychannel, 1000, "rpt/invalid-freq");
04874
04875 return DC_ERROR;
04876
04877 case 3:
04878
04879 for (i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++) {
04880 if (digitbuf[i] == '*') {
04881 j++;
04882 continue;
04883 }
04884 if ((digitbuf[i] < '0') || (digitbuf[i] > '9'))
04885 return DC_ERROR;
04886 else {
04887 if (j)
04888 l++;
04889 else
04890 k++;
04891 }
04892 }
04893 if ((j > 1) || (k > 3) || (l > 1))
04894 return DC_ERROR;
04895 i = strlen(digitbuf) - 1;
04896 if ((j != 1) || (k < 2)|| (l != 1))
04897 break;
04898 ast_debug(1, "PL digits entered %s\n", digitbuf);
04899
04900 ast_copy_string(tmp, digitbuf, sizeof(tmp));
04901
04902 s = strchr(tmp, '*');
04903 if (s)
04904 *s = '.';
04905 ast_copy_string(savestr, myrpt->rxpl, sizeof(savestr));
04906 ast_copy_string(myrpt->rxpl, tmp, sizeof(myrpt->rxpl));
04907
04908 if (setrem(myrpt) == -1) {
04909 ast_copy_string(myrpt->rxpl, savestr, sizeof(myrpt->rxpl));
04910 return DC_ERROR;
04911 }
04912
04913 return DC_COMPLETE;
04914 case 4:
04915 for (i = 0, j = 0, k = 0, l = 0 ; digitbuf[i] ; i++) {
04916 if (digitbuf[i] == '*') {
04917 j++;
04918 continue;
04919 }
04920 if ((digitbuf[i] < '0') || (digitbuf[i] > '9'))
04921 return DC_ERROR;
04922 else {
04923 if (j)
04924 l++;
04925 else
04926 k++;
04927 }
04928 }
04929 if ((j > 1) || (k > 3) || (l > 1))
04930 return DC_ERROR;
04931 i = strlen(digitbuf) - 1;
04932 if ((j != 1) || (k < 2)|| (l != 1))
04933 break;
04934 ast_debug(1, "PL digits entered %s\n", digitbuf);
04935
04936 ast_copy_string(tmp, digitbuf, sizeof(tmp));
04937
04938 s = strchr(tmp, '*');
04939 if (s)
04940 *s = '.';
04941 ast_copy_string(savestr, myrpt->txpl, sizeof(savestr));
04942 ast_copy_string(myrpt->txpl, tmp, sizeof(myrpt->txpl));
04943
04944 if (setrem(myrpt) == -1) {
04945 ast_copy_string(myrpt->txpl, savestr, sizeof(myrpt->txpl));
04946 return DC_ERROR;
04947 }
04948
04949 return DC_COMPLETE;
04950
04951 case 6:
04952 if (strlen(digitbuf) < 1)
04953 break;
04954
04955 if (!multimode)
04956 return DC_ERROR;
04957
04958 switch (*digitbuf) {
04959 case '1':
04960 split_freq(&mhz, &decimals, myrpt->freq);
04961 if (mhz < 29)
04962 return DC_ERROR;
04963 myrpt->remmode = REM_MODE_FM;
04964 res = rmt_saycharstr(myrpt, mychannel, 1000, "FM");
04965 break;
04966
04967 case '2':
04968 myrpt->remmode = REM_MODE_USB;
04969 res = rmt_saycharstr(myrpt, mychannel, 1000, "USB");
04970 break;
04971
04972 case '3':
04973 myrpt->remmode = REM_MODE_LSB;
04974 res = rmt_saycharstr(myrpt, mychannel, 1000, "LSB");
04975 break;
04976
04977 case '4':
04978 myrpt->remmode = REM_MODE_AM;
04979 res = rmt_saycharstr(myrpt, mychannel, 1000, "AM");
04980 break;
04981
04982 default:
04983 return DC_ERROR;
04984 }
04985 if (res)
04986 return DC_ERROR;
04987
04988 if (setrem(myrpt))
04989 return DC_ERROR;
04990 return DC_COMPLETE;
04991
04992 case 100:
04993 case 101:
04994 case 102:
04995 case 103:
04996 case 104:
04997 case 105:
04998 case 106:
04999 res = rmt_telem_start(myrpt, mychannel, 1000);
05000 switch (myatoi(param)) {
05001 case 100:
05002 myrpt->rxplon = 0;
05003 if (!res)
05004 res = sayfile(mychannel, "rpt/rxpl");
05005 if (!res)
05006 sayfile(mychannel, "rpt/off");
05007 break;
05008
05009 case 101:
05010 myrpt->rxplon = 1;
05011 if (!res)
05012 res = sayfile(mychannel, "rpt/rxpl");
05013 if (!res)
05014 sayfile(mychannel, "rpt/on");
05015 break;
05016
05017 case 102:
05018 myrpt->txplon = 0;
05019 if (!res)
05020 res = sayfile(mychannel, "rpt/txpl");
05021 if (!res)
05022 sayfile(mychannel, "rpt/off");
05023 break;
05024
05025 case 103:
05026 myrpt->txplon = 1;
05027 if (!res)
05028 res = sayfile(mychannel, "rpt/txpl");
05029 if (!res)
05030 sayfile(mychannel, "rpt/on");
05031 break;
05032
05033 case 104:
05034 myrpt->powerlevel = REM_LOWPWR;
05035 if (!res)
05036 res = sayfile(mychannel, "rpt/lopwr");
05037 break;
05038
05039 case 105:
05040 myrpt->powerlevel = REM_MEDPWR;
05041 if (!res)
05042 res = sayfile(mychannel, "rpt/medpwr");
05043 break;
05044
05045 case 106:
05046 myrpt->powerlevel = REM_HIPWR;
05047 if (!res)
05048 res = sayfile(mychannel, "rpt/hipwr");
05049 break;
05050
05051 default:
05052 if (!res)
05053 rmt_telem_finish(myrpt, mychannel);
05054 return DC_ERROR;
05055 }
05056 if (!res)
05057 res = rmt_telem_finish(myrpt, mychannel);
05058 if (res)
05059 return DC_ERROR;
05060
05061 if (setrem(myrpt) == -1)
05062 return DC_ERROR;
05063 return DC_COMPLETE;
05064
05065 case 107:
05066 multimode_bump_freq(myrpt, -20);
05067 return DC_COMPLETE;
05068
05069 case 108:
05070 multimode_bump_freq(myrpt, -100);
05071 return DC_COMPLETE;
05072
05073 case 109:
05074 multimode_bump_freq(myrpt, -500);
05075 return DC_COMPLETE;
05076
05077 case 110:
05078 multimode_bump_freq(myrpt, 20);
05079 return DC_COMPLETE;
05080
05081 case 111:
05082 multimode_bump_freq(myrpt, 100);
05083 return DC_COMPLETE;
05084
05085 case 112:
05086 multimode_bump_freq(myrpt, 500);
05087 return DC_COMPLETE;
05088
05089 case 113:
05090 case 114:
05091 case 115:
05092 case 116:
05093 case 117:
05094 case 118:
05095 myrpt->remotetx = 0;
05096 ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_UNKEY);
05097 if (!myrpt->remoterx)
05098 ast_indicate(mychannel, AST_CONTROL_RADIO_KEY);
05099 if (ast_safe_sleep(mychannel, 1000) == -1)
05100 return DC_ERROR;
05101
05102 switch (myatoi(param)) {
05103 case 113:
05104 res = sayfile(mychannel, "rpt/down");
05105 if (!res)
05106 res = sayfile(mychannel, "rpt/slow");
05107 if (!res) {
05108 myrpt->scantimer = REM_SCANTIME;
05109 myrpt->hfscanmode = HF_SCAN_DOWN_SLOW;
05110 }
05111 break;
05112
05113 case 114:
05114 res = sayfile(mychannel, "rpt/down");
05115 if (!res)
05116 res = sayfile(mychannel, "rpt/quick");
05117 if (!res) {
05118 myrpt->scantimer = REM_SCANTIME;
05119 myrpt->hfscanmode = HF_SCAN_DOWN_QUICK;
05120 }
05121 break;
05122
05123 case 115:
05124 res = sayfile(mychannel, "rpt/down");
05125 if (!res)
05126 res = sayfile(mychannel, "rpt/fast");
05127 if (!res) {
05128 myrpt->scantimer = REM_SCANTIME;
05129 myrpt->hfscanmode = HF_SCAN_DOWN_FAST;
05130 }
05131 break;
05132
05133 case 116:
05134 res = sayfile(mychannel, "rpt/up");
05135 if (!res)
05136 res = sayfile(mychannel, "rpt/slow");
05137 if (!res) {
05138 myrpt->scantimer = REM_SCANTIME;
05139 myrpt->hfscanmode = HF_SCAN_UP_SLOW;
05140 }
05141 break;
05142
05143 case 117:
05144 res = sayfile(mychannel, "rpt/up");
05145 if (!res)
05146 res = sayfile(mychannel, "rpt/quick");
05147 if (!res) {
05148 myrpt->scantimer = REM_SCANTIME;
05149 myrpt->hfscanmode = HF_SCAN_UP_QUICK;
05150 }
05151 break;
05152
05153 case 118:
05154 res = sayfile(mychannel, "rpt/up");
05155 if (!res)
05156 res = sayfile(mychannel, "rpt/fast");
05157 if (!res) {
05158 myrpt->scantimer = REM_SCANTIME;
05159 myrpt->hfscanmode = HF_SCAN_UP_FAST;
05160 }
05161 break;
05162 }
05163 rmt_telem_finish(myrpt, mychannel);
05164 return DC_COMPLETE;
05165
05166
05167 case 119:
05168 myrpt->tunerequest = 1;
05169 return DC_COMPLETE;
05170
05171 case 5:
05172 case 140:
05173 res = rmt_telem_start(myrpt, mychannel, 1000);
05174
05175 res = sayfile(mychannel, "rpt/node");
05176 if (!res)
05177 res = saycharstr(mychannel, myrpt->name);
05178 if (!res)
05179 res = sayfile(mychannel, "rpt/frequency");
05180 if (!res)
05181 res = split_freq(&mhz, &decimals, myrpt->freq);
05182 if (!res) {
05183 if (mhz < 100)
05184 res = saynum(mychannel, mhz);
05185 else
05186 res = saydigits(mychannel, mhz);
05187 }
05188 if (!res)
05189 res = sayfile(mychannel, "letters/dot");
05190 if (!res)
05191 res = saydigits(mychannel, decimals);
05192
05193 if (res) {
05194 rmt_telem_finish(myrpt, mychannel);
05195 return DC_ERROR;
05196 }
05197 if (myrpt->remmode == REM_MODE_FM) {
05198 switch (myrpt->offset) {
05199 case REM_MINUS:
05200 res = sayfile(mychannel, "rpt/minus");
05201 break;
05202
05203 case REM_SIMPLEX:
05204 res = sayfile(mychannel, "rpt/simplex");
05205 break;
05206
05207 case REM_PLUS:
05208 res = sayfile(mychannel, "rpt/plus");
05209 break;
05210
05211 default:
05212 return DC_ERROR;
05213
05214 }
05215 } else {
05216 switch (myrpt->remmode) {
05217 case REM_MODE_USB:
05218 res = saycharstr(mychannel, "USB");
05219 break;
05220 case REM_MODE_LSB:
05221 res = saycharstr(mychannel, "LSB");
05222 break;
05223 case REM_MODE_AM:
05224 res = saycharstr(mychannel, "AM");
05225 break;
05226 default:
05227 return DC_ERROR;
05228 }
05229 }
05230
05231 if (res == -1) {
05232 rmt_telem_finish(myrpt, mychannel);
05233 return DC_ERROR;
05234 }
05235
05236 if (myatoi(param) == 140) {
05237 if (!res)
05238 res = rmt_telem_finish(myrpt, mychannel);
05239 if (res)
05240 return DC_ERROR;
05241 return DC_COMPLETE;
05242 }
05243
05244 switch (myrpt->powerlevel) {
05245 case REM_LOWPWR:
05246 res = sayfile(mychannel, "rpt/lopwr") ;
05247 break;
05248 case REM_MEDPWR:
05249 res = sayfile(mychannel, "rpt/medpwr");
05250 break;
05251 case REM_HIPWR:
05252 res = sayfile(mychannel, "rpt/hipwr");
05253 break;
05254 }
05255 if (res || (sayfile(mychannel, "rpt/rxpl") == -1) ||
05256 (sayfile(mychannel, "rpt/frequency") == -1) ||
05257 (saycharstr(mychannel, myrpt->rxpl) == -1) ||
05258 (sayfile(mychannel, "rpt/txpl") == -1) ||
05259 (sayfile(mychannel, "rpt/frequency") == -1) ||
05260 (saycharstr(mychannel, myrpt->txpl) == -1) ||
05261 (sayfile(mychannel, "rpt/txpl") == -1) ||
05262 (sayfile(mychannel, ((myrpt->txplon) ? "rpt/on" : "rpt/off")) == -1) ||
05263 (sayfile(mychannel, "rpt/rxpl") == -1) ||
05264 (sayfile(mychannel, ((myrpt->rxplon) ? "rpt/on" : "rpt/off")) == -1))
05265 {
05266 rmt_telem_finish(myrpt, mychannel);
05267 return DC_ERROR;
05268 }
05269 if (!res)
05270 res = rmt_telem_finish(myrpt, mychannel);
05271 if (res)
05272 return DC_ERROR;
05273
05274 return DC_COMPLETE;
05275 default:
05276 return DC_ERROR;
05277 }
05278
05279 return DC_INDETERMINATE;
05280 }
05281
05282 static int handle_remote_dtmf_digit(struct rpt *myrpt, char c, char *keyed, int phonemode)
05283 {
05284 time_t now;
05285 int ret, res = 0, src;
05286
05287
05288 if (myrpt->hfscanmode) {
05289 stop_scan(myrpt, 0);
05290 return 0;
05291 }
05292
05293 time(&now);
05294
05295 if ((myrpt->dtmf_time_rem + DTMF_TIMEOUT) < now) {
05296 myrpt->dtmfidx = -1;
05297 myrpt->dtmfbuf[0] = 0;
05298 myrpt->dtmf_time_rem = 0;
05299 }
05300
05301 if (myrpt->dtmfidx == -1) {
05302
05303 if (c != myrpt->p.funcchar)
05304 return 0;
05305 myrpt->dtmfidx = 0;
05306 myrpt->dtmfbuf[0] = 0;
05307 myrpt->dtmf_time_rem = now;
05308 return 0;
05309 }
05310
05311 if (myrpt->dtmfidx >= MAXDTMF) {
05312 myrpt->dtmfidx = 0;
05313 myrpt->dtmfbuf[0] = 0;
05314 myrpt->dtmf_time_rem = now;
05315 }
05316 if (c == myrpt->p.funcchar) {
05317
05318 if ((myrpt->dtmfidx < 1) || (myrpt->dtmfbuf[myrpt->dtmfidx - 1] == myrpt->p.funcchar)) {
05319 myrpt->dtmfidx = 0;
05320 myrpt->dtmfbuf[0] = 0;
05321 myrpt->dtmf_time_rem = now;
05322 return 0;
05323 }
05324 }
05325 myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
05326 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
05327 myrpt->dtmf_time_rem = now;
05328
05329
05330 src = SOURCE_RMT;
05331 if (phonemode > 1)
05332 src = SOURCE_DPHONE;
05333 else if (phonemode)
05334 src = SOURCE_PHONE;
05335 ret = collect_function_digits(myrpt, myrpt->dtmfbuf, src, NULL);
05336
05337 switch(ret) {
05338 case DC_INDETERMINATE:
05339 res = 0;
05340 break;
05341 case DC_DOKEY:
05342 if (keyed)
05343 *keyed = 1;
05344 res = 0;
05345 break;
05346 case DC_REQ_FLUSH:
05347 myrpt->dtmfidx = 0;
05348 myrpt->dtmfbuf[0] = 0;
05349 res = 0;
05350 break;
05351 case DC_COMPLETE:
05352 myrpt->totalexecdcommands++;
05353 myrpt->dailyexecdcommands++;
05354 ast_copy_string(myrpt->lastdtmfcommand, myrpt->dtmfbuf, MAXDTMF);
05355 myrpt->dtmfbuf[0] = 0;
05356 myrpt->dtmfidx = -1;
05357 myrpt->dtmf_time_rem = 0;
05358 res = 1;
05359 break;
05360 case DC_ERROR:
05361 default:
05362 myrpt->dtmfbuf[0] = 0;
05363 myrpt->dtmfidx = -1;
05364 myrpt->dtmf_time_rem = 0;
05365 res = 0;
05366 }
05367
05368 return res;
05369 }
05370
05371 static int handle_remote_data(struct rpt *myrpt, char *str)
05372 {
05373 char cmd[300], dest[300], src[300], c;
05374 int seq, res;
05375
05376 if (!strcmp(str, discstr))
05377 return 0;
05378 if (sscanf(str, "%s %s %s %d %c", cmd, dest, src, &seq, &c) != 5) {
05379 ast_log(LOG_WARNING, "Unable to parse link string %s\n", str);
05380 return 0;
05381 }
05382 if (strcmp(cmd, "D")) {
05383 ast_log(LOG_WARNING, "Unable to parse link string %s\n", str);
05384 return 0;
05385 }
05386
05387 if (strcmp(dest, myrpt->name))
05388 return 0;
05389 res = handle_remote_dtmf_digit(myrpt, c, NULL, 0);
05390 if (res != 1)
05391 return res;
05392 myrpt->remotetx = 0;
05393 ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_UNKEY);
05394 if (!myrpt->remoterx) {
05395 ast_indicate(myrpt->remchannel, AST_CONTROL_RADIO_KEY);
05396 }
05397 if (ast_safe_sleep(myrpt->remchannel, 1000) == -1)
05398 return -1;
05399 res = telem_lookup(myrpt, myrpt->remchannel, myrpt->name, "functcomplete");
05400 rmt_telem_finish(myrpt, myrpt->remchannel);
05401 return res;
05402 }
05403
05404 static int handle_remote_phone_dtmf(struct rpt *myrpt, char c, char *keyed, int phonemode)
05405 {
05406 int res;
05407
05408 if (keyed && *keyed && (c == myrpt->p.endchar)) {
05409 *keyed = 0;
05410 return DC_INDETERMINATE;
05411 }
05412
05413 res = handle_remote_dtmf_digit(myrpt, c, keyed, phonemode);
05414 if (res != 1)
05415 return res;
05416 myrpt->remotetx = 0;
05417 ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_UNKEY);
05418 if (!myrpt->remoterx) {
05419 ast_indicate(myrpt->remchannel, AST_CONTROL_RADIO_KEY);
05420 }
05421 if (ast_safe_sleep(myrpt->remchannel, 1000) == -1)
05422 return -1;
05423 res = telem_lookup(myrpt, myrpt->remchannel, myrpt->name, "functcomplete");
05424 rmt_telem_finish(myrpt, myrpt->remchannel);
05425 return res;
05426 }
05427
05428 static int attempt_reconnect(struct rpt *myrpt, struct rpt_link *l)
05429 {
05430 const char *val;
05431 char *s, *tele;
05432 char deststr[300] = "";
05433 AST_DECLARE_APP_ARGS(args,
05434 AST_APP_ARG(channel);
05435 AST_APP_ARG(extra);
05436 );
05437
05438 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, l->name);
05439 if (!val) {
05440 ast_log(LOG_ERROR, "attempt_reconnect: cannot find node %s\n", l->name);
05441 return -1;
05442 }
05443
05444 rpt_mutex_lock(&myrpt->lock);
05445
05446 remque((struct qelem *) l);
05447 rpt_mutex_unlock(&myrpt->lock);
05448 s = ast_strdupa(val);
05449 AST_STANDARD_APP_ARGS(args, s);
05450
05451
05452 snprintf(deststr, sizeof(deststr), "IAX2/%s", args.channel);
05453 tele = strchr(deststr, '/');
05454 if (!tele) {
05455 ast_log(LOG_ERROR, "attempt_reconnect:Dial number (%s) must be in format tech/number\n", deststr);
05456 return -1;
05457 }
05458 *tele++ = 0;
05459 l->elaptime = 0;
05460 l->connecttime = 0;
05461 l->chan = ast_request(deststr, AST_FORMAT_SLINEAR, tele, NULL);
05462 if (l->chan) {
05463 ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
05464 ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
05465 l->chan->whentohangup = 0;
05466 l->chan->appl = "Apprpt";
05467 l->chan->data = "(Remote Rx)";
05468 ast_verb(3, "rpt (attempt_reconnect) initiating call to %s/%s on %s\n",
05469 deststr, tele, l->chan->name);
05470 if (l->chan->cid.cid_num)
05471 ast_free(l->chan->cid.cid_num);
05472 l->chan->cid.cid_num = ast_strdup(myrpt->name);
05473 ast_call(l->chan, tele, 999);
05474
05475 } else {
05476 ast_verb(3, "Unable to place call to %s/%s on %s\n",
05477 deststr, tele, l->chan->name);
05478 return -1;
05479 }
05480 rpt_mutex_lock(&myrpt->lock);
05481
05482 insque((struct qelem *)l, (struct qelem *)myrpt->links.next);
05483 rpt_mutex_unlock(&myrpt->lock);
05484 ast_log(LOG_NOTICE, "Reconnect Attempt to %s in process\n", l->name);
05485 return 0;
05486 }
05487
05488
05489 static void local_dtmf_helper(struct rpt *myrpt, char c)
05490 {
05491 int res;
05492 char cmd[MAXDTMF+1] = "";
05493
05494 if (c == myrpt->p.endchar) {
05495
05496 if (myrpt->p.simple && myrpt->callmode) {
05497 rpt_mutex_lock(&myrpt->lock);
05498 myrpt->callmode = 0;
05499 rpt_mutex_unlock(&myrpt->lock);
05500 rpt_telemetry(myrpt, TERM, NULL);
05501 return;
05502 }
05503 rpt_mutex_lock(&myrpt->lock);
05504 myrpt->stopgen = 1;
05505 if (myrpt->cmdnode[0]) {
05506 myrpt->cmdnode[0] = 0;
05507 myrpt->dtmfidx = -1;
05508 myrpt->dtmfbuf[0] = 0;
05509 rpt_mutex_unlock(&myrpt->lock);
05510 rpt_telemetry(myrpt, COMPLETE, NULL);
05511 } else
05512 rpt_mutex_unlock(&myrpt->lock);
05513 return;
05514 }
05515 rpt_mutex_lock(&myrpt->lock);
05516 if (myrpt->cmdnode[0]) {
05517 rpt_mutex_unlock(&myrpt->lock);
05518 send_link_dtmf(myrpt, c);
05519 return;
05520 }
05521 if (!myrpt->p.simple) {
05522 if (c == myrpt->p.funcchar) {
05523 myrpt->dtmfidx = 0;
05524 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
05525 rpt_mutex_unlock(&myrpt->lock);
05526 time(&myrpt->dtmf_time);
05527 return;
05528 } else if ((c != myrpt->p.endchar) && (myrpt->dtmfidx >= 0)) {
05529 time(&myrpt->dtmf_time);
05530
05531 if (myrpt->dtmfidx < MAXDTMF) {
05532 myrpt->dtmfbuf[myrpt->dtmfidx++] = c;
05533 myrpt->dtmfbuf[myrpt->dtmfidx] = 0;
05534
05535 ast_copy_string(cmd, myrpt->dtmfbuf, sizeof(cmd));
05536
05537 rpt_mutex_unlock(&myrpt->lock);
05538 res = collect_function_digits(myrpt, cmd, SOURCE_RPT, NULL);
05539 rpt_mutex_lock(&myrpt->lock);
05540 switch(res) {
05541 case DC_INDETERMINATE:
05542 break;
05543 case DC_REQ_FLUSH:
05544 myrpt->dtmfidx = 0;
05545 myrpt->dtmfbuf[0] = 0;
05546 break;
05547 case DC_COMPLETE:
05548 myrpt->totalexecdcommands++;
05549 myrpt->dailyexecdcommands++;
05550 ast_copy_string(myrpt->lastdtmfcommand, cmd, MAXDTMF);
05551 myrpt->dtmfbuf[0] = 0;
05552 myrpt->dtmfidx = -1;
05553 myrpt->dtmf_time = 0;
05554 break;
05555
05556 case DC_ERROR:
05557 default:
05558 myrpt->dtmfbuf[0] = 0;
05559 myrpt->dtmfidx = -1;
05560 myrpt->dtmf_time = 0;
05561 break;
05562 }
05563 if (res != DC_INDETERMINATE) {
05564 rpt_mutex_unlock(&myrpt->lock);
05565 return;
05566 }
05567 }
05568 }
05569 } else {
05570 if ((!myrpt->callmode) && (c == myrpt->p.funcchar)) {
05571 myrpt->callmode = 1;
05572 myrpt->patchnoct = 0;
05573 myrpt->patchquiet = 0;
05574 myrpt->patchfarenddisconnect = 0;
05575 myrpt->patchdialtime = 0;
05576 ast_copy_string(myrpt->patchcontext, myrpt->p.ourcontext, sizeof(myrpt->patchcontext));
05577 myrpt->cidx = 0;
05578 myrpt->exten[myrpt->cidx] = 0;
05579 rpt_mutex_unlock(&myrpt->lock);
05580 ast_pthread_create_detached(&myrpt->rpt_call_thread, NULL, rpt_call, (void *)myrpt);
05581 return;
05582 }
05583 }
05584 if (myrpt->callmode == 1) {
05585 myrpt->exten[myrpt->cidx++] = c;
05586 myrpt->exten[myrpt->cidx] = 0;
05587
05588 if (ast_exists_extension(myrpt->pchannel, myrpt->patchcontext, myrpt->exten, 1, NULL)) {
05589 myrpt->callmode = 2;
05590 rpt_mutex_unlock(&myrpt->lock);
05591 if (!myrpt->patchquiet)
05592 rpt_telemetry(myrpt, PROC, NULL);
05593 return;
05594 }
05595
05596 if (!ast_canmatch_extension(myrpt->pchannel, myrpt->patchcontext, myrpt->exten, 1, NULL)) {
05597
05598 myrpt->callmode = 4;
05599 }
05600 rpt_mutex_unlock(&myrpt->lock);
05601 return;
05602 }
05603 if ((myrpt->callmode == 2) || (myrpt->callmode == 3)) {
05604 myrpt->mydtmf = c;
05605 }
05606 rpt_mutex_unlock(&myrpt->lock);
05607 return;
05608 }
05609
05610
05611
05612
05613 static void queue_id(struct rpt *myrpt)
05614 {
05615 myrpt->mustid = myrpt->tailid = 0;
05616 myrpt->idtimer = myrpt->p.idtime;
05617 rpt_mutex_unlock(&myrpt->lock);
05618 rpt_telemetry(myrpt, ID, NULL);
05619 rpt_mutex_lock(&myrpt->lock);
05620 }
05621
05622
05623
05624 static void do_scheduler(struct rpt *myrpt)
05625 {
05626 int res;
05627 struct ast_tm tmnow;
05628
05629 memcpy(&myrpt->lasttv, &myrpt->curtv, sizeof(struct timeval));
05630
05631 if ( (res = gettimeofday(&myrpt->curtv, NULL)) < 0)
05632 ast_log(LOG_NOTICE, "Scheduler gettime of day returned: %s\n", strerror(res));
05633
05634
05635
05636 if (myrpt->lasttv.tv_sec == myrpt->curtv.tv_sec)
05637 return;
05638
05639 ast_localtime(&myrpt->curtv, &tmnow, NULL);
05640
05641
05642
05643 if ((tmnow.tm_hour == 0) && (tmnow.tm_min == 0) && (tmnow.tm_sec == 0)) {
05644 myrpt->dailykeyups = 0;
05645 myrpt->dailytxtime = 0;
05646 myrpt->dailykerchunks = 0;
05647 myrpt->dailyexecdcommands = 0;
05648 }
05649 }
05650
05651
05652
05653 static void *rpt(void *this)
05654 {
05655 struct rpt *myrpt = (struct rpt *)this;
05656 char *tele, c;
05657 const char *idtalkover;
05658 int ms = MSWAIT, i, lasttx=0, val, remrx=0, identqueued, othertelemqueued, tailmessagequeued, ctqueued;
05659 struct ast_channel *who;
05660 struct dahdi_confinfo ci;
05661 time_t t;
05662 struct rpt_link *l, *m;
05663 struct rpt_tele *telem;
05664 char tmpstr[300];
05665
05666 rpt_mutex_lock(&myrpt->lock);
05667
05668 telem = myrpt->tele.next;
05669 while (telem != &myrpt->tele) {
05670 ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV);
05671 telem = telem->next;
05672 }
05673 rpt_mutex_unlock(&myrpt->lock);
05674
05675 for (i = 0; i < nrpts; i++) {
05676 if (&rpt_vars[i] == myrpt) {
05677 load_rpt_vars(i, 0);
05678 break;
05679 }
05680 }
05681 rpt_mutex_lock(&myrpt->lock);
05682 ast_copy_string(tmpstr, myrpt->rxchanname, sizeof(tmpstr));
05683 tele = strchr(tmpstr, '/');
05684 if (!tele) {
05685 ast_log(LOG_ERROR, "rpt:Rxchannel Dial number (%s) must be in format tech/number\n", myrpt->rxchanname);
05686 rpt_mutex_unlock(&myrpt->lock);
05687 myrpt->rpt_thread = AST_PTHREADT_STOP;
05688 pthread_exit(NULL);
05689 }
05690 *tele++ = 0;
05691 myrpt->rxchannel = ast_request(tmpstr, AST_FORMAT_SLINEAR, tele, NULL);
05692 if (myrpt->rxchannel) {
05693 if (myrpt->rxchannel->_state == AST_STATE_BUSY) {
05694 ast_log(LOG_ERROR, "rpt:Sorry unable to obtain Rx channel\n");
05695 rpt_mutex_unlock(&myrpt->lock);
05696 ast_hangup(myrpt->rxchannel);
05697 myrpt->rpt_thread = AST_PTHREADT_STOP;
05698 pthread_exit(NULL);
05699 }
05700 ast_set_read_format(myrpt->rxchannel, AST_FORMAT_SLINEAR);
05701 ast_set_write_format(myrpt->rxchannel, AST_FORMAT_SLINEAR);
05702 myrpt->rxchannel->whentohangup = 0;
05703 myrpt->rxchannel->appl = "Apprpt";
05704 myrpt->rxchannel->data = "(Repeater Rx)";
05705 ast_verb(3, "rpt (Rx) initiating call to %s/%s on %s\n",
05706 tmpstr, tele, myrpt->rxchannel->name);
05707 ast_call(myrpt->rxchannel, tele, 999);
05708 if (myrpt->rxchannel->_state != AST_STATE_UP) {
05709 rpt_mutex_unlock(&myrpt->lock);
05710 ast_hangup(myrpt->rxchannel);
05711 myrpt->rpt_thread = AST_PTHREADT_STOP;
05712 pthread_exit(NULL);
05713 }
05714 } else {
05715 ast_log(LOG_ERROR, "rpt:Sorry unable to obtain Rx channel\n");
05716 rpt_mutex_unlock(&myrpt->lock);
05717 myrpt->rpt_thread = AST_PTHREADT_STOP;
05718 pthread_exit(NULL);
05719 }
05720 if (myrpt->txchanname) {
05721 ast_copy_string(tmpstr, myrpt->txchanname, sizeof(tmpstr));
05722 tele = strchr(tmpstr, '/');
05723 if (!tele) {
05724 ast_log(LOG_ERROR, "rpt:Txchannel Dial number (%s) must be in format tech/number\n", myrpt->txchanname);
05725 rpt_mutex_unlock(&myrpt->lock);
05726 ast_hangup(myrpt->rxchannel);
05727 myrpt->rpt_thread = AST_PTHREADT_STOP;
05728 pthread_exit(NULL);
05729 }
05730 *tele++ = 0;
05731 myrpt->txchannel = ast_request(tmpstr, AST_FORMAT_SLINEAR, tele, NULL);
05732 if (myrpt->txchannel) {
05733 if (myrpt->txchannel->_state == AST_STATE_BUSY) {
05734 ast_log(LOG_ERROR, "rpt:Sorry unable to obtain Tx channel\n");
05735 rpt_mutex_unlock(&myrpt->lock);
05736 ast_hangup(myrpt->txchannel);
05737 ast_hangup(myrpt->rxchannel);
05738 myrpt->rpt_thread = AST_PTHREADT_STOP;
05739 pthread_exit(NULL);
05740 }
05741 ast_set_read_format(myrpt->txchannel, AST_FORMAT_SLINEAR);
05742 ast_set_write_format(myrpt->txchannel, AST_FORMAT_SLINEAR);
05743 myrpt->txchannel->whentohangup = 0;
05744 myrpt->txchannel->appl = "Apprpt";
05745 myrpt->txchannel->data = "(Repeater Tx)";
05746 ast_verb(3, "rpt (Tx) initiating call to %s/%s on %s\n",
05747 tmpstr, tele, myrpt->txchannel->name);
05748 ast_call(myrpt->txchannel, tele, 999);
05749 if (myrpt->rxchannel->_state != AST_STATE_UP) {
05750 rpt_mutex_unlock(&myrpt->lock);
05751 ast_hangup(myrpt->rxchannel);
05752 ast_hangup(myrpt->txchannel);
05753 myrpt->rpt_thread = AST_PTHREADT_STOP;
05754 pthread_exit(NULL);
05755 }
05756 } else {
05757 ast_log(LOG_ERROR, "rpt:Sorry unable to obtain Tx channel\n");
05758 rpt_mutex_unlock(&myrpt->lock);
05759 ast_hangup(myrpt->rxchannel);
05760 myrpt->rpt_thread = AST_PTHREADT_STOP;
05761 pthread_exit(NULL);
05762 }
05763 } else {
05764 myrpt->txchannel = myrpt->rxchannel;
05765 }
05766 ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_KEY);
05767 ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_UNKEY);
05768
05769 myrpt->pchannel = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
05770 if (!myrpt->pchannel) {
05771 ast_log(LOG_ERROR, "rpt:Sorry unable to obtain pseudo channel\n");
05772 rpt_mutex_unlock(&myrpt->lock);
05773 if (myrpt->txchannel != myrpt->rxchannel)
05774 ast_hangup(myrpt->txchannel);
05775 ast_hangup(myrpt->rxchannel);
05776 myrpt->rpt_thread = AST_PTHREADT_STOP;
05777 pthread_exit(NULL);
05778 }
05779
05780 ci.chan = 0;
05781 ci.confno = -1;
05782 ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER;
05783
05784 if (ioctl(myrpt->txchannel->fds[0], DAHDI_SETCONF, &ci) == -1) {
05785 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05786 rpt_mutex_unlock(&myrpt->lock);
05787 ast_hangup(myrpt->pchannel);
05788 if (myrpt->txchannel != myrpt->rxchannel)
05789 ast_hangup(myrpt->txchannel);
05790 ast_hangup(myrpt->rxchannel);
05791 myrpt->rpt_thread = AST_PTHREADT_STOP;
05792 pthread_exit(NULL);
05793 }
05794
05795 myrpt->txconf = ci.confno;
05796
05797 ci.chan = 0;
05798 ci.confno = -1;
05799 ci.confmode = ((myrpt->p.duplex == 2) || (myrpt->p.duplex == 4)) ? DAHDI_CONF_CONFANNMON :
05800 (DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER);
05801
05802 if (ioctl(myrpt->pchannel->fds[0], DAHDI_SETCONF, &ci) == -1) {
05803 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05804 rpt_mutex_unlock(&myrpt->lock);
05805 ast_hangup(myrpt->pchannel);
05806 if (myrpt->txchannel != myrpt->rxchannel)
05807 ast_hangup(myrpt->txchannel);
05808 ast_hangup(myrpt->rxchannel);
05809 myrpt->rpt_thread = AST_PTHREADT_STOP;
05810 pthread_exit(NULL);
05811 }
05812
05813 myrpt->conf = ci.confno;
05814
05815 myrpt->txpchannel = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
05816 if (!myrpt->txpchannel) {
05817 ast_log(LOG_ERROR, "rpt:Sorry unable to obtain pseudo channel\n");
05818 rpt_mutex_unlock(&myrpt->lock);
05819 ast_hangup(myrpt->pchannel);
05820 if (myrpt->txchannel != myrpt->rxchannel)
05821 ast_hangup(myrpt->txchannel);
05822 ast_hangup(myrpt->rxchannel);
05823 myrpt->rpt_thread = AST_PTHREADT_STOP;
05824 pthread_exit(NULL);
05825 }
05826
05827 ci.chan = 0;
05828 ci.confno = myrpt->txconf;
05829 ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER ;
05830
05831 if (ioctl(myrpt->txpchannel->fds[0], DAHDI_SETCONF, &ci) == -1) {
05832 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
05833 rpt_mutex_unlock(&myrpt->lock);
05834 ast_hangup(myrpt->txpchannel);
05835 ast_hangup(myrpt->pchannel);
05836 if (myrpt->txchannel != myrpt->rxchannel)
05837 ast_hangup(myrpt->txchannel);
05838 ast_hangup(myrpt->rxchannel);
05839 myrpt->rpt_thread = AST_PTHREADT_STOP;
05840 pthread_exit(NULL);
05841 }
05842
05843
05844
05845 myrpt->links.next = &myrpt->links;
05846 myrpt->links.prev = &myrpt->links;
05847 myrpt->tailtimer = 0;
05848 myrpt->totimer = 0;
05849 myrpt->tmsgtimer = myrpt->p.tailmessagetime;
05850 myrpt->idtimer = myrpt->p.politeid;
05851 myrpt->mustid = myrpt->tailid = 0;
05852 myrpt->callmode = 0;
05853 myrpt->tounkeyed = 0;
05854 myrpt->tonotify = 0;
05855 myrpt->retxtimer = 0;
05856 myrpt->skedtimer = 0;
05857 myrpt->tailevent = 0;
05858 lasttx = 0;
05859 myrpt->keyed = 0;
05860 idtalkover = ast_variable_retrieve(myrpt->cfg, myrpt->name, "idtalkover");
05861 myrpt->dtmfidx = -1;
05862 myrpt->dtmfbuf[0] = 0;
05863 myrpt->rem_dtmfidx = -1;
05864 myrpt->rem_dtmfbuf[0] = 0;
05865 myrpt->dtmf_time = 0;
05866 myrpt->rem_dtmf_time = 0;
05867 myrpt->enable = 1;
05868 myrpt->disgorgetime = 0;
05869 myrpt->lastnodewhichkeyedusup[0] = '\0';
05870 myrpt->dailytxtime = 0;
05871 myrpt->totaltxtime = 0;
05872 myrpt->dailykeyups = 0;
05873 myrpt->totalkeyups = 0;
05874 myrpt->dailykerchunks = 0;
05875 myrpt->totalkerchunks = 0;
05876 myrpt->dailyexecdcommands = 0;
05877 myrpt->totalexecdcommands = 0;
05878 myrpt->timeouts = 0;
05879 myrpt->exten[0] = '\0';
05880 myrpt->lastdtmfcommand[0] = '\0';
05881 if (myrpt->p.startupmacro) {
05882 snprintf(myrpt->macrobuf, sizeof(myrpt->macrobuf), "PPPP%s", myrpt->p.startupmacro);
05883 }
05884 if (myrpt->p.startupgosub) {
05885 snprintf(myrpt->gosubbuf, sizeof(myrpt->gosubbuf), "PPPP%s", myrpt->p.startupgosub);
05886 }
05887 rpt_mutex_unlock(&myrpt->lock);
05888 val = 0;
05889 ast_channel_setoption(myrpt->rxchannel, AST_OPTION_TONE_VERIFY, &val, sizeof(char), 0);
05890 val = 1;
05891 ast_channel_setoption(myrpt->rxchannel, AST_OPTION_RELAXDTMF, &val, sizeof(char), 0);
05892 while (ms >= 0) {
05893 struct ast_frame *f;
05894 struct ast_channel *cs[300];
05895 int totx=0, elap=0, n, toexit = 0;
05896
05897
05898 if ((myrpt->disgorgetime) && (time(NULL) >= myrpt->disgorgetime)) {
05899 struct rpt_link *zl;
05900 struct rpt_tele *zt;
05901
05902 myrpt->disgorgetime = 0;
05903 ast_log(LOG_NOTICE, "********** Variable Dump Start (app_rpt) **********\n");
05904 ast_log(LOG_NOTICE, "totx = %d\n", totx);
05905 ast_log(LOG_NOTICE, "remrx = %d\n", remrx);
05906 ast_log(LOG_NOTICE, "lasttx = %d\n", lasttx);
05907 ast_log(LOG_NOTICE, "elap = %d\n", elap);
05908 ast_log(LOG_NOTICE, "toexit = %d\n", toexit);
05909
05910 ast_log(LOG_NOTICE, "myrpt->keyed = %d\n", myrpt->keyed);
05911 ast_log(LOG_NOTICE, "myrpt->localtx = %d\n", myrpt->localtx);
05912 ast_log(LOG_NOTICE, "myrpt->callmode = %d\n", myrpt->callmode);
05913 ast_log(LOG_NOTICE, "myrpt->enable = %d\n", myrpt->enable);
05914 ast_log(LOG_NOTICE, "myrpt->mustid = %d\n", myrpt->mustid);
05915 ast_log(LOG_NOTICE, "myrpt->tounkeyed = %d\n", myrpt->tounkeyed);
05916 ast_log(LOG_NOTICE, "myrpt->tonotify = %d\n", myrpt->tonotify);
05917 ast_log(LOG_NOTICE, "myrpt->retxtimer = %ld\n", myrpt->retxtimer);
05918 ast_log(LOG_NOTICE, "myrpt->totimer = %d\n", myrpt->totimer);
05919 ast_log(LOG_NOTICE, "myrpt->tailtimer = %d\n", myrpt->tailtimer);
05920 ast_log(LOG_NOTICE, "myrpt->tailevent = %d\n", myrpt->tailevent);
05921
05922 zl = myrpt->links.next;
05923 while (zl != &myrpt->links) {
05924 ast_log(LOG_NOTICE, "*** Link Name: %s ***\n", zl->name);
05925 ast_log(LOG_NOTICE, " link->lasttx %d\n", zl->lasttx);
05926 ast_log(LOG_NOTICE, " link->lastrx %d\n", zl->lastrx);
05927 ast_log(LOG_NOTICE, " link->connected %d\n", zl->connected);
05928 ast_log(LOG_NOTICE, " link->hasconnected %d\n", zl->hasconnected);
05929 ast_log(LOG_NOTICE, " link->outbound %d\n", zl->outbound);
05930 ast_log(LOG_NOTICE, " link->disced %d\n", zl->disced);
05931 ast_log(LOG_NOTICE, " link->killme %d\n", zl->killme);
05932 ast_log(LOG_NOTICE, " link->disctime %ld\n", zl->disctime);
05933 ast_log(LOG_NOTICE, " link->retrytimer %ld\n", zl->retrytimer);
05934 ast_log(LOG_NOTICE, " link->retries = %d\n", zl->retries);
05935 ast_log(LOG_NOTICE, " link->reconnects = %d\n", zl->reconnects);
05936 zl = zl->next;
05937 }
05938
05939 zt = myrpt->tele.next;
05940 if (zt != &myrpt->tele)
05941 ast_log(LOG_NOTICE, "*** Telemetry Queue ***\n");
05942 while (zt != &myrpt->tele) {
05943 ast_log(LOG_NOTICE, " Telemetry mode: %d\n", zt->mode);
05944 zt = zt->next;
05945 }
05946 ast_log(LOG_NOTICE, "******* Variable Dump End (app_rpt) *******\n");
05947 }
05948
05949 if (myrpt->reload) {
05950 struct rpt_tele *telem;
05951
05952 rpt_mutex_lock(&myrpt->lock);
05953 telem = myrpt->tele.next;
05954 while (telem != &myrpt->tele) {
05955 ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV);
05956 telem = telem->next;
05957 }
05958 myrpt->reload = 0;
05959 rpt_mutex_unlock(&myrpt->lock);
05960 usleep(10000);
05961
05962 for (i = 0; i < nrpts; i++) {
05963 if (&rpt_vars[i] == myrpt) {
05964 load_rpt_vars(i, 0);
05965 break;
05966 }
05967 }
05968 }
05969
05970 rpt_mutex_lock(&myrpt->lock);
05971 if (ast_check_hangup(myrpt->rxchannel)) break;
05972 if (ast_check_hangup(myrpt->txchannel)) break;
05973 if (ast_check_hangup(myrpt->pchannel)) break;
05974 if (ast_check_hangup(myrpt->txpchannel)) break;
05975
05976
05977 myrpt->localtx = myrpt->keyed && (myrpt->dtmfidx == -1) && (!myrpt->cmdnode[0]);
05978
05979 l = myrpt->links.next;
05980 remrx = 0;
05981 while (l != &myrpt->links) {
05982 if (l->lastrx) {
05983 remrx = 1;
05984 if (l->name[0] != '0')
05985 strcpy(myrpt->lastnodewhichkeyedusup, l->name);
05986 }
05987 l = l->next;
05988 }
05989
05990 myrpt->mustid |= (myrpt->idtimer) && (myrpt->keyed || remrx) ;
05991
05992 totx = myrpt->callmode;
05993
05994 if (myrpt->p.duplex > 1) totx = totx || myrpt->localtx;
05995
05996 identqueued = 0;
05997 othertelemqueued = 0;
05998 tailmessagequeued = 0;
05999 ctqueued = 0;
06000 telem = myrpt->tele.next;
06001 while (telem != &myrpt->tele) {
06002 if ((telem->mode == ID) || (telem->mode == IDTALKOVER)) {
06003 identqueued = 1;
06004 } else if (telem->mode == TAILMSG) {
06005 tailmessagequeued = 1;
06006 } else {
06007 if (telem->mode != UNKEY)
06008 othertelemqueued = 1;
06009 else
06010 ctqueued = 1;
06011 }
06012 telem = telem->next;
06013 }
06014
06015
06016 if (myrpt->p.duplex > 0)
06017 totx = totx || othertelemqueued;
06018
06019 myrpt->exttx = totx;
06020
06021 if (myrpt->p.duplex < 2)
06022 myrpt->exttx = myrpt->exttx || myrpt->localtx;
06023
06024 totx = totx || remrx;
06025
06026 if (myrpt->p.duplex > 0)
06027 totx = totx || identqueued || ctqueued;
06028
06029 if (!totx) {
06030 myrpt->totimer = myrpt->p.totime;
06031 myrpt->tounkeyed = 0;
06032 myrpt->tonotify = 0;
06033 } else
06034 myrpt->tailtimer = myrpt->p.hangtime;
06035
06036 totx = totx && myrpt->totimer;
06037
06038 if ((!myrpt->totimer) && (!myrpt->tonotify)) {
06039 myrpt->tonotify = 1;
06040 myrpt->timeouts++;
06041 rpt_mutex_unlock(&myrpt->lock);
06042 rpt_telemetry(myrpt, TIMEOUT, NULL);
06043 rpt_mutex_lock(&myrpt->lock);
06044 }
06045
06046
06047 if ((!totx) && (!myrpt->totimer) && (!myrpt->tounkeyed) && (!myrpt->keyed)) {
06048 myrpt->tounkeyed = 1;
06049 }
06050 if ((!totx) && (!myrpt->totimer) && myrpt->tounkeyed && myrpt->keyed) {
06051 myrpt->totimer = myrpt->p.totime;
06052 myrpt->tounkeyed = 0;
06053 myrpt->tonotify = 0;
06054 rpt_mutex_unlock(&myrpt->lock);
06055 continue;
06056 }
06057
06058 if ((!totx) && (!myrpt->totimer) && (myrpt->callmode == 4)) {
06059 myrpt->callmode = 0;
06060 }
06061
06062 if (!myrpt->totimer)
06063 myrpt->tailtimer = 0;
06064
06065 if (myrpt->totimer)
06066 totx = totx || myrpt->tailtimer;
06067
06068
06069 if ((myrpt->keyed || remrx) && ((identqueued && idtalkover) || (tailmessagequeued))) {
06070 int hasid = 0, hastalkover = 0;
06071
06072 telem = myrpt->tele.next;
06073 while (telem != &myrpt->tele) {
06074 if (telem->mode == ID) {
06075 if (telem->chan)
06076 ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV);
06077 hasid = 1;
06078 }
06079 if (telem->mode == TAILMSG) {
06080 if (telem->chan)
06081 ast_softhangup(telem->chan, AST_SOFTHANGUP_DEV);
06082 }
06083 if (telem->mode == IDTALKOVER)
06084 hastalkover = 1;
06085 telem = telem->next;
06086 }
06087 rpt_mutex_unlock(&myrpt->lock);
06088 if (hasid && (!hastalkover))
06089 rpt_telemetry(myrpt, IDTALKOVER, NULL);
06090 rpt_mutex_lock(&myrpt->lock);
06091 }
06092
06093
06094
06095
06096
06097 if (myrpt->mustid && (!myrpt->idtimer))
06098 queue_id(myrpt);
06099
06100 if ((totx && (!myrpt->exttx) &&
06101 (myrpt->idtimer <= myrpt->p.politeid) && myrpt->tailtimer)) {
06102 myrpt->tailid = 1;
06103 }
06104
06105
06106
06107 if (myrpt->tailevent) {
06108 myrpt->tailevent = 0;
06109 if (myrpt->tailid) {
06110 totx = 1;
06111 queue_id(myrpt);
06112 }
06113 else if ((myrpt->p.tailmsg.msgs[0]) &&
06114 (myrpt->p.tailmessagetime) && (myrpt->tmsgtimer == 0)) {
06115 totx = 1;
06116 myrpt->tmsgtimer = myrpt->p.tailmessagetime;
06117 rpt_mutex_unlock(&myrpt->lock);
06118 rpt_telemetry(myrpt, TAILMSG, NULL);
06119 rpt_mutex_lock(&myrpt->lock);
06120 }
06121 }
06122
06123
06124
06125
06126 if (myrpt->p.duplex > 0)
06127 totx = totx || (myrpt->tele.next != &myrpt->tele);
06128 if (totx && (!lasttx)) {
06129 lasttx = 1;
06130 myrpt->dailykeyups++;
06131 myrpt->totalkeyups++;
06132 rpt_mutex_unlock(&myrpt->lock);
06133 ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_KEY);
06134 rpt_mutex_lock(&myrpt->lock);
06135 }
06136 totx = totx && myrpt->enable;
06137 if ((!totx) && lasttx) {
06138 lasttx = 0;
06139 rpt_mutex_unlock(&myrpt->lock);
06140 ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_UNKEY);
06141 rpt_mutex_lock(&myrpt->lock);
06142 }
06143 time(&t);
06144
06145 if ((!myrpt->cmdnode[0]) && (myrpt->dtmfidx >= 0) && ((myrpt->dtmf_time + DTMF_TIMEOUT) < t)) {
06146 myrpt->dtmfidx = -1;
06147 myrpt->dtmfbuf[0] = 0;
06148 }
06149
06150 if ((myrpt->rem_dtmfidx >= 0) && ((myrpt->rem_dtmf_time + DTMF_TIMEOUT) < t)) {
06151 myrpt->rem_dtmfidx = -1;
06152 myrpt->rem_dtmfbuf[0] = 0;
06153 }
06154
06155
06156
06157 l = myrpt->links.next;
06158 while (l != &myrpt->links) {
06159 if (l->killme) {
06160
06161 remque((struct qelem *) l);
06162 if (!strcmp(myrpt->cmdnode, l->name))
06163 myrpt->cmdnode[0] = 0;
06164 rpt_mutex_unlock(&myrpt->lock);
06165
06166 if (l->chan)
06167 ast_hangup(l->chan);
06168 ast_hangup(l->pchan);
06169 ast_free(l);
06170 rpt_mutex_lock(&myrpt->lock);
06171
06172 l = myrpt->links.next;
06173 continue;
06174 }
06175 l = l->next;
06176 }
06177 n = 0;
06178 cs[n++] = myrpt->rxchannel;
06179 cs[n++] = myrpt->pchannel;
06180 cs[n++] = myrpt->txpchannel;
06181 if (myrpt->txchannel != myrpt->rxchannel)
06182 cs[n++] = myrpt->txchannel;
06183 l = myrpt->links.next;
06184 while (l != &myrpt->links) {
06185 if ((!l->killme) && (!l->disctime) && l->chan) {
06186 cs[n++] = l->chan;
06187 cs[n++] = l->pchan;
06188 }
06189 l = l->next;
06190 }
06191 rpt_mutex_unlock(&myrpt->lock);
06192 ms = MSWAIT;
06193 who = ast_waitfor_n(cs, n, &ms);
06194 if (who == NULL)
06195 ms = 0;
06196 elap = MSWAIT - ms;
06197 rpt_mutex_lock(&myrpt->lock);
06198 l = myrpt->links.next;
06199 while (l != &myrpt->links) {
06200 if (!l->lasttx) {
06201 if ((l->retxtimer += elap) >= REDUNDANT_TX_TIME) {
06202 l->retxtimer = 0;
06203 if (l->chan)
06204 ast_indicate(l->chan, AST_CONTROL_RADIO_UNKEY);
06205 }
06206 } else
06207 l->retxtimer = 0;
06208 if (l->disctime) {
06209 l->disctime -= elap;
06210 if (l->disctime <= 0)
06211 l->disctime = 0;
06212 }
06213
06214 if (l->retrytimer) {
06215 l->retrytimer -= elap;
06216 if (l->retrytimer < 0)
06217 l->retrytimer = 0;
06218 }
06219
06220
06221 l->connecttime += elap;
06222
06223
06224 if (l->elaptime < 0) {
06225 l = l->next;
06226 continue;
06227 }
06228 l->elaptime += elap;
06229
06230 if ((l->elaptime > MAXCONNECTTIME) &&
06231 ((!l->chan) || (l->chan->_state != AST_STATE_UP))) {
06232 l->elaptime = 0;
06233 rpt_mutex_unlock(&myrpt->lock);
06234 if (l->chan)
06235 ast_softhangup(l->chan, AST_SOFTHANGUP_DEV);
06236 rpt_mutex_lock(&myrpt->lock);
06237 break;
06238 }
06239 if ((!l->chan) && (!l->retrytimer) && l->outbound &&
06240 (l->retries++ < MAX_RETRIES) && (l->hasconnected)) {
06241 if (l->chan)
06242 ast_hangup(l->chan);
06243 rpt_mutex_unlock(&myrpt->lock);
06244 if ((l->name[0] != '0') && (!l->isremote)) {
06245 l->retrytimer = MAX_RETRIES + 1;
06246 } else {
06247 if (attempt_reconnect(myrpt, l) == -1) {
06248 l->retrytimer = RETRY_TIMER_MS;
06249 }
06250 }
06251 rpt_mutex_lock(&myrpt->lock);
06252 break;
06253 }
06254 if ((!l->chan) && (!l->retrytimer) && l->outbound && (l->retries >= MAX_RETRIES)) {
06255
06256 remque((struct qelem *) l);
06257 if (!strcmp(myrpt->cmdnode, l->name))
06258 myrpt->cmdnode[0] = 0;
06259 rpt_mutex_unlock(&myrpt->lock);
06260 if (l->name[0] != '0') {
06261 if (!l->hasconnected)
06262 rpt_telemetry(myrpt, CONNFAIL, l);
06263 else
06264 rpt_telemetry(myrpt, REMDISC, l);
06265 }
06266
06267 ast_hangup(l->pchan);
06268 ast_free(l);
06269 rpt_mutex_lock(&myrpt->lock);
06270 break;
06271 }
06272 if ((!l->chan) && (!l->disctime) && (!l->outbound)) {
06273
06274 remque((struct qelem *) l);
06275 if (!strcmp(myrpt->cmdnode, l->name))
06276 myrpt->cmdnode[0] = 0;
06277 rpt_mutex_unlock(&myrpt->lock);
06278 if (l->name[0] != '0') {
06279 rpt_telemetry(myrpt, REMDISC, l);
06280 }
06281
06282 ast_hangup(l->pchan);
06283 ast_free(l);
06284 rpt_mutex_lock(&myrpt->lock);
06285 break;
06286 }
06287 l = l->next;
06288 }
06289 if (totx) {
06290 myrpt->dailytxtime += elap;
06291 myrpt->totaltxtime += elap;
06292 }
06293 i = myrpt->tailtimer;
06294 if (myrpt->tailtimer)
06295 myrpt->tailtimer -= elap;
06296 if (myrpt->tailtimer < 0)
06297 myrpt->tailtimer = 0;
06298 if ((i) && (myrpt->tailtimer == 0))
06299 myrpt->tailevent = 1;
06300 if (myrpt->totimer)
06301 myrpt->totimer -= elap;
06302 if (myrpt->totimer < 0)
06303 myrpt->totimer = 0;
06304 if (myrpt->idtimer)
06305 myrpt->idtimer -= elap;
06306 if (myrpt->idtimer < 0)
06307 myrpt->idtimer = 0;
06308 if (myrpt->tmsgtimer)
06309 myrpt->tmsgtimer -= elap;
06310 if (myrpt->tmsgtimer < 0)
06311 myrpt->tmsgtimer = 0;
06312
06313 if (myrpt->macrotimer)
06314 myrpt->macrotimer -= elap;
06315 if (myrpt->macrotimer < 0)
06316 myrpt->macrotimer = 0;
06317
06318 if (myrpt->gosubtimer)
06319 myrpt->gosubtimer -= elap;
06320 if (myrpt->gosubtimer < 0)
06321 myrpt->gosubtimer = 0;
06322
06323 if (myrpt->skedtimer <= 0) {
06324 myrpt->skedtimer = 200;
06325 do_scheduler(myrpt);
06326 } else
06327 myrpt->skedtimer -= elap;
06328 if (!ms) {
06329 rpt_mutex_unlock(&myrpt->lock);
06330 continue;
06331 }
06332 c = myrpt->macrobuf[0];
06333 if (c && (!myrpt->macrotimer)) {
06334 myrpt->macrotimer = MACROTIME;
06335 memmove(myrpt->macrobuf, myrpt->macrobuf + 1, sizeof(myrpt->macrobuf) - 1);
06336 if ((c == 'p') || (c == 'P'))
06337 myrpt->macrotimer = MACROPTIME;
06338 rpt_mutex_unlock(&myrpt->lock);
06339 local_dtmf_helper(myrpt, c);
06340 } else
06341 rpt_mutex_unlock(&myrpt->lock);
06342 c = myrpt->gosubbuf[0];
06343 if (c && (!myrpt->gosubtimer)) {
06344 myrpt->gosubtimer = GOSUBTIME;
06345 memmove(myrpt->gosubbuf, myrpt->gosubbuf + 1, sizeof(myrpt->gosubbuf) - 1);
06346 if ((c == 'p') || (c == 'P'))
06347 myrpt->gosubtimer = GOSUBPTIME;
06348 rpt_mutex_unlock(&myrpt->lock);
06349 local_dtmf_helper(myrpt, c);
06350 } else
06351 rpt_mutex_unlock(&myrpt->lock);
06352 if (who == myrpt->rxchannel) {
06353 f = ast_read(myrpt->rxchannel);
06354 if (!f) {
06355 ast_debug(1, "@@@@ rpt:Hung Up\n");
06356 break;
06357 }
06358 if (f->frametype == AST_FRAME_VOICE) {
06359 #ifdef _MDC_DECODE_H_
06360 unsigned char ubuf[2560];
06361 short *sp;
06362 int n;
06363 #endif
06364
06365 if (!myrpt->localtx) {
06366 memset(f->data, 0, f->datalen);
06367 }
06368
06369 #ifdef _MDC_DECODE_H_
06370 sp = (short *) f->data;
06371
06372 for (n = 0; n < f->datalen / 2; n++) {
06373 ubuf[n] = (*sp++ >> 8) + 128;
06374 }
06375 n = mdc_decoder_process_samples(myrpt->mdc, ubuf, f->datalen / 2);
06376 if (n == 1) {
06377 unsigned char op, arg;
06378 unsigned short unitID;
06379
06380 mdc_decoder_get_packet(myrpt->mdc, &op, &arg, &unitID);
06381 if (debug > 2) {
06382 ast_log(LOG_NOTICE, "Got (single-length) packet:\n");
06383 ast_log(LOG_NOTICE, "op: %02x, arg: %02x, UnitID: %04x\n", op & 255, arg & 255, unitID);
06384 }
06385 if ((op == 1) && (arg == 0)) {
06386 myrpt->lastunit = unitID;
06387 }
06388 }
06389 if ((debug > 2) && (i == 2)) {
06390 unsigned char op, arg, ex1, ex2, ex3, ex4;
06391 unsigned short unitID;
06392
06393 mdc_decoder_get_double_packet(myrpt->mdc, &op, &arg, &unitID, &ex1, &ex2, &ex3, &ex4);
06394 ast_log(LOG_NOTICE, "Got (double-length) packet:\n");
06395 ast_log(LOG_NOTICE, "op: %02x, arg: %02x, UnitID: %04x\n", op & 255, arg & 255, unitID);
06396 ast_log(LOG_NOTICE, "ex1: %02x, ex2: %02x, ex3: %02x, ex4: %02x\n",
06397 ex1 & 255, ex2 & 255, ex3 & 255, ex4 & 255);
06398 }
06399 #endif
06400 #ifdef __RPT_NOTCH
06401
06402 rpt_filter(myrpt, f->data, f->datalen / 2);
06403 #endif
06404 ast_write(myrpt->pchannel, f);
06405 } else if (f->frametype == AST_FRAME_DTMF) {
06406 c = (char) f->subclass;
06407 ast_frfree(f);
06408 if (!myrpt->keyed)
06409 continue;
06410 local_dtmf_helper(myrpt, c);
06411 continue;
06412 } else if (f->frametype == AST_FRAME_CONTROL) {
06413 if (f->subclass == AST_CONTROL_HANGUP) {
06414 ast_debug(1, "@@@@ rpt:Hung Up\n");
06415 ast_frfree(f);
06416 break;
06417 }
06418
06419 if (f->subclass == AST_CONTROL_RADIO_KEY) {
06420 if ((!lasttx) || (myrpt->p.duplex > 1)) {
06421 ast_debug(8, "@@@@ rx key\n");
06422 myrpt->keyed = 1;
06423 }
06424 }
06425
06426 if (f->subclass == AST_CONTROL_RADIO_UNKEY) {
06427 if ((!lasttx) || (myrpt->p.duplex > 1)) {
06428 ast_debug(8, "@@@@ rx un-key\n");
06429 if (myrpt->keyed) {
06430 rpt_telemetry(myrpt, UNKEY, NULL);
06431 }
06432 myrpt->keyed = 0;
06433 }
06434 }
06435 }
06436 ast_frfree(f);
06437 continue;
06438 }
06439 if (who == myrpt->pchannel) {
06440 f = ast_read(myrpt->pchannel);
06441 if (!f) {
06442 ast_debug(1, "@@@@ rpt:Hung Up\n");
06443 break;
06444 }
06445 if (f->frametype == AST_FRAME_VOICE) {
06446 ast_write(myrpt->txpchannel, f);
06447 }
06448 if (f->frametype == AST_FRAME_CONTROL) {
06449 if (f->subclass == AST_CONTROL_HANGUP) {
06450 ast_debug(1, "@@@@ rpt:Hung Up\n");
06451 ast_frfree(f);
06452 break;
06453 }
06454 }
06455 ast_frfree(f);
06456 continue;
06457 }
06458 if (who == myrpt->txchannel) {
06459 f = ast_read(myrpt->txchannel);
06460 if (!f) {
06461 ast_debug(1, "@@@@ rpt:Hung Up\n");
06462 break;
06463 }
06464 if (f->frametype == AST_FRAME_CONTROL) {
06465 if (f->subclass == AST_CONTROL_HANGUP) {
06466 ast_debug(1, "@@@@ rpt:Hung Up\n");
06467 ast_frfree(f);
06468 break;
06469 }
06470 }
06471 ast_frfree(f);
06472 continue;
06473 }
06474 toexit = 0;
06475 rpt_mutex_lock(&myrpt->lock);
06476 l = myrpt->links.next;
06477 while (l != &myrpt->links) {
06478 if (l->disctime) {
06479 l = l->next;
06480 continue;
06481 }
06482 if (who == l->chan) {
06483 remrx = 0;
06484
06485 m = myrpt->links.next;
06486 while (m != &myrpt->links) {
06487
06488 if ((m != l) && (m->lastrx))
06489 remrx = 1;
06490 m = m->next;
06491 }
06492 rpt_mutex_unlock(&myrpt->lock);
06493 totx = (((l->isremote) ? myrpt->localtx :
06494 myrpt->exttx) || remrx) && l->mode;
06495 if (l->chan && (l->lasttx != totx)) {
06496 if (totx) {
06497 ast_indicate(l->chan, AST_CONTROL_RADIO_KEY);
06498 } else {
06499 ast_indicate(l->chan, AST_CONTROL_RADIO_UNKEY);
06500 }
06501 }
06502 l->lasttx = totx;
06503 f = ast_read(l->chan);
06504 if (!f) {
06505 if ((!l->disced) && (!l->outbound)) {
06506 if ((l->name[0] == '0') || l->isremote)
06507 l->disctime = 1;
06508 else
06509 l->disctime = DISC_TIME;
06510 rpt_mutex_lock(&myrpt->lock);
06511 ast_hangup(l->chan);
06512 l->chan = 0;
06513 break;
06514 }
06515
06516 if (l->retrytimer) {
06517 rpt_mutex_lock(&myrpt->lock);
06518 break;
06519 }
06520 if (l->outbound && (l->retries++ < MAX_RETRIES) && (l->hasconnected)) {
06521 rpt_mutex_lock(&myrpt->lock);
06522 ast_hangup(l->chan);
06523 l->chan = 0;
06524 rpt_mutex_unlock(&myrpt->lock);
06525 if (attempt_reconnect(myrpt, l) == -1) {
06526 l->retrytimer = RETRY_TIMER_MS;
06527 }
06528 rpt_mutex_lock(&myrpt->lock);
06529 break;
06530 }
06531 rpt_mutex_lock(&myrpt->lock);
06532
06533 remque((struct qelem *) l);
06534 if (!strcmp(myrpt->cmdnode, l->name))
06535 myrpt->cmdnode[0] = 0;
06536 rpt_mutex_unlock(&myrpt->lock);
06537 if (!l->hasconnected)
06538 rpt_telemetry(myrpt, CONNFAIL, l);
06539 else if (l->disced != 2)
06540 rpt_telemetry(myrpt, REMDISC, l);
06541
06542 ast_hangup(l->chan);
06543 ast_hangup(l->pchan);
06544 ast_free(l);
06545 rpt_mutex_lock(&myrpt->lock);
06546 break;
06547 }
06548 if (f->frametype == AST_FRAME_VOICE) {
06549 if (!l->lastrx) {
06550 memset(f->data, 0, f->datalen);
06551 }
06552 ast_write(l->pchan, f);
06553 }
06554 if (f->frametype == AST_FRAME_TEXT) {
06555 handle_link_data(myrpt, l, f->data);
06556 }
06557 if (f->frametype == AST_FRAME_DTMF) {
06558 handle_link_phone_dtmf(myrpt, l, f->subclass);
06559 }
06560 if (f->frametype == AST_FRAME_CONTROL) {
06561 if (f->subclass == AST_CONTROL_ANSWER) {
06562 char lconnected = l->connected;
06563 l->connected = 1;
06564 l->hasconnected = 1;
06565 l->elaptime = -1;
06566 l->retries = 0;
06567 if (!lconnected)
06568 rpt_telemetry(myrpt, CONNECTED, l);
06569 else
06570 l->reconnects++;
06571 }
06572
06573 if (f->subclass == AST_CONTROL_RADIO_KEY) {
06574 ast_debug(8, "@@@@ rx key\n");
06575 l->lastrx = 1;
06576 }
06577
06578 if (f->subclass == AST_CONTROL_RADIO_UNKEY) {
06579 ast_debug(8, "@@@@ rx un-key\n");
06580 l->lastrx = 0;
06581 }
06582 if (f->subclass == AST_CONTROL_HANGUP) {
06583 ast_frfree(f);
06584 if ((!l->outbound) && (!l->disced)) {
06585 if ((l->name[0] == '0') || l->isremote)
06586 l->disctime = 1;
06587 else
06588 l->disctime = DISC_TIME;
06589 rpt_mutex_lock(&myrpt->lock);
06590 ast_hangup(l->chan);
06591 l->chan = 0;
06592 break;
06593 }
06594 if (l->retrytimer) {
06595 rpt_mutex_lock(&myrpt->lock);
06596 break;
06597 }
06598 if (l->outbound && (l->retries++ < MAX_RETRIES) && (l->hasconnected)) {
06599 rpt_mutex_lock(&myrpt->lock);
06600 ast_hangup(l->chan);
06601 l->chan = 0;
06602 rpt_mutex_unlock(&myrpt->lock);
06603 if (attempt_reconnect(myrpt, l) == -1) {
06604 l->retrytimer = RETRY_TIMER_MS;
06605 }
06606 rpt_mutex_lock(&myrpt->lock);
06607 break;
06608 }
06609 rpt_mutex_lock(&myrpt->lock);
06610
06611 remque((struct qelem *) l);
06612 if (!strcmp(myrpt->cmdnode, l->name))
06613 myrpt->cmdnode[0] = 0;
06614 rpt_mutex_unlock(&myrpt->lock);
06615 if (!l->hasconnected)
06616 rpt_telemetry(myrpt, CONNFAIL, l);
06617 else if (l->disced != 2)
06618 rpt_telemetry(myrpt, REMDISC, l);
06619
06620 ast_hangup(l->chan);
06621 ast_hangup(l->pchan);
06622 ast_free(l);
06623 rpt_mutex_lock(&myrpt->lock);
06624 break;
06625 }
06626 }
06627 ast_frfree(f);
06628 rpt_mutex_lock(&myrpt->lock);
06629 break;
06630 }
06631 if (who == l->pchan) {
06632 rpt_mutex_unlock(&myrpt->lock);
06633 f = ast_read(l->pchan);
06634 if (!f) {
06635 ast_debug(1, "@@@@ rpt:Hung Up\n");
06636 toexit = 1;
06637 rpt_mutex_lock(&myrpt->lock);
06638 break;
06639 }
06640 if (f->frametype == AST_FRAME_VOICE) {
06641 if (l->chan)
06642 ast_write(l->chan, f);
06643 }
06644 if (f->frametype == AST_FRAME_CONTROL) {
06645 if (f->subclass == AST_CONTROL_HANGUP) {
06646 ast_debug(1, "@@@@ rpt:Hung Up\n");
06647 ast_frfree(f);
06648 toexit = 1;
06649 rpt_mutex_lock(&myrpt->lock);
06650 break;
06651 }
06652 }
06653 ast_frfree(f);
06654 rpt_mutex_lock(&myrpt->lock);
06655 break;
06656 }
06657 l = l->next;
06658 }
06659 rpt_mutex_unlock(&myrpt->lock);
06660 if (toexit)
06661 break;
06662 if (who == myrpt->txpchannel) {
06663 f = ast_read(myrpt->txpchannel);
06664 if (!f) {
06665 ast_debug(1, "@@@@ rpt:Hung Up\n");
06666 break;
06667 }
06668 if (f->frametype == AST_FRAME_CONTROL) {
06669 if (f->subclass == AST_CONTROL_HANGUP) {
06670 ast_debug(1, "@@@@ rpt:Hung Up\n");
06671 ast_frfree(f);
06672 break;
06673 }
06674 }
06675 ast_frfree(f);
06676 continue;
06677 }
06678 }
06679 usleep(100000);
06680 ast_hangup(myrpt->pchannel);
06681 ast_hangup(myrpt->txpchannel);
06682 if (myrpt->txchannel != myrpt->rxchannel)
06683 ast_hangup(myrpt->txchannel);
06684 ast_hangup(myrpt->rxchannel);
06685 rpt_mutex_lock(&myrpt->lock);
06686 l = myrpt->links.next;
06687 while (l != &myrpt->links) {
06688 struct rpt_link *ll = l;
06689
06690 remque((struct qelem *) l);
06691
06692 if (l->chan)
06693 ast_hangup(l->chan);
06694 ast_hangup(l->pchan);
06695 l = l->next;
06696 ast_free(ll);
06697 }
06698 rpt_mutex_unlock(&myrpt->lock);
06699 ast_debug(1, "@@@@ rpt:Hung up channel\n");
06700 myrpt->rpt_thread = AST_PTHREADT_STOP;
06701 pthread_exit(NULL);
06702 return NULL;
06703 }
06704
06705
06706 static void *rpt_master(void *config)
06707 {
06708 int i, n;
06709 struct ast_config *cfg;
06710 char *this;
06711 const char *val;
06712
06713
06714 this = NULL;
06715 n = 0;
06716 rpt_vars[n].cfg = config;
06717 cfg = rpt_vars[n].cfg;
06718 if (!cfg) {
06719 ast_log(LOG_NOTICE, "Unable to open radio repeater configuration rpt.conf. Radio Repeater disabled.\n");
06720 pthread_exit(NULL);
06721 }
06722 while ((this = ast_category_browse(cfg, this)) != NULL) {
06723 for (i = 0; i < strlen(this); i++) {
06724 if ((this[i] < '0') || (this[i] > '9'))
06725 break;
06726 }
06727 if (i != strlen(this))
06728 continue;
06729 memset(&rpt_vars[n], 0, sizeof(rpt_vars[n]));
06730 rpt_vars[n].name = ast_strdup(this);
06731 val = ast_variable_retrieve(cfg, this, "rxchannel");
06732 if (val)
06733 rpt_vars[n].rxchanname = ast_strdup(val);
06734 val = ast_variable_retrieve(cfg, this, "txchannel");
06735 if (val)
06736 rpt_vars[n].txchanname = ast_strdup(val);
06737 val = ast_variable_retrieve(cfg, this, "remote");
06738 if (val)
06739 rpt_vars[n].remote = ast_strdup(val);
06740 ast_mutex_init(&rpt_vars[n].lock);
06741 rpt_vars[n].tele.next = &rpt_vars[n].tele;
06742 rpt_vars[n].tele.prev = &rpt_vars[n].tele;
06743 rpt_vars[n].rpt_thread = AST_PTHREADT_NULL;
06744 rpt_vars[n].tailmessagen = 0;
06745 #ifdef _MDC_DECODE_H_
06746 rpt_vars[n].mdc = mdc_decoder_new(8000);
06747 #endif
06748 n++;
06749 }
06750 nrpts = n;
06751 ast_config_destroy(cfg);
06752
06753
06754 for (i = 0; i < n; i++) {
06755 load_rpt_vars(i, 1);
06756
06757
06758 if (rpt_vars[i].remote) {
06759 ast_copy_string(rpt_vars[i].freq, "146.580", sizeof(rpt_vars[i].freq));
06760 ast_copy_string(rpt_vars[i].rxpl, "100.0", sizeof(rpt_vars[i].rxpl));
06761 ast_copy_string(rpt_vars[i].txpl, "100.0", sizeof(rpt_vars[i].txpl));
06762 rpt_vars[i].remmode = REM_MODE_FM;
06763 rpt_vars[i].offset = REM_SIMPLEX;
06764 rpt_vars[i].powerlevel = REM_MEDPWR;
06765 continue;
06766 }
06767 if (!rpt_vars[i].p.ident) {
06768 ast_log(LOG_WARNING, "Did not specify ident for node %s\n", rpt_vars[i].name);
06769 ast_config_destroy(cfg);
06770 pthread_exit(NULL);
06771 }
06772 ast_pthread_create_detached(&rpt_vars[i].rpt_thread, NULL, rpt, (void *) &rpt_vars[i]);
06773 }
06774 usleep(500000);
06775 for (;;) {
06776
06777 for (i = 0; i < n; i++) {
06778 int rv;
06779 if (rpt_vars[i].remote)
06780 continue;
06781 if (rpt_vars[i].rpt_thread == AST_PTHREADT_STOP)
06782 rv = -1;
06783 else
06784 rv = pthread_kill(rpt_vars[i].rpt_thread, 0);
06785 if (rv) {
06786 if (time(NULL) - rpt_vars[i].lastthreadrestarttime <= 15) {
06787 if (rpt_vars[i].threadrestarts >= 5) {
06788 ast_log(LOG_ERROR, "Continual RPT thread restarts, killing Asterisk\n");
06789 ast_cli_command(STDERR_FILENO, "restart now");
06790 } else {
06791 ast_log(LOG_NOTICE, "RPT thread restarted on %s\n", rpt_vars[i].name);
06792 rpt_vars[i].threadrestarts++;
06793 }
06794 } else
06795 rpt_vars[i].threadrestarts = 0;
06796
06797 rpt_vars[i].lastthreadrestarttime = time(NULL);
06798 ast_pthread_create_detached(&rpt_vars[i].rpt_thread, NULL, rpt, (void *) &rpt_vars[i]);
06799 ast_log(LOG_WARNING, "rpt_thread restarted on node %s\n", rpt_vars[i].name);
06800 }
06801
06802 }
06803 sleep(2);
06804 }
06805 ast_config_destroy(cfg);
06806 pthread_exit(NULL);
06807 }
06808
06809 static int rpt_exec(struct ast_channel *chan, void *data)
06810 {
06811 int res = -1, i, rem_totx, n, phone_mode = 0;
06812 char *tmp, keyed = 0;
06813 char *options = NULL, *tele, c;
06814 struct rpt *myrpt;
06815 struct ast_frame *f;
06816 struct ast_channel *who;
06817 struct ast_channel *cs[20];
06818 struct rpt_link *l;
06819 struct dahdi_confinfo ci;
06820 struct dahdi_params par;
06821 int ms, elap;
06822 AST_DECLARE_APP_ARGS(args,
06823 AST_APP_ARG(node);
06824 AST_APP_ARG(options);
06825 );
06826
06827 if (ast_strlen_zero(data)) {
06828 ast_log(LOG_WARNING, "Rpt requires an argument (system node)\n");
06829 return -1;
06830 }
06831 tmp = ast_strdupa((char *)data);
06832 AST_STANDARD_APP_ARGS(args, tmp);
06833 myrpt = NULL;
06834
06835 for (i = 0; i < nrpts; i++) {
06836
06837 if (!strcmp(args.node, rpt_vars[i].name)) {
06838 myrpt = &rpt_vars[i];
06839 break;
06840 }
06841 }
06842 if (myrpt == NULL) {
06843 ast_log(LOG_WARNING, "Cannot find specified system node %s\n", args.node);
06844 return -1;
06845 }
06846
06847
06848 if (options && ((*options == 'P') || (*options == 'D') || (*options == 'R'))) {
06849 phone_mode = 1;
06850 if (*options == 'D')
06851 phone_mode = 2;
06852 ast_set_callerid(chan, "0", "app_rpt user", "0");
06853 } else {
06854 if (strncmp(chan->name, "IAX2", 4)) {
06855 ast_log(LOG_WARNING, "We only accept links via IAX2!!\n");
06856 return -1;
06857 }
06858 }
06859 if (*args.options == 'R') {
06860
06861 int m, lot, timeout = 0;
06862 char tmp[256];
06863 char *s;
06864 AST_DECLARE_APP_ARGS(optionarg,
06865 AST_APP_ARG(template);
06866 AST_APP_ARG(timeout);
06867 AST_APP_ARG(return_context);
06868 );
06869
06870 rpt_mutex_lock(&myrpt->lock);
06871 m = myrpt->callmode;
06872 rpt_mutex_unlock(&myrpt->lock);
06873
06874 if ((!myrpt->p.nobusyout) && m) {
06875 if (chan->_state != AST_STATE_UP) {
06876 ast_indicate(chan, AST_CONTROL_BUSY);
06877 }
06878 while (ast_safe_sleep(chan, 10000) != -1) {
06879
06880 usleep(1);
06881 }
06882 return -1;
06883 }
06884
06885 if (chan->_state != AST_STATE_UP) {
06886 ast_answer(chan);
06887 }
06888
06889 s = ast_strdupa(options);
06890 AST_STANDARD_APP_ARGS(optionarg, s);
06891 if (optionarg.argc == 0 || ast_strlen_zero(optionarg.template)) {
06892 ast_log(LOG_WARNING, "An announce template must be defined\n");
06893 return -1;
06894 }
06895
06896 if (optionarg.argc >= 2) {
06897 timeout = atoi(optionarg.timeout) * 1000;
06898 }
06899
06900 if (!ast_strlen_zero(optionarg.return_context)) {
06901 if (ast_parseable_goto(chan, optionarg.return_context)) {
06902 ast_verb(3, "Warning: Return Context Invalid, call will return to default|s\n");
06903 }
06904 }
06905
06906
06907
06908
06909 ast_masq_park_call(chan, NULL, timeout, &lot);
06910 ast_verb(3, "Call Parking Called, lot: %d, timeout: %d, context: %s\n", lot, timeout, optionarg.return_context);
06911
06912 snprintf(tmp, sizeof(tmp), "%d,%s", lot, optionarg.template + 1);
06913 rpt_telemetry(myrpt, REV_PATCH, tmp);
06914
06915 return 0;
06916 }
06917
06918 if (!options) {
06919 struct ast_hostent ahp;
06920 struct hostent *hp;
06921 struct in_addr ia;
06922 char hisip[100], nodeip[100];
06923 const char *val;
06924 char *s, *s1, *s2;
06925
06926
06927 if (!chan->cid.cid_num) {
06928 ast_log(LOG_WARNING, "Doesn't have callerid on %s\n", args.node);
06929 return -1;
06930 }
06931
06932
06933 pbx_substitute_variables_helper(chan, "${IAXPEER(CURRENTCHANNEL)}", hisip, sizeof(hisip) - 1);
06934 if (ast_strlen_zero(hisip)) {
06935 ast_log(LOG_WARNING, "Link IP address cannot be determined!!\n");
06936 return -1;
06937 }
06938
06939 if (!strcmp(myrpt->name, chan->cid.cid_num)) {
06940 ast_log(LOG_WARNING, "Trying to link to self!!\n");
06941 return -1;
06942 }
06943
06944 if (*(chan->cid.cid_num) < '1') {
06945 ast_log(LOG_WARNING, "Node %s Invalid for connection here!!\n", chan->cid.cid_num);
06946 return -1;
06947 }
06948
06949
06950 val = ast_variable_retrieve(myrpt->cfg, myrpt->p.nodes, chan->cid.cid_num);
06951 if (!val) {
06952 ast_log(LOG_WARNING, "Reported node %s cannot be found!!\n", chan->cid.cid_num);
06953 return -1;
06954 }
06955 ast_copy_string(tmp, val, sizeof(tmp));
06956 s = tmp;
06957 s1 = strsep(&s, ",");
06958 s2 = strsep(&s, ",");
06959 if (!s2) {
06960 ast_log(LOG_WARNING, "Reported node %s not in correct format!!\n", chan->cid.cid_num);
06961 return -1;
06962 }
06963 if (strcmp(s2, "NONE")) {
06964 hp = ast_gethostbyname(s2, &ahp);
06965 if (!hp) {
06966 ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n", chan->cid.cid_num, s2);
06967 return -1;
06968 }
06969 memcpy(&ia, hp->h_addr, sizeof(in_addr_t));
06970 ast_copy_string(nodeip, ast_inet_ntoa(ia), sizeof(nodeip));
06971 if (strcmp(hisip, nodeip)) {
06972 char *s3 = strchr(s1, '@');
06973 if (s3)
06974 s1 = s3 + 1;
06975 s3 = strchr(s1, '/');
06976 if (s3)
06977 *s3 = 0;
06978 hp = ast_gethostbyname(s1, &ahp);
06979 if (!hp) {
06980 ast_log(LOG_WARNING, "Reported node %s, name %s cannot be found!!\n", chan->cid.cid_num, s1);
06981 return -1;
06982 }
06983 memcpy(&ia, hp->h_addr, sizeof(in_addr_t));
06984 ast_copy_string(nodeip, ast_inet_ntoa(ia), sizeof(nodeip));
06985 if (strcmp(hisip, nodeip)) {
06986 ast_log(LOG_WARNING, "Node %s IP %s does not match link IP %s!!\n", chan->cid.cid_num, nodeip, hisip);
06987 return -1;
06988 }
06989 }
06990 }
06991 }
06992
06993
06994 if (!myrpt->remote) {
06995 int reconnects = 0;
06996
06997
06998 if (!chan->cid.cid_num) {
06999 ast_log(LOG_WARNING, "Doesnt have callerid on %s\n", args.node);
07000 return -1;
07001 }
07002
07003 if (!strcmp(myrpt->name, chan->cid.cid_num)) {
07004 ast_log(LOG_WARNING, "Trying to link to self!!\n");
07005 return -1;
07006 }
07007 rpt_mutex_lock(&myrpt->lock);
07008 l = myrpt->links.next;
07009
07010 while (l != &myrpt->links) {
07011 if (l->name[0] == '0') {
07012 l = l->next;
07013 continue;
07014 }
07015
07016 if (!strcmp(l->name, chan->cid.cid_num))
07017 break;
07018 l = l->next;
07019 }
07020
07021 if (l != &myrpt->links) {
07022 l->killme = 1;
07023 l->retries = MAX_RETRIES + 1;
07024 l->disced = 2;
07025 reconnects = l->reconnects;
07026 reconnects++;
07027 rpt_mutex_unlock(&myrpt->lock);
07028 usleep(500000);
07029 } else
07030 rpt_mutex_unlock(&myrpt->lock);
07031
07032 l = ast_calloc(1, sizeof(*l));
07033 if (!l) {
07034 ast_log(LOG_WARNING, "Unable to malloc\n");
07035 pthread_exit(NULL);
07036 }
07037 l->mode = 1;
07038 ast_copy_string(l->name, chan->cid.cid_num, sizeof(l->name));
07039 l->isremote = 0;
07040 l->chan = chan;
07041 l->connected = 1;
07042 l->hasconnected = 1;
07043 l->reconnects = reconnects;
07044 l->phonemode = phone_mode;
07045 ast_set_read_format(l->chan, AST_FORMAT_SLINEAR);
07046 ast_set_write_format(l->chan, AST_FORMAT_SLINEAR);
07047
07048 l->pchan = ast_request("zap", AST_FORMAT_SLINEAR, "pseudo", NULL);
07049 if (!l->pchan) {
07050 ast_log(LOG_ERROR, "rpt:Sorry unable to obtain pseudo channel\n");
07051 pthread_exit(NULL);
07052 }
07053 ast_set_read_format(l->pchan, AST_FORMAT_SLINEAR);
07054 ast_set_write_format(l->pchan, AST_FORMAT_SLINEAR);
07055
07056 ci.chan = 0;
07057 ci.confno = myrpt->conf;
07058 ci.confmode = DAHDI_CONF_CONF | DAHDI_CONF_LISTENER | DAHDI_CONF_TALKER;
07059
07060 if (ioctl(l->pchan->fds[0], DAHDI_SETCONF, &ci) == -1) {
07061 ast_log(LOG_WARNING, "Unable to set conference mode to Announce\n");
07062 pthread_exit(NULL);
07063 }
07064 rpt_mutex_lock(&myrpt->lock);
07065 if (phone_mode > 1)
07066 l->lastrx = 1;
07067
07068 insque((struct qelem *)l, (struct qelem *)myrpt->links.next);
07069 rpt_mutex_unlock(&myrpt->lock);
07070 if (chan->_state != AST_STATE_UP) {
07071 ast_answer(chan);
07072 }
07073 return 0;
07074 }
07075 rpt_mutex_lock(&myrpt->lock);
07076
07077 if (myrpt->remoteon) {
07078 rpt_mutex_unlock(&myrpt->lock);
07079 usleep(500000);
07080 if (myrpt->remoteon) {
07081 ast_log(LOG_WARNING, "Trying to use busy link on %s\n", args.node);
07082 return -1;
07083 }
07084 rpt_mutex_lock(&myrpt->lock);
07085 }
07086 myrpt->remoteon = 1;
07087 if (ioperm(myrpt->p.iobase, 1, 1) == -1) {
07088 rpt_mutex_unlock(&myrpt->lock);
07089 ast_log(LOG_WARNING, "Cant get io permission on IO port %x hex\n", myrpt->p.iobase);
07090 return -1;
07091 }
07092 rpt_mutex_unlock(&myrpt->lock);
07093
07094 for (i = 0; i < nrpts; i++) {
07095 if (&rpt_vars[i] == myrpt) {
07096 load_rpt_vars(i, 0);
07097 break;
07098 }
07099 }
07100 rpt_mutex_lock(&myrpt->lock);
07101 tele = strchr(myrpt->rxchanname, '/');
07102 if (!tele) {
07103 ast_log(LOG_ERROR, "rpt:Dial number must be in format tech/number\n");
07104 rpt_mutex_unlock(&myrpt->lock);
07105 pthread_exit(NULL);
07106 }
07107 *tele++ = 0;
07108 myrpt->rxchannel = ast_request(myrpt->rxchanname, AST_FORMAT_SLINEAR, tele, NULL);
07109 if (myrpt->rxchannel) {
07110 ast_set_read_format(myrpt->rxchannel, AST_FORMAT_SLINEAR);
07111 ast_set_write_format(myrpt->rxchannel, AST_FORMAT_SLINEAR);
07112 myrpt->rxchannel->whentohangup = 0;
07113 myrpt->rxchannel->appl = "Apprpt";
07114 myrpt->rxchannel->data = "(Link Rx)";
07115 ast_verb(3, "rpt (Rx) initiating call to %s/%s on %s\n",
07116 myrpt->rxchanname, tele, myrpt->rxchannel->name);
07117 rpt_mutex_unlock(&myrpt->lock);
07118 ast_call(myrpt->rxchannel, tele, 999);
07119 rpt_mutex_lock(&myrpt->lock);
07120 } else {
07121 ast_log(LOG_ERROR, "rpt:Sorry unable to obtain Rx channel\n");
07122 rpt_mutex_unlock(&myrpt->lock);
07123 pthread_exit(NULL);
07124 }
07125 *--tele = '/';
07126 if (myrpt->txchanname) {
07127 tele = strchr(myrpt->txchanname, '/');
07128 if (!tele) {
07129 ast_log(LOG_ERROR, "rpt:Dial number must be in format tech/number\n");
07130 rpt_mutex_unlock(&myrpt->lock);
07131 ast_hangup(myrpt->rxchannel);
07132 pthread_exit(NULL);
07133 }
07134 *tele++ = 0;
07135 myrpt->txchannel = ast_request(myrpt->txchanname, AST_FORMAT_SLINEAR, tele, NULL);
07136 if (myrpt->txchannel) {
07137 ast_set_read_format(myrpt->txchannel, AST_FORMAT_SLINEAR);
07138 ast_set_write_format(myrpt->txchannel, AST_FORMAT_SLINEAR);
07139 myrpt->txchannel->whentohangup = 0;
07140 myrpt->txchannel->appl = "Apprpt";
07141 myrpt->txchannel->data = "(Link Tx)";
07142 ast_verb(3, "rpt (Tx) initiating call to %s/%s on %s\n",
07143 myrpt->txchanname, tele, myrpt->txchannel->name);
07144 rpt_mutex_unlock(&myrpt->lock);
07145 ast_call(myrpt->txchannel, tele, 999);
07146 rpt_mutex_lock(&myrpt->lock);
07147 } else {
07148 ast_log(LOG_ERROR, "rpt:Sorry unable to obtain Tx channel\n");
07149 rpt_mutex_unlock(&myrpt->lock);
07150 ast_hangup(myrpt->rxchannel);
07151 pthread_exit(NULL);
07152 }
07153 *--tele = '/';
07154 } else {
07155 myrpt->txchannel = myrpt->rxchannel;
07156 }
07157 myrpt->remoterx = 0;
07158 myrpt->remotetx = 0;
07159 myrpt->retxtimer = 0;
07160 myrpt->remoteon = 1;
07161 myrpt->dtmfidx = -1;
07162 myrpt->dtmfbuf[0] = 0;
07163 myrpt->dtmf_time_rem = 0;
07164 myrpt->hfscanmode = 0;
07165 myrpt->hfscanstatus = 0;
07166 if (myrpt->p.startupmacro) {
07167 myrpt->remchannel = chan;
07168 snprintf(myrpt->macrobuf, sizeof(myrpt->macrobuf), "PPPP%s", myrpt->p.startupmacro);
07169 }
07170 if (myrpt->p.startupgosub) {
07171 myrpt->remchannel = chan;
07172 snprintf(myrpt->gosubbuf, sizeof(myrpt->gosubbuf), "PPPP%s", myrpt->p.startupgosub);
07173 }
07174 myrpt->reload = 0;
07175 rpt_mutex_unlock(&myrpt->lock);
07176 setrem(myrpt);
07177 ast_set_write_format(chan, AST_FORMAT_SLINEAR);
07178 ast_set_read_format(chan, AST_FORMAT_SLINEAR);
07179
07180 if (myrpt->remote && (myrpt->rxchannel == myrpt->txchannel)) {
07181 i = 128;
07182 ioctl(myrpt->rxchannel->fds[0], DAHDI_ECHOCANCEL, &i);
07183 }
07184 if (chan->_state != AST_STATE_UP) {
07185 ast_answer(chan);
07186 }
07187
07188 if (ioctl(myrpt->txchannel->fds[0], DAHDI_GET_PARAMS, &par) != -1) {
07189 if (par.rxisoffhook) {
07190 ast_indicate(chan, AST_CONTROL_RADIO_KEY);
07191 myrpt->remoterx = 1;
07192 }
07193 }
07194 n = 0;
07195 cs[n++] = chan;
07196 cs[n++] = myrpt->rxchannel;
07197 if (myrpt->rxchannel != myrpt->txchannel)
07198 cs[n++] = myrpt->txchannel;
07199 for (;;) {
07200 if (ast_check_hangup(chan))
07201 break;
07202 if (ast_check_hangup(myrpt->rxchannel))
07203 break;
07204 if (myrpt->reload) {
07205 myrpt->reload = 0;
07206 rpt_mutex_unlock(&myrpt->lock);
07207
07208 for (i = 0; i < nrpts; i++) {
07209 if (&rpt_vars[i] == myrpt) {
07210 load_rpt_vars(i, 0);
07211 break;
07212 }
07213 }
07214 rpt_mutex_lock(&myrpt->lock);
07215 }
07216 ms = MSWAIT;
07217 who = ast_waitfor_n(cs, n, &ms);
07218 if (who == NULL)
07219 ms = 0;
07220 elap = MSWAIT - ms;
07221 if (myrpt->macrotimer)
07222 myrpt->macrotimer -= elap;
07223 if (myrpt->macrotimer < 0)
07224 myrpt->macrotimer = 0;
07225 if (myrpt->gosubtimer)
07226 myrpt->gosubtimer -= elap;
07227 if (myrpt->gosubtimer < 0)
07228 myrpt->gosubtimer = 0;
07229 rpt_mutex_unlock(&myrpt->lock);
07230 if (!ms)
07231 continue;
07232 rem_totx = keyed;
07233
07234
07235 if ((!myrpt->remoterx) && (!myrpt->remotetx)) {
07236 if ((myrpt->retxtimer += elap) >= REDUNDANT_TX_TIME) {
07237 myrpt->retxtimer = 0;
07238 ast_indicate(chan, AST_CONTROL_RADIO_UNKEY);
07239 }
07240 } else
07241 myrpt->retxtimer = 0;
07242 if (rem_totx && (!myrpt->remotetx)) {
07243 myrpt->remotetx = 1;
07244 ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_KEY);
07245 }
07246 if ((!rem_totx) && myrpt->remotetx) {
07247 myrpt->remotetx = 0;
07248 ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_UNKEY);
07249 }
07250
07251 if (myrpt->tunerequest && (!strcmp(myrpt->remote, remote_rig_ft897))) {
07252 myrpt->tunerequest = 0;
07253 set_mode_ft897(myrpt, REM_MODE_AM);
07254 simple_command_ft897(myrpt, 8);
07255 myrpt->remotetx = 0;
07256 ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_UNKEY);
07257 if (!myrpt->remoterx)
07258 ast_indicate(chan, AST_CONTROL_RADIO_KEY);
07259 if (play_tone(chan, 800, 6000, 8192) == -1)
07260 break;
07261
07262 rmt_telem_finish(myrpt, chan);
07263 set_mode_ft897(myrpt, 0x88);
07264 setrem(myrpt);
07265 }
07266
07267 if (myrpt->hfscanmode) {
07268 myrpt->scantimer -= elap;
07269 if (myrpt->scantimer <= 0) {
07270 myrpt->scantimer = REM_SCANTIME;
07271 service_scan(myrpt);
07272 }
07273 }
07274 if (who == chan) {
07275 f = ast_read(chan);
07276 if (!f) {
07277 ast_debug(1, "@@@@ link:Hung Up\n");
07278 break;
07279 }
07280 if (f->frametype == AST_FRAME_VOICE) {
07281
07282 if (!myrpt->remotetx)
07283 memset(f->data, 0, f->datalen);
07284 ast_write(myrpt->txchannel, f);
07285 }
07286 if (f->frametype == AST_FRAME_DTMF) {
07287 myrpt->remchannel = chan;
07288 if (handle_remote_phone_dtmf(myrpt, f->subclass, &keyed, phone_mode) == -1) {
07289 ast_debug(1, "@@@@ rpt:Hung Up\n");
07290 ast_frfree(f);
07291 break;
07292 }
07293 }
07294 if (f->frametype == AST_FRAME_TEXT) {
07295 myrpt->remchannel = chan;
07296 if (handle_remote_data(myrpt, f->data) == -1) {
07297 ast_debug(1, "@@@@ rpt:Hung Up\n");
07298 ast_frfree(f);
07299 break;
07300 }
07301 }
07302 if (f->frametype == AST_FRAME_CONTROL) {
07303 if (f->subclass == AST_CONTROL_HANGUP) {
07304 ast_debug(1, "@@@@ rpt:Hung Up\n");
07305 ast_frfree(f);
07306 break;
07307 }
07308
07309 if (f->subclass == AST_CONTROL_RADIO_KEY) {
07310 ast_debug(8, "@@@@ rx key\n");
07311 keyed = 1;
07312 }
07313
07314 if (f->subclass == AST_CONTROL_RADIO_UNKEY) {
07315 ast_debug(8, "@@@@ rx un-key\n");
07316 keyed = 0;
07317 }
07318 }
07319 if (myrpt->hfscanstatus) {
07320 myrpt->remchannel = chan;
07321 myrpt->remotetx = 0;
07322 ast_indicate(myrpt->txchannel, AST_CONTROL_RADIO_UNKEY);
07323 if (!myrpt->remoterx) {
07324 ast_indicate(myrpt->remchannel, AST_CONTROL_RADIO_KEY);
07325 }
07326 if (myrpt->hfscanstatus < 0) {
07327 if (myrpt->hfscanstatus == -1) {
07328 if (ast_safe_sleep(myrpt->remchannel, 1000) == -1)
07329 break;
07330 }
07331 sayfile(myrpt->remchannel, "rpt/stop");
07332 } else {
07333 saynum(myrpt->remchannel, myrpt->hfscanstatus );
07334 }
07335 rmt_telem_finish(myrpt, myrpt->remchannel);
07336 myrpt->hfscanstatus = 0;
07337 }
07338 ast_frfree(f);
07339 rpt_mutex_lock(&myrpt->lock);
07340 c = myrpt->macrobuf[0];
07341 if (c && (!myrpt->macrotimer)) {
07342 myrpt->macrotimer = MACROTIME;
07343 memmove(myrpt->macrobuf, myrpt->macrobuf + 1, sizeof(myrpt->macrobuf) - 1);
07344 if ((c == 'p') || (c == 'P'))
07345 myrpt->macrotimer = MACROPTIME;
07346 rpt_mutex_unlock(&myrpt->lock);
07347 if (handle_remote_dtmf_digit(myrpt, c, &keyed, 0) == -1)
07348 break;
07349 continue;
07350 }
07351 c = myrpt->gosubbuf[0];
07352 if (c && (!myrpt->gosubtimer)) {
07353 myrpt->gosubtimer = GOSUBTIME;
07354 memmove(myrpt->gosubbuf, myrpt->gosubbuf + 1, sizeof(myrpt->gosubbuf) - 1);
07355 if ((c == 'p') || (c == 'P'))
07356 myrpt->gosubtimer = GOSUBPTIME;
07357 rpt_mutex_unlock(&myrpt->lock);
07358 if (handle_remote_dtmf_digit(myrpt, c, &keyed, 0) == -1)
07359 break;
07360 continue;
07361 }
07362 rpt_mutex_unlock(&myrpt->lock);
07363 continue;
07364 }
07365 if (who == myrpt->rxchannel) {
07366 f = ast_read(myrpt->rxchannel);
07367 if (!f) {
07368 ast_debug(1, "@@@@ link:Hung Up\n");
07369 break;
07370 }
07371 if (f->frametype == AST_FRAME_VOICE) {
07372 if ((myrpt->remote) && (myrpt->remotetx))
07373 memset(f->data, 0, f->datalen);
07374 ast_write(chan, f);
07375 } else if (f->frametype == AST_FRAME_CONTROL) {
07376 if (f->subclass == AST_CONTROL_HANGUP) {
07377 ast_debug(1, "@@@@ rpt:Hung Up\n");
07378 ast_frfree(f);
07379 break;
07380 }
07381
07382 if (f->subclass == AST_CONTROL_RADIO_KEY) {
07383 ast_debug(8, "@@@@ remote rx key\n");
07384 if (!myrpt->remotetx) {
07385 ast_indicate(chan, AST_CONTROL_RADIO_KEY);
07386 myrpt->remoterx = 1;
07387 }
07388 }
07389
07390 if (f->subclass == AST_CONTROL_RADIO_UNKEY) {
07391 ast_debug(8, "@@@@ remote rx un-key\n");
07392 if (!myrpt->remotetx) {
07393 ast_indicate(chan, AST_CONTROL_RADIO_UNKEY);
07394 myrpt->remoterx = 0;
07395 }
07396 }
07397 }
07398 ast_frfree(f);
07399 continue;
07400 }
07401 if ((myrpt->rxchannel != myrpt->txchannel) && (who == myrpt->txchannel)) {
07402
07403 f = ast_read(myrpt->txchannel);
07404 if (!f) {
07405 ast_debug(1, "@@@@ link:Hung Up\n");
07406 break;
07407 }
07408 if (f->frametype == AST_FRAME_CONTROL) {
07409 if (f->subclass == AST_CONTROL_HANGUP) {
07410 ast_debug(1, "@@@@ rpt:Hung Up\n");
07411 ast_frfree(f);
07412 break;
07413 }
07414 }
07415 ast_frfree(f);
07416 continue;
07417 }
07418
07419 }
07420 rpt_mutex_lock(&myrpt->lock);
07421 if (myrpt->rxchannel != myrpt->txchannel)
07422 ast_hangup(myrpt->txchannel);
07423 ast_hangup(myrpt->rxchannel);
07424 myrpt->hfscanmode = 0;
07425 myrpt->hfscanstatus = 0;
07426 myrpt->remoteon = 0;
07427 rpt_mutex_unlock(&myrpt->lock);
07428 closerem(myrpt);
07429 return res;
07430 }
07431
07432 static int unload_module(void)
07433 {
07434 int i;
07435
07436 for (i = 0; i < nrpts; i++) {
07437 if (!strcmp(rpt_vars[i].name, rpt_vars[i].p.nodes))
07438 continue;
07439 ast_mutex_destroy(&rpt_vars[i].lock);
07440 }
07441 i = ast_unregister_application(app);
07442
07443
07444 ast_cli_unregister_multiple(cli_rpt, sizeof(cli_rpt) / sizeof(struct ast_cli_entry));
07445
07446 return i;
07447 }
07448
07449 static int load_module(void)
07450 {
07451 struct ast_flags config_flags = { CONFIG_FLAG_NOCACHE };
07452 struct ast_config *cfg = ast_config_load("rpt.conf", config_flags);
07453 if (!cfg) {
07454 ast_log(LOG_WARNING, "No such configuration file rpt.conf\n");
07455 return AST_MODULE_LOAD_DECLINE;
07456 }
07457 ast_pthread_create(&rpt_master_thread, NULL, rpt_master, cfg);
07458
07459
07460 ast_cli_register_multiple(cli_rpt, sizeof(cli_rpt) / sizeof(struct ast_cli_entry));
07461
07462 return ast_register_application(app, rpt_exec, synopsis, descrip);
07463 }
07464
07465 static int reload(void)
07466 {
07467 int n;
07468
07469 for (n = 0; n < nrpts; n++)
07470 rpt_vars[n].reload = 1;
07471 return(0);
07472 }
07473
07474 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Radio Repeater / Remote Base",
07475 .load = load_module,
07476 .unload = unload_module,
07477 .reload = reload,
07478 );