Files
sicspsi/tecs/six.c
zolliker c33fb15498 - inserted possiblity to send spy commands when busy
- general enhancements of six
2005-03-17 16:08:08 +00:00

700 lines
19 KiB
C

#include <unistd.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <assert.h>
#include <string.h>
#include "term.h"
#include "coc_util.h"
#include "myc_err.h"
#include "myc_str.h"
typedef enum { NORMAL, SPY, CLIENT } Mode;
#define MAXMSG 256
static char *host;
static char instr[32];
static int sock[2]; /* main socket and spy socket */
static int level=3;
static int deflevel=0;
static int remember=1;
static int hidecom=1;
static char user1[32]="";
static char pswd1[32]="";
static char user2[32]="";
static char pswd2[32]="";
static char status[MAXMSG]="Busy";
static int busy[2];
static int port;
static char msg0[MAXMSG];
static char msg1[MAXMSG]; /* contains messages for main and spy */
static int pos0 = 0;
static int pos1 = 0;
static char *prefix[3]={"| ", "* ", ""};
void Usage(int cmds_only) {
if (!cmds_only) {
printf(" \n");
printf(" six commandline options:\n");
printf(" - login as spy\n");
printf(" + login as manager\n");
printf(" 0 login as user\n");
printf(" -- set spy as default\n");
printf(" 00 set user as default\n");
printf(" ++ set manager as default\n");
printf(" help show this help text\n");
printf(" -a or a ask always for username/password, forget passwords\n");
printf(" -s or s simulation mode (on some instruments)\n");
printf(" -h \"host\" connect to a SICServer on a different host\n");
printf(" -p \"port\" connect to a SICServer on a different port\n");
printf(" -n do only a miminal login (no check of instrument)\n");
printf(" no option login with default privilege\n");
}
printf("\n");
printf(" Special commands treated by six (these are no SICS commands!)\n");
printf("\n");
printf(" quit exit six\n");
printf(" exit exit six\n");
printf(" stop interrupt SICS\n");
printf(" six help show this help text\n");
printf(" + increase privilege\n");
printf(" - decrease privilege\n");
printf("\n");
printf(" The SICS status is shown, if it is not 'Eager to execute commands'.\n");
printf(" A shown status does not prohibit to enter commands.\n");
printf("\n");
printf(" When SICS is busy, an asterisk '*' is shown at the left of the line.\n");
printf(" You may then enter more commands, but only under Spy privilege.\n");
printf(" All communication to and from SICS is prefixed with '|' or '*',\n");
printf(" messages from the six client have no prefix.\n");
printf("\n");
printf(" Markus Zolliker, Mar. 2005\n");
printf("\n");
}
int CocCreateSockAdr(
struct sockaddr_in *sockaddrPtr, /* Socket address */
const char *host, /* Host. NULL implies INADDR_ANY */
int port) /* Port number */
{
struct hostent *hostent; /* Host database entry */
struct in_addr addr; /* For 64/32 bit madness */
(void) memset((char *) sockaddrPtr, '\0', sizeof(struct sockaddr_in));
sockaddrPtr->sin_family = AF_INET;
sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF));
if (host == NULL || host[0]=='\0') {
addr.s_addr = INADDR_ANY;
} else {
hostent = gethostbyname(host);
if (hostent != NULL) {
memcpy((char *) &addr,
(char *) hostent->h_addr_list[0], (size_t) hostent->h_length);
} else {
addr.s_addr = inet_addr(host);
if (addr.s_addr == (unsigned long)-1) {
return -1; /* error */
}
}
}
/*
* There is a rumor that this assignment may require care on
* some 64 bit machines.
*/
sockaddrPtr->sin_addr.s_addr = addr.s_addr;
return 0;
}
char* readWrite(int tmo, int skip, char *find) {
int lbuf, go, iret, n, shortTmo, l, socket;
Mode idx;
char *msg, *p, *q;
char chr;
static char result[MAXMSG];
int match;
static int laststat=0, laststatlen=0;
static int newline[2]={1,1};
/*
* read from registered sockets and write to stdout until a key pressed,
* a timeout occurred (tmo [msec]), or a TRANSACTIONFINISHED message
* received. Handle also status and TRANSACTIONSTART messages.
*
* skip=0: skip response that does not match
* skip=1: skip all responses
* skip=2: skip all responses, quit on match
*
* if the response starts with the contents of find
* the second part of the line is returned
* if the response contain the contents of find, but not at the beginning
* "1" is returned
* if the text is not found, or find=NULL, an empty line is returned
*/
n=0;
go=0;
shortTmo = 0;
str_copy(result, "");
socket=term_wait_socket(0, tmo);
while (socket > 0) {
idx = (socket == sock[1]);
ERR_SI(lbuf=recv(socket, &chr, 1, 0));
if (lbuf==0) return "0";
while (lbuf>0) {
if (chr == '\n') break;
if (idx) {
if (chr != '\r' && pos1 < MAXMSG-1) { /* cut lines longer than MAXMSG */
msg1[pos1]=chr;
pos1++;
}
} else {
if (chr != '\r' && pos0 < MAXMSG-1) { /* cut lines longer than MAXMSG */
msg0[pos0]=chr;
pos0++;
}
}
socket=term_wait_socket(0, tmo);
if (socket <= 0) break;
idx = (socket == sock[1]);
ERR_SI(lbuf=recv(socket, &chr, 1, 0));
}
if (idx) {
msg1[pos1] = '\0';
pos1 = 0;
msg = msg1;
} else {
msg0[pos0] = '\0';
pos0 = 0;
msg = msg0;
}
/* printf("[%s]\n", msg); */
match=0;
if (strncmp(msg, "TRANSACTIONSTART", 16) == 0) {
busy[idx] = 1;
match = 1;
} else if (strncmp(msg, "TRANSACTIONFINISHED", 19) == 0) {
busy[idx] = 0;
if (skip != 2) go = 1;
shortTmo = 1;
match = 1;
} else if (idx == 0 && strncmp(msg, "status = ", 9) == 0) {
strcpy(status, msg+9);
l = strlen(msg);
if (status[0] == 'E') {
} else if (laststat!=status[0] || laststatlen != l) {
laststat = status[0];
laststatlen = l;
}
match = 1;
}
if (idx == 0 && find != NULL) {
p=strstr(msg, find);
if (p!=NULL) { /* copy message to result */
if (p==msg) {
str_copy(result, msg+strlen(find));
q=strchr(result,'\r');
if (q != NULL) *q='\0';
} else {
str_copy(result, "1");
}
match=1;
if (skip == 2) go = 1;
}
}
if (hidecom && (skip || match)) { /* skip text */
n+=strlen(msg);
} else {
term_clear();
if (newline[idx]) {
fputs(prefix[idx], stdout);
newline[idx]=0;
}
if (strncmp(msg, "ERROR:", 6)==0) {
fputs("\033[1;31m", stdout); /* red bold */
fputs(msg, stdout);
fputs("\033[0m", stdout); /* clear colors */
} else {
fputs(msg, stdout);
}
if (chr=='\n') {
newline[idx]=1;
fputs("\n", stdout);
}
}
if (go) break;
socket = term_wait_socket(0, shortTmo?100:tmo);
shortTmo = 0;
}
fflush(stdout);
if (iret==0) laststat=0;
return result;
OnError: return NULL;
}
void PrintCmd(char *buf, int mode) {
fputs("\r", stdout); /* clear command line */
fputs(prefix[mode], stdout);
fputs("\033[K\n", stdout); /* empty line */
fputs(prefix[mode], stdout);
fputs("\033[1;34m", stdout); /* bold blue */
fputs(">> ", stdout);
fputs(buf, stdout);
fputs("\033[0m\n", stdout); /* clear colors */
}
int sendCmd(int socket, char *cmd) {
int l;
char buf[256];
snprintf(buf, sizeof buf, "fulltransact %s\n", cmd);
ERR_SI(l=send(socket, buf, strlen(buf), 0));
return l;
OnError: return -1;
}
int scramble(char *buf) {
int i, n, cnt, chr;
int x;
/* Scrambles a string. Twice scramble gives original.
It does never convert a plain char to a ctrl char
and all standard ascii-codes to special chars and vice versa.
returns the number of special chars on output
*/
n=strlen(buf);
x=23;
cnt=0;
for (i=0; i<n; i++) {
chr=(buf[i] & 255) ^ (x % 32 + 128);
if (chr & 128) cnt++;
x=(x*13+5) % 256;
buf[i]=chr;
}
return cnt;
}
void getscrambled(char *buf, int size, FILE *fil) {
term_fgets(buf, size, fil);
if (scramble(buf) > 0) scramble(buf);
}
void putscrambled(char *buf, FILE *fil) {
char cvt[256];
str_copy(cvt, buf);
scramble(cvt);
fprintf(fil, "%s\n", cvt);
}
int setrights(int gotolevel) {
char user[32];
char pswd[32];
char *pw, *us, *p;
char prefhead[128], buf[128];
FILE *fil;
int ask;
us="";
user[0]='\0';
pw=pswd;
pswd[0]='\0';
p=getenv("HOME");
if (p != NULL) str_copy(prefhead, p);
str_append(prefhead, "/.six.");
str_append(prefhead, instr);
str_append(prefhead, ".");
if (0==strcmp(host, "0") && remember) {
fil=term_open_pref(prefhead, "r");
if (fil != NULL) {
term_fgets(buf, sizeof(buf), fil);
getscrambled(user1, sizeof(user1), fil);
getscrambled(pswd1, sizeof(pswd1), fil);
getscrambled(user2, sizeof(user2), fil);
getscrambled(pswd2, sizeof(pswd2), fil);
fclose(fil);
}
if (deflevel==0) {
deflevel=buf[0]-'0';
if (deflevel<1 || deflevel>3) deflevel=2;
}
} else {
deflevel=2;
}
if (gotolevel==0) gotolevel=deflevel;
if (gotolevel==1) {
if (user1[0]=='\0') {
str_copy(user1, "lnsmanager");
}
us=user1;
pw=pswd1;
} else if (gotolevel==2) {
if (user2[0]=='\0') {
str_copy(user2, instr);
str_lowcase(user2, user2);
str_append(user2, "user");
}
us=user2;
pw=pswd2;
} else if (gotolevel==3) {
us="Spy";
pw="007";
}
ask=1;
if (us[0]!='\0' && pw[0]!='\0' && remember) {
sprintf(buf, "config rights %s %s", us, pw);
ERR_I(sendCmd(sock[0], buf));
ERR_P(p=readWrite(12000,0,"Acknowledged"));
if (*p=='\0') {
if (0==strcmp(us, user1)) {
user1[0]='\0';
pswd1[0]='\0';
}
if (0==strcmp(us, user2)) {
user2[0]='\0';
pswd2[0]='\0';
}
} else {
ask=0;
pw=NULL;
}
}
if (ask) {
printf("SICS username");
if (us[0]!='\0') {
printf(" [%s]", us);
}
printf(": ");
term_fgets(user, sizeof(user), stdin);
if (0==strcmp(user, "quit")) return 1;
if (0==strcmp(user, "exit")) return 1;
if (user[0]=='\0') {
str_copy(user, us);
}
printf("password: ");
term_fgets(pswd, sizeof(pswd), stdin);
if (0==strcmp(pswd, "quit")) return 1;
if (0==strcmp(pswd, "exit")) return 1;
if (pswd[0]!='\0') {
sprintf(buf, "config rights %s %s", user, pswd);
ERR_I(sendCmd(sock[0], buf));
ERR_P(p=readWrite(12000,0,"Acknowledged"));
if (*p=='\0') { /* no success */
gotolevel=3;
if (0==strcmp(user, user1)) {
user1[0]='\0';
pswd1[0]='\0';
}
if (0==strcmp(user, user2)) {
user2[0]='\0';
pswd2[0]='\0';
}
pw=NULL;
} else { /* success */
if (0==strcmp(user, user1)) {
str_copy(pswd1, pswd);
}
if (0==strcmp(user, user2)) {
str_copy(pswd2, pswd);
}
us=user;
pw=pswd;
}
} else {
gotolevel=3;
}
}
level=gotolevel;
ERR_I(sendCmd(sock[0], "config list"));
ERR_P(p=readWrite(12000,1,"UserRights = "));
if (*p!='\0') {
level=*p-'0';
}
if (level==3) {
us="Spy";
}
if (pw!=NULL) {
if (level==1) {
str_copy(user1, us);
str_copy(pswd1, pw);
if (0==strcmp(user1, user2)) {
user2[0]='\0';
pswd2[0]='\0';
}
} else if (level==2) {
str_copy(user2, us);
str_copy(pswd2, pw);
if (0==strcmp(user2, user1)) {
user1[0]='\0';
pswd1[0]='\0';
}
}
}
if (0==strcmp(host, "0")) {
fil=term_open_pref(prefhead, "w");
if (fil!=NULL) {
fprintf(fil, "%d\n", deflevel);
if (remember) {
putscrambled(user1, fil);
putscrambled(pswd1, fil);
putscrambled(user2, fil);
putscrambled(pswd2, fil);
}
fclose(fil);
}
}
return 0;
OnError: return -1;
}
int Connect(void) {
int sock;
struct sockaddr_in sadr;
char *p;
ERR_I(CocCreateSockAdr(&sadr, host, port));
ERR_SI(sock=socket(AF_INET, SOCK_STREAM, 0));
term_reg_socket(sock);
ERR_SI(connect(sock, (struct sockaddr *)&sadr, sizeof(sadr)));
ERR_SI(send(sock, "Spy 007\n", 8, 0));
ERR_P(p=readWrite(12000,2,"Login O"));
if (*p!='K') { /* looking for the 'K' of 'Login OK' */
printf("rejected\n");
return 0;
}
return sock;
OnError: return -1;
}
int main (int argc, char *argv[]) {
int iret, pos;
fd_set mask;
int i, j, gotolevel, sicslogin;
int savehist = 0;
char buf[128], lbuf[16], ilow[64];
char stdPrompt[128], prompt[256];
char *sim="";
char *p;
char *bar;
char *pnam[4]={"0", "MANAGER", "user", "spy"};
printf("---------------------------------------------------\n");
printf("six, a fast SICS commandline client (doc: six help)\n");
printf("---------------------------------------------------\n");
port=2911;
sicslogin=1;
j=0;
deflevel=0;
gotolevel=0;
host="0"; /* localhost by default */
sock[1]=0; /* do not yet connect 2nd connection */
for (i=1; i<argc; i++) {
if (0==strcmp(argv[i], "-s") || 0==strcmp(argv[i], "s")) {
port=2927; sim="-sim";
} else if (0==strcmp(argv[i], "-a") || 0==strcmp(argv[i], "a")) {
remember=0;
} else if (0==strcmp(argv[i], "-d") || 0==strcmp(argv[i], "d")) {
hidecom=0;
} else if (0==strcmp(argv[i], "+")) {
gotolevel=1;
} else if (0==strcmp(argv[i], "-")) {
gotolevel=3;
} else if (0==strcmp(argv[i], "0")) {
gotolevel=2;
} else if (0==strcmp(argv[i], "++")) {
gotolevel=1;
deflevel=1;
} else if (0==strcmp(argv[i], "--")) {
gotolevel=3;
deflevel=3;
} else if (0==strcmp(argv[i], "00")) {
gotolevel=2;
deflevel=2;
} else if (0==strcmp(argv[i], "help")) {
Usage(0);
return 0;
} else if (0==strcmp(argv[i], "-h")) {
i++;
if (i>=argc) {
printf("missing host\n");
Usage(0); return 0;
}
host=argv[i];
} else if (0==strcmp(argv[i], "-p")) {
i++;
if (i>=argc) {
printf("missing port\n");
Usage(0); return 0;
}
port=atoi(argv[i]);
if (port == 0) {
printf("illegal port\n");
Usage(0); return 0;
}
} else if (0==strcmp(argv[i], "-n")) {
sicslogin=0;
} else {
if (strlen(argv[i])>=32) {
printf("argument too long\n");
Usage(0); return 0;
} else if (argv[i][0]!='-') {
if (j==0) {
printf("syntax has changed, username can not be given as argument\n");
Usage(0); j=1;
}
} else {
printf("unknown option: %s\n", argv[i]);
Usage(0); return 0;
}
}
}
ERR_I(sock[0]=Connect());
if (sock[0] == 0) return 0;
if (sicslogin) {
ERR_I(sendCmd(sock[0], "Instrument"));
ERR_P(p=readWrite(12000,0,"Instrument = "));
str_copy(instr, p);
if (*instr=='\0') {
printf("can not detect instrument\n");
return 0;
}
p=strchr(instr,' ');
if (p!=NULL) *p='\0';
if (0==strcmp(instr,"SANS-II")) {
str_copy(instr, "SANS2");
}
ERR_I(i=setrights(gotolevel));
printf("\rlogged in to SICS as %s on %s\n", pnam[level], instr);
str_lowcase(ilow,instr);
sprintf(stdPrompt, "six[%s] ", ilow);
ERR_I(sendCmd(sock[0], "status interest"));
ERR_P(readWrite(12000,0,"OK"));
ERR_I(sendCmd(sock[0], "status"));
ERR_P(readWrite(12000,0,NULL));
} else {
sprintf(stdPrompt, "six[%s] ", host);
status[0]='E'; status[1]='\0';
}
iret=1;
buf[0]='\0';
pos=0;
term_read_hist("six");
savehist = 1;
while (1) {
if (busy[0]) {
bar = prefix[SPY];
} else {
bar = "";
}
if (status[0] == 'E') { /* Eager to ... */
sprintf(prompt, "%s%s", bar, stdPrompt);
} else {
sprintf(prompt, "%s%s(%s) ", bar, stdPrompt, status);
}
FD_ZERO(&mask);
FD_SET(sock[0], &mask);
iret=term_get_line(buf, sizeof(buf)-2, &pos, prompt, &mask);
if (iret==STDIN_FILENO) { /* input line terminated */
str_lowcase(lbuf, buf);
if (0==strcmp(lbuf,"quit") || 0==strcmp(lbuf,"exit")) {
PrintCmd(buf, CLIENT);
break;
}
if (0==strcmp(lbuf,"stop")) {
PrintCmd(buf, CLIENT);
ERR_SI(send(sock[1], "INT1712 3\n", 10, 0));
buf[0]='\0';
} else if (0==strcmp(buf, "-") ||
0==strcmp(buf, "--") ||
0==strcmp(buf, "+") ||
0==strcmp(buf, "++")) {
PrintCmd(buf, CLIENT);
j=level;
if (buf[0]=='-') {
if (level<3) level++;
} else {
if (level>1) level--;
}
if (strlen(buf)==2) {
deflevel=level;
}
term_off();
ERR_I(i=setrights(level)); /* level might be changed */
if (j!=level) {
printf("\rswitched to %s privilege\n", pnam[level]);
} else {
printf("\rremain at %s privilege\n", pnam[level]);
}
buf[0]='\0';
} else if (0==strcmp(buf, "help six")) {
PrintCmd(buf, CLIENT);
Usage(1);
buf[0]='\0';
} else if (0==strcmp(buf, "six help")) {
PrintCmd(buf, CLIENT);
Usage(0);
buf[0]='\0';
}
if (buf[0] != 0) {
if (busy[0]) {
if (!sock[1]) {
ERR_I(sock[1] = Connect());
if (!sock[1]) {
printf("spy connection rejected\n");
}
}
if (busy[1]) {
/* print in red bold */
PrintCmd(buf, CLIENT);
fputs("\033[1;31mBUSY (already 2 commands pending)\033[0m\n", stdout);
buf[0]='\0';
} else if (sock[1]) {
PrintCmd(buf, SPY);
ERR_I(sendCmd(sock[1], buf));
} else {
PrintCmd(buf, CLIENT);
buf[0]='\0';
}
} else {
PrintCmd(buf, NORMAL);
ERR_I(sendCmd(sock[0], buf));
}
}
if (buf[0] != '\0') {
ERR_P(p=readWrite(500,0,NULL));
} else {
p="";
}
buf[0]='\0';
pos=0;
} else { /* something arrived from sockets */
assert(iret == sock[0] || iret == sock[1]);
ERR_P(p=readWrite(500,0,NULL));
}
if (strcmp(p, "0") == 0) {
term_clear();
printf("\nconnection lost");
break;
}
}
printf("\nexit %s\n", prompt);
term_save_hist(1); /* save history without last line */
return 0;
OnError:
if (savehist) term_save_hist(0); /* save history with last line */
ErrShow("end");
return 0;
}