/* Win.c */ #include "Sys.h" #include "Curses.h" #include #include #include #include "Util.h" #include "Main.h" #include "Version.h" #include "Bookmark.h" #include "RCmd.h" #include "LGets.h" #include "GetPass.h" #ifdef USE_CURSES #include "WGets.h" extern int endwin(void); extern long gEventNumber; WINDOW *gListWin; WINDOW *gInputWin; WINDOW *gPromptWin; WINDOW *gBarWin; int gCurRow, gLastRow, gSkipToEnd; int gPageNum; int gMultiLineMode = 0; int gPendingNL = 0; int gBackgroundProcessing = 0; int gUsingDefaultBar = 0; int gUsingTmpCenterBar = 0; string gBarLeft, gBarCenter, gBarRight; /* Other protos, whose parameters aren't WINDOW *ptrs, are in Win.h */ void WAddCenteredStr(WINDOW *, int, char *); void WAttr(WINDOW *w, int attr, int on); extern WINDOW *gPrefsWin, *gHostWin; #endif /* USE_CURSES */ string gPrompt = kLineModePrompt; int gWinInit = 0; char *gSprintfBuf = NULL; int gScreenWidth = 80; extern longstring gRemoteCWD; extern longstring gLockFileName; extern int gConnected, gVerbosity; extern Bookmark gRmtInfo; extern string gHost; extern int gStdout, gRealStdout, gOtherSessionRunning; extern FILE *gTraceLogFile; extern int gDebug, gTrace; extern LineList gCmdHistory; extern int gVisualMode, gIsToTTY, gIsFromTTY, gStartup; extern int gRedialModeEnabled; void EndWin(void) { if (gWinInit) { gWinInit = 0; #ifdef USE_CURSES if (gEventNumber > 0L) { clear(); refresh(); } endwin(); #endif /* USE_CURSES */ } } /* EndWin */ void Exit(int exitStatus) { if (gOtherSessionRunning == 0) { (void) UNLINK(gLockFileName); } EndWin(); exit(exitStatus); } /* Exit */ static void SigTerm(void) { Exit(kExitSignal); } /* SigTerm */ void SaveScreen(void) { #ifdef USE_CURSES if (gWinInit) { /* Clearing the screen is necessary * because ncurses doesn't move the * cursor to the bottom left. * * This also causes the restore * operation to require that we paint * all our windows by hand, because we * have just left the screen blank so * when refresh gets called in the * restore it just returns the screen * to blank. * * If it weren't for this screen clear, * we would be able to get away with * just doing an endwin(), the shell, * and then a refresh() without us * re-drawing any windows manually. */ clear(); refresh(); endwin(); fflush(stdout); fflush(stderr); } #endif /* USE_CURSES */ } /* SaveScreen */ static void TTYWaitForReturn(void) { int tty; int junk; tty = open("/dev/tty", O_RDWR); if (tty != -1) { write(tty, "[Hit return]", 12); read(tty, &junk, 1); close(tty); } } /* TTYWaitForReturn */ void RestoreScreen(int pressKey) { #ifdef USE_CURSES if (gWinInit) { if (pressKey) { # if (CURSES_SHELL_BUG == 0) TTYWaitForReturn(); # else sleep(2); # endif } refresh(); UpdateScreen(1); } #endif /* USE_CURSES */ } /* RestoreScreen */ void Beep(int on) { static time_t lastBeepTime = 0; time_t now; time(&now); /* Don't flood the user with beeps. Once per two seconds is reasonable. */ if ((on > 0) && ((int) (now - lastBeepTime) > 1)) { #ifdef USE_CURSES if (gWinInit) beep(); else #endif { fprintf(stderr, "\007"); /* ^G */ fflush(stderr); } } lastBeepTime = now; } /* Beep */ #ifdef USE_CURSES /* Many old curses libraries don't support wattron() and its attributes. * They should support wstandout() though. This routine is an attempt * to use the best substitute available, depending on what the curses * library has. */ void WAttr(WINDOW *w, int attr, int on) { /* Define PLAIN_TEXT_ONLY if you have the attributes, but don't want * to use them. */ #ifndef PLAIN_TEXT_ONLY #ifdef A_REVERSE if (attr & kReverse) { if (on) wattron(w, A_REVERSE); else wattroff(w, A_REVERSE); } #else if (attr & kReverse) { if (on) wstandout(w); else wstandend(w); /* Nothing else will be done anyway, so just return now. */ return; } #endif /* A_REVERSE */ #ifdef A_BOLD if (attr & kBold) { if (on) wattron(w, A_BOLD); else wattroff(w, A_BOLD); } #else /* Do nothing. Plain is best substitute. */ #endif /* A_BOLD */ #ifdef A_UNDERLINE if (attr & kUnderline) { if (on) wattron(w, A_UNDERLINE); else wattroff(w, A_UNDERLINE); } #else /* Try using standout mode in place of underline. */ if (attr & kUnderline) { if (on) wstandout(w); else wstandend(w); /* Nothing else will be done anyway, so just return now. */ return; } #endif /* A_UNDERLINE */ #ifdef A_DIM if (attr & kDim) { if (on) wattron(w, A_DIM); else wattroff(w, A_DIM); } #else /* Do nothing. Plain is best substitute. */ #endif /* A_DIM */ #ifdef A_NORMAL if (attr == kNormal) { wattrset(w, A_NORMAL); return; } #else /* At least make sure standout mode is off. */ if (attr == kNormal) { wstandend(w); return; } #endif /* A_NORMAL */ #endif /* PLAIN_TEXT_ONLY */ } /* WAttr */ #endif /* USE_CURSES */ void UpdateScreen(int wholeScreen) { #ifdef USE_CURSES if (gWinInit) { if (wholeScreen) { touchwin(gListWin); touchwin(gBarWin); touchwin(gPromptWin); touchwin(gInputWin); wnoutrefresh(gListWin); wnoutrefresh(gBarWin); wnoutrefresh(gPromptWin); wnoutrefresh(gInputWin); } doupdate(); } #endif /* USE_CURSES */ } /* UpdateScreen */ void FlushListWindow(void) { #ifdef USE_CURSES if (gWinInit) { wnoutrefresh(gListWin); doupdate(); return; } #endif /* USE_CURSES */ fflush(stdout); fflush(stderr); /* Overkill, since stderr _should_ be unbuffered. */ } /* FlushListWindow */ #ifdef USE_CURSES #ifdef SIGTSTP static void SigTStp(int sigNum) { /* TO-DO: (doesn't work 100% correctly yet) */ if (sigNum == SIGTSTP) { if ((gPrefsWin != NULL) || (gHostWin != NULL)) { /* Doing this with these windows open can cause problems. */ return; } SaveScreen(); TraceMsg("SIGTSTP: Suspended.\n"); SIGNAL(SIGTSTP, SIG_DFL); kill(getpid(), SIGSTOP); /* Send stop signal to ourselves. */ } else { SIGNAL(SIGTSTP, SigTStp); SIGNAL(SIGCONT, SigTStp); if (sigNum == SIGCONT) { TraceMsg("SIGCONT: Resumed.\n"); } else { TraceMsg("SIG %d.\n", sigNum); } if (InForeGround()) RestoreScreen(0); else gBackgroundProcessing = 1; } } /* SigTStp */ #endif #endif /* USE_CURSES */ /* Read a line of input, and axe the end-of-line. */ char *Gets(char *str, size_t size) { string pr; #ifdef USE_CURSES int result; WGetsParams wgp; int maxy, maxx; #endif /* USE_CURSES */ #ifdef USE_CURSES if (gWinInit) { /* Background processing only gets turned on if you use ^Z * from within the program and then "bg" it. We assume that * when you do that, you want to get a "tty output" message * when the operation finishes. Note that you wouldn't get * gBackgroundProcessing == 1 if you did "ncftp &" because * you would never get to the part that turns it on (the ^Z * handler). */ if (gBackgroundProcessing) { /* Want to give you a "stopped - tty output" message in * your shell when we get here. */ PrintF("\nBackground processing has finished.\n"); FlushListWindow(); while (! InForeGround()) sleep(1); gBackgroundProcessing = 0; RestoreScreen(0); } str[0] = '\0'; wnoutrefresh(gListWin); if (gMultiLineMode) { SetPrompt(gPrompt); gMultiLineMode = 0; } else { werase(gInputWin); wnoutrefresh(gInputWin); } SetScreenInfo(); doupdate(); wgp.w = gInputWin; wgp.sy = 0; wgp.sx = 0; getmaxyx(gInputWin, maxy, maxx); wgp.fieldLen = maxx - 1; wgp.dst = str; wgp.dstSize = size; wgp.useCurrentContents = 0; wgp.echoMode = wg_RegularEcho; wgp.history = &gCmdHistory; result = wg_Gets(&wgp); if (result < 0) return (NULL); /* Error, or EOF. */ return (str); } else #endif /* USE_CURSES */ { Echo(stdin, 1); /* Turn echo on, if it wasn't already. */ STRNCPY(pr, gPrompt); STRNCAT(pr, kPromptTail); return LineModeGets(pr, str, size); } } /* Gets */ void GetAnswer(char *prompt, char *answer, size_t siz, int noEcho) { #ifdef USE_CURSES WGetsParams wgp; int maxy, maxx; #endif PTRZERO(answer, siz); #ifdef USE_CURSES if (gWinInit) { wnoutrefresh(gListWin); MakeBottomLine(prompt, kReverse, 0); doupdate(); wgp.w = gInputWin; wgp.sy = 0; wgp.sx = 0; getmaxyx(gInputWin, maxy, maxx); wgp.fieldLen = maxx - 1; wgp.dst = answer; wgp.dstSize = siz; wgp.useCurrentContents = 0; wgp.echoMode = noEcho ? wg_BulletEcho : wg_RegularEcho; wgp.history = wg_NoHistory; wg_Gets(&wgp); return; } #endif /* USE_CURSES */ if (noEcho) GetPass(prompt, answer, siz); else { StdioGets(prompt, answer, siz); } } /* GetAnswer */ void SetBar(char *l, char *c, char *r, int doUp, int tmpCenter) { #ifdef USE_CURSES int maxy, maxx; int i; int rmax; int llen, rlen, clen; string bar; string barTmp; if (gWinInit) { if (l == NULL) l = gBarLeft; else if (doUp != -1) STRNCPY(gBarLeft, l); if (r == NULL) r = gBarRight; else if (doUp != -1) STRNCPY(gBarRight, r); if (c == NULL) { c = gBarCenter; /* if (gUsingDefaultBar == 1) { *c = '\0'; gUsingDefaultBar = 0; } else */ if (gUsingTmpCenterBar == 1) { *c = '\0'; gUsingTmpCenterBar = 0; } } else { STRNCPY(gBarCenter, c); gUsingTmpCenterBar = 0; if (tmpCenter) gUsingTmpCenterBar = 1; } getmaxyx(gBarWin, maxy, maxx); for (i=0; i maxx - 1) llen = maxx - 1; rlen = (int) strlen(r); if (rlen > maxx - 1) rlen = maxx - 1; clen = (int) strlen(c); if (clen > maxx - 1) clen = maxx - 1; if /* (rlen + (clen/2) > (maxx/2)) */ ((2*rlen) + (clen) > (maxx)) { /* Put the center part on the left so we can see it. */ memcpy(bar, c, (size_t) clen); /* Do the right side. */ rmax = maxx - 1 - clen; if (rmax > 0) { AbbrevStr(barTmp, r, (size_t) rmax, 0); rmax = strlen(barTmp); memcpy(bar + maxx - rmax, r, (size_t) rmax); } } else { /* Do the left side. */ memcpy(bar, l, (size_t) llen); /* Do the middle. */ if (*c != '\0') { rlen = maxx - 1; AbbrevStr(barTmp, c, (size_t) rlen, 0); rlen = strlen(barTmp); memcpy(bar + (maxx - 1 - rlen) / 2, barTmp, (size_t) rlen); } /* Do the right side. */ rmax = maxx - 1 - llen; if (rmax > 0) { AbbrevStr(barTmp, r, (size_t) rmax, 0); rmax = strlen(barTmp); memcpy(bar + maxx - rmax, r, (size_t) rmax); } } bar[maxx] = '\0'; wmove(gBarWin, 0, 0); waddstr(gBarWin, bar); if (doUp == 0) wnoutrefresh(gBarWin); else wrefresh(gBarWin); } #endif /* USE_CURSES */ } /* SetBar */ void SetDefaultBar(void) { #ifdef USE_CURSES string str; if (gWinInit) { STRNCPY(str, "NcFTP "); STRNCAT(str, kVersion); STRNCAT(str, " by Mike Gleason (mgleason@NcFTP.com)."); gUsingDefaultBar = 1; SetBar("", str, "", 0, 0); } else { SetPrompt(kUseDefaultPrompt); } #else SetPrompt(kUseDefaultPrompt); #endif } /* SetDefaultBar */ void SetScreenInfo(void) { string pr; string pcwd; char *cp; int len, len2; size_t maxPCwdLen; MakeStringPrintable(pcwd, (unsigned char *) gRemoteCWD, sizeof(pcwd)); if (gWinInit) { if (gConnected) { maxPCwdLen = gScreenWidth - strlen(gRmtInfo.name) - 2; AbbrevStr(pr, pcwd, maxPCwdLen, 0); SetBar(gRmtInfo.name, NULL, pr, 0, 0); SetPrompt(gRmtInfo.bookmarkName); } else { SetDefaultBar(); SetPrompt(kUseDefaultPrompt); } } else { if (gConnected) { STRNCPY(pr, gRmtInfo.bookmarkName); STRNCAT(pr, ":"); len = (int) strlen(pr); len2 = (int) strlen(pcwd); if (len + len2 > kPromptLimit) { STRNCAT(pr, "..."); cp = pcwd + len2 - (kPromptLimit - len - 3); STRNCAT(pr, cp); } else { STRNCAT(pr, pcwd); } SetPrompt(pr); } else { SetPrompt(kUseDefaultPrompt); } } } /* SetScreenInfo */ #ifdef USE_CURSES void PrintToListWindow(char *buf, int multi) { char *endp, *startp; int c, haveNL; int haveCR; int y, x; string pr; int extraLines; if (multi != 0) { if (gSkipToEnd == 1) return; /* Don't wait between pages if they are redialing. We don't * want to page the site's connect message if redialing is * turned on. */ if (gRedialModeEnabled != 0) multi = 0; } endp = buf; startp = buf; while (1) { if (*startp == '\0') break; haveCR = 0; haveNL = 0; for (endp = startp; ; endp++) { if (*endp == '\0') { endp = NULL; break; } else if (*endp == '\n') { haveNL = 1; *endp = '\0'; break; } else if (*endp == '\r') { /* Have to do CRs manually because * some systems don't do 'em. (AIX). */ haveCR = 1; *endp = '\0'; break; } } /* Take long lines that wrap into account. */ extraLines = endp == startp ? 0 : (endp - startp - 1) / gScreenWidth; gCurRow += extraLines; if ((multi) && (gCurRow >= gLastRow) && (!gSkipToEnd) && (!haveCR)) { wnoutrefresh(gListWin); sprintf(pr, "--Page %d--", (++gPageNum)); MakeBottomLine(pr, kReverse, 0); doupdate(); cbreak(); c = mvwgetch(gInputWin, 0, 0); nocbreak(); if (c == 'q') { gSkipToEnd = 1; gCurRow = 0; gPendingNL = 1; break; } gCurRow = extraLines; } if (gPendingNL) { waddch(gListWin, '\n'); } /* Weird things happened if I did wprintw(gListWin, "%s", startp). */ waddstr(gListWin, startp); /* May need to gCurRow++ if line wraps around other side... */ if (haveNL) { gCurRow++; } else if (haveCR) { getyx(gListWin, y, x); wmove(gListWin, y, 0); } gPendingNL = haveNL; if (endp == NULL) break; startp = endp + 1; } } /* PrintToListWindow */ #endif /* USE_CURSES */ /* Prints a message, if you have debbuging mode turned on. */ /*VARARGS*/ #ifndef HAVE_STDARG_H void DebugMsg(va_alist) va_dcl #else void DebugMsg(char *fmt0, ...) #endif { va_list ap; char *fmt; #ifndef HAVE_STDARG_H va_start(ap); fmt = va_arg(ap, char *); #else va_start(ap, fmt0); fmt = fmt0; #endif if (gDebug == kDebuggingOn) { if (gWinInit) { #ifdef USE_CURSES strcpy(gSprintfBuf, "#DB# "); (void) vsprintf(gSprintfBuf + 5, fmt, ap); PrintToListWindow(gSprintfBuf, 0); #endif /* USE_CURSES */ } else { (void) fprintf(kDebugStream, "#DB# "); (void) vfprintf(kDebugStream, fmt, ap); (void) fflush(kDebugStream); } } if ((gTrace == kTracingOn) && (gTraceLogFile != NULL)) { (void) fprintf(gTraceLogFile, "#DB# "); (void) vfprintf(gTraceLogFile, fmt, ap); (void) fflush(gTraceLogFile); } va_end(ap); } /* DebugMsg */ /* This is similar to DebugMsg, but only writes to the debug log * file. This is useful for putting messages in the log that * shouldn't show up on screen (i.e. would make a mess in visual * mode. */ /*VARARGS*/ #ifndef HAVE_STDARG_H void TraceMsg(va_alist) va_dcl #else void TraceMsg(char *fmt0, ...) #endif { va_list ap; char *fmt; #ifndef HAVE_STDARG_H va_start(ap); fmt = va_arg(ap, char *); #else va_start(ap, fmt0); fmt = fmt0; #endif if ((gTrace == kTracingOn) && (gTraceLogFile != NULL)) { (void) fprintf(gTraceLogFile, "#TR# "); (void) vfprintf(gTraceLogFile, fmt, ap); (void) fflush(gTraceLogFile); } va_end(ap); } /* TraceMsg */ /* Prints to our own standard output stream. */ /*VARARGS*/ #ifndef HAVE_STDARG_H void PrintF(va_alist) va_dcl #else void PrintF(char *fmt0, ...) #endif { va_list ap; char *fmt; #ifndef HAVE_STDARG_H va_start(ap); fmt = va_arg(ap, char *); #else va_start(ap, fmt0); fmt = fmt0; #endif /* If it's an important message, don't use this function, use * EPrintF() instead. */ if (gVerbosity > kErrorsOnly) { if ((gWinInit) && (gRealStdout == gStdout)) { #ifdef USE_CURSES (void) vsprintf(gSprintfBuf, fmt, ap); PrintToListWindow(gSprintfBuf, 0); #endif /* USE_CURSES */ } else { (void) vsprintf(gSprintfBuf, fmt, ap); (void) write(gStdout, gSprintfBuf, strlen(gSprintfBuf)); } } if ((gTrace == kTracingOn) && (gTraceLogFile != NULL)) { (void) vfprintf(gTraceLogFile, fmt, ap); (void) fflush(gTraceLogFile); } va_end(ap); } /* PrintF */ /*VARARGS*/ #ifndef HAVE_STDARG_H void BoldPrintF(va_alist) va_dcl #else void BoldPrintF(char *fmt0, ...) #endif { va_list ap; char *fmt; #ifndef HAVE_STDARG_H va_start(ap); fmt = va_arg(ap, char *); #else va_start(ap, fmt0); fmt = fmt0; #endif if (gVerbosity > kErrorsOnly) { if ((gWinInit) && (gRealStdout == gStdout)) { #ifdef USE_CURSES (void) vsprintf(gSprintfBuf, fmt, ap); WAttr(gListWin, kBold, 1); PrintToListWindow(gSprintfBuf, 0); WAttr(gListWin, kBold, 0); #endif /* USE_CURSES */ } else { (void) vsprintf(gSprintfBuf, fmt, ap); (void) write(gStdout, gSprintfBuf, strlen(gSprintfBuf)); } } if ((gTrace == kTracingOn) && (gTraceLogFile != NULL)) { (void) vfprintf(gTraceLogFile, fmt, ap); (void) fflush(gTraceLogFile); } va_end(ap); } /* BoldPrintF */ /* Prints to stderr. */ /*VARARGS*/ #ifndef HAVE_STDARG_H void EPrintF(va_alist) va_dcl #else void EPrintF(char *fmt0, ...) #endif { va_list ap; char *fmt; char *cp; #ifndef HAVE_STDARG_H va_start(ap); fmt = va_arg(ap, char *); #else va_start(ap, fmt0); fmt = fmt0; #endif if (gVerbosity > kQuiet) { if (gWinInit) { #ifdef USE_CURSES (void) vsprintf(gSprintfBuf, fmt, ap); PrintToListWindow(gSprintfBuf, 0); /* No buffering on error stream. */ wnoutrefresh(gListWin); doupdate(); #endif /* USE_CURSES */ } else { (void) vfprintf(stderr, fmt, ap); } } if ((gTrace == kTracingOn) && (gTraceLogFile != NULL)) { /* Special hack so when progress meters use \r's we don't * print them in the trace file. */ (void) vsprintf(gSprintfBuf, fmt, ap); for (cp = gSprintfBuf; ; ) { /* Replace all carriage returns with newlines. */ cp = strchr(cp, '\r'); if (cp == NULL) break; *cp++ = '\n'; } fputs(gSprintfBuf, gTraceLogFile); (void) fflush(gTraceLogFile); } va_end(ap); } /* EPrintF */ /*VARARGS*/ #ifndef HAVE_STDARG_H void Error(va_alist) va_dcl #else void Error(int pError0, char *fmt0, ...) #endif { va_list ap; char *fmt; int pError; longstring buf2; #ifndef HAVE_STDARG_H va_start(ap); pError = va_arg(ap, int); fmt = va_arg(ap, char *); #else va_start(ap, fmt0); fmt = fmt0; pError = pError0; #endif if (gVerbosity > kQuiet) { if (gWinInit) { #ifdef USE_CURSES (void) vsprintf(gSprintfBuf, fmt, ap); if (gDebug == kDebuggingOn) sprintf(buf2, "Error(%d): ", errno); else STRNCPY(buf2, "Error: "); STRNCAT(buf2, gSprintfBuf); #ifdef HAVE_STRERROR if ((pError == kDoPerror) && (errno > 0)) { STRNCAT(buf2, "Reason: "); STRNCAT(buf2, strerror(errno)); STRNCAT(buf2, "\n"); } #endif /* HAVE_STRERROR */ PrintToListWindow(buf2, 0); #endif /* USE_CURSES */ } else { (void) fprintf(stderr, "Error"); if (gDebug == kDebuggingOn) (void) fprintf(stderr, "(%d)", errno); (void) fprintf(stderr, ": "); (void) vfprintf(stderr, fmt, ap); (void) fflush(stderr); if ((pError == kDoPerror) && (errno > 0)) perror("Reason"); } } if ((gTrace == kTracingOn) && (gTraceLogFile != NULL)) { (void) fprintf(gTraceLogFile, "Error(%d): ", errno); (void) vfprintf(gTraceLogFile, fmt, ap); #ifdef HAVE_STRERROR if ((pError == kDoPerror) && (errno > 0)) (void) fprintf(gTraceLogFile, "Reason: %s\n", strerror(errno)); #endif (void) fflush(gTraceLogFile); } va_end(ap); } /* Error */ void MultiLineInit(void) { #ifdef USE_CURSES int maxy, maxx; if (gWinInit) { gCurRow = 0; getmaxyx(gListWin, maxy, maxx); gLastRow = maxy; gSkipToEnd = 0; gPageNum = 0; gMultiLineMode = 1; } #endif /* USE_CURSES */ } /* MultiLineInit */ /*VARARGS*/ #ifndef HAVE_STDARG_H void MultiLinePrintF(va_alist) va_dcl #else void MultiLinePrintF(char *fmt0, ...) #endif { va_list ap; char *fmt; if (gVerbosity > kErrorsOnly) { #ifndef HAVE_STDARG_H va_start(ap); fmt = va_arg(ap, char *); #else va_start(ap, fmt0); fmt = fmt0; #endif if ((gWinInit) && (gRealStdout == gStdout)) { #ifdef USE_CURSES (void) vsprintf(gSprintfBuf, fmt, ap); PrintToListWindow(gSprintfBuf, 1); #endif /* USE_CURSES */ } else { (void) vsprintf(gSprintfBuf, fmt, ap); (void) write(gStdout, gSprintfBuf, strlen(gSprintfBuf)); } va_end(ap); } if ((gTrace == kTracingOn) && (gTraceLogFile != NULL)) { #ifndef HAVE_STDARG_H va_start(ap); fmt = va_arg(ap, char *); #else va_start(ap, fmt0); fmt = fmt0; #endif (void) vfprintf(gTraceLogFile, fmt, ap); (void) fflush(gTraceLogFile); va_end(ap); } } /* MultiLinePrintF */ void MakeBottomLine(char *pr, int flags, int addTail) { #ifdef USE_CURSES int len; int doCreate; int maxy, maxx; len = (int) strlen(pr); if (addTail) len += strlen(kPromptTail); else if (flags & kReverse) len++; /* Will add a space so you can see cursor. */ doCreate = 0; if (gPromptWin != NULL) { getmaxyx(gPromptWin, maxy, maxx); if (maxx != len) { delwin(gPromptWin); delwin(gInputWin); doCreate = 1; } } else { doCreate = 1; } if (doCreate) { gPromptWin = newwin(1, len, LINES - 1, 0); gInputWin = newwin(1, COLS - len, LINES - 1, len); if ((gPromptWin == NULL) || (gInputWin == NULL)) Exit(kExitWinFail2); } werase(gPromptWin); WAttr(gPromptWin, flags, 1); if (addTail) { mvwprintw(gPromptWin, 0,0, "%s%s", pr, kPromptTail); WAttr(gPromptWin, flags, 0); } else { mvwprintw(gPromptWin, 0,0, "%s", pr); WAttr(gPromptWin, flags, 0); } wnoutrefresh(gPromptWin); werase(gInputWin); touchwin(gInputWin); wnoutrefresh(gInputWin); doupdate(); #endif /* USE_CURSES */ } /* MakeBottomLine */ void SetPrompt(char *pr) { string p; if ((pr == kUseDefaultPrompt) || STREQ(pr, kLineModePrompt) || STREQ(pr, kVisualModePrompt)) { if (gWinInit) STRNCPY(p, kVisualModePrompt); else STRNCPY(p, kLineModePrompt); } else { STRNCPY(p, pr); } STRNCPY(gPrompt, p); #ifdef USE_CURSES if (gWinInit) MakeBottomLine(p, kBold, 1); #endif /* USE_CURSES */ } /* SetPrompt */ #ifdef USE_CURSES /* Draws a string centered in a window. */ void WAddCenteredStr(WINDOW *w, int y, char *str) { int x; int maxy, maxx; getmaxyx(w, maxy, maxx); x = (maxx - strlen(str)) / 2; if (x < 0) x = 0; wmove(w, y, x); waddstr(w, str); } /* WAddCenteredStr */ #endif /* USE_CURSES */ void InitWindows(void) { char *cp; int on; #ifdef USE_CURSES int maxx, maxy; #endif on = gVisualMode && gIsToTTY && gIsFromTTY; #ifdef USE_CURSES if (on) { initscr(); if (stdscr == NULL) goto fail; gWinInit = 1; SIGNAL(SIGTERM, SigTerm); nl(); gPromptWin = gInputWin = NULL; gListWin = newwin(LINES - 2, COLS, 0, 0); gBarWin = newwin(1, COLS, LINES - 2, 0); if ((gListWin == NULL) || (gBarWin == NULL)) Exit(kExitWinFail1); scrollok(gListWin, TRUE); idlok(gListWin, TRUE); wmove(gListWin, 0, 0); noecho(); /* Leave this off until we need it. */ WAttr(gBarWin, kReverse, 1); getmaxyx(gListWin, maxy, maxx); if (gScreenWidth > ((int) sizeof(string) - 1)) { fprintf(stderr, "Visual mode for NcFTP only supports windows of %d columns or less.\nReduce your window size or use line mode (ncftp -L).\n", (int) sizeof(string) - 1); Exit(kExitWinFail1); } gScreenWidth = maxx; gBarLeft[0] = '\0'; gBarCenter[0] = '\0'; gBarRight[0] = '\0'; LoadHistory(); /* Probably not set yet, unless you specified a host on * the command line. */ SetScreenInfo(); #ifdef SIGTSTP if (SIGNAL(SIGTSTP, SIG_IGN) != SIG_IGN) { SIGNAL(SIGTSTP, SigTStp); SIGNAL(SIGCONT, SigTStp); } #endif return; } fail: #endif /* USE_CURSES */ gWinInit = 0; cp = (char *) getenv("COLUMNS"); if (cp != NULL) gScreenWidth = atoi(cp); /* Prompt will already be set if connected. */ if (gConnected == 0) SetPrompt(kUseDefaultPrompt); } /* InitWindows */ /* eof */