/* :ts=8 */ /* * These are the new interfaces between vt100 and the new Kermit protocol * module. */ #include "vt100.h" /* Get defines and so on */ /* * Here are the declarations for our communication with kermitproto.c */ extern int cx, cz; /* Abort flags */ extern char start; /* Start state for Kermit */ char *cmarg; /* Command argument for server */ /* * The below variables have to do with the status of the communcation * so far. They should be maintained over in kermitproto.w so that * things like the number of bytes sent and the packet type can be * printed as status. */ static int npackets, /* Number of packets sent so far */ naks; /* Number of naks */ static char message[80]; /* Message line to output */ /* * Do Kermit sending. This expands wild cards into local variables for * gnfile() below. */ static int nfiles, wild; static char **lp, **list; doksend(file,more) char *file; int more; { char *p; list = NULL; p = file; while(*p && *p != '*' && *p != '?') p++; if (*p) { wild = 1; list = expand(file, &nfiles); if (list == NULL) { InfoMsg1Line("KERMIT: No wild card match"); return FALSE; } } else { nfiles = 1; wild = 0; list = (char **) malloc(sizeof(char *)); *list = (char *) malloc(strlen(file) + 1); strcpy(*list, file); } lp = list; start = 's'; /* Set start state to send */ npackets = naks = 0; message[0] = '\0'; proto(); /* Call protocol */ if (wild == 1) free_expand(list); else { free((void *) *list); free((void *) list); } return TRUE; } /* * gnfile(s, n) char *s; int n; * * Returns in string s the name of the next file for Kermit to process, * which can be up to n characters in length. Returns a positive value * if there are more files, 0 if not. */ int gnfile(s, n) char *s; int n; { if (--nfiles >= 0) { strncpy(s, *lp, n); lp++; return 1; } else return 0; } /* * Do Kermit receiving. The file and more arguments in this routine are * for Get'ting files when the remote machine is the server. */ dokreceive(file,more) char *file; int more; { naks = npackets = 0; message[0] = '\0'; /* Initialize */ if (!server) start = 'v'; /* Start state to receive */ else { cmarg = file; /* Files to get from remote */ start = 'r'; /* Start state to get */ } proto(); return TRUE; } /* kermit_directory()--request a remote directory from a Kermit server. */ #define tochar(c) ((c) + 32) void kermit_directory(dir) char *dir; { char command[80]; strcpy(command, "D"); /* Generic directory command */ command[1] = tochar(strlen(dir)); /* Length of directory name */ strcpy(&command[2], dir); /* The directory itself */ cmarg = command; start = 'g'; /* Generic command start state */ naks = npackets = 0; proto(); } /* * saybye()--send a FINISH command to a remote Kermit server. This is * in fact what the original VT100 saybye() does. A true Kermit BYE * command would mean changing the "F" below to "L", and it would actually * log out the remote host as well as shut down the Kermit server. */ void saybye() { static char bye_command[] = "F"; cmarg = &bye_command[0]; start = 'g'; /* Generic command start state */ naks = npackets = 0; proto(); return /* TRUE */; } /* * ttinl(dest, max, eol, timelimit) * * Read up to max characters from serial port into the array pointed * to by dest. Return value is the number of characters received. * If eol is greater than 0, terminate read upon first * eol character received. If timelimit is greater than 0, wait at * most timelimit seconds for the characters. The array is null * terminated; in addition, if we do see an eol, we overwrite it * with the NULL and the returned character count does not include it. * (This behavior is required by the code in the C Kermit book but is * not explicitly stated there.) * * This version is most unsatisfactory as it does I/O one character * at a time, but extensive changes in the rest of VT100 would be * needed in order to use a multi-character read. */ static int pushedser = -1; /* pushed character */ int ttinl(dest, max, eol, timelimit) char *dest; int max, eol, timelimit; { int i; void ttflui(); if (timelimit > 0) ttime = timelimit; else ttime = 30; /* Maximum timeout if not given */ for (i = 0; i < max; i++) { dest[i] = readchar(); if (timeout != GOODREAD) { if (timeout == USERABORT) { /* User abort requested */ if (cx == 1) start = 'a'; /* Second escape--abort mess */ else cx = cz = 1; /* Set abort flags */ continue; /* Continue receiving anyway */ } else { i = -1; /* Some other error. */ break; } } if (eol > 0 && dest[i] == eol) break; ttime = 2; /* Intrapacket timeout */ } if (i >= 0) dest[i] = '\0'; /* Null terminate what we got */ else dest[0] = '\0'; return i; /* Return length or failure */ } /* * ttol(out, n) * * Send n characters pointed to by out through the serial port using * current settings of word length, parity, and flow control. Return * * * Here I bypass sendchar() and go direct to the low level. */ int ttol(out, n) char *out; int n; { int retval; Write_Request->IOSer.io_Data = (APTR) out; Write_Request->IOSer.io_Length = n; Write_Request->IOSer.io_Command = CMD_WRITE; SendIO((struct IORequest *)Write_Request); retval = WaitIO((struct IORequest *)Write_Request); /* * Restore old values. */ Write_Request->IOSer.io_Data = (APTR) rs_out; Write_Request->IOSer.io_Length = 1; if (retval != 0) return -1; else return ((int)Write_Request->IOSer.io_Actual); } /* * ttflui() * * Remove any pending characters from the serial port. * * Even worse than ttinl() and ttol(), this reads characters with a minimal * timeout until there aren't any more. Note that I also changed readchar() * in xmodem.c to check if ttime is 0, and if it is, to set its timeout to * 100,000 ticks (0.1 seconds). I also removed the InfoMsg1Line call which * warned about timeouts so this would work. Ideally, ttinl() should do * a single CMD_READ in ReadRequest, and ttflui() should AbortIO() it. */ void ttflui() { int c; ttime = 0; do { c = readchar(); } while (timeout == GOODREAD); } void sleep(seconds) int seconds; { if (seconds > 0) Delay(seconds*TICKS_PER_SECOND); } /* * Now here are tmsg() and tchar() for putting out warnings. What I've done * is to use tchar()'s argument as a flag to put out whatever status we need. * tmsg()'s argument is put out as a message line. */ /* * tchar(c)--put the single character c onto the user's screen as part * of Kermit's communication to said user. */ void tchar(c) char c; { char status[80]; void tmsg(); switch (c) { case '.': npackets++; break; case '%': naks++; break; default: status[0] = c; status[1] = '\0'; tmsg(status); /* Output unknown chars */ return; } sprintf(status, "Packets: %4d Retries: %4d", npackets, naks); InfoMsgNoScroll(status); } /* * tmsg(s) char *s;--Put a message string onto the user's screen as part * of the communication from Kermit. * * I put out a message using InfoMsg. We store it up until we get a newline, * then we scroll and put it out. */ void tmsg(more_message) char *more_message; { /* * If new message won't fit, put out message so far and copy it. * Otherwise, just catenate new message to old. */ if (strlen(more_message) + strlen(message) < sizeof(message)) { strcat(message,more_message); } else { InfoMsg1Line(message); strcpy(message,more_message); } } /* * tmsgl(s) char *s;--Put out a newline-terminated message to the user's * screen as part of Kermit communication. */ void tmsgl(more_message) char *more_message; { tmsg(more_message); InfoMsg1Line(message); message[0] = '\0'; }