Logo Search packages:      
Sourcecode: ncftp version File versions

bmed.c

/* bookmark editor */

#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 */

Generated by  Doxygen 1.6.0   Back to index