/* * NIM daemon command parser * * Frank Pronk * Copyright (c) 1984 */ #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <netccitt/x25.h> #include <netdb.h> #include "../h/x29.h" #include "nim.h" #define NEXTC (*sym.s_next ? *sym.s_next++ : (char)0) #define SSET 0200+0 #define SPAR 0200+1 #define SPROF 0200+2 #define SSTATUS 0200+3 #define SRESET 0200+4 #define SINT 0200+5 #define SINTD 0200+6 #define SCLEAR 0200+7 #define SHELP 0200+8 #define SCALL 0200+9 #define SPRI 0200+10 #define SREV 0200+11 #define SNUM 0200+12 #define SSTR 0200+13 #define SNUI 0200+14 struct NIMCommand { char *c_name; short c_value; } Commands[] = { "set", SSET, "par", SPAR, "prof", SPROF, "profile", SPROF, "stat", SSTATUS, "status", SSTATUS, "reset", SRESET, "int", SINT, "intd", SINTD, "clear", SCLEAR, "help", SHELP, "call", SCALL, "p", SPRI, "rev", SREV, "nui", SNUI, 0, 0, }; struct sockaddr_x25 RemoteHostAddr; char *RemoteHostName; char *Nui; /* network user identification */ /* * Structure used by insymbol() keep track of its * current position in the command string being * parsed and to hold the results of the last * call to insymbol() */ struct symbol { char *s_start; /* start of line to be parsed */ char *s_next; /* current position in line */ short s_type; /* see defines above */ int s_num; /* value if current symbol is a number */ char *s_str; /* address of symbol if a string */ } sym; /* * List of symbolic names that can be * used as replacements for numeric codes * in specific "set parameter" requests */ struct NameList { char *n_name; short n_value; } ForwardList[] = { "cr", 2, "control", 126, "off", 0, 0, 0 }, OnOffList[] = { "on", 1, "off", 0, 0, 0}, LfList[] = { "on", 4, "off", 0, "none", 0, "local", 4, "remote", 1, "both", 5, 0, 0}; /* * list of x.29 symbolic keywords that can be substituted * for numeric codes. Note that this list contains only * the x.29 parameters that an average user would ever * want to change. */ struct X29Keyword { char *x_word; /* parameter name */ short x_param; /* parameter code */ struct NameList *x_list; } X29Keywords[] = { "escape", X29_ESCAPE_TO_CMD_CODE, OnOffList, "echo", X29_ECHO_CODE, OnOffList, "forward", X29_FORWARDING_SIGNAL_CODE, ForwardList, "timer", X29_IDLE_TIMER_CODE, OnOffList, "break", X29_BREAK_PROCEDURE_CODE, 0, "lf", X29_LF_AFTER_CR, LfList, "lf-insertion", X29_LF_AFTER_CR, LfList, "editing", X29_EDITING, OnOffList, "erase", X29_CHARACTER_DELETE, 0, "kill", X29_LINE_DELETE, 0, "replay", X29_LINE_DISPLAY, 0, "display", X29_LINE_DISPLAY, 0, 0, 0, 0 }; /* * Attempt to parse string pointed to by 'cp'. */ NimCommand(cp) register char *cp; { sym.s_start = sym.s_next = cp; /* * strip parity bit from command */ while ((*cp&0177) != '\0') *cp++ &= 0177; switch(insymbol(0)) { case SCLEAR: ClearCommand(); return; case SHELP: case '?': HelpCommand(); return; case SINT: InterruptCommand(0); break; case SINTD: InterruptCommand(1); return; case SPAR: ParCommand(); return; case SPROF: ProfileCommand(); return; case SRESET: ResetCommand(); return; case SSET: SetCommand(); return; case SSTATUS: StatusCommand(); return; case SPRI: case SREV: case SNUM: X121CallCommand(); return; case SCALL: CallCommand(); return; case SNUI: NuiCommand (); return; case '\0': NullCommand(); return; case '.': DotCommand(); return; default: message ("Unknown NIM command\r"); return; } } GetNumber(np) register struct NameList *np; { (void) insymbol(0); if (sym.s_type == SNUM) return (1); if (sym.s_type == '(') { register int value; switch (insymbol(1)) { case SSTR: if (strlen (sym.s_str) != 1) return (0); value = *sym.s_str; break; case SNUM: value = sym.s_num; break; default: if (sym.s_type == '\r') return (0); value = sym.s_type; } (void) insymbol(0); if(sym.s_type == ')') { sym.s_num = value; return(1); } return(0); } if (sym.s_type == SSTR && np) for (; np->n_name; np++) if (strcmp(np->n_name, sym.s_str) == 0) { sym.s_num = np->n_value; return (1); } return (0); } /* * Save the string pointed to by 's' */ char * saves(s) char *s; { register char *p; char *malloc(); p = malloc(strlen(s) + 1); strcpy(p, s); return (p); } char GetEscaped () { register char c, value; c = NEXTC; if (c < '0' || c > '7') return (c); value = c - '0'; c = NEXTC; if (c >= '0' && c <= '7') { register int n; value = value*8 + c - '0'; c = NEXTC; if (c >= '0' && c <= '7' && (n = value*8 + c-'0') < 256) { value = n; c = NEXTC; } } return (value); } insymbol(special) { register char c, *cp; char buf[128]; if (sym.s_str) { free(sym.s_str); sym.s_str = 0; } cp = buf; while ((c = NEXTC) == ' ' || c == '\t'); if (c == '\'' || c == '"') { register char quote = c; while (1) { c = NEXTC; if (c == '\0') return (sym.s_type = 0); if (c == quote) break; if (c == '\\') c = GetEscaped (); if(cp < buf + sizeof (buf)) *cp++ = c; } *cp = '\0'; sym.s_type = SSTR; sym.s_str = saves (buf); return (sym.s_type); } if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '\\') { do { if (c == '\\') c = GetEscaped (); if(cp < buf + sizeof (buf)) { if (!special && c >= 'A' && c <= 'Z') c -= 'A' - 'a'; *cp++ = c; } c = NEXTC; } while (c >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_' || c == '-'); *cp = '\0'; if (c) sym.s_next--; /* * set symbol type to SSTR and * then look for keywords */ sym.s_type = SSTR; if (!special) { register struct NIMCommand *np; cp = &buf[0]; for (np = Commands; np->c_name; np++) if(strcmp(cp, np->c_name) == 0) { sym.s_type = np->c_value; break; } } if (sym.s_type == SSTR) sym.s_str = saves(buf); return (sym.s_type); } if (c >= '0' && c <= '9') { do { if(cp < buf + sizeof (buf)) *cp++ = c; c = NEXTC; } while(c >= '0' && c <= '9'); *cp = '\0'; if (c) sym.s_next--; sym.s_num = atoi(buf); sym.s_type = SNUM; sym.s_str = saves(buf); return (SNUM); } return (sym.s_type = c); } /* * Does nothing useful - retained for * compatibility with Datapac. */ DotCommand() { message (Banner); } X121CallCommand() { register int len, havenet = 0; if (State & ST_DATA) { message ("You are connected to %s, please clear this call before attempting another\r", RemoteHostName?RemoteHostName:(char *)RemoteHostAddr.x25_addr); return; } bzero ((char *)&RemoteHostAddr, sizeof (RemoteHostAddr)); if (RemoteHostName) { free (RemoteHostName); RemoteHostName = (char *)0; } while (sym.s_type == SPRI || sym.s_type == SREV) { if (sym.s_type == SPRI) /* Datapac specific */ RemoteHostAddr.x25_opts.op_psize = X25_PS128; else if (sym.s_type == SREV) RemoteHostAddr.x25_opts.op_flags |= X25_REVERSE_CHARGE; (void) insymbol(0); } getaddr: if (sym.s_type != SNUM) { message("Non-numeric destination address\r"); return; } if (strlen(sym.s_str) > sizeof (RemoteHostAddr.x25_addr) - 1) { message ("Destination address too long\r"); return; } strcpy(RemoteHostAddr.x25_addr, sym.s_str); (void) insymbol(1); if (sym.s_type == ':' || sym.s_type == '.') { if (havenet) { message("Destination address error\r"); return; } havenet++; RemoteHostAddr.x25_net = atoi(RemoteHostAddr.x25_addr); (void) insymbol(1); goto getaddr; } if (sym.s_type == ',') /* skip optional comma */ (void) insymbol(1); RemoteHostAddr.x25_udata[0] = ITI_CALL; RemoteHostAddr.x25_udlen = 4; if (sym.s_type == SSTR || sym.s_type == SNUM) { if ((len = strlen(sym.s_str)) > sizeof (RemoteHostAddr.x25_udata) - 4) { message ("Userdata field too long\r"); RemoteHostAddr.x25_addr[0] = '\0'; return; } strcpy(RemoteHostAddr.x25_udata + 4, sym.s_str); RemoteHostAddr.x25_udlen += len; (void) insymbol(1); } if (sym.s_type == ',') /* skip optional comma */ (void) insymbol(1); if (sym.s_type == SSTR || sym.s_type == SNUM) { /* protocol id */ if (strlen(sym.s_str) > 4) { message ("Protocol field too long\r"); RemoteHostAddr.x25_addr[0] = '\0'; return; } strcpy(RemoteHostAddr.x25_udata, sym.s_str); (void) insymbol(0); } if (sym.s_type != '\0') { /* still more to come? */ message ("usage: [options] address [userdata] [protocol id]\r"); RemoteHostAddr.x25_addr[0] = '\0'; return; } InitiateSession (); } CallCommand () { register struct hostent *hp; struct hostent *getx25hostbyname (); if (insymbol(1) == '\0') { if (RemoteHostAddr.x25_addr[0] == '\0') { message ("Call who?\r"); return; } } else { if (sym.s_type != SSTR) { message("nimd: usage: call [hostname]\r"); return; } if ((hp = getx25hostbyname (sym.s_str)) == 0) { message ("nimd: can't find \"%s\" in host table\r", sym.s_str); return; } if (RemoteHostName) free (RemoteHostName); RemoteHostName = saves (sym.s_str); bcopy (hp->h_addr, (char *)&RemoteHostAddr, sizeof (RemoteHostAddr)); RemoteHostAddr.x25_udata[0] = ITI_CALL; } InitiateSession (); } InitiateSession () { register char *cp; struct sockaddr_x25 peer; int slen = sizeof (struct sockaddr_x25); char buf[256]; int on = 1; #ifdef waterloo extern char user_name[]; if ((RemoteHostAddr.x25_opts.op_flags & X25_REVERSE_CHARGE) == 0 && !(user_name[0] ? x25_can_callin(user_name) : 1)) { message("You may not place locally charged calls\r"); return; } #endif sprint (buf, "calling %s", RemoteHostAddr.x25_addr); cp = buf + strlen (buf); if (RemoteHostName) { sprint (cp, " (%s)", RemoteHostName); cp = cp + strlen (cp); } if (RemoteHostAddr.x25_opts.op_flags & X25_REVERSE_CHARGE) strcat (cp, " collect"); log (buf); if ((NetFd = socket (AF_CCITT, SOCK_STREAM, 0)) < 0) { error (); return; } RemoteHostAddr.x25_family = AF_CCITT; RemoteHostAddr.x25_opts.op_flags |= X25_MQBIT; if (connect (NetFd, (char *)&RemoteHostAddr, sizeof (RemoteHostAddr)) < 0) { error (); close (NetFd); NetFd = -1; return; } if (getpeername (NetFd, (struct sockaddr *)&peer, &slen)) error (); NetInfo.n_psize = (1 << peer.x25_opts.op_psize); log ("call succeeded: packet size=%d", NetInfo.n_psize); if (CurrentX29Parms[X29_RECEIVE_NET_MSGS_CODE]) { message ("nimd:\tCall connected to %s", RemoteHostAddr.x25_addr); if (RemoteHostName) message (" (%s)", RemoteHostName); message ("\r\t(%s charging, packet size: %d)\r\r", RemoteHostAddr.x25_opts.op_flags & X25_REVERSE_CHARGE ? "remote" : "local", NetInfo.n_psize); } ioctl (NetFd, FIONBIO, (char *)&on); State |= ST_DATA; State &= ~ST_COMMAND; } struct X29Keyword * LookupX29Keyword(word) char *word; { register struct X29Keyword *xp; for (xp = X29Keywords; xp->x_word; xp++) if (strcmp(word, xp->x_word) == 0) return (xp); return ((struct X29Keyword *)0); } ParCommand() { register int param; register struct X29Keyword *xp; if (insymbol(0) == '\0') { DisplayCurrentParms(); return; } while (sym.s_type != '\0') { switch (sym.s_type) { case SNUM: param = sym.s_num; xp = 0; break; case SSTR: if ((xp = LookupX29Keyword(sym.s_str)) == 0) { message("%s: unknown X.29 parameter\r", sym.s_str); return; } param = xp->x_param; break; default: message("number or X.29 parameter name expected\r"); return; } if (xp) message ("%s:%d\r", xp->x_word, CurrentX29Parms[param]); else message ("%d:%d\r", param, CurrentX29Parms[param]); if (insymbol(0) == ',') /* skip optional comma */ (void) insymbol(0); } } DisplayCurrentParms() { register int nparams, pnum, i; nparams = NetInfo.n_nparms; for (i=0; i<nparams; i++) { pnum = pnums[i]; message (i%6 ? ", %d:%d" : "\t%d:%d", pnum, CurrentX29Parms[pnum]); if (i % 6 == 5) message ("\r"); } if (nparams % 6) message ("\r"); } SetCommand() { register int setandread = 0, param; register struct X29Keyword *xp; (void) insymbol(0); if (sym.s_type == '?') { setandread++; insymbol(0); } while (sym.s_type != '\0') { switch (sym.s_type) { case SNUM: param = sym.s_num; xp = 0; break; case SSTR: if ((xp = LookupX29Keyword(sym.s_str)) == 0) { message("%s: unknown X.29 parameter\r", sym.s_str); return; } param = xp->x_param; break; default: message("number or X.29 parameter name expected\r"); return; } (void) insymbol(0); if (sym.s_type != ':' && sym.s_type != '=') { message("':' or '=' expected between parameter and value\r"); return; } if (GetNumber(xp ? xp->x_list : 0)) { if (SetX29Parm(param, sym.s_num)) if (xp) message ("par %s:invalid\r", xp->x_word); else message("par %d:invalid\r", param); else if (setandread) if (xp) message ("par %s:%d\r", xp->x_word, sym.s_num); else message("PAR %d:%d\r", param, sym.s_num); } else { message("number expected\r"); return; } (void) insymbol(0); if (sym.s_type == ',') /* skip optional comma */ (void) insymbol(0); } } ProfileCommand() { register int displayonly = 0, profile; if (insymbol(0) == '?') { displayonly++; (void) insymbol(0); } if (sym.s_type == SNUM) { profile = sym.s_num; if (profile >= 0 && profile <= 6) if (insymbol(0) == '\0') { if (displayonly) DisplayProfile(profile); else InitProfile(profile); return; } } message("usage: prof n or prof?n where n is a number between 1 and 6\r"); } DisplayProfile (profile) { register int i, nparms, pnum, value; extern char profiles[NPROFILES+1][NX29_PARMS]; nparms = NetInfo.n_nparms; for (i=1; i<=nparms; i++) { pnum = pnums[i]; value = profiles[profile][pnum]; if (i % 6 == 0) if (i == 0) message ("prof %d\t%d:%d", profile, pnum, value); else message ("\t%d:%d", pnum, value); else message (", %d:%d", pnum, value); if (i % 6 == 5) message ("\r"); } if (nparms % 6) message ("\r"); } StatusCommand () { if (State & ST_DATA) message ("Connected to %s\r", RemoteHostName); else message ("idle\r"); } InterruptCommand(discard) { if (discard) Break (21); else Break (1); } ClearCommand () { if (State & ST_DATA) ExitDataState ("local directive"); else message ("you are not connected to anybody\r"); } NullCommand () { if (State & ST_ESCCOMM) State &= ~(ST_COMMAND|ST_ESCCOMM); else message (Banner); } ResetCommand() { ResetBufs (); } HelpCommand() { GetHelp ("general-info"); } GetHelp (topic) char *topic; { register int fd; char HelpFile[128]; strcpy (HelpFile, HELPFILE); strcat (HelpFile, topic); if ((fd = open (HelpFile, 0)) < 0) { message ("No help with %s\r", topic); return; } /* not yet implemented */ close (fd); } NuiCommand () /* net completely implemented */ { if (insymbol (1) == '\0') { if (Nui) message ("NUI = %s\r", Nui); else message ("No valid NUI\r"); return; } }