* $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
#define MAXPATHLEN 256
#endif
-#define DEFPACLEN 128
+#define DEFPACLEN 236
#define MAXPACLEN 236
+#define MAXCALLSIGN 9
#define DBUF 1
#define DMSG 2
+#define DSTS 4
+
+#define UC unsigned char
typedef struct
{
} myregex_t;
-char *node_addr = "localhost"; /* the node tcp address, can be overridden by DXSPIDER_HOST */
+char *node_addr = "127.0.0.1"; /* the node tcp address, can be overridden by DXSPIDER_HOST */
int node_port = 27754; /* the tcp port of the node at the above address can be overidden by DXSPIDER_PORT*/
char *call; /* the caller's callsign */
char *connsort; /* the type of connection */
fcb_t *in; /* the fcb of 'stdin' that I shall use */
fcb_t *node; /* the fcb of the msg system */
char nl = '\n'; /* line end character */
+char mode = 1; /* 0 - ax25, 1 - normal telnet, 2 - nlonly telnet */
char ending = 0; /* set this to end the program */
-char send_Z = 1; /* set a Z record to the node on termination */
char echo = 1; /* echo characters on stdout from stdin */
char int_tabs = 0; /* interpret tabs -> spaces */
char *root = "/spider"; /* root of data tree, can be overridden by DXSPIDER_ROOT */
int timeout = 60; /* default timeout for logins and things */
int paclen = DEFPACLEN; /* default buffer size for outgoing packets */
int tabsize = 8; /* default tabsize for text messages */
+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 */
{
- "^[A-Z]+[0-9]+[A-Z]+[1-9]?$", 0
+ "^[A-Z]+[0-9]+[A-Z]+[1-9]?$", 0 /* G1TLH G1TLH1 */
},
{
- "^[0-9]+[A-Z]+[0-9]+[A-Z]+[1-9]?$", 0
+ "^[0-9]+[A-Z]+[0-9]+[A-Z]+[1-9]?$", 0 /* 2E0AAA 2E0AAA1 */
},
{
- "^[A-Z]+[0-9]+[A-Z]+[1-9]?-[1-9]$", 0
+ "^[A-Z]+[0-9]+[A-Z]+-[0-9]$", 0 /* G1TLH-2 */
},
{
- "^[0-9]+[A-Z]+[0-9]+[A-Z]+[1-9]?-[1-9]$", 0
+ "^[0-9]+[A-Z]+[0-9]+[A-Z]+-[0-9]$", 0 /* 2E0AAA-2 */
},
{
- "^[A-Z]+[0-9]+[A-Z]+[1-9]?-1[0-5]$", 0
+ "^[A-Z]+[0-9]+[A-Z]+-1[0-5]$", 0 /* G1TLH-11 */
},
{
- "^[0-9]+[A-Z]+[0-9]+[A-Z]+[1-9]?-1[0-5]$", 0
+ "^[0-9]+[A-Z]+[0-9]+[A-Z]+-1[0-5]$", 0 /* 2E0AAA-11 */
},
{
0, 0
* utility routines - various
*/
+void chgstate(int new)
+{
+ laststate = state;
+ state = new;
+ dbg(DSTS, "chg state %d->%d", laststate, state);
+}
+
void die(char *s, ...)
{
char buf[2000];
return (strcmp(a, b) == 0);
}
-int xopen(char *dir, char *name, int mode)
+FILE *xopen(char *dir, char *name, char *mode)
{
char fn[MAXPATHLEN+1];
snprintf(fn, MAXPATHLEN, "%s/%s/%s", root, dir, name);
- return open(fn, mode);
+ return fopen(fn, mode);
}
int iscallsign(char *s)
{
myregex_t *rp;
+
+ if (strlen(s) > MAXCALLSIGN)
+ return 0;
+
for (rp = iscallreg; rp->in; ++rp) {
if (regexec(rp->regex, s, 0, 0, 0) == 0)
return 1;
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;
}
}
-void send_text(fcb_t *f, char *s, int l)
+void send_text(fcb_t *f, char *s, int l, int nlreq)
{
cmsg_t *mp;
char *p;
f->obuf = mp = cmsg_new(paclen+1, f->sort, f);
}
+ /* remove trailing spaces */
+ while (l > 0 &&isspace(s[l-1]))
+ --l;
+
for (p = s; p < s+l; ) {
if (mp->inp >= mp->data + paclen) {
flush_text(f);
flush_text(f);
f->obuf = mp = cmsg_new(paclen+1, f->sort, f);
}
- *mp->inp++ = nl;
+ if (nlreq) {
+ if (nl == '\r')
+ *mp->inp++ = nl;
+ else {
+ if (mode != 2)
+ *mp->inp++ = '\r';
+ *mp->inp++ = '\n';
+ }
+ }
if (!f->buffer_it)
flush_text(f);
}
-void send_msg(fcb_t *f, char let, char *s, int l)
+void send_msg(fcb_t *f, char let, UC *s, int l)
{
cmsg_t *mp;
int ln;
int myl = strlen(call)+2+l;
mp = cmsg_new(myl+4+1, f->sort, f);
- ln = htonl(myl);
- memcpy(mp->inp, &ln, 4);
- mp->inp += 4;
*mp->inp++ = let;
strcpy(mp->inp, call);
mp->inp += strlen(call);
*mp->inp++ = '|';
if (l > 0) {
- memcpy(mp->inp, s, l);
- mp->inp += l;
- }
+ UC *p;
+ for (p = s; p < s+l; ++p) {
+ if (mp->inp >= mp->data + (myl - 4)) {
+ int off = mp->inp - mp->data;
+ myl += 256;
+ mp = realloc(mp, myl);
+ mp->inp = mp->data + off;
+ }
+
+ if (*p < 0x20 || *p > 0x7e || *p == '%') {
+ sprintf(mp->inp, "%%%02X", *p & 0xff);
+ mp->inp += strlen(mp->inp);
+ } else
+ *mp->inp++ = *p;
+ }
+ }
+ *mp->inp++ = '\n';
*mp->inp = 0;
cmsg_send(f->outq, mp, 0);
f->sp->flags |= SEL_OUTPUT;
}
+/*
+ * send a file out to the user
+ */
+void send_file(char *name)
+{
+ int i;
+ char buf[MAXPACLEN+1];
+
+ FILE *f = xopen("data", name, "r");
+ if (f) {
+ while (fgets(buf, paclen, f)) {
+ i = strlen(buf);
+ if (i && buf[i-1] == '\n')
+ buf[--i] = 0;
+ send_text(in, buf, i, 1);
+ }
+ fclose(f);
+ }
+}
+
/*
* the callback (called by sel_run) that handles all the inputs and outputs
*/
{
fcb_t *f = sp->fcb;
cmsg_t *mp, *omp;
+ UC c;
/* input modes */
- if (in) {
+ if (ending == 0 && in) {
char *p, buf[MAXBUFL];
int r;
case EAGAIN:
goto lout;
default:
- if (f->sort == MSG)
- send_Z = 0;
+ dbg(DBUF,"got errno %d in input", errno);
ending++;
- return 0;
+ return 1;
}
} else if (r == 0) {
- if (f->sort == MSG)
- send_Z = 0;
+ dbg(DBUF, "ending normally");
ending++;
- return 0;
+ return 1;
}
dbgdump(DBUF, "in ->", buf, r);
strcpy(omp->inp, "\b \b");
omp->inp += strlen(omp->inp);
break;
+ case '\r':
+ break;
+ case '\n':
+ strcpy(omp->inp, "\r\n");
+ omp->inp += 2;
+ break;
default:
*omp->inp++ = *p;
}
*mp->inp++ = *p++;
}
break;
- case '\b':
+ case 0x08:
case 0x7f:
if (mp->inp > mp->data)
mp->inp--;
default:
if (nl == '\n' && *p == '\r') { /* ignore \r in telnet mode (ugh) */
p++;
+ } else if (nl == '\r' && *p == '\n') { /* and ignore \n in ax25 mode (double ugh) */
+ p++;
} else if (*p == nl) {
if (mp->inp == mp->data)
*mp->inp++ = ' ';
case MSG:
p = buf;
while (r > 0 && p < &buf[r]) {
+ UC ch = *p++;
+
+ if (mp->inp >= mp->data + (MAXBUFL-1)) {
+ mp->state = 0;
+ mp->inp = mp->data;
+ dbg(DMSG, "Message longer than %d received", MAXBUFL);
+ }
- /* build up the size into the likely message length (yes I know it's a short) */
switch (mp->state) {
- case 0:
- case 1:
- mp->state++;
- break;
- case 2:
- case 3:
- mp->size = (mp->size << 8) | (*p++ & 0xff);
- if (mp->size > MAXBUFL)
- die("Message size too big from node (%d > %d)", mp->size, MAXBUFL);
- mp->state++;
- break;
- default:
- if (mp->inp - mp->data < mp->size) {
- *mp->inp++ = *p++;
- }
- if (mp->inp - mp->data >= mp->size) {
+ case 0:
+ if (ch == '%') {
+ c = 0;
+ mp->state = 1;
+ } else if (ch == '\n') {
/* kick it upstairs */
+ *mp->inp = 0;
dbgdump(DMSG, "QUEUE MSG", mp->data, mp->inp - mp->data);
cmsg_send(f->inq, mp, 0);
mp = f->in = cmsg_new(MAXBUFL+1, f->sort, f);
+ } else if (ch < 0x20 || ch > 0x7e) {
+ dbg(DMSG, "Illegal character (0x%02X) received", *p);
+ mp->inp = mp->data;
+ } else {
+ *mp->inp++ = ch;
+ }
+ break;
+
+ case 1:
+ mp->state = 2;
+ if (ch >= '0' && ch <= '9')
+ c = (ch - '0') << 4;
+ else if (ch >= 'A' && ch <= 'F')
+ c = (ch - 'A' + 10) << 4;
+ else {
+ dbg(DMSG, "Illegal hex char (%c) received in state 1", ch);
+ mp->inp = mp->data;
+ mp->state = 0;
}
+ break;
+
+ case 2:
+ if (ch >= '0' && ch <= '9')
+ *mp->inp++ = c | (ch - '0');
+ else if (ch >= 'A' && ch <= 'F')
+ *mp->inp++ = c | (ch - 'A' + 10);
+ else {
+ dbg(DMSG, "Illegal hex char (%c) received in state 2", ch);
+ mp->inp = mp->data;
+ }
+ mp->state = 0;
}
}
break;
case EAGAIN:
goto lend;
default:
- if (f->sort == MSG)
- send_Z = 0;
+ dbg(DBUF,"got errno %d in output", errno);
ending++;
return;
}
return 0;
}
+/*
+ * set up the various mode flags, NL endings and things
+ */
+void setconntype(char *m)
+{
+ connsort = strlower(m);
+ if (eq(connsort, "telnet") || eq(connsort, "local") || eq(connsort, "nlonly")) {
+ nl = '\n';
+ echo = 1;
+ mode = eq(connsort, "nlonly") ? 2 : 1;
+ } else if (eq(connsort, "ax25")) {
+ nl = '\r';
+ echo = 0;
+ mode = 0;
+ } else if (eq(connsort, "connect")) {
+ nl = '\n';
+ echo = 0;
+ mode = 3;
+ } else {
+ die("Connection type must be \"telnet\", \"nlonly\", \"ax25\", \"login\" or \"local\"");
+ }
+}
+
+
+/*
+ * things to do with ongoing processing of inputs
+ */
+
+void process_stdin()
+{
+ 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 (mp->size > 0) {
+ send_msg(node, 'I', mp->data, mp->size);
+ }
+ break;
+ case WAITLOGIN:
+ for (i = 0; i < mp->size; ++i) {
+ UC ch = mp->data[i];
+ if (i < MAXCALLSIGN) {
+ if (isalpha(ch))
+ ++hasa;
+ if (isdigit(ch))
+ ++hasn;
+ if (isalnum(ch) || ch == '-')
+ callsign[i] = ch;
+ else
+ die("invalid callsign");
+ } else
+ die("invalid callsign");
+ }
+ callsign[i]= 0;
+ if (strlen(callsign) < 3)
+ die("invalid callsign");
+ if (hasa && hasn)
+ ;
+ else
+ die("invalid callsign");
+ call = strupper(callsign);
+
+ /* 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;
+
+ alarm(0);
+ signal(SIGALRM, SIG_IGN);
+
+ /* tell the cluster who I am */
+ send_msg(node, 'A', connsort, strlen(connsort));
+
+ chgstate(CONNECTED);
+ send_file("connected");
+ break;
+
+ case DOCHAT:
+
+ break;
+ }
+
+ cmsg_callback(mp, 0);
+
+ }
+}
+
+void process_node()
+{
+ cmsg_t *mp = cmsg_next(node->inq);
+ if (mp) {
+ dbg(DMSG, "MSG size: %d", mp->size);
+
+ if (mp->size > 0 && mp->inp > mp->data) {
+ char *p = strchr(mp->data, '|');
+ if (p)
+ p++;
+ switch (mp->data[0]) {
+ case 'Z':
+ ending++;
+ return;
+ case 'E':
+ if (isdigit(*p))
+ in->echo = *p - '0';
+ break;
+ case 'B':
+ if (isdigit(*p))
+ in->buffer_it = *p - '0';
+ break;
+ case 'D':
+ if (p) {
+ int l = mp->inp - (UC *) p;
+ send_text(in, p, l, 1);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ cmsg_callback(mp, 0);
+ } else {
+ flush_text(in);
+ }
+}
+
+/*
+ * things to do with going away
+ */
+
+void term_timeout(int i)
+{
+ /* none of this is going to be reused so don't bother cleaning up properly */
+ if (isatty(0))
+ tcflush(0, TCIOFLUSH);
+ kill(getpid(), 9); /* commit suicide */
+}
+
+void terminate(int i)
+{
+ signal(SIGALRM, term_timeout);
+ alarm(10);
+
+ 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);
+ exit(i);
+}
+
+void login_timeout(int i)
+{
+ write(0, "Timed Out", 10);
+ write(0, &nl, 1);
+ terminate(0);
+}
+
/*
* things to do with initialisation
*/
{
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) {
- connsort = strlower(argv[optind]);
- if (eq(connsort, "telnet") || eq(connsort, "local")) {
- nl = '\n';
- echo = 1;
- } else if (eq(connsort, "ax25")) {
- nl = '\r';
- echo = 0;
- } else {
- die("2nd argument must be \"telnet\" or \"ax25\" or \"local\"");
- }
+ setconntype(argv[optind]);
} else {
- connsort = "local";
- nl = '\n';
- echo = 1;
+ setconntype("local");
}
/* this is kludgy, but hey so is the rest of this! */
- if (!eq(connsort, "ax25") && paclen == DEFPACLEN) {
+ if (mode != 0 && paclen == DEFPACLEN) {
paclen = MAXPACLEN;
}
}
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);
}
- node = fcb_new(nodef, MSG);
- node->sp = sel_open(nodef, node, "Msg System", fcb_handler, MSG, SEL_INPUT);
-
-}
-/*
- * things to do with going away
- */
-
-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) {
- close(node->cnum);
+ 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);
}
- exit(i);
-}
-
-void terminate(int i)
-{
- if (node && send_Z && call) {
- send_msg(node, 'Z', "", 0);
+ 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);
}
- signal(SIGALRM, term_timeout);
- alarm(10);
+ node = fcb_new(nodef, MSG);
+ node->sp = sel_open(nodef, node, "Msg System", fcb_handler, MSG, SEL_INPUT);
- while ((in && !is_chain_empty(in->outq)) ||
- (node && !is_chain_empty(node->outq))) {
- sel_run();
- }
- if (in && in->t_set)
- tcsetattr(0, TCSADRAIN, &in->t);
- if (node)
- close(node->cnum);
- exit(i);
-}
-
-void login_timeout(int 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);
}
/*
- * things to do with ongoing processing of inputs
+ * the program itself....
*/
-void process_stdin()
+main(int argc, char *argv[])
{
- cmsg_t *mp = cmsg_next(in->inq);
- if (mp) {
- dbg(DMSG, "MSG size: %d", mp->size);
-
- if (mp->size > 0 && mp->inp > mp->data) {
- send_msg(node, 'I', mp->data, mp->size);
+ /* compile regexes for iscallsign */
+ {
+ myregex_t *rp;
+ for (rp = iscallreg; rp->in; ++rp) {
+ regex_t reg;
+ int r = regcomp(®, rp->in, REG_EXTENDED|REG_ICASE|REG_NOSUB);
+ if (r)
+ die("regcomp returned %d for '%s'", r, rp->in);
+ rp->regex = malloc(sizeof(regex_t));
+ if (!rp->regex)
+ die("out of room - compiling regexes");
+ *rp->regex = reg;
}
- cmsg_callback(mp, 0);
}
-}
-
-void process_node()
-{
- cmsg_t *mp = cmsg_next(node->inq);
- if (mp) {
- dbg(DMSG, "MSG size: %d", mp->size);
- if (mp->size > 0 && mp->inp > mp->data) {
- char *p = strchr(mp->data, '|');
- if (p)
- p++;
- switch (mp->data[0]) {
- case 'Z':
- send_Z = 0;
- ending++;
- return;
- case 'E':
- if (isdigit(*p))
- in->echo = *p - '0';
- break;
- case 'B':
- if (isdigit(*p))
- in->buffer_it = *p - '0';
- break;
- case 'D':
- if (p) {
- int l = mp->inp - (unsigned char *) p;
- send_text(in, p, l);
- }
- break;
- default:
- break;
- }
- }
- cmsg_callback(mp, 0);
- } else {
- flush_text(in);
- }
-}
-
-/*
- * the program itself....
- */
-
-main(int argc, char *argv[])
-{
/* set up environment */
{
char *p = getenv("DXSPIDER_ROOT");
#ifdef SIGPWR
signal(SIGPWR, terminate);
#endif
-
- /* compile regexes for iscallsign */
- {
- myregex_t *rp;
- for (rp = iscallreg; rp->in; ++rp) {
- regex_t reg;
- int r = regcomp(®, rp->in, REG_EXTENDED|REG_ICASE|REG_NOSUB);
- if (r)
- die("regcomp returned %d for '%s'", r, rp->in);
- rp->regex = malloc(sizeof(regex_t));
- if (!rp->regex)
- die("out of room - compiling regexes");
- *rp->regex = reg;
- }
- }
- /* is this a login? */
- if (eq(call, "LOGIN")) {
- char buf[MAXPACLEN+1];
- int r;
- int f = xopen("data", "issue", 0);
- if (f > 0) {
- while ((r = read(f, buf, paclen)) > 0) {
- if (nl != '\n') {
- char *p;
- for (p = buf; p < &buf[r]; ++p) {
- if (*p == '\n')
- *p = nl;
- }
- }
- write(0, buf, r);
- }
- close(f);
- }
- signal(SIGALRM, login_timeout);
- alarm(timeout);
- write(0, "login: ", 7);
- r = read(0, buf, 20);
- if (r <= 0)
- die("No login or error (%d)", errno);
- signal(SIGALRM, SIG_IGN);
- alarm(0);
- while (r > 0) {
- if (buf[r-1] == ' ' || buf[r-1] == '\r' || buf[r-1] == '\n')
- --r;
- else
- break;
- }
- buf[r] = 0;
- call = strupper(buf);
- }
+ /* init a few things */
+ chain_init(&echobase);
- /* check the callsign */
- if (!iscallsign(call)) {
- die("Sorry, %s isn't a valid callsign", call);
- }
-
/* 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 {
struct termios t = in->t;
t.c_lflag &= ~(ECHO|ECHONL|ICANON);
+ t.c_oflag = 0;
if (tcsetattr(0, TCSANOW, &t) < 0)
die("tcsetattr (%d)", errno);
in->echo = echo;
/* connect up node */
connect_to_node();
- /* tell the cluster who I am */
- send_msg(node, 'A', connsort, strlen(connsort));
+ /* is this a login? */
+ if (eq(call, "LOGIN") || eq(call, "login")) {
+ send_file("issue");
+ signal(SIGALRM, login_timeout);
+ alarm(timeout);
+ 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));
+
+ chgstate(CONNECTED);
+ send_file("connected");
+ }
+
/* main processing loop */
- while (!ending) {
+ while (ending == 0) {
sel_run();
- if (!ending) {
+ if (ending == 0) {
process_stdin();
process_node();
}