/* Hostwin.c */ #include "Sys.h" #include "Curses.h" #include #include #include #include "Util.h" #include "Cmds.h" #include "Bookmark.h" #include "Open.h" #include "Hostwin.h" #ifdef USE_CURSES #include "WGets.h" /* This is the full-screen window that pops up when you run the * host editor. Not much is done with it, except display directions * and getting host editor commands. */ WINDOW *gHostWin = NULL; /* This is a window devoted solely to serve as a scrolling list * of bookmarks. */ WINDOW *gHostListWin = NULL; /* This is another full-screen window that opens when a user wants * to edit the parameters for a site. */ WINDOW *gEditHostWin = NULL; extern void WAddCenteredStr(WINDOW *w, int y, char *str); void WAttr(WINDOW *w, int attr, int on); #endif /* USE_CURSES */ /* This is an index into the host list. This indicates the position * in the host list where we draw the current "page" of the host list. */ int gHostListWinStart; /* This index is the currently selected host. This index must be >= * to gHostListWinStart and less than gHostListWinStart + pageLen - 1, * so that this host will show up in the current page of the host list. */ int gHilitedHost; /* This is a pointer to the actual information of the currently * selected host. */ BookmarkPtr gCurHostListItem; /* How many lines compose a "page" in the host list's scrolling window. */ int gHostListPageSize; /* A flag saying if we need to erase a message after the next input key. */ int gNeedToClearMsg = 0; /* When we edit gCurHostListItem's stuff, we actually edit a copy of it. * This is so we could restore the information if the user wanted to * abort the changes. */ Bookmark gEditRsi; jmp_buf gHostWinJmp; extern int gWinInit, gNumBookmarks, gRmtInfoIsNew; extern BookmarkPtrList gBookmarks; extern BookmarkPtr gHosts; extern Bookmark gRmtInfo; extern string gEmailAddress, gAnonPassword; extern unsigned int gFTPPort; void AtoIMaybe(int *dst, char *str) { char *cp; /* Don't change the value if the user just hit return. */ for (cp = str; *cp != '\0'; cp++) if (isdigit(*cp)) break; if (isdigit(*cp)) *dst = atoi(str); } /* AtoIMaybe */ #ifdef USE_CURSES /* Draws the screen when we're using the host editor's main screen. * You can can specify whether to draw each character whether it needs * it or not if you like. */ void UpdateHostWindows(int uptAll) { if (uptAll) { DrawHostList(); touchwin(gHostListWin); touchwin(gHostWin); } wnoutrefresh(gHostListWin); wnoutrefresh(gHostWin); doupdate(); } /* UpdateHostWindows */ /* This draws the scrolling list of bookmarks, and hilites the currently * selected host. */ void DrawHostList(void) { int lastLine, i; BookmarkPtr rsip; string str; int maxy, maxx; int lmaxy, lmaxx; int begy, begx; char spec[32]; getmaxyx(gHostListWin, lmaxy, lmaxx); getbegyx(gHostListWin, begy, begx); getmaxyx(gHostWin, maxy, maxx); /* We have a status line saying how many bookmarks there are in * the list. That way the user knows something is supposed to * be there when the host list is totally empty, and also that * there are more bookmarks to look at when the entire host list * doesn't fit in the scroll window. */ WAttr(gHostWin, kUnderline, 1); mvwprintw( gHostWin, begy - 1, begx, "%s", "Number of bookmarks" ); WAttr(gHostWin, kUnderline, 0); wprintw( gHostWin, ": %3d", gNumBookmarks ); sprintf(spec, "%%-16s %%-%ds", lmaxx - 17); lastLine = lmaxy + gHostListWinStart; for (i=gHostListWinStart; (ibookmarkName, rsip->name); str[lmaxx] = '\0'; mvwaddstr(gHostListWin, i - gHostListWinStart, 0, str); if (rsip == gCurHostListItem) WAttr(gHostListWin, kReverse, 0); } /* Add 'vi' style empty-lines. */ for ( ; icomment[0] == '\0')) str[0] = '\0'; else { STRNCPY(str, "``"); STRNCAT(str, gCurHostListItem->comment); AbbrevStr(str + 2, gCurHostListItem->comment, maxx - 8, 1); STRNCAT(str, "''"); } wprintw(gHostWin, spec, str); wmove(gHostWin, maxy - 1, 0); UpdateHostWindows(0); } /* DrawHostList */ /* This prompts for a key of input when in the main host editor window. */ int HostWinGetKey(void) { int c; int maxy, maxx; getmaxyx(gHostWin, maxy, maxx); wmove(gHostWin, maxy - 1, 0); c = wgetch(gHostWin); TraceMsg("[%c, 0x%x]\n", c, c); return (c); } /* HostWinGetKey */ static void NewHilitedHostIndex(int newIdx) { int oldIdx, lastLine; if (gNumBookmarks <= 0) { HostWinMsg( "No bookmarks in the list. Try a /new, or open a site manually to add one."); } else { oldIdx = gHilitedHost; if (gNumBookmarks < gHostListPageSize) lastLine = gHostListWinStart + gNumBookmarks - 1; else lastLine = gHostListWinStart + gHostListPageSize - 1; if (newIdx < gHostListWinStart) { /* Will need to scroll the window up. */ if (newIdx < 0) { newIdx = 0; if (oldIdx == newIdx) HostWinMsg("You are at the top of the list."); } gHilitedHost = gHostListWinStart = newIdx; } else if (newIdx > lastLine) { /* Will need to scroll the window down. */ if (newIdx > (gNumBookmarks - 1)) { newIdx = gNumBookmarks - 1; if (oldIdx == newIdx) HostWinMsg("You are at the bottom of the list."); } gHilitedHost = newIdx; gHostListWinStart = newIdx - (gHostListPageSize - 1); if (gHostListWinStart < 0) gHostListWinStart = 0; } else { /* Don't need to scroll window, just move pointer. */ gHilitedHost = newIdx; } gCurHostListItem = gBookmarks[gHilitedHost]; if (oldIdx != newIdx) DrawHostList(); } } /* NewHilitedHostIndex */ /* You can zip to a different area of the list without using the arrow * or page scrolling keys. Just type a letter, and the list will scroll * to the first host starting with that letter. */ void HostWinZoomTo(int c) { int i, j; if (gNumBookmarks > 0) { if (islower(c)) c = toupper(c); for (i=0; ibookmarkName[0]; if (islower(j)) j = toupper(j); if (j >= c) break; } NewHilitedHostIndex(i); } else { HostWinMsg("No bookmarks to select. Try a /new."); } DrawHostList(); } /* HostWinZoomTo */ void HostListLineUp(void) { NewHilitedHostIndex(gHilitedHost - 1); } /* HostListLineUp */ void HostListLineDown(void) { NewHilitedHostIndex(gHilitedHost + 1); } /* HostListLineDown */ void HostListPageUp(void) { NewHilitedHostIndex(gHilitedHost - gHostListPageSize); } /* HostListPageUp */ void HostListPageDown(void) { NewHilitedHostIndex(gHilitedHost + gHostListPageSize); } /* HostListPageDown */ /* This marks the start of a section that belongs to the Bookmark Options * window. This window pops up on top of the host editor's main window * when you wish to edit a site's settings. When the user finishes, * we close it and the host editor resumes. */ /* This displays a message in the Bookmark Options window. */ void EditHostWinMsg(char *msg) { int maxy, maxx; getmaxyx(gEditHostWin, maxy, maxx); mvwaddstr(gEditHostWin, maxy - 2, 0, msg); wclrtoeol(gEditHostWin); wmove(gEditHostWin, maxy - 1, 0); wrefresh(gEditHostWin); } /* EditHostWinMsg */ /* Prompts for a line of input. */ void EditHostWinGetStr(char *dst, size_t size, int canBeEmpty, int canEcho) { string str; WGetsParams wgp; int maxy, maxx; WAttr(gEditHostWin, kBold, 1); getmaxyx(gEditHostWin, maxy, maxx); mvwaddstr(gEditHostWin, maxy - 1, 0, "> "); WAttr(gEditHostWin, kBold, 0); wclrtoeol(gEditHostWin); wrefresh(gEditHostWin); curs_set(1); wgp.w = gEditHostWin; wgp.sy = maxy - 1; wgp.sx = 2; wgp.fieldLen = maxx - 3; wgp.dst = str; wgp.dstSize = size; wgp.useCurrentContents = 0; wgp.echoMode = canEcho ? wg_RegularEcho : wg_BulletEcho; wgp.history = wg_NoHistory; (void) wg_Gets(&wgp); cbreak(); /* wg_Gets turns off cbreak and delay. */ TraceMsg("[%s]\n", wgp.dst); /* See if the user just hit return. We may not want to overwrite * the dst here, which would make it an empty string. */ if ((wgp.changed) || (canBeEmpty == kOkayIfEmpty)) strcpy(dst, str); wmove(gEditHostWin, maxy - 1, 0); wclrtoeol(gEditHostWin); wrefresh(gEditHostWin); curs_set(0); } /* EditHostWinGetStr */ /* Prompts for an integer of input. */ void EditHostWinGetNum(int *dst) { WGetsParams wgp; string str; int maxy, maxx; getmaxyx(gEditHostWin, maxy, maxx); WAttr(gEditHostWin, kBold, 1); mvwaddstr(gEditHostWin, maxy - 1, 0, "> "); WAttr(gEditHostWin, kBold, 0); wclrtoeol(gEditHostWin); wrefresh(gEditHostWin); curs_set(1); wgp.w = gEditHostWin; wgp.sy = maxy - 1; wgp.sx = 2; wgp.fieldLen = maxx - 3; wgp.dst = str; wgp.dstSize = sizeof(str); wgp.useCurrentContents = 0; wgp.echoMode = wg_RegularEcho; wgp.history = wg_NoHistory; (void) wg_Gets(&wgp); cbreak(); /* wg_Gets turns off cbreak and delay. */ TraceMsg("[%s]\n", str); AtoIMaybe(dst, str); wmove(gEditHostWin, maxy - 1, 0); wclrtoeol(gEditHostWin); wrefresh(gEditHostWin); curs_set(0); } /* EditHostWinGetNum */ /* This is the meat of the site options window. We can selectively update * portions of the window by using a bitmask with bits set for items * we want to update. */ void EditHostWinDraw(int flags, int hilite) { int maxy, maxx; int i, f; string str; char spec[32]; char *cp; /* Draw the keys the user can type in reverse text. */ WAttr(gEditHostWin, kReverse, 1); f = 5; for (i = kFirstEditWindowItem; i <= kLastEditWindowItem; i++) { if (TESTBIT(flags, i)) mvwaddch(gEditHostWin, f + i, 2, 'A' + i); } /* The "quit" item is a special item that is offset a line, and * always has the "X" key assigned to it. */ i = kQuitEditWindowItem; if (TESTBIT(flags, i)) mvwaddch(gEditHostWin, 1 + f + i, 2, 'X'); WAttr(gEditHostWin, kReverse, 0); /* We can use this to hilite a whole line, to indicate to the * user that a certain item is being edited. */ if (hilite) WAttr(gEditHostWin, kReverse, 1); getmaxyx(gEditHostWin, maxy, maxx); sprintf(spec, " %%-26s%%-%ds", maxx - 32); /* Now draw the items on a case-by-case basis. */ if (TESTBIT(flags, kNicknameEditWindowItem)) { mvwprintw(gEditHostWin, kNicknameEditWindowItem + f, 3, spec, "Bookmark name:", gEditRsi.bookmarkName ); wclrtoeol(gEditHostWin); } if (TESTBIT(flags, kHostnameEditWindowItem)) { mvwprintw(gEditHostWin, kHostnameEditWindowItem + f, 3, spec, "Hostname:", gEditRsi.name ); wclrtoeol(gEditHostWin); } if (TESTBIT(flags, kUserEditWindowItem)) { mvwprintw(gEditHostWin, kUserEditWindowItem + f, 3, spec, "User:", gEditRsi.user[0] == '\0' ? "anonymous" : gEditRsi.user ); wclrtoeol(gEditHostWin); } if (TESTBIT(flags, kPassEditWindowItem)) { if (gEditRsi.pass[0] == '\0' && gEditRsi.user[0] == '\0') STRNCPY(str, gAnonPassword); mvwprintw(gEditHostWin, kPassEditWindowItem + f, 3, spec, "Password:", strcmp(str, gAnonPassword) ? "********" : str ); wclrtoeol(gEditHostWin); } if (TESTBIT(flags, kAcctEditWindowItem)) { mvwprintw(gEditHostWin, kAcctEditWindowItem + f, 3, spec, "Account:", gEditRsi.acct[0] == '\0' ? "none" : gEditRsi.acct ); wclrtoeol(gEditHostWin); } if (TESTBIT(flags, kDirEditWindowItem)) { if (gEditRsi.dir[0] == '\0') STRNCPY(str, "/"); else AbbrevStr(str, gEditRsi.dir, maxx - 32, 0); mvwprintw(gEditHostWin, kDirEditWindowItem + f, 3, spec, "Directory:", str ); wclrtoeol(gEditHostWin); } if (TESTBIT(flags, kXferTypeEditWindowItem)) { if ((gEditRsi.xferType == 'I') || (gEditRsi.xferType == 'B')) cp = "Binary"; else if (gEditRsi.xferType == 'A') cp = "ASCII Text"; else cp = "Tenex"; mvwprintw(gEditHostWin, kXferTypeEditWindowItem + f, 3, spec, "Transfer type:", cp ); wclrtoeol(gEditHostWin); } if (TESTBIT(flags, kPortEditWindowItem)) { sprintf(str, "%u", gEditRsi.port); mvwprintw(gEditHostWin, kPortEditWindowItem + f, 3, spec, "Port:", str ); wclrtoeol(gEditHostWin); } if (TESTBIT(flags, kSizeEditWindowItem)) { mvwprintw(gEditHostWin, kSizeEditWindowItem + f, 3, spec, "Has SIZE command:", gEditRsi.hasSIZE ? "Yes" : "No" ); wclrtoeol(gEditHostWin); } if (TESTBIT(flags, kMdtmEditWindowItem)) { mvwprintw(gEditHostWin, kMdtmEditWindowItem + f, 3, spec, "Has MDTM command:", gEditRsi.hasMDTM ? "Yes" : "No" ); wclrtoeol(gEditHostWin); } if (TESTBIT(flags, kPasvEditWindowItem)) { mvwprintw(gEditHostWin, kPasvEditWindowItem + f, 3, spec, "Can use passive FTP:", gEditRsi.hasPASV ? "Yes" : "No" ); wclrtoeol(gEditHostWin); } if (TESTBIT(flags, kOSEditWindowItem)) { mvwprintw(gEditHostWin, kOSEditWindowItem + f, 3, spec, "Operating System:", (gEditRsi.isUnix == 1) ? "UNIX" : "Non-UNIX" ); wclrtoeol(gEditHostWin); } if (TESTBIT(flags, kCommentEditWindowItem)) { if (gEditRsi.comment[0] == '\0') STRNCPY(str, "(none)"); else AbbrevStr(str, gEditRsi.comment, maxx - 32, 0); mvwprintw(gEditHostWin, kCommentEditWindowItem + f, 3, spec, "Comment:", str ); wclrtoeol(gEditHostWin); } if (TESTBIT(flags, kQuitEditWindowItem)) { mvwprintw(gEditHostWin, kQuitEditWindowItem + f + 1, 3, spec, "(Done editing)", "" ); wclrtoeol(gEditHostWin); } if (hilite) WAttr(gEditHostWin, kReverse, 0); wmove(gEditHostWin, maxy - 1, 0); wrefresh(gEditHostWin); } /* EditHostWinDraw */ /* The user can hit space to change the transfer type. For these toggle * functions we do an update each time so the user can see the change * immediately. */ void ToggleXferType(void) { int c; while (1) { c = wgetch(gEditHostWin); TraceMsg("[%c, 0x%x]\n", c, c); if ((c == 'x') || (c == 10) || (c == 13) #ifdef KEY_ENTER || (c == KEY_ENTER) #endif ) break; else if (isspace(c)) { if (gEditRsi.xferType == 'A') gEditRsi.xferType = 'I'; else if ((gEditRsi.xferType == 'B') || (gEditRsi.xferType == 'I')) gEditRsi.xferType = 'T'; else gEditRsi.xferType = 'A'; EditHostWinDraw(BIT(kXferTypeEditWindowItem), kHilite); } } } /* ToggleXferType */ void EditWinToggle(int *val, int bitNum, int min, int max) { int c; while (1) { c = wgetch(gEditHostWin); TraceMsg("[%c, 0x%x]\n", c, c); if ((c == 'x') || (c == 10) || (c == 13) #ifdef KEY_ENTER || (c == KEY_ENTER) #endif ) break; else if (isspace(c)) { *val = *val + 1; if (*val > max) *val = min; EditHostWinDraw(BIT(bitNum), kHilite); } } } /* EditWinToggle */ /* This opens and handles the site options window. */ void HostWinEdit(void) { long amt; double rate; char rstr[32]; int c, field; int needUpdate; string str; if (gCurHostListItem != NULL) { gEditHostWin = newwin(LINES, COLS, 0, 0); if (gEditHostWin == NULL) return; /* Set the clear flag for the first update. */ wclear(gEditHostWin); /* leaveok(gEditHostWin, TRUE); * Not sure if I like this... */ WAttr(gEditHostWin, kBold, 1); WAddCenteredStr(gEditHostWin, 0, "Bookmark Options"); WAttr(gEditHostWin, kBold, 0); /* We'll be editing a copy of the current host's settings. */ gEditRsi = *gCurHostListItem; if (gEditRsi.lastCall != (time_t) 0) { strcpy(str, ctime(&gEditRsi.lastCall)); /* Why-o-why does ctime append a newline. I hate that! */ str[strlen(str) - 1] = '\0'; mvwprintw(gEditHostWin, 2, 5, "Number of calls: %d. Last call: %s", gEditRsi.nCalls, str ); amt = gEditRsi.xferKbytes; if (amt > 0) { if (amt < 1000) { sprintf(str, "%ld kBytes", amt); } else if (amt < 1000000) { sprintf(str, "%.2f MBytes", ((double) amt / 1000.0)); } else { sprintf(str, "%.2f GBytes", ((double) amt / 1000000.0)); } rate = (double) amt / gEditRsi.xferHSeconds * 100.0; if (rate > 0) { if (rate < 1000.0) { sprintf(rstr, "%.2f kBytes/sec", rate); } else if (rate < 1000000.0) { sprintf(rstr, "%.2f MBytes/sec", rate / 1000.0); } else { sprintf(rstr, "%.2f GBytes/sec", rate / 1000000.0); } mvwprintw(gEditHostWin, 3, 5, "You have transferred %s, averaging %s.", str, rstr ); } } } EditHostWinDraw(kAllWindowItems, kNoHilite); field = 1; while (1) { EditHostWinMsg("Select an item to edit by typing its corresponding letter."); c = wgetch(gEditHostWin); TraceMsg("[%c, 0x%x]\n", c, c); if (islower(c)) c = toupper(c); if (!isupper(c)) continue; if (c == 'X') break; field = c - 'A'; needUpdate = 1; /* Hilite the current item to edit. */ EditHostWinDraw(BIT(field), kHilite); switch(field) { case kNicknameEditWindowItem: EditHostWinMsg("Type a new bookmark name, or hit to continue."); EditHostWinGetStr(gEditRsi.bookmarkName, sizeof(gEditRsi.bookmarkName), kNotOkayIfEmpty, kGetAndEcho); break; case kHostnameEditWindowItem: EditHostWinMsg("Type a new hostname, or hit to continue."); EditHostWinGetStr(gEditRsi.name, sizeof(gEditRsi.name), kNotOkayIfEmpty, kGetAndEcho); break; case kUserEditWindowItem: EditHostWinMsg("Type a username, or hit to signify anonymous."); EditHostWinGetStr(gEditRsi.user, sizeof(gEditRsi.user), kOkayIfEmpty, kGetAndEcho); break; case kPassEditWindowItem: EditHostWinMsg("Type a password, or hit if no password is required."); EditHostWinGetStr(gEditRsi.pass, sizeof(gEditRsi.pass), kOkayIfEmpty, kGetNoEcho); break; case kAcctEditWindowItem: EditHostWinMsg("Type an account name, or hit if no account is required."); EditHostWinGetStr(gEditRsi.acct, sizeof(gEditRsi.acct), kOkayIfEmpty, kGetAndEcho); break; case kDirEditWindowItem: EditHostWinMsg("Type a directory path to start in after a connection is established."); EditHostWinGetStr(gEditRsi.dir, sizeof(gEditRsi.dir), kOkayIfEmpty, kGetAndEcho); break; case kXferTypeEditWindowItem: EditHostWinMsg(kToggleMsg); ToggleXferType(); break; case kPortEditWindowItem: EditHostWinMsg("Type a port number to use for FTP."); EditHostWinGetNum((int *) &gEditRsi.port); break; case kSizeEditWindowItem: EditHostWinMsg(kToggleMsg); EditWinToggle(&gEditRsi.hasSIZE, field, 0, 1); break; case kMdtmEditWindowItem: EditHostWinMsg(kToggleMsg); EditWinToggle(&gEditRsi.hasMDTM, field, 0, 1); break; case kPasvEditWindowItem: EditHostWinMsg(kToggleMsg); EditWinToggle(&gEditRsi.hasPASV, field, 0, 1); break; case kOSEditWindowItem: EditHostWinMsg(kToggleMsg); EditWinToggle(&gEditRsi.isUnix, field, 0, 1); break; case kCommentEditWindowItem: EditHostWinMsg("Enter a line of information to store about this site."); EditHostWinGetStr(gEditRsi.comment, sizeof(gEditRsi.comment), kOkayIfEmpty, kGetAndEcho); break; default: needUpdate = 0; break; } if (needUpdate) EditHostWinDraw(BIT(field), kNoHilite); } delwin(gEditHostWin); gEditHostWin = NULL; *gCurHostListItem = gEditRsi; SortBookmarks(); NewHilitedHostIndex(gCurHostListItem->index); UpdateHostWindows(1); } } /* HostWinEdit */ /* Clones an existing site in the host list. */ void HostWinDup(void) { if (gCurHostListItem != NULL) { gCurHostListItem = DuplicateBookmark(gCurHostListItem); gHilitedHost = gCurHostListItem->index; } else HostWinMsg("Nothing to duplicate."); DrawHostList(); } /* HostWinDup */ /* Removes a site from the host list. */ void HostWinDelete(void) { BookmarkPtr toDelete; int newi; if (gCurHostListItem != NULL) { toDelete = gCurHostListItem; /* Need to choose a new active host after deletion. */ if (gHilitedHost == gNumBookmarks - 1) { if (gNumBookmarks == 1) { newi = -1; /* None left. */ } else { /* At last one before delete. */ newi = gHilitedHost - 1; } } else { /* Won't need to increment gHilitedHost here, since after deletion, * the next one will move up into this slot. */ newi = gHilitedHost; } DeleteBookmark(toDelete); if (newi < 0) gCurHostListItem = NULL; else { gCurHostListItem = gBookmarks[newi]; gHilitedHost = newi; } } else HostWinMsg("Nothing to delete."); DrawHostList(); } /* HostWinDelete */ /* Adds a new site to the host list, with default settings in place. */ void HostWinNew(void) { BookmarkPtr rsip; Bookmark rsi; SetNewBookmarkDefaults(&rsi); rsip = AddBookmarkPtr(&rsi); rsip->port = gFTPPort; SortBookmarks(); gCurHostListItem = rsip; gHilitedHost = rsip->index; gHostListWinStart = rsip->index - gHostListPageSize + 1; if (gHostListWinStart < 0) gHostListWinStart = 0; DrawHostList(); } /* HostWinNew */ /* This displays a message in the host editor's main window. * Used mostly for error messages. */ void HostWinMsg(char *msg) { int maxy, maxx; getmaxyx(gHostWin, maxy, maxx); mvwaddstr(gHostWin, maxy - 2, 0, msg); wclrtoeol(gHostWin); wmove(gHostWin, maxy - 1, 0); wrefresh(gHostWin); beep(); gNeedToClearMsg = 1; } /* HostWinMsg */ /* Prompts for a line of input. */ void HostWinGetStr(char *str, size_t size) { WGetsParams wgp; int maxy, maxx; getmaxyx(gHostWin, maxy, maxx); mvwaddstr(gHostWin, maxy - 1, 0, "/"); wclrtoeol(gHostWin); wrefresh(gHostWin); curs_set(1); wgp.w = gHostWin; wgp.sy = maxy - 1; wgp.sx = 1; wgp.fieldLen = maxx - 1; wgp.dst = str; wgp.dstSize = size; wgp.useCurrentContents = 0; wgp.echoMode = wg_RegularEcho; wgp.history = wg_NoHistory; (void) wg_Gets(&wgp); cbreak(); /* wg_Gets turns off cbreak and delay. */ TraceMsg("[%s]\n", str); wmove(gHostWin, maxy - 1, 0); wclrtoeol(gHostWin); wrefresh(gHostWin); curs_set(0); } /* HostWinGetStr */ /*ARGSUSED*/ void SigIntHostWin(/* int sigNum */ void) { alarm(0); longjmp(gHostWinJmp, 1); } /* SigIntHostWin */ #endif /* USE_CURSES */ /* Runs the host editor. Another big use for this is to open sites * that are in your host list. */ int HostWindow(void) { #ifdef USE_CURSES int c; string cmd; volatile BookmarkPtr toOpen; VSig_t si; int maxy, maxx; int lmaxy, lmaxx; OpenOptions openopt; si = kNoSignalHandler; if (gWinInit) { gHostListWin = NULL; gHostWin = NULL; gHostWin = newwin(LINES, COLS, 0, 0); if (gHostWin == NULL) return (kCmdErr); curs_set(0); cbreak(); /* Set the clear flag for the first update. */ wclear(gHostWin); keypad(gHostWin, TRUE); /* For arrow keys. */ #ifdef HAVE_NOTIMEOUT notimeout(gHostWin, TRUE); #endif if (setjmp(gHostWinJmp) == 0) { /* Gracefully cleanup the screen if the user ^C's. */ si = (VSig_t) SIGNAL(SIGINT, SigIntHostWin); /* Initialize the page start and select a host to be * the current one. */ gHostListWinStart = 0; gHilitedHost = 0; if (gNumBookmarks == 0) gCurHostListItem = NULL; else gCurHostListItem = gBookmarks[gHilitedHost]; /* Initially, we don't want to connect to any site in * the host list. */ toOpen = NULL; WAttr(gHostWin, kBold, 1); WAddCenteredStr(gHostWin, 0, "Bookmark Editor"); WAttr(gHostWin, kBold, 0); mvwaddstr(gHostWin, 3, 2, "Open selected site: "); mvwaddstr(gHostWin, 4, 2, "Edit selected site: /ed"); mvwaddstr(gHostWin, 5, 2, "Delete selected site: /del"); mvwaddstr(gHostWin, 6, 2, "Duplicate selected site: /dup"); mvwaddstr(gHostWin, 7, 2, "Add a new site: /new"); mvwaddstr(gHostWin, 9, 2, "Up one: "); mvwaddstr(gHostWin, 10, 2, "Down one: "); mvwaddstr(gHostWin, 11, 2, "Previous page:

