home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Geek Gadgets 1
/
ADE-1.bin
/
ade-dist
/
ncftp-2.3.0-src.tgz
/
tar.out
/
contrib
/
ncftp
/
Hostwin.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-09-28
|
28KB
|
1,155 lines
/* Hostwin.c */
#include "Sys.h"
#include "Curses.h"
#include <ctype.h>
#include <signal.h>
#include <setjmp.h>
#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; (i<lastLine) && (i<gNumBookmarks); i++) {
rsip = gBookmarks[i];
if (rsip == gCurHostListItem)
WAttr(gHostListWin, kReverse, 1);
sprintf(str, spec, rsip->bookmarkName, rsip->name);
str[lmaxx] = '\0';
mvwaddstr(gHostListWin, i - gHostListWinStart, 0, str);
if (rsip == gCurHostListItem)
WAttr(gHostListWin, kReverse, 0);
}
/* Add 'vi' style empty-lines. */
for ( ; i<lastLine; ++i) {
mvwaddstr(gHostListWin, i - gHostListWinStart, 0, "~");
wclrtoeol(gHostListWin);
}
wmove(gHostWin, maxy - 3, 2);
sprintf(spec, "%%-%ds", maxx - 4);
if ((gCurHostListItem == NULL) || (gCurHostListItem->comment[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; i<gNumBookmarks - 1; i++) {
j = gBookmarks[i]->bookmarkName[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 <RETURN> to continue.");
EditHostWinGetStr(gEditRsi.bookmarkName, sizeof(gEditRsi.bookmarkName), kNotOkayIfEmpty, kGetAndEcho);
break;
case kHostnameEditWindowItem:
EditHostWinMsg("Type a new hostname, or hit <RETURN> to continue.");
EditHostWinGetStr(gEditRsi.name, sizeof(gEditRsi.name), kNotOkayIfEmpty, kGetAndEcho);
break;
case kUserEditWindowItem:
EditHostWinMsg("Type a username, or hit <RETURN> to signify anonymous.");
EditHostWinGetStr(gEditRsi.user, sizeof(gEditRsi.user), kOkayIfEmpty, kGetAndEcho);
break;
case kPassEditWindowItem:
EditHostWinMsg("Type a password, or hit <RETURN> if no password is required.");
EditHostWinGetStr(gEditRsi.pass, sizeof(gEditRsi.pass), kOkayIfEmpty, kGetNoEcho);
break;
case kAcctEditWindowItem:
EditHostWinMsg("Type an account name, or hit <RETURN> 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)
{
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: <enter>");
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: <u>");
mvwaddstr(gHostWin, 10, 2, "Down one: <d>");
mvwaddstr(gHostWin, 11, 2, "Previous page: <p>");
mvwaddstr(gHostWin, 12, 2, "Next page: <n>");
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: <x>");
/* 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(int argc, char **argv)
{
#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 */