* $Id$
*/
+#include <sys/types.h>
#include <stdio.h>
#include <sys/time.h>
-#include <sys/types.h>
+#include <sys/wait.h>
#include <unistd.h>
#include <ctype.h>
#include <stdlib.h>
#include "sel.h"
#include "cmsg.h"
+#include "chain.h"
#include "debug.h"
#define TEXT 1
char *connsort = "local"; /* the connection variety */
int state = 0; /* the current state of the connection */
int laststate = 0; /* the last state we were in */
-
-
+char echocancel = 1; /* echo cancelling */
+reft echobase; /* the anti echo queue */
+int maxecho = 5; /* the depth of the anti echo queue */
+int echon; /* no of entries in the anti echo queue */
#define CONNECTED 100
#define WAITLOGIN 1
#define WAITPASSWD 2
#define WAITINPUT 10
-
+#define DOCHAT 20
myregex_t iscallreg[] = { /* regexes to determine whether this is a reasonable callsign */
{
"^[0-9]+[A-Z]+[0-9]+[A-Z]+[1-9]?$", 0 /* 2E0AAA 2E0AAA1 */
},
{
- "^[A-Z]+[0-9]+[A-Z]+-[1-9]$", 0 /* G1TLH-2 */
+ "^[A-Z]+[0-9]+[A-Z]+-[0-9]$", 0 /* G1TLH-2 */
},
{
- "^[0-9]+[A-Z]+[0-9]+[A-Z]+-[1-9]$", 0 /* 2E0AAA-2 */
+ "^[0-9]+[A-Z]+[0-9]+[A-Z]+-[0-9]$", 0 /* 2E0AAA-2 */
},
{
"^[A-Z]+[0-9]+[A-Z]+-1[0-5]$", 0 /* G1TLH-11 */
return 0;
}
+void reaper(int i)
+{
+ pid_t mypid;
+ while ((mypid = waitpid(-1, 0, WNOHANG)) > 0) {
+ ;
+ }
+}
+
/*
* higher level send and receive routines
*/
void flush_text(fcb_t *f)
{
if (f->obuf) {
- cmsg_send(f->outq, f->obuf, 0);
+ /* save this onto the front of the echo chain */
+ cmsg_t *imp = f->obuf;
+ int size = imp->inp - imp->data;
+ cmsg_t *emp = cmsg_new(size, imp->sort, imp->portp);
+
+ emp->size = size;
+ memcpy(emp->data, imp->data, size);
+ emp->inp = emp->data + size; /* just in case */
+ if (echocancel) {
+ chain_add(&echobase, emp);
+ if (++echon > maxecho) {
+ emp = cmsg_prev(&echobase);
+ cmsg_free(emp);
+ }
+ }
+
+ /* queue it for sending */
+ cmsg_send(f->outq, imp, 0);
f->sp->flags |= SEL_OUTPUT;
f->obuf = 0;
}
default:
dbg(DBUF,"got errno %d in input", errno);
ending++;
- return 0;
+ return 1;
}
} else if (r == 0) {
dbg(DBUF, "ending normally");
ending++;
- return 0;
+ return 1;
}
dbgdump(DBUF, "in ->", buf, r);
/*
* set up the various mode flags, NL endings and things
*/
-void setmode(char *m)
+void setconntype(char *m)
{
connsort = strlower(m);
if (eq(connsort, "telnet") || eq(connsort, "local") || eq(connsort, "nlonly")) {
void process_stdin()
{
- cmsg_t *mp = cmsg_next(in->inq);
+ cmsg_t *wmp, *mp = cmsg_next(in->inq);
char *p, hasa, hasn, i;
char callsign[MAXCALLSIGN+1];
if (mp) {
dbg(DMSG, "MSG size: %d", mp->size);
+
+ /* check for echos */
+ if (echocancel) {
+ for (wmp = 0; wmp = chain_get_next(&echobase, wmp); ) {
+ if (!memcmp(wmp->data, mp->data, wmp->size)) {
+ cmsg_callback(mp, 0);
+ return;
+ }
+ }
+ }
switch (state) {
case CONNECTED:
if (!iscallsign(call)) {
die("Sorry, %s isn't a valid callsign", call);
}
+
+ /* strip off a '-0' at the end */
+ i = strlen(call);
+ if (call[i-1] == '0' && call[i-2] == '-')
+ call[i-2] = 0;
alarm(0);
signal(SIGALRM, SIG_IGN);
chgstate(CONNECTED);
send_file("connected");
+ break;
+
+ case DOCHAT:
+
+ break;
}
cmsg_callback(mp, 0);
void term_timeout(int i)
{
/* none of this is going to be reused so don't bother cleaning up properly */
- if (in && in->t_set)
- tcsetattr(0, TCSANOW, &in->t);
- if (node) {
- shutdown(node->cnum, 3);
- close(node->cnum);
- }
- exit(i);
+ if (isatty(0))
+ tcflush(0, TCIOFLUSH);
+ kill(getpid(), 9); /* commit suicide */
}
void terminate(int i)
signal(SIGALRM, term_timeout);
alarm(10);
- while ((in && !is_chain_empty(in->outq)) ||
- (node && !is_chain_empty(node->outq))) {
+ if (node && node->sp->sort) {
+ sel_close(node->sp);
+ }
+ while (in && in->sp->sort && !is_chain_empty(in->outq)) {
sel_run();
}
+ sel_run();
+ sel_run();
+ sel_run();
+ sel_run();
+ sel_run();
+ sel_run();
+ sel_run();
+ sel_run();
if (in && in->t_set)
tcsetattr(0, TCSADRAIN, &in->t);
- if (node) {
- shutdown(node->cnum, 3);
- close(node->cnum);
- }
exit(i);
}
{
write(0, "Timed Out", 10);
write(0, &nl, 1);
- sel_run(); /* force a coordination */
- if (in && in->t_set)
- tcsetattr(0, TCSANOW, &in->t);
- exit(i);
+ terminate(0);
}
/*
{
int i, c, err = 0;
- while ((c = getopt(argc, argv, "h:p:x:")) > 0) {
+ while ((c = getopt(argc, argv, "eh:l:p:x:")) > 0) {
switch (c) {
+ case 'e':
+ echocancel ^= 1;
+ break;
case 'h':
node_addr = optarg;
break;
lerr:
if (err) {
- die("usage: client [-x n|-h<host>|-p<port>|-l<paclen>] <call>|login [local|telnet|ax25]");
+ die("usage: client [-e|-x n|-h<host>|-p<port>|-l<paclen>] <call>|login [local|telnet|ax25]");
}
if (optind < argc) {
die("Must have at least a callsign (for now)");
if (optind < argc) {
- setmode(argv[optind]);
+ setconntype(argv[optind]);
} else {
- setmode("local");
+ setconntype("local");
}
/* this is kludgy, but hey so is the rest of this! */
struct hostent *hp, *gethostbyname();
struct sockaddr_in server;
int nodef;
+ int one = 1;
sel_t *sp;
-
+ struct linger lg;
+
if ((hp = gethostbyname(node_addr)) == 0)
die("Unknown host tcp host %s for printer", node_addr);
if (connect(nodef, (struct sockaddr *) &server, sizeof server) < 0) {
die("Error on connect to %s port %d (%d)", node_addr, node_port, errno);
}
+
+ memset(&lg, 0, sizeof lg);
+ if (setsockopt(nodef, SOL_SOCKET, SO_LINGER, &lg, sizeof lg) < 0) {
+ die("Error on SO_LINGER to %s port %d (%d)", node_addr, node_port, errno);
+ }
+ if (setsockopt(nodef, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof one) < 0) {
+ die("Error on SO_KEEPALIVE to %s port %d (%d)", node_addr, node_port, errno);
+ }
+
node = fcb_new(nodef, MSG);
node->sp = sel_open(nodef, node, "Msg System", fcb_handler, MSG, SEL_INPUT);
#ifdef SIGPWR
signal(SIGPWR, terminate);
#endif
+
+ /* init a few things */
+ chain_init(&echobase);
/* connect up stdin */
in = fcb_new(0, TEXT);
in->sp = sel_open(0, in, "STDIN", fcb_handler, TEXT, SEL_INPUT);
- if (tcgetattr(0, &in->t) < 0) {
-/* echo = 0; */
+ if (!isatty(0) || tcgetattr(0, &in->t) < 0) {
in->echo = echo;
in->t_set = 0;
} else {
send_text(in, "login: ", 7, 0);
chgstate(WAITLOGIN);
} else {
-
+ int i;
+
/* check the callsign against the regexes */
if (!iscallsign(call)) {
die("Sorry, %s isn't a valid callsign", call);
}
+ /* strip off a '-0' at the end */
+ i = strlen(call);
+ if (call[i-1] == '0' && call[i-2] == '-')
+ call[i-2] = 0;
+
/* tell the cluster who I am */
send_msg(node, 'A', connsort, strlen(connsort));