home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.ncftp.com
/
ftp.ncftp.com.zip
/
ftp.ncftp.com
/
ncftp
/
older_versions
/
ncftp-3.2.2-src.tar.bz2
/
ncftp-3.2.2-src.tar
/
ncftp-3.2.2
/
vis
/
bmed.c
next >
Wrap
C/C++ Source or Header
|
2005-01-01
|
35KB
|
1,456 lines
/* bmed.c (bookmark editor)
*
* Copyright (c) 1996-2005 Mike Gleason, NcFTP Software.
* All rights reserved.
*
*/
#include "syshdrs.h"
#ifdef PRAGMA_HDRSTOP
# pragma hdrstop
#endif
#include "../ncftp/util.h"
#include "../ncftp/trace.h"
#include "../ncftp/pref.h"
#include "../ncftp/bookmark.h"
#include "wutil.h"
#include "wgets.h"
#include "bmed.h"
/* Are we being run as a regular process, or a
* subprocess of ncftp?
*/
int gStandAlone;
/* 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;
int gHostListWinWide;
/* This is another full-screen window that opens when a user wants
* to edit the parameters for a site.
*/
WINDOW *gEditHostWin = NULL;
/* 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;
#ifdef HAVE_SIGSETJMP
sigjmp_buf gHostWinJmp;
#else /* HAVE_SIGSETJMP */
jmp_buf gHostWinJmp;
#endif /* HAVE_SIGSETJMP */
/* If set to a valid pathname, hitting enter at the host selection
* screen will write the name of the bookmark into this file.
* This is a cheap form of IPC with a parent NcFTP process.
*/
const char *gBookmarkSelectionFile = NULL;
/* Needed by prefs. */
FTPLibraryInfo gLib;
FTPConnectionInfo gConn;
extern int gWinInit;
extern int gScreenWidth;
extern int gScreenHeight;
extern int gNumBookmarks;
extern BookmarkPtr gBookmarkTable;
extern int gDebug;
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((int) *cp))
break;
if (isdigit((int) *cp))
*dst = atoi(str);
} /* AtoIMaybe */
/* 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(1);
} /* UpdateHostWindows */
/* This draws the scrolling list of bookmarks, and hilites the currently
* selected host.
*/
void DrawHostList(void)
{
int lastLine, i;
BookmarkPtr rsip;
char str[256];
char url[256];
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,
strcpy(spec, "%s"), /* avoid warnings on BSD */
"Number of bookmarks"
);
WAttr(gHostWin, kUnderline, 0);
wprintw(
gHostWin,
strcpy(spec, ": %3d"),
gNumBookmarks
);
if (gHostListWinWide == 0) {
sprintf(spec, "%%-16.16s %%-%ds", lmaxx - 17);
lastLine = lmaxy + gHostListWinStart;
for (i=gHostListWinStart; (i<lastLine) && (i<gNumBookmarks); i++) {
rsip = &gBookmarkTable[i];
if (rsip == gCurHostListItem)
WAttr(gHostListWin, kReverse, 1);
sprintf(str, spec, rsip->bookmarkName, rsip->name);
str[lmaxx] = '\0';
DrawStrAt(gHostListWin, i - gHostListWinStart, 0, str);
swclrtoeol(gHostListWin);
if (rsip == gCurHostListItem) {
WAttr(gHostListWin, kReverse, 0);
}
}
} else {
lastLine = lmaxy + gHostListWinStart;
for (i=gHostListWinStart; (i<lastLine) && (i<gNumBookmarks); i++) {
rsip = &gBookmarkTable[i];
if (rsip == gCurHostListItem)
WAttr(gHostListWin, kReverse, 1);
BookmarkToURL(rsip, url, sizeof(url));
sprintf(str, "%-16.16s ", rsip->bookmarkName);
STRNCAT(str, url);
memset(url, 0, sizeof(url));
AbbrevStr(url, str, (size_t) lmaxx, 1);
DrawStrAt(gHostListWin, i - gHostListWinStart, 0, url);
swclrtoeol(gHostListWin);
if (rsip == gCurHostListItem) {
WAttr(gHostListWin, kReverse, 0);
}
}
}
/* Add 'vi' style empty-lines. */
for ( ; i<lastLine; ++i) {
DrawStrAt(gHostListWin, i - gHostListWinStart, 0, "~");
swclrtoeol(gHostListWin);
}
wmove(gHostWin, maxy - 3, 2);
sprintf(spec, "%%-%ds", maxx - 4);
if (gCurHostListItem == NULL) {
str[0] = '\0';
} else if (gCurHostListItem->comment[0] == '\0') {
memset(str, 0, sizeof(str));
if (gHostListWinWide == 0) {
BookmarkToURL(gCurHostListItem, url, sizeof(url));
AbbrevStr(str, url, (size_t) maxx - 2, 1);
}
} else {
STRNCPY(str, "``");
STRNCAT(str, gCurHostListItem->comment);
AbbrevStr(str + 2, gCurHostListItem->comment, (size_t) 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 uc;
int escmode;
int maxy;
maxy = getmaxy(gHostWin);
wmove(gHostWin, maxy - 1, 0);
for (escmode = 0; ; escmode++) {
uc = (unsigned int) wgetch(gHostWin);
c = (int) uc;
if (uc > 255) {
Trace(1, "[0x%04X]\n", c);
} else if (isprint(c) && !iscntrl(c)) {
Trace(1, "[0x%04X, %c]\n", c, c);
} else if (iscntrl(c)) {
Trace(1, "[0x%04X, ^%c]\n", c, (c & 31) | ('A' - 1));
} else {
Trace(1, "[0x%04X]\n", c);
}
/* Some implementations of curses (i.e. Mac OS X)
* don't seem to detect the arrow keys on
* typical terminal types like "vt100" or "ansi",
* so we try and detect them the hard way.
*/
switch (escmode) {
case 0:
if (uc != 0x001B) {
goto gotch;
}
/* else ESC key (^[) */
break;
case 1:
if ((c != '[') && (c != 'O')) {
goto gotch;
}
/* else ANSI ESC sequence continues */
break;
case 2:
switch (c) {
case 'A':
case 'a':
#ifdef KEY_UP
c = KEY_UP;
Trace(1, " --> [0x%04X, %s]\n", c, "UP");
#else
c = 'k'; /* vi UP */
Trace(1, " --> [0x%04X, %s]\n", c, "k");
#endif
break;
case 'B':
case 'b':
#ifdef KEY_DOWN
c = KEY_DOWN;
Trace(1, " --> [0x%04X, %s]\n", c, "DOWN");
#else
c = 'j'; /* vi DOWN */
Trace(1, " --> [0x%04X, %s]\n", c, "j");
#endif
break;
case 'D':
case 'd':
#ifdef KEY_LEFT
c = KEY_LEFT;
Trace(1, " --> [0x%04X, %s]\n", c, "LEFT");
#else
c = 'h'; /* vi LEFT */
Trace(1, " --> [0x%04X, %s]\n", c, "h");
#endif
break;
case 'C':
case 'c':
#ifdef KEY_RIGHT
c = KEY_RIGHT;
Trace(1, " --> [0x%04X, %s]\n", c, "RIGHT");
#else
c = 'l'; /* vi RIGHT */
Trace(1, " --> [0x%04X, %s]\n", c, "l");
#endif
break;
}
goto gotch;
}
}
gotch:
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 = &gBookmarkTable[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 = gBookmarkTable[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(const char *msg)
{
int maxy;
maxy = getmaxy(gEditHostWin);
DrawStrAt(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)
{
char str[256];
WGetsParams wgp;
int maxy, maxx;
WAttr(gEditHostWin, kBold, 1);
getmaxyx(gEditHostWin, maxy, maxx);
DrawStrAt(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. */
/* 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;
char str[256];
int maxy, maxx;
getmaxyx(gEditHostWin, maxy, maxx);
WAttr(gEditHostWin, kBold, 1);
DrawStrAt(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. */
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;
char str[256];
char spec[32];
const 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, gLib.defaultAnonPassword);
mvwprintw(gEditHostWin, kPassEditWindowItem + f, 3, spec,
"Password:",
strcmp(str, gLib.defaultAnonPassword) ? "********" : 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, (size_t) maxx - 32, 0);
mvwprintw(gEditHostWin, kDirEditWindowItem + f, 3, spec,
"Remote Directory:",
str
);
wclrtoeol(gEditHostWin);
}
if (TESTBIT(flags, kLDirEditWindowItem)) {
if (gEditRsi.ldir[0] == '\0')
STRNCPY(str, "(current)");
else
AbbrevStr(str, gEditRsi.ldir, (size_t) maxx - 32, 0);
mvwprintw(gEditHostWin, kLDirEditWindowItem + f, 3, spec,
"Local 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 == 0) ? 21 : (unsigned int) gEditRsi.port);
mvwprintw(gEditHostWin, kPortEditWindowItem + f, 3, spec,
"Port:",
str
);
wclrtoeol(gEditHostWin);
}
#if 0
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);
}
#endif
if (TESTBIT(flags, kCommentEditWindowItem)) {
if (gEditRsi.comment[0] == '\0')
STRNCPY(str, "(none)");
else
AbbrevStr(str, gEditRsi.comment, (size_t) 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;
for (;;) {
c = wgetch(gEditHostWin);
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;
for (;;) {
c = wgetch(gEditHostWin);
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 */
static void
SaveAndReload(void)
{
SaveBookmarkTable();
if (LoadBookmarkTable() < 0) {
fprintf(stderr, "Suddenly unable to re-load bookmarks.");
Exit(1);
}
} /* SaveAndReload */
/* This opens and handles the site options window. */
void HostWinEdit(void)
{
int c, field;
int needUpdate;
char bmname[128];
BookmarkPtr rsip;
if (gCurHostListItem != NULL) {
gEditHostWin = newwin(LINES, COLS, 0, 0);
if (gEditHostWin == NULL)
return;
STRNCPY(bmname, gCurHostListItem->bookmarkName);
/* 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;
EditHostWinDraw(kAllWindowItems, kNoHilite);
field = 1;
for (;;) {
EditHostWinMsg("Select an item to edit by typing its corresponding letter.");
c = wgetch(gEditHostWin);
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);
gEditRsi.lastIP[0] = '\0'; /* In case it changed. */
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 remote directory path to start in after a connection is established.");
EditHostWinGetStr(gEditRsi.dir, sizeof(gEditRsi.dir), kOkayIfEmpty, kGetAndEcho);
break;
case kLDirEditWindowItem:
EditHostWinMsg("Type a local directory path to start in after a connection is established.");
EditHostWinGetStr(gEditRsi.ldir, sizeof(gEditRsi.ldir), 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;
#if 0
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;
#endif
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;
SaveAndReload();
/* Note: newly reallocated array, modified gNumBookmarks */
rsip = SearchBookmarkTable(bmname);
if (rsip == NULL)
rsip = &gBookmarkTable[0];
gCurHostListItem = rsip;
gHilitedHost = BMTINDEX(rsip);
gHostListWinStart = BMTINDEX(rsip) - gHostListPageSize + 1;
if (gHostListWinStart < 0)
gHostListWinStart = 0;
UpdateHostWindows(1);
}
} /* HostWinEdit */
/* Clones an existing site in the host list. */
void HostWinDup(void)
{
BookmarkPtr rsip;
char bmname[128];
if (gCurHostListItem != NULL) {
/* Use the extra slot in the array for the new one. */
rsip = &gBookmarkTable[gNumBookmarks];
*rsip = *gCurHostListItem;
STRNCAT(rsip->bookmarkName, "-copy");
STRNCPY(bmname, rsip->bookmarkName);
gNumBookmarks++;
SaveAndReload();
/* Note: newly reallocated array, modified gNumBookmarks */
rsip = SearchBookmarkTable(bmname);
if (rsip == NULL)
rsip = &gBookmarkTable[0];
gCurHostListItem = rsip;
gHilitedHost = BMTINDEX(rsip);
gHostListWinStart = BMTINDEX(rsip) - gHostListPageSize + 1;
if (gHostListWinStart < 0)
gHostListWinStart = 0;
DrawHostList();
} else {
HostWinMsg("Nothing to duplicate.");
}
DrawHostList();
} /* HostWinDup */
static void
DeleteBookmark(BookmarkPtr bmp)
{
bmp->deleted = 1;
SaveAndReload();
} /* DeleteBookmark */
/* 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 if (newi < gNumBookmarks) {
gCurHostListItem = &gBookmarkTable[newi];
gHilitedHost = newi;
} else {
newi = 0;
gCurHostListItem = &gBookmarkTable[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;
/* Use the extra slot in the array for the new one. */
rsip = &gBookmarkTable[gNumBookmarks];
SetBookmarkDefaults(rsip);
STRNCPY(rsip->bookmarkName, "(untitled)");
STRNCPY(rsip->name, "(Use /ed to edit)");
gNumBookmarks++;
SaveAndReload();
/* Note: newly reallocated array, modified gNumBookmarks */
rsip = &gBookmarkTable[0];
gCurHostListItem = rsip;
gHilitedHost = BMTINDEX(rsip);
gHostListWinStart = BMTINDEX(rsip) - 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(const char *msg)
{
int maxy;
maxy = getmaxy(gHostWin);
DrawStrAt(gHostWin, maxy - 2, 0, msg);
wclrtoeol(gHostWin);
wmove(gHostWin, maxy - 1, 0);
wrefresh(gHostWin);
BEEP(1);
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);
DrawStrAt(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. */
wmove(gHostWin, maxy - 1, 0);
wclrtoeol(gHostWin);
wrefresh(gHostWin);
curs_set(0);
} /* HostWinGetStr */
/*ARGSUSED*/
static void
SigIntHostWin(int UNUSED(sig))
{
LIBNCFTP_USE_VAR(sig);
alarm(0);
#ifdef HAVE_SIGSETJMP
siglongjmp(gHostWinJmp, 1);
#else /* HAVE_SIGSETJMP */
longjmp(gHostWinJmp, 1);
#endif /* HAVE_SIGSETJMP */
} /* SigIntHostWin */
static void
WriteSelectedBMToFile(char *bookmarkName)
{
FILE *fp;
fp = fopen(gBookmarkSelectionFile, "w");
if (fp == NULL)
return;
(void) fprintf(fp, "%s\n", bookmarkName);
(void) fclose(fp);
} /* WriteSelectedBMToFile */
static void
LaunchNcFTP(char *bookmarkName)
{
char *av[8];
EndWin();
av[0] = strdup("ncftp");
av[1] = strdup(bookmarkName);
av[2] = NULL;
#ifdef NCFTPPATH
(void) execv(NCFTPPATH, av);
#else
(void) execvp(av[0], av);
#endif
free(av[0]);
free(av[1]);
} /* LaunchNcFTP */
/* Runs the host editor. Another big use for this is to open sites
* that are in your host list.
*/
int HostWindow(void)
{
int c;
char cmd[256];
volatile BookmarkPtr toOpen;
vsigproc_t si;
int maxy, maxx;
int lmaxy;
si = (sigproc_t) (-1);
if (gWinInit) {
gHostListWin = NULL;
gHostWin = NULL;
gHostWin = newwin(LINES, COLS, 0, 0);
if (gHostWin == NULL)
return (-1);
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
#ifdef HAVE_SIGSETJMP
if (sigsetjmp(gHostWinJmp, 1) == 0) {
#else /* HAVE_SIGSETJMP */
if (setjmp(gHostWinJmp) == 0) {
#endif /* HAVE_SIGSETJMP */
/* Gracefully cleanup the screen if the user ^C's. */
si = NcSignal(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 = &gBookmarkTable[gHilitedHost];
/* Initially, we don't want to connect to any site in
* the host list.
*/
toOpen = NULL;
getmaxyx(gHostWin, maxy, maxx);
WAttr(gHostWin, kBold, 1);
WAddCenteredStr(gHostWin, 0, "NcFTP Bookmark Editor");
WAttr(gHostWin, kBold, 0);
DrawStrAt(gHostWin, 3, 2, "Open selected site: <enter>");
DrawStrAt(gHostWin, 4, 2, "Edit selected site: /ed");
DrawStrAt(gHostWin, 5, 2, "Delete selected site: /del");
DrawStrAt(gHostWin, 6, 2, "Duplicate selected site: /dup");
DrawStrAt(gHostWin, 7, 2, "Add a new site: /new");
DrawStrAt(gHostWin, 9, 2, "Up one: <u>");
DrawStrAt(gHostWin, 10, 2, "Down one: <d>");
DrawStrAt(gHostWin, 11, 2, "Previous page: <p>");
DrawStrAt(gHostWin, 12, 2, "Next page: <n>");
DrawStrAt(gHostWin, 14, 2, "Capital letters selects first");
DrawStrAt(gHostWin, 15, 2, " site starting with the letter.");
DrawStrAt(gHostWin, 17, 2, "Exit the bookmark editor: <x>");
/* Initialize the scrolling host list window. */
if (maxx < 110) {
gHostListWinWide = 0;
gHostListWin = subwin(
gHostWin,
LINES - 7,
40,
3,
COLS - 40 - 2
);
} else {
gHostListWinWide = COLS - 42;
gHostListWin = subwin(
gHostWin,
LINES - 7,
gHostListWinWide,
3,
38
);
}
if (gHostListWin == NULL)
return (-1);
lmaxy = getmaxy(gHostListWin);
gHostListPageSize = lmaxy;
DrawHostList();
wmove(gHostWin, maxy - 1, 0);
UpdateHostWindows(1);
for (;;) {
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 */
goto enter;
case 13: /* ^M == carriage return */
goto enter;
#ifdef KEY_ENTER
case KEY_ENTER:
Trace(1, " [0x%04X, %s]\n", c, "ENTER");
#endif
enter:
if (gCurHostListItem == NULL)
HostWinMsg("Nothing to open. Try 'open sitename' from the main screen.");
else {
toOpen = (BookmarkPtr) gCurHostListItem;
goto done;
}
break;
case kControl_L:
UpdateHostWindows(1);
break;
case 'u':
case 'k': /* vi up key */
case 'h': /* vi left key */
HostListLineUp();
break;
#ifdef KEY_UP
case KEY_UP:
Trace(1, " [0x%04X, %s]\n", c, "UP");
HostListLineUp();
break;
#endif
#ifdef KEY_LEFT
case KEY_LEFT:
Trace(1, " [0x%04X, %s]\n", c, "LEFT");
HostListLineUp();
break;
#endif
case 'd':
case 'j': /* vi down key */
case 'l': /* vi right key */
HostListLineDown();
break;
#ifdef KEY_DOWN
case KEY_DOWN:
Trace(1, " [0x%04X, %s]\n", c, "DOWN");
HostListLineDown();
break;
#endif
#ifdef KEY_RIGHT
case KEY_RIGHT:
Trace(1, " [0x%04X, %s]\n", c, "RIGHT");
HostListLineDown();
break;
#endif
case 'p':
HostListPageUp();
break;
#ifdef KEY_PPAGE
case KEY_PPAGE:
Trace(1, " [0x%04X, %s]\n", c, "PPAGE");
HostListPageUp();
break;
#endif
case 'n':
HostListPageDown();
break;
#ifdef KEY_NPAGE
case KEY_NPAGE:
Trace(1, " [0x%04X, %s]\n", c, "NPAGE");
HostListPageDown();
break;
#endif
case 'x':
case 'q':
goto done;
default:
HostWinMsg("Invalid key.");
Trace(1, " [0x%04X, %s]\n", c, "<invalid>");
break;
}
}
}
NcSignal(SIGINT, (FTPSigProc) SIG_IGN);
done:
if (gHostListWin != NULL)
delwin(gHostListWin);
if (gHostWin != NULL)
delwin(gHostWin);
gHostListWin = gHostWin = NULL;
if (si != (sigproc_t) (-1))
NcSignal(SIGINT, si);
if (toOpen != (BookmarkPtr) 0) {
/* If the user selected a site to open, connect to it now. */
if (gStandAlone != 0) {
LaunchNcFTP(toOpen->bookmarkName);
/*NOTREACHED*/
Exit(0);
} else if (gBookmarkSelectionFile != NULL) {
WriteSelectedBMToFile(toOpen->bookmarkName);
}
return (kNoErr);
}
}
return (kNoErr);
} /* HostWindow */
main_void_return_t
main(int argc, const char **argv)
{
int result;
int argi;
gStandAlone = 1;
gBookmarkSelectionFile = NULL;
InitUserInfo();
if (LoadBookmarkTable() < 0) {
exit(7);
}
if (argc > 1) {
/* The following hack is used by NcFTP
* to get the number of columns without
* having to link with curses/termcap.
* This simplifies things since the
* system may or may not have a good
* curses implementation, and we don't
* want to complicate NcFTP itself with
* that.
*/
argi = 1;
if (strcmp(argv[1], "--dimensions") == 0) {
result = PrintDimensions(0);
exit((result == 0) ? 0 : 1);
} else if (strcmp(argv[1], "--dimensions-terse") == 0) {
result = PrintDimensions(1);
exit((result == 0) ? 0 : 1);
} else if (strcmp(argv[1], "--debug") == 0) {
SetDebug(1);
argi++;
}
/* Requested that we were run from ncftp. */
gStandAlone = 0;
if ((argc > argi) && (argv[argi][0] == '/'))
gBookmarkSelectionFile = (const char *) argv[argi];
if (gNumBookmarks < 1)
exit(7);
}
result = FTPInitLibrary(&gLib);
if (result < 0) {
(void) fprintf(stderr, "ncftp: init library error %d (%s).\n", result, FTPStrError(result));
exit(1);
}
result = FTPInitConnectionInfo(&gLib, &gConn, kDefaultFTPBufSize);
if (result < 0) {
(void) fprintf(stderr, "ncftp: init connection info error %d (%s).\n", result, FTPStrError(result));
exit(1);
}
if (gDebug > 0)
OpenTrace();
InitPrefs();
LoadFirewallPrefs(0);
LoadPrefs();
InitWindows();
Trace(1, "Terminal size is %d columns by %d rows.\n", gScreenWidth, gScreenHeight);
HostWindow();
if (gDebug > 0)
CloseTrace();
EndWin();
exit(0);
} /* main */