* $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 <signal.h>
#include <string.h>
#include <termios.h>
+#include <regex.h>
#include "sel.h"
#include "cmsg.h"
+#include "chain.h"
#include "debug.h"
#define TEXT 1
#define MSG 2
#define MAXBUFL 1024
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 256
+#endif
+
+#define DEFPACLEN 236
+#define MAXPACLEN 236
+#define MAXCALLSIGN 9
+
#define DBUF 1
#define DMSG 2
+#define DSTS 4
+
+#define UC unsigned char
typedef struct
{
int sort; /* the type of connection either text or msg */
cmsg_t *in; /* current input message being built up */
cmsg_t *out; /* current output message being sent */
+ cmsg_t *obuf; /* current output being buffered */
reft *inq; /* input queue */
reft *outq; /* output queue */
sel_t *sp; /* my select fcb address */
- int echo; /* echo characters back to this cnum */
struct termios t; /* any termios associated with this cnum */
+ char echo; /* echo characters back to this cnum */
+ char t_set; /* the termios structure is valid */
+ char buffer_it; /* buffer outgoing packets for paclen */
} fcb_t;
-char *node_addr = "localhost"; /* the node tcp address */
-int node_port = 27754; /* the tcp port of the node at the above address */
+typedef struct
+{
+ char *in;
+ regex_t *regex;
+} myregex_t;
+
+
+char *node_addr = "localhost"; /* 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 /* G1TLH G1TLH1 */
+ },
+ {
+ "^[0-9]+[A-Z]+[0-9]+[A-Z]+[1-9]?$", 0 /* 2E0AAA 2E0AAA1 */
+ },
+ {
+ "^[A-Z]+[0-9]+[A-Z]+-[0-9]$", 0 /* G1TLH-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 */
+ },
+ {
+ "^[0-9]+[A-Z]+[0-9]+[A-Z]+-1[0-5]$", 0 /* 2E0AAA-11 */
+ },
+ {
+ 0, 0
+ }
+};
void terminate(int);
* 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];
va_list ap;
va_start(ap, s);
- vsprintf(buf, s, ap);
+ vsnprintf(buf, sizeof(buf)-1, s, ap);
va_end(ap);
fprintf(stderr,"%s\n", buf);
terminate(-1);
return (strcmp(a, b) == 0);
}
+FILE *xopen(char *dir, char *name, char *mode)
+{
+ char fn[MAXPATHLEN+1];
+ snprintf(fn, MAXPATHLEN, "%s/%s/%s", root, dir, name);
+ 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
*/
return f;
}
-void send_text(fcb_t *f, char *s, int l)
+void flush_text(fcb_t *f)
+{
+ if (f->obuf) {
+ /* 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, int nlreq)
{
cmsg_t *mp;
- mp = cmsg_new(l+1, f->sort, f);
- memcpy(mp->inp, s, l);
- mp->inp += l;
- *mp->inp++ = nl;
- cmsg_send(f->outq, mp, 0);
- f->sp->flags |= SEL_OUTPUT;
+ char *p;
+
+ if (f->buffer_it && f->obuf) {
+ mp = f->obuf;
+ } else {
+ 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);
+ f->obuf = mp = cmsg_new(paclen+1, f->sort, f);
+ }
+ *mp->inp++ = *p++;
+ }
+ if (mp->inp >= mp->data + paclen) {
+ flush_text(f);
+ f->obuf = mp = cmsg_new(paclen+1, f->sort, f);
+ }
+ 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, f->sort, f);
- ln = htonl(myl);
- memcpy(mp->inp, &ln, 4);
- mp->inp += 4;
+ mp = cmsg_new(myl+4+1, f->sort, f);
*mp->inp++ = let;
strcpy(mp->inp, call);
mp->inp += strlen(call);
*mp->inp++ = '|';
- if (l) {
- memcpy(mp->inp, s, l);
- mp->inp += l;
- }
+ if (l > 0) {
+ 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
+ */
+
int fcb_handler(sel_t *sp, int in, int out, int err)
{
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);
/* create a new message buffer if required */
if (!f->in)
- f->in = cmsg_new(MAXBUFL, f->sort, f);
+ f->in = cmsg_new(MAXBUFL+1, f->sort, f);
mp = f->in;
switch (f->sort) {
case TEXT:
p = buf;
if (f->echo)
- omp = cmsg_new(3*r, f->sort, f);
+ omp = cmsg_new(3*r+1, f->sort, f);
while (r > 0 && p < &buf[r]) {
/* echo processing */
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;
}
/* character processing */
switch (*p) {
- case '\b':
+ case '\t':
+ if (int_tabs) {
+ memset(mp->inp, ' ', tabsize);
+ mp->inp += tabsize;
+ ++p;
+ } else {
+ *mp->inp++ = *p++;
+ }
+ break;
+ case 0x08:
case 0x7f:
if (mp->inp > mp->data)
mp->inp--;
++p;
break;
default:
- if (*p == nl) {
+ 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++ = ' ';
*mp->inp = 0; /* zero terminate it, but don't include it in the length */
dbgdump(DMSG, "QUEUE TEXT", mp->data, mp->inp-mp->data);
cmsg_send(f->inq, mp, 0);
- f->in = mp = cmsg_new(MAXBUFL, f->sort, f);
+ f->in = mp = cmsg_new(MAXBUFL+1, f->sort, f);
++p;
} else {
- if (mp->inp < &mp->data[MAXBUFL])
+ if (mp->inp < &mp->data[MAXBUFL-8])
*mp->inp++ = *p++;
else {
mp->inp = mp->data;
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);
- 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, f->sort, f);
+ 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;
}
if (mp->inp - mp->data >= mp->size) {
cmsg_callback(mp, 0);
f->out = 0;
-/* if (is_chain_empty(f->outq))
- sp->flags &= ~SEL_OUTPUT; */
}
}
lend:;
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, "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;
+ case 'l':
+ paclen = atoi(optarg);
+ if (paclen < 80)
+ paclen = 80;
+ if (paclen > MAXPACLEN)
+ paclen = MAXPACLEN;
+ break;
+ case 'p':
+ node_port = atoi(optarg);
+ break;
case 'x':
dbginit("client");
dbgset(atoi(optarg));
lerr:
if (err) {
- die("usage: client [-x nn] <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) {
call = strupper(argv[optind]);
- if (eq(call, "LOGIN"))
- die("login not implemented (yet)");
++optind;
}
if (!call)
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 (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)
- 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 (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)
- tcsetattr(0, TCSANOW, &in->t);
- if (node)
- close(node->cnum);
- 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 'D':
- if (p) {
- int l = mp->inp - (unsigned char *) p;
- send_text(in, p, l);
- }
- break;
- default:
- break;
- }
+ /* set up environment */
+ {
+ char *p = getenv("DXSPIDER_ROOT");
+ if (p)
+ root = p;
+ p = getenv("DXSPIDER_HOST");
+ if (p)
+ node_addr = p;
+ p = getenv("DXSPIDER_PORT");
+ if (p)
+ node_port = atoi(p);
+ p = getenv("DXSPIDER_PACLEN");
+ if (p) {
+ paclen = atoi(p);
+ if (paclen < 80)
+ paclen = 80;
+ if (paclen > MAXPACLEN)
+ paclen = MAXPACLEN;
}
- cmsg_callback(mp, 0);
}
-}
-
-/*
- * the program itself....
- */
-
-main(int argc, char *argv[])
-{
+
+ /* get program arguments, initialise stuff */
initargs(argc, argv);
sel_init(10, 0, 10000);
+ /* trap signals */
signal(SIGHUP, SIG_IGN);
-
signal(SIGINT, terminate);
signal(SIGQUIT, terminate);
signal(SIGTERM, terminate);
+#ifdef SIGPWR
signal(SIGPWR, terminate);
+#endif
+
+ /* init a few things */
+ chain_init(&echobase);
- /* connect up stdin, stdout and message system */
+ /* 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)
- die("tcgetattr (%d)", errno);
- {
+ 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;
+ in->t_set = 1;
}
+ in->buffer_it = 1;
+
+ /* 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();
}