/* NOS User Session control * Copyright 1991 Phil Karn, KA9Q */ #include #include "global.h" #include "mbuf.h" #include "proc.h" #include "ftpcli.h" #include "icmp.h" #include "telnet.h" #include "tty.h" #include "session.h" #include "hardware.h" #include "socket.h" #include "cmdparse.h" #include "commands.h" #include "main.h" struct session *Sessions; struct session *Command; struct session *Current; struct session *Lastcurr; int Row; int Morewait; char Notval[] = "Not a valid control block\n"; static char Badsess[] = "Invalid session\n"; char *Sestypes[] = { "", "Telnet", "FTP", "AX25", "Finger", "Ping", "NET/ROM", "Command", "More", "Hopcheck", "Tip", "PPP PAP", "Dial", "Query", "Cache" }; /* Convert a character string containing a decimal session index number * into a pointer. If the arg is NULLCHAR, use the current default session. * If the index is out of range or unused, return NULLSESSION. */ struct session * sessptr(cp) char *cp; { register struct session *sp; unsigned int i; if(cp == NULLCHAR){ sp = Lastcurr; } else { i = (unsigned)atoi(cp); if(i >= Nsessions) sp = NULLSESSION; else sp = &Sessions[i]; } if(sp == NULLSESSION || sp->type == FREE) sp = NULLSESSION; return sp; } /* Select and display sessions */ int dosession(argc,argv,p) int argc; char *argv[]; void *p; { struct session *sp; struct sockaddr fsocket; int i,k,s; int r,t; char *cp; sp = (struct session *)p; if(argc > 1){ if((sp = sessptr(argv[1])) != NULLSESSION){ go(0,NULL,sp); } else tprintf("Session %s not active\n",argv[1]); return 0; } tprintf(" # S# Type Rcv-Q Snd-Q State Remote socket\n"); for(sp=Sessions; sp < &Sessions[Nsessions];sp++){ if(sp->type == FREE || sp->type == COMMAND) continue; /* Rcv-Q includes output pending at the screen driver */ r = socklen(sp->output,1); t = 0; cp = NULLCHAR; if((s = sp->s) != -1){ i = SOCKSIZE; s = sp->s; k = getpeername(s,(char *)&fsocket,&i); r += socklen(s,0); t += socklen(s,1); cp = sockstate(s); } tprintf("%c", (Lastcurr == sp)? '*':' '); tprintf("%-3u", (unsigned)(sp - Sessions)); tprintf("%-4d%-8s%6d%6d %-13s", s, Sestypes[sp->type], r, t, (cp != NULLCHAR) ? cp : ""); if(sp->name != NULLCHAR) tprintf("%s ",sp->name); if(sp->s != -1 && k == 0) tprintf("(%s)",psocket(&fsocket)); tprintf("\n"); if(sp->type == FTP && (s = sp->cb.ftp->data) != -1){ /* Display data channel, if any */ i = SOCKSIZE; k = getpeername(s,(char *)&fsocket,&i); r = socklen(s,0); t = socklen(s,1); cp = sockstate(s); tprintf(" %-4d%-8s%6d%6d %-13s%s", s, Sestypes[sp->type], r, t, (cp != NULLCHAR) ? cp : "", (sp->name != NULLCHAR) ? sp->name : ""); if(k == 0) tprintf(" (%s)",psocket(&fsocket)); if(tprintf("\n") == EOF) break; } if(sp->rfile != NULLCHAR) tprintf(" Record: %s\n",sp->rfile); if(sp->ufile != NULLCHAR) tprintf(" Upload: %s\n",sp->ufile); } return 0; } /* Resume current session, and wait for it */ int go(argc,argv,p) int argc; char *argv[]; void *p; { struct session *sp; sp = (struct session *)p; if(sp == NULLSESSION || sp->type == FREE || sp->type == COMMAND) return 0; Current = sp; swapscreen(Command,sp); psignal(sp,0); return 0; } int doclose(argc,argv,p) int argc; char *argv[]; void *p; { struct session *sp; sp = (struct session *)p; if(argc > 1) sp = sessptr(argv[1]); if(sp == NULLSESSION){ tprintf(Badsess); return -1; } shutdown(sp->s,1); return 0; } int doreset(argc,argv,p) int argc; char *argv[]; void *p; { struct session *sp; sp = (struct session *)p; if(argc > 1) sp = sessptr(argv[1]); if(sp == NULLSESSION){ tprintf(Badsess); return -1; } /* Unwedge anyone waiting for a domain resolution, etc */ alert(sp->proc,EABORT); shutdown(sp->s,2); if(sp->type == FTP) shutdown(sp->cb.ftp->data,2); return 0; } int dokick(argc,argv,p) int argc; char *argv[]; void *p; { struct session *sp; sp = (struct session *)p; if(argc > 1) sp = sessptr(argv[1]); if(sp == NULLSESSION){ tprintf(Badsess); return -1; } sockkick(sp->s); if(sp->type == FTP) sockkick(sp->cb.ftp->data); return 0; } struct session * newsession(name,type,makecur) char *name; int type; int makecur; { register struct session *sp; int i; for(i=0,sp=Sessions;i < Nsessions;sp++,i++) if(sp->type == FREE) break; if(i == Nsessions) return NULLSESSION; sp->type = type; sp->s = -1; if(name != NULLCHAR) sp->name = strdup(name); sp->proc = Curproc; /* Create standard input and output sockets. Output is * translated to local end-of-line by default */ Curproc->input = sp->input = socket(AF_LOCAL,SOCK_STREAM,0); seteol(Curproc->input,Eol); sockmode(Curproc->input,SOCK_BINARY); Curproc->output = sp->output = socket(AF_LOCAL,SOCK_STREAM,0); seteol(Curproc->output,Eol); sockmode(Curproc->output,SOCK_ASCII); /* on by default */ sp->ttystate.crnl = sp->ttystate.edit = sp->ttystate.echo = 1; sp->flowmode = 1; /* On by default */ sp->row = MOREROWS; sp->morewait = 0; newscreen(sp); if(makecur){ swapscreen(Current,sp); Current = sp; } return sp; } void freesession(sp) struct session *sp; { if(sp == NULLSESSION) return; pwait(NULL); /* Wait for any pending output to go */ rflush(); if(sp->proc1 != NULLPROC) killproc(sp->proc1); sp->proc1 = NULLPROC; if(sp->proc2 != NULLPROC) killproc(sp->proc2); sp->proc2 = NULLPROC; free_p(sp->ttystate.line); sp->ttystate.line = NULLBUF; if(sp->s != -1) close_s(sp->s); if(sp->record != NULLFILE){ fclose(sp->record); sp->record = NULLFILE; } free(sp->rfile); sp->rfile = NULLCHAR; if(sp->upload != NULLFILE){ fclose(sp->upload); sp->upload = NULLFILE; } free(sp->ufile); sp->ufile = NULLCHAR; free(sp->name); sp->name = NULLCHAR; sp->type = FREE; close_s(sp->input); sp->input = -1; sp->proc->input = -1; close_s(sp->output); sp->output = -1; sp->proc->output = -1; freescreen(sp); if(Current == sp){ Current = Command; swapscreen(NULLSESSION,Command); alert(Display,1); } if(Lastcurr == sp) Lastcurr = NULLSESSION; } /* Control session recording */ int dorecord(argc,argv,p) int argc; char *argv[]; void *p; { struct session *sp; char *mode; sp = (struct session *)p; if(sp == NULLSESSION){ tprintf("No current session\n"); return 1; } if(argc > 1){ if(sp->rfile != NULLCHAR){ fclose(sp->record); free(sp->rfile); sp->record = NULLFILE; sp->rfile = NULLCHAR; } /* Open new record file, unless file name is "off", which means * disable recording */ if(strcmp(argv[1],"off") != 0){ if(sockmode(sp->output,-1) == SOCK_ASCII) mode = APPEND_TEXT; else mode = APPEND_BINARY; if((sp->record = fopen(argv[1],mode)) == NULLFILE) tprintf("Can't open %s: %s\n",argv[1],sys_errlist[errno]); else sp->rfile = strdup(argv[1]); } } if(sp->rfile != NULLCHAR) tprintf("Recording into %s\n",sp->rfile); else tprintf("Recording off\n"); return 0; } /* Control file transmission */ int doupload(argc,argv,p) int argc; char *argv[]; void *p; { register struct session *sp; sp = (struct session *)p; if(sp == NULLSESSION){ tprintf("No current session\n"); return 1; } if(argc < 2){ if(sp->ufile != NULLCHAR) tprintf("Uploading %s\n",sp->ufile); else tprintf("Uploading off\n"); return 0; } if(strcmp(argv[1],"stop") == 0 && sp->upload != NULLFILE){ /* Abort upload */ fclose(sp->upload); sp->upload = NULLFILE; free(sp->ufile); sp->ufile = NULLCHAR; killproc(sp->proc2); sp->proc2 = NULLPROC; return 0; } /* Open upload file */ if((sp->upload = fopen(argv[1],READ_TEXT)) == NULLFILE){ tprintf("Can't read %s: %s\n",argv[1],sys_errlist[errno]); return 1; } sp->ufile = strdup(argv[1]); /* All set, invoke the upload process */ sp->proc2 = newproc("upload",1024,upload,0,sp,NULL,0); return 0; } /* File uploading task */ void upload(unused,sp1,p) int unused; void *sp1; void *p; { struct session *sp; int oldf; char *buf; sp = (struct session *)sp1; /* Disable newline buffering for the duration */ oldf = setflush(sp->s,-1); buf = mallocw(BUFSIZ); while(fgets(buf,BUFSIZ,sp->upload) != NULLCHAR) if(usputs(sp->s,buf) == EOF) break; free(buf); usflush(sp->s); setflush(sp->s,oldf); fclose(sp->upload); sp->upload = NULLFILE; free(sp->ufile); sp->ufile = NULLCHAR; sp->proc2 = NULLPROC; }