"); mvwaddstr(gHostWin, 12, 2, "Next page: "); mvwaddstr(gHostWin, 14, 2, "Capital letters selects first"); mvwaddstr(gHostWin, 15, 2, " site starting with the letter."); mvwaddstr(gHostWin, 17, 2, "Exit the bookmark editor: "); /* Initialize the scrolling host list window. */ gHostListWin = subwin( gHostWin, LINES - 7, 40, 3, COLS - 40 - 2 ); if (gHostListWin == NULL) return (kCmdErr); getmaxyx(gHostListWin, lmaxy, lmaxx); getmaxyx(gHostWin, maxy, maxx); gHostListPageSize = lmaxy; DrawHostList(); wmove(gHostWin, maxy - 1, 0); UpdateHostWindows(1); while (1) { c = HostWinGetKey(); if (gNeedToClearMsg) { wmove(gHostWin, maxy - 2, 0); wclrtoeol(gHostWin); wrefresh(gHostWin); } if ((c >= 'A') && (c <= 'Z')) { /* isupper can coredump if wgetch returns a meta key. */ HostWinZoomTo(c); } else if (c == '/') { /* Get an "extended" command. Sort of like vi's * :colon commands. */ HostWinGetStr(cmd, sizeof(cmd)); if (ISTREQ(cmd, "ed")) HostWinEdit(); else if (ISTREQ(cmd, "dup")) HostWinDup(); else if (ISTREQ(cmd, "del")) HostWinDelete(); else if (ISTREQ(cmd, "new")) HostWinNew(); else HostWinMsg("Invalid bookmark editor command."); } else switch(c) { case 10: /* ^J == newline */ case 13: /* ^M == carriage return */ #ifdef KEY_ENTER case KEY_ENTER: #endif if (gCurHostListItem == NULL) HostWinMsg("Nothing to open. Try 'open sitename' from the main screen."); else { toOpen = (volatile BookmarkPtr) gCurHostListItem; goto done; } break; case kControl_L: UpdateHostWindows(1); break; case 'u': case 'k': /* vi up key */ #ifdef KEY_UP case KEY_UP: #endif HostListLineUp(); break; case 'd': case 'j': /* vi down key */ #ifdef KEY_DOWN case KEY_DOWN: #endif HostListLineDown(); break; case 'p': #ifdef KEY_LEFT case KEY_LEFT: #endif #ifdef KEY_PPAGE case KEY_PPAGE: #endif HostListPageUp(); break; case 'n': #ifdef KEY_RIGHT case KEY_RIGHT: #endif #ifdef KEY_NPAGE case KEY_NPAGE: #endif HostListPageDown(); break; #ifdef KEY_END case KEY_END: #endif case 'x': case 'q': goto done; default: HostWinMsg("Invalid key."); break; } } } SIGNAL(SIGINT, SIG_IGN); done: if (gHostListWin != NULL) delwin(gHostListWin); if (gHostWin != NULL) delwin(gHostWin); gHostListWin = gHostWin = NULL; curs_set(1); nocbreak(); UpdateScreen(1); flushinp(); if (si != (Sig_t) kNoSignalHandler) SIGNAL(SIGINT, si); if (toOpen != (volatile BookmarkPtr) 0) { /* If the user selected a site to open, connect to it now. */ InitOpenOptions(&openopt); STRNCPY(openopt.hostname, ((BookmarkPtr) toOpen)->bookmarkName); GetBookmark(openopt.hostname, sizeof(openopt.hostname)); openopt.port = gRmtInfo.port; Beep(0); /* Reset beep timer. */ return (Open(&openopt)); } } #endif /* USE_CURSES */ Beep(0); /* User should be aware that it took a while, so no beep. */ return (kNoErr); } /* HostWindow */ int HostsCmd(void) { #ifdef USE_CURSES if (!gWinInit) { Error(kDontPerror, "This only works in visual mode.\n"); return (kCmdErr); } return HostWindow(); #else Error(kDontPerror, "You can't do this because the program doesn't have the curses library.\n"); return (kCmdErr); #endif /* USE_CURSES */ } /* HostsCmd */