1 /* bmed.c (bookmark editor)
2 *
3 * Copyright (c) 1996-2005 Mike Gleason, NcFTP Software.
4 * All rights reserved.
5 *
6 */
7
8 #include "syshdrs.h"
9 #ifdef PRAGMA_HDRSTOP
10 # pragma hdrstop
11 #endif
12
13 #include "../ncftp/util.h"
14 #include "../ncftp/trace.h"
15 #include "../ncftp/pref.h"
16 #include "../ncftp/bookmark.h"
17 #include "wutil.h"
18 #include "wgets.h"
19 #include "bmed.h"
20
21 /* Are we being run as a regular process, or a
22 * subprocess of ncftp?
23 */
24 int gStandAlone;
25
26 /* This is the full-screen window that pops up when you run the
27 * host editor. Not much is done with it, except display directions
28 * and getting host editor commands.
29 */
30 WINDOW *gHostWin = NULL;
31
32 /* This is a window devoted solely to serve as a scrolling list
33 * of bookmarks.
34 */
35 WINDOW *gHostListWin = NULL;
36
37 int gHostListWinWide;
38
39 /* This is another full-screen window that opens when a user wants
40 * to edit the parameters for a site.
41 */
42 WINDOW *gEditHostWin = NULL;
43
44 /* This is an index into the host list. This indicates the position
45 * in the host list where we draw the current "page" of the host list.
46 */
47 int gHostListWinStart;
48
49 /* This index is the currently selected host. This index must be >=
50 * to gHostListWinStart and less than gHostListWinStart + pageLen - 1,
51 * so that this host will show up in the current page of the host list.
52 */
53 int gHilitedHost;
54
55 /* This is a pointer to the actual information of the currently
56 * selected host.
57 */
58 BookmarkPtr gCurHostListItem;
59
60 /* How many lines compose a "page" in the host list's scrolling window. */
61 int gHostListPageSize;
62
63 /* A flag saying if we need to erase a message after the next input key. */
64 int gNeedToClearMsg = 0;
65
66 /* When we edit gCurHostListItem's stuff, we actually edit a copy of it.
67 * This is so we could restore the information if the user wanted to
68 * abort the changes.
69 */
70 Bookmark gEditRsi;
71
72 #ifdef HAVE_SIGSETJMP
73 sigjmp_buf gHostWinJmp;
74 #else /* HAVE_SIGSETJMP */
75 jmp_buf gHostWinJmp;
76 #endif /* HAVE_SIGSETJMP */
77
78 /* If set to a valid pathname, hitting enter at the host selection
79 * screen will write the name of the bookmark into this file.
80 * This is a cheap form of IPC with a parent NcFTP process.
81 */
82 const char *gBookmarkSelectionFile = NULL;
83
84 /* Needed by prefs. */
85 FTPLibraryInfo gLib;
86 FTPConnectionInfo gConn;
87
88 extern int gWinInit;
89 extern int gScreenWidth;
90 extern int gScreenHeight;
91 extern int gNumBookmarks;
92 extern BookmarkPtr gBookmarkTable;
93 extern int gDebug;
94
95
96
97
AtoIMaybe(int * dst,char * str)98 void AtoIMaybe(int *dst, char *str)
99 {
100 char *cp;
101
102 /* Don't change the value if the user just hit return. */
103 for (cp = str; *cp != '\0'; cp++)
104 if (isdigit((int) *cp))
105 break;
106 if (isdigit((int) *cp))
107 *dst = atoi(str);
108 } /* AtoIMaybe */
109
110
111
112
113
114 /* Draws the screen when we're using the host editor's main screen.
115 * You can can specify whether to draw each character whether it needs
116 * it or not if you like.
117 */
UpdateHostWindows(int uptAll)118 void UpdateHostWindows(int uptAll)
119 {
120 if (uptAll) {
121 DrawHostList();
122 touchwin(gHostListWin);
123 touchwin(gHostWin);
124 }
125 wnoutrefresh(gHostListWin);
126 wnoutrefresh(gHostWin);
127 DOUPDATE(1);
128 } /* UpdateHostWindows */
129
130
131
132 /* This draws the scrolling list of bookmarks, and hilites the currently
133 * selected host.
134 */
DrawHostList(void)135 void DrawHostList(void)
136 {
137 int lastLine, i;
138 BookmarkPtr rsip;
139 char str[256];
140 char url[256];
141 int maxy, maxx;
142 int lmaxy, lmaxx;
143 int begy, begx;
144 char spec[32];
145
146 #ifdef __clang__
147 #pragma clang diagnostic push
148 #pragma clang diagnostic ignored "-Wformat-nonliteral"
149 #endif
150 getmaxyx(gHostListWin, lmaxy, lmaxx);
151 getbegyx(gHostListWin, begy, begx);
152 getmaxyx(gHostWin, maxy, maxx);
153 /* We have a status line saying how many bookmarks there are in
154 * the list. That way the user knows something is supposed to
155 * be there when the host list is totally empty, and also that
156 * there are more bookmarks to look at when the entire host list
157 * doesn't fit in the scroll window.
158 */
159 WAttr(gHostWin, kUnderline, 1);
160 mvwprintw(
161 gHostWin,
162 begy - 1,
163 begx,
164 strcpy(spec, "%s"), /* avoid warnings on BSD */
165 "Number of bookmarks"
166 );
167 WAttr(gHostWin, kUnderline, 0);
168 wprintw(
169 gHostWin,
170 strcpy(spec, ": %3d"),
171 gNumBookmarks
172 );
173
174 if (gHostListWinWide == 0) {
175 sprintf(spec, "%%-16.16s %%-%ds", lmaxx - 17);
176 lastLine = lmaxy + gHostListWinStart;
177 for (i=gHostListWinStart; (i<lastLine) && (i<gNumBookmarks); i++) {
178 rsip = &gBookmarkTable[i];
179 if (rsip == gCurHostListItem)
180 WAttr(gHostListWin, kReverse, 1);
181 sprintf(str, spec, rsip->bookmarkName, rsip->name);
182 str[lmaxx] = '\0';
183 DrawStrAt(gHostListWin, i - gHostListWinStart, 0, str);
184 swclrtoeol(gHostListWin);
185 if (rsip == gCurHostListItem) {
186 WAttr(gHostListWin, kReverse, 0);
187 }
188 }
189 } else {
190 lastLine = lmaxy + gHostListWinStart;
191 for (i=gHostListWinStart; (i<lastLine) && (i<gNumBookmarks); i++) {
192 rsip = &gBookmarkTable[i];
193 if (rsip == gCurHostListItem)
194 WAttr(gHostListWin, kReverse, 1);
195 BookmarkToURL(rsip, url, sizeof(url));
196 sprintf(str, "%-16.16s ", rsip->bookmarkName);
197 STRNCAT(str, url);
198 memset(url, 0, sizeof(url));
199 AbbrevStr(url, str, (size_t) lmaxx, 1);
200 DrawStrAt(gHostListWin, i - gHostListWinStart, 0, url);
201 swclrtoeol(gHostListWin);
202 if (rsip == gCurHostListItem) {
203 WAttr(gHostListWin, kReverse, 0);
204 }
205 }
206 }
207
208
209 /* Add 'vi' style empty-lines. */
210 for ( ; i<lastLine; ++i) {
211 DrawStrAt(gHostListWin, i - gHostListWinStart, 0, "~");
212 swclrtoeol(gHostListWin);
213 }
214 wmove(gHostWin, maxy - 3, 2);
215 sprintf(spec, "%%-%ds", maxx - 4);
216 if (gCurHostListItem == NULL) {
217 str[0] = '\0';
218 } else if (gCurHostListItem->comment[0] == '\0') {
219 memset(str, 0, sizeof(str));
220 if (gHostListWinWide == 0) {
221 BookmarkToURL(gCurHostListItem, url, sizeof(url));
222 AbbrevStr(str, url, (size_t) maxx - 2, 1);
223 }
224 } else {
225 STRNCPY(str, "``");
226 STRNCAT(str, gCurHostListItem->comment);
227 AbbrevStr(str + 2, gCurHostListItem->comment, (size_t) maxx - 8, 1);
228 STRNCAT(str, "''");
229 }
230 wprintw(gHostWin, spec, str);
231 wmove(gHostWin, maxy - 1, 0);
232 UpdateHostWindows(0);
233
234 #ifdef __clang__
235 #pragma clang diagnostic pop
236 #endif
237 } /* DrawHostList */
238
239
240
241 /* This prompts for a key of input when in the main host editor window. */
HostWinGetKey(void)242 int HostWinGetKey(void)
243 {
244 int c;
245 unsigned int uc;
246 int escmode;
247 int maxy;
248
249 maxy = getmaxy(gHostWin);
250 wmove(gHostWin, maxy - 1, 0);
251 for (escmode = 0; ; escmode++) {
252 uc = (unsigned int) wgetch(gHostWin);
253 c = (int) uc;
254 if (uc > 255) {
255 Trace(1, "[0x%04X]\n", c);
256 } else if (isprint(c) && !iscntrl(c)) {
257 Trace(1, "[0x%04X, %c]\n", c, c);
258 } else if (iscntrl(c)) {
259 Trace(1, "[0x%04X, ^%c]\n", c, (c & 31) | ('A' - 1));
260 } else {
261 Trace(1, "[0x%04X]\n", c);
262 }
263
264 /* Some implementations of curses (i.e. Mac OS X)
265 * don't seem to detect the arrow keys on
266 * typical terminal types like "vt100" or "ansi",
267 * so we try and detect them the hard way.
268 */
269 switch (escmode) {
270 case 0:
271 if (uc != 0x001B) {
272 goto gotch;
273 }
274 /* else ESC key (^[) */
275 break;
276 case 1:
277 if ((c != '[') && (c != 'O')) {
278 goto gotch;
279 }
280 /* else ANSI ESC sequence continues */
281 break;
282 case 2:
283 switch (c) {
284 case 'A':
285 case 'a':
286 #ifdef KEY_UP
287 c = KEY_UP;
288 Trace(1, " --> [0x%04X, %s]\n", c, "UP");
289 #else
290 c = 'k'; /* vi UP */
291 Trace(1, " --> [0x%04X, %s]\n", c, "k");
292 #endif
293 break;
294 case 'B':
295 case 'b':
296 #ifdef KEY_DOWN
297 c = KEY_DOWN;
298 Trace(1, " --> [0x%04X, %s]\n", c, "DOWN");
299 #else
300 c = 'j'; /* vi DOWN */
301 Trace(1, " --> [0x%04X, %s]\n", c, "j");
302 #endif
303 break;
304 case 'D':
305 case 'd':
306 #ifdef KEY_LEFT
307 c = KEY_LEFT;
308 Trace(1, " --> [0x%04X, %s]\n", c, "LEFT");
309 #else
310 c = 'h'; /* vi LEFT */
311 Trace(1, " --> [0x%04X, %s]\n", c, "h");
312 #endif
313 break;
314 case 'C':
315 case 'c':
316 #ifdef KEY_RIGHT
317 c = KEY_RIGHT;
318 Trace(1, " --> [0x%04X, %s]\n", c, "RIGHT");
319 #else
320 c = 'l'; /* vi RIGHT */
321 Trace(1, " --> [0x%04X, %s]\n", c, "l");
322 #endif
323 break;
324 }
325 goto gotch;
326 }
327 }
328 gotch:
329 return (c);
330 } /* HostWinGetKey */
331
332
333
334 static
NewHilitedHostIndex(int newIdx)335 void NewHilitedHostIndex(int newIdx)
336 {
337 int oldIdx, lastLine;
338
339 if (gNumBookmarks <= 0) {
340 HostWinMsg(
341 "No bookmarks in the list. Try a /new, or open a site manually to add one.");
342 } else {
343 oldIdx = gHilitedHost;
344 if (gNumBookmarks < gHostListPageSize)
345 lastLine = gHostListWinStart + gNumBookmarks - 1;
346 else
347 lastLine = gHostListWinStart + gHostListPageSize - 1;
348 if (newIdx < gHostListWinStart) {
349 /* Will need to scroll the window up. */
350 if (newIdx < 0) {
351 newIdx = 0;
352 if (oldIdx == newIdx)
353 HostWinMsg("You are at the top of the list.");
354 }
355 gHilitedHost = gHostListWinStart = newIdx;
356 } else if (newIdx > lastLine) {
357 /* Will need to scroll the window down. */
358 if (newIdx > (gNumBookmarks - 1)) {
359 newIdx = gNumBookmarks - 1;
360 if (oldIdx == newIdx)
361 HostWinMsg("You are at the bottom of the list.");
362 }
363 gHilitedHost = newIdx;
364 gHostListWinStart = newIdx - (gHostListPageSize - 1);
365 if (gHostListWinStart < 0)
366 gHostListWinStart = 0;
367 } else {
368 /* Don't need to scroll window, just move pointer. */
369 gHilitedHost = newIdx;
370 }
371 gCurHostListItem = &gBookmarkTable[gHilitedHost];
372 if (oldIdx != newIdx) {
373 DrawHostList();
374 }
375 }
376 } /* NewHilitedHostIndex */
377
378
379
380
381 /* You can zip to a different area of the list without using the arrow
382 * or page scrolling keys. Just type a letter, and the list will scroll
383 * to the first host starting with that letter.
384 */
HostWinZoomTo(int c)385 void HostWinZoomTo(int c)
386 {
387 int i, j;
388
389 if (gNumBookmarks > 0) {
390 if (islower(c))
391 c = toupper(c);
392 for (i=0; i<gNumBookmarks - 1; i++) {
393 j = gBookmarkTable[i].bookmarkName[0];
394 if (islower(j))
395 j = toupper(j);
396 if (j >= c)
397 break;
398 }
399 NewHilitedHostIndex(i);
400 } else {
401 HostWinMsg("No bookmarks to select. Try a /new.");
402 }
403 DrawHostList();
404 } /* HostWinZoomTo */
405
406
407
408
409
HostListLineUp(void)410 void HostListLineUp(void)
411 {
412 NewHilitedHostIndex(gHilitedHost - 1);
413 } /* HostListLineUp */
414
415
416
417
418
HostListLineDown(void)419 void HostListLineDown(void)
420 {
421 NewHilitedHostIndex(gHilitedHost + 1);
422 } /* HostListLineDown */
423
424
425
426
HostListPageUp(void)427 void HostListPageUp(void)
428 {
429 NewHilitedHostIndex(gHilitedHost - gHostListPageSize);
430 } /* HostListPageUp */
431
432
433
434
HostListPageDown(void)435 void HostListPageDown(void)
436 {
437 NewHilitedHostIndex(gHilitedHost + gHostListPageSize);
438 } /* HostListPageDown */
439
440
441
442 /* This marks the start of a section that belongs to the Bookmark Options
443 * window. This window pops up on top of the host editor's main window
444 * when you wish to edit a site's settings. When the user finishes,
445 * we close it and the host editor resumes.
446 */
447
448 /* This displays a message in the Bookmark Options window. */
EditHostWinMsg(const char * msg)449 void EditHostWinMsg(const char *msg)
450 {
451 int maxy;
452
453 maxy = getmaxy(gEditHostWin);
454 DrawStrAt(gEditHostWin, maxy - 2, 0, msg);
455 wclrtoeol(gEditHostWin);
456 wmove(gEditHostWin, maxy - 1, 0);
457 wrefresh(gEditHostWin);
458 } /* EditHostWinMsg */
459
460
461
462
463 /* Prompts for a line of input. */
EditHostWinGetStr(char * dst,size_t size,int canBeEmpty,int canEcho)464 void EditHostWinGetStr(char *dst, size_t size, int canBeEmpty, int canEcho)
465 {
466 char str[256];
467 WGetsParams wgp;
468 int maxy, maxx;
469
470 WAttr(gEditHostWin, kBold, 1);
471 getmaxyx(gEditHostWin, maxy, maxx);
472 DrawStrAt(gEditHostWin, maxy - 1, 0, "> ");
473 WAttr(gEditHostWin, kBold, 0);
474 wclrtoeol(gEditHostWin);
475 wrefresh(gEditHostWin);
476 curs_set(1);
477
478 wgp.w = gEditHostWin;
479 wgp.sy = maxy - 1;
480 wgp.sx = 2;
481 wgp.fieldLen = maxx - 3;
482 wgp.dst = str;
483 wgp.dstSize = size;
484 wgp.useCurrentContents = 0;
485 wgp.echoMode = canEcho ? wg_RegularEcho : wg_BulletEcho;
486 wgp.history = wg_NoHistory;
487 (void) wg_Gets(&wgp);
488 cbreak(); /* wg_Gets turns off cbreak and delay. */
489
490 /* See if the user just hit return. We may not want to overwrite
491 * the dst here, which would make it an empty string.
492 */
493 if ((wgp.changed) || (canBeEmpty == kOkayIfEmpty))
494 strcpy(dst, str);
495
496 wmove(gEditHostWin, maxy - 1, 0);
497 wclrtoeol(gEditHostWin);
498 wrefresh(gEditHostWin);
499 curs_set(0);
500 } /* EditHostWinGetStr */
501
502
503
504
505
506 /* Prompts for an integer of input. */
EditHostWinGetNum(int * dst)507 void EditHostWinGetNum(int *dst)
508 {
509 WGetsParams wgp;
510 char str[256];
511 int maxy, maxx;
512
513 getmaxyx(gEditHostWin, maxy, maxx);
514 WAttr(gEditHostWin, kBold, 1);
515 DrawStrAt(gEditHostWin, maxy - 1, 0, "> ");
516 WAttr(gEditHostWin, kBold, 0);
517 wclrtoeol(gEditHostWin);
518 wrefresh(gEditHostWin);
519 curs_set(1);
520
521 wgp.w = gEditHostWin;
522 wgp.sy = maxy - 1;
523 wgp.sx = 2;
524 wgp.fieldLen = maxx - 3;
525 wgp.dst = str;
526 wgp.dstSize = sizeof(str);
527 wgp.useCurrentContents = 0;
528 wgp.echoMode = wg_RegularEcho;
529 wgp.history = wg_NoHistory;
530 (void) wg_Gets(&wgp);
531 cbreak(); /* wg_Gets turns off cbreak and delay. */
532
533 AtoIMaybe(dst, str);
534 wmove(gEditHostWin, maxy - 1, 0);
535 wclrtoeol(gEditHostWin);
536 wrefresh(gEditHostWin);
537 curs_set(0);
538 } /* EditHostWinGetNum */
539
540
541
542
543 /* This is the meat of the site options window. We can selectively update
544 * portions of the window by using a bitmask with bits set for items
545 * we want to update.
546 */
EditHostWinDraw(int flags,int hilite)547 void EditHostWinDraw(int flags, int hilite)
548 {
549 int maxy, maxx;
550 int i, f;
551 char str[256];
552 char spec[32];
553 const char *cp;
554
555 /* Draw the keys the user can type in reverse text. */
556 WAttr(gEditHostWin, kReverse, 1);
557 f = 5;
558 for (i = kFirstEditWindowItem; i <= kLastEditWindowItem; i++) {
559 if (TESTBIT(flags, i))
560 mvwaddch(gEditHostWin, f + i, 2, 'A' + i);
561 }
562
563 /* The "quit" item is a special item that is offset a line, and
564 * always has the "X" key assigned to it.
565 */
566 i = kQuitEditWindowItem;
567 if (TESTBIT(flags, i))
568 mvwaddch(gEditHostWin, 1 + f + i, 2, 'X');
569 WAttr(gEditHostWin, kReverse, 0);
570
571 /* We can use this to hilite a whole line, to indicate to the
572 * user that a certain item is being edited.
573 */
574 if (hilite)
575 WAttr(gEditHostWin, kReverse, 1);
576 getmaxyx(gEditHostWin, maxy, maxx);
577 sprintf(spec, " %%-26s%%-%ds",
578 maxx - 32);
579
580 /* Now draw the items on a case-by-case basis. */
581 if (TESTBIT(flags, kNicknameEditWindowItem)) {
582 mvwprintw(gEditHostWin, kNicknameEditWindowItem + f, 3, spec,
583 "Bookmark name:",
584 gEditRsi.bookmarkName
585 );
586 wclrtoeol(gEditHostWin);
587 }
588 if (TESTBIT(flags, kHostnameEditWindowItem)) {
589 mvwprintw(gEditHostWin, kHostnameEditWindowItem + f, 3, spec,
590 "Hostname:",
591 gEditRsi.name
592 );
593 wclrtoeol(gEditHostWin);
594 }
595 if (TESTBIT(flags, kUserEditWindowItem)) {
596 mvwprintw(gEditHostWin, kUserEditWindowItem + f, 3, spec,
597 "User:",
598 gEditRsi.user[0] == '\0' ? "anonymous" : gEditRsi.user
599 );
600 wclrtoeol(gEditHostWin);
601 }
602 if (TESTBIT(flags, kPassEditWindowItem)) {
603 if (gEditRsi.pass[0] == '\0' && gEditRsi.user[0] == '\0')
604 STRNCPY(str, gLib.defaultAnonPassword);
605 mvwprintw(gEditHostWin, kPassEditWindowItem + f, 3, spec,
606 "Password:",
607 strcmp(str, gLib.defaultAnonPassword) ? "********" : str
608 );
609 wclrtoeol(gEditHostWin);
610 }
611 if (TESTBIT(flags, kAcctEditWindowItem)) {
612 mvwprintw(gEditHostWin, kAcctEditWindowItem + f, 3, spec,
613 "Account:",
614 gEditRsi.acct[0] == '\0' ? "none" : gEditRsi.acct
615 );
616 wclrtoeol(gEditHostWin);
617 }
618 if (TESTBIT(flags, kDirEditWindowItem)) {
619 if (gEditRsi.dir[0] == '\0')
620 STRNCPY(str, "/");
621 else
622 AbbrevStr(str, gEditRsi.dir, (size_t) maxx - 32, 0);
623 mvwprintw(gEditHostWin, kDirEditWindowItem + f, 3, spec,
624 "Remote Directory:",
625 str
626 );
627 wclrtoeol(gEditHostWin);
628 }
629 if (TESTBIT(flags, kLDirEditWindowItem)) {
630 if (gEditRsi.ldir[0] == '\0')
631 STRNCPY(str, "(current)");
632 else
633 AbbrevStr(str, gEditRsi.ldir, (size_t) maxx - 32, 0);
634 mvwprintw(gEditHostWin, kLDirEditWindowItem + f, 3, spec,
635 "Local Directory:",
636 str
637 );
638 wclrtoeol(gEditHostWin);
639 }
640 if (TESTBIT(flags, kXferTypeEditWindowItem)) {
641 if ((gEditRsi.xferType == 'I') || (gEditRsi.xferType == 'B'))
642 cp = "Binary";
643 else if (gEditRsi.xferType == 'A')
644 cp = "ASCII Text";
645 else
646 cp = "Tenex";
647 mvwprintw(gEditHostWin, kXferTypeEditWindowItem + f, 3, spec,
648 "Transfer type:",
649 cp
650 );
651 wclrtoeol(gEditHostWin);
652 }
653 if (TESTBIT(flags, kPortEditWindowItem)) {
654 sprintf(str, "%u", (gEditRsi.port == 0) ? 21 : (unsigned int) gEditRsi.port);
655 mvwprintw(gEditHostWin, kPortEditWindowItem + f, 3, spec,
656 "Port:",
657 str
658 );
659 wclrtoeol(gEditHostWin);
660 }
661 #if 0
662 if (TESTBIT(flags, kSizeEditWindowItem)) {
663 mvwprintw(gEditHostWin, kSizeEditWindowItem + f, 3, spec,
664 "Has SIZE command:",
665 gEditRsi.hasSIZE ? "Yes" : "No"
666 );
667 wclrtoeol(gEditHostWin);
668 }
669 if (TESTBIT(flags, kMdtmEditWindowItem)) {
670 mvwprintw(gEditHostWin, kMdtmEditWindowItem + f, 3, spec,
671 "Has MDTM command:",
672 gEditRsi.hasMDTM ? "Yes" : "No"
673 );
674 wclrtoeol(gEditHostWin);
675 }
676 if (TESTBIT(flags, kPasvEditWindowItem)) {
677 mvwprintw(gEditHostWin, kPasvEditWindowItem + f, 3, spec,
678 "Can use passive FTP:",
679 gEditRsi.hasPASV ? "Yes" : "No"
680 );
681 wclrtoeol(gEditHostWin);
682 }
683 if (TESTBIT(flags, kOSEditWindowItem)) {
684 mvwprintw(gEditHostWin, kOSEditWindowItem + f, 3, spec,
685 "Operating System:",
686 (gEditRsi.isUnix == 1) ? "UNIX" : "Non-UNIX"
687 );
688 wclrtoeol(gEditHostWin);
689 }
690 #endif
691 if (TESTBIT(flags, kCommentEditWindowItem)) {
692 if (gEditRsi.comment[0] == '\0')
693 STRNCPY(str, "(none)");
694 else
695 AbbrevStr(str, gEditRsi.comment, (size_t) maxx - 32, 0);
696 mvwprintw(gEditHostWin, kCommentEditWindowItem + f, 3, spec,
697 "Comment:",
698 str
699 );
700 wclrtoeol(gEditHostWin);
701 }
702 if (TESTBIT(flags, kQuitEditWindowItem)) {
703 mvwprintw(gEditHostWin, kQuitEditWindowItem + f + 1, 3, spec,
704 "(Done editing)",
705 ""
706 );
707 wclrtoeol(gEditHostWin);
708 }
709
710 if (hilite)
711 WAttr(gEditHostWin, kReverse, 0);
712
713 wmove(gEditHostWin, maxy - 1, 0);
714 wrefresh(gEditHostWin);
715 } /* EditHostWinDraw */
716
717
718
719 /* The user can hit space to change the transfer type. For these toggle
720 * functions we do an update each time so the user can see the change
721 * immediately.
722 */
ToggleXferType(void)723 void ToggleXferType(void)
724 {
725 int c;
726
727 for (;;) {
728 c = wgetch(gEditHostWin);
729 if ((c == 'x') || (c == 10) || (c == 13)
730 #ifdef KEY_ENTER
731 || (c == KEY_ENTER)
732 #endif
733 )
734 break;
735 else if (isspace(c)) {
736 if (gEditRsi.xferType == 'A')
737 gEditRsi.xferType = 'I';
738 else if ((gEditRsi.xferType == 'B') || (gEditRsi.xferType == 'I'))
739 gEditRsi.xferType = 'T';
740 else
741 gEditRsi.xferType = 'A';
742 EditHostWinDraw(BIT(kXferTypeEditWindowItem), kHilite);
743 }
744 }
745 } /* ToggleXferType */
746
747
748
749
EditWinToggle(int * val,int bitNum,int min,int max)750 void EditWinToggle(int *val, int bitNum, int min, int max)
751 {
752 int c;
753
754 for (;;) {
755 c = wgetch(gEditHostWin);
756 if ((c == 'x') || (c == 10) || (c == 13)
757 #ifdef KEY_ENTER
758 || (c == KEY_ENTER)
759 #endif
760 )
761 break;
762 else if (isspace(c)) {
763 *val = *val + 1;
764 if (*val > max)
765 *val = min;
766 EditHostWinDraw(BIT(bitNum), kHilite);
767 }
768 }
769 } /* EditWinToggle */
770
771
772
773
774 static void
SaveAndReload(void)775 SaveAndReload(void)
776 {
777 SaveBookmarkTable();
778 if (LoadBookmarkTable() < 0) {
779 fprintf(stderr, "Suddenly unable to re-load bookmarks.");
780 Exit(1);
781 }
782 } /* SaveAndReload */
783
784
785
786 /* This opens and handles the site options window. */
HostWinEdit(void)787 void HostWinEdit(void)
788 {
789 int c, field;
790 int needUpdate;
791 char bmname[128];
792 BookmarkPtr rsip;
793
794 if (gCurHostListItem != NULL) {
795 gEditHostWin = newwin(LINES, COLS, 0, 0);
796 if (gEditHostWin == NULL)
797 return;
798
799 STRNCPY(bmname, gCurHostListItem->bookmarkName);
800
801 /* Set the clear flag for the first update. */
802 wclear(gEditHostWin);
803
804 /* leaveok(gEditHostWin, TRUE); * Not sure if I like this... */
805 WAttr(gEditHostWin, kBold, 1);
806 WAddCenteredStr(gEditHostWin, 0, "Bookmark Options");
807 WAttr(gEditHostWin, kBold, 0);
808
809 /* We'll be editing a copy of the current host's settings. */
810 gEditRsi = *gCurHostListItem;
811
812 EditHostWinDraw(kAllWindowItems, kNoHilite);
813 field = 1;
814 for (;;) {
815 EditHostWinMsg("Select an item to edit by typing its corresponding letter.");
816 c = wgetch(gEditHostWin);
817 if (islower(c))
818 c = toupper(c);
819 if (!isupper(c))
820 continue;
821 if (c == 'X')
822 break;
823 field = c - 'A';
824 needUpdate = 1;
825
826 /* Hilite the current item to edit. */
827 EditHostWinDraw(BIT(field), kHilite);
828 switch(field) {
829 case kNicknameEditWindowItem:
830 EditHostWinMsg("Type a new bookmark name, or hit <RETURN> to continue.");
831 EditHostWinGetStr(gEditRsi.bookmarkName, sizeof(gEditRsi.bookmarkName), kNotOkayIfEmpty, kGetAndEcho);
832 break;
833
834 case kHostnameEditWindowItem:
835 EditHostWinMsg("Type a new hostname, or hit <RETURN> to continue.");
836 EditHostWinGetStr(gEditRsi.name, sizeof(gEditRsi.name), kNotOkayIfEmpty, kGetAndEcho);
837 gEditRsi.lastIP[0] = '\0'; /* In case it changed. */
838 break;
839
840 case kUserEditWindowItem:
841 EditHostWinMsg("Type a username, or hit <RETURN> to signify anonymous.");
842 EditHostWinGetStr(gEditRsi.user, sizeof(gEditRsi.user), kOkayIfEmpty, kGetAndEcho);
843 break;
844
845 case kPassEditWindowItem:
846 EditHostWinMsg("Type a password, or hit <RETURN> if no password is required.");
847 EditHostWinGetStr(gEditRsi.pass, sizeof(gEditRsi.pass), kOkayIfEmpty, kGetNoEcho);
848 break;
849
850 case kAcctEditWindowItem:
851 EditHostWinMsg("Type an account name, or hit <RETURN> if no account is required.");
852 EditHostWinGetStr(gEditRsi.acct, sizeof(gEditRsi.acct), kOkayIfEmpty, kGetAndEcho);
853 break;
854
855 case kDirEditWindowItem:
856 EditHostWinMsg("Type a remote directory path to start in after a connection is established.");
857 EditHostWinGetStr(gEditRsi.dir, sizeof(gEditRsi.dir), kOkayIfEmpty, kGetAndEcho);
858 break;
859
860 case kLDirEditWindowItem:
861 EditHostWinMsg("Type a local directory path to start in after a connection is established.");
862 EditHostWinGetStr(gEditRsi.ldir, sizeof(gEditRsi.ldir), kOkayIfEmpty, kGetAndEcho);
863 break;
864
865 case kXferTypeEditWindowItem:
866 EditHostWinMsg(kToggleMsg);
867 ToggleXferType();
868 break;
869
870 case kPortEditWindowItem:
871 EditHostWinMsg("Type a port number to use for FTP.");
872 EditHostWinGetNum((int *) &gEditRsi.port);
873 break;
874
875 #if 0
876 case kSizeEditWindowItem:
877 EditHostWinMsg(kToggleMsg);
878 EditWinToggle(&gEditRsi.hasSIZE, field, 0, 1);
879 break;
880
881 case kMdtmEditWindowItem:
882 EditHostWinMsg(kToggleMsg);
883 EditWinToggle(&gEditRsi.hasMDTM, field, 0, 1);
884 break;
885
886 case kPasvEditWindowItem:
887 EditHostWinMsg(kToggleMsg);
888 EditWinToggle(&gEditRsi.hasPASV, field, 0, 1);
889 break;
890
891 case kOSEditWindowItem:
892 EditHostWinMsg(kToggleMsg);
893 EditWinToggle(&gEditRsi.isUnix, field, 0, 1);
894 break;
895 #endif
896
897 case kCommentEditWindowItem:
898 EditHostWinMsg("Enter a line of information to store about this site.");
899 EditHostWinGetStr(gEditRsi.comment, sizeof(gEditRsi.comment), kOkayIfEmpty, kGetAndEcho);
900 break;
901
902 default:
903 needUpdate = 0;
904 break;
905 }
906 if (needUpdate)
907 EditHostWinDraw(BIT(field), kNoHilite);
908 }
909 delwin(gEditHostWin);
910 gEditHostWin = NULL;
911 *gCurHostListItem = gEditRsi;
912
913 SaveAndReload();
914 /* Note: newly reallocated array, modified gNumBookmarks */
915
916 rsip = SearchBookmarkTable(bmname);
917 if (rsip == NULL)
918 rsip = &gBookmarkTable[0];
919 gCurHostListItem = rsip;
920 gHilitedHost = BMTINDEX(rsip);
921 gHostListWinStart = BMTINDEX(rsip) - gHostListPageSize + 1;
922 if (gHostListWinStart < 0)
923 gHostListWinStart = 0;
924 UpdateHostWindows(1);
925 }
926 } /* HostWinEdit */
927
928
929
930 /* Clones an existing site in the host list. */
HostWinDup(void)931 void HostWinDup(void)
932 {
933 BookmarkPtr rsip;
934 char bmname[128];
935
936 if (gCurHostListItem != NULL) {
937 /* Use the extra slot in the array for the new one. */
938 rsip = &gBookmarkTable[gNumBookmarks];
939 *rsip = *gCurHostListItem;
940 STRNCAT(rsip->bookmarkName, "-copy");
941 STRNCPY(bmname, rsip->bookmarkName);
942 gNumBookmarks++;
943 SaveAndReload();
944 /* Note: newly reallocated array, modified gNumBookmarks */
945
946 rsip = SearchBookmarkTable(bmname);
947 if (rsip == NULL)
948 rsip = &gBookmarkTable[0];
949 gCurHostListItem = rsip;
950 gHilitedHost = BMTINDEX(rsip);
951 gHostListWinStart = BMTINDEX(rsip) - gHostListPageSize + 1;
952 if (gHostListWinStart < 0)
953 gHostListWinStart = 0;
954 DrawHostList();
955 } else {
956 HostWinMsg("Nothing to duplicate.");
957 }
958 DrawHostList();
959 } /* HostWinDup */
960
961
962
963
964 static void
DeleteBookmark(BookmarkPtr bmp)965 DeleteBookmark(BookmarkPtr bmp)
966 {
967 bmp->deleted = 1;
968 SaveAndReload();
969 } /* DeleteBookmark */
970
971
972
973
974 /* Removes a site from the host list. */
HostWinDelete(void)975 void HostWinDelete(void)
976 {
977 BookmarkPtr toDelete;
978 int newi;
979
980 if (gCurHostListItem != NULL) {
981 toDelete = gCurHostListItem;
982
983 /* Need to choose a new active host after deletion. */
984 if (gHilitedHost == gNumBookmarks - 1) {
985 if (gNumBookmarks == 1) {
986 newi = -1; /* None left. */
987 } else {
988 /* At last one before delete. */
989 newi = gHilitedHost - 1;
990 }
991 } else {
992 /* Won't need to increment gHilitedHost here, since after deletion,
993 * the next one will move up into this slot.
994 */
995 newi = gHilitedHost;
996 }
997 DeleteBookmark(toDelete);
998 if (newi < 0) {
999 gCurHostListItem = NULL;
1000 } else if (newi < gNumBookmarks) {
1001 gCurHostListItem = &gBookmarkTable[newi];
1002 gHilitedHost = newi;
1003 } else {
1004 newi = 0;
1005 gCurHostListItem = &gBookmarkTable[newi];
1006 gHilitedHost = newi;
1007 }
1008 } else
1009 HostWinMsg("Nothing to delete.");
1010 DrawHostList();
1011 } /* HostWinDelete */
1012
1013
1014
1015
1016 /* Adds a new site to the host list, with default settings in place. */
HostWinNew(void)1017 void HostWinNew(void)
1018 {
1019 BookmarkPtr rsip;
1020
1021 /* Use the extra slot in the array for the new one. */
1022 rsip = &gBookmarkTable[gNumBookmarks];
1023 SetBookmarkDefaults(rsip);
1024 STRNCPY(rsip->bookmarkName, "(untitled)");
1025 STRNCPY(rsip->name, "(Use /ed to edit)");
1026 gNumBookmarks++;
1027 SaveAndReload();
1028 /* Note: newly reallocated array, modified gNumBookmarks */
1029
1030 rsip = &gBookmarkTable[0];
1031 gCurHostListItem = rsip;
1032 gHilitedHost = BMTINDEX(rsip);
1033 gHostListWinStart = BMTINDEX(rsip) - gHostListPageSize + 1;
1034 if (gHostListWinStart < 0)
1035 gHostListWinStart = 0;
1036 DrawHostList();
1037 } /* HostWinNew */
1038
1039
1040
1041
1042 /* This displays a message in the host editor's main window.
1043 * Used mostly for error messages.
1044 */
HostWinMsg(const char * msg)1045 void HostWinMsg(const char *msg)
1046 {
1047 int maxy;
1048
1049 maxy = getmaxy(gHostWin);
1050 DrawStrAt(gHostWin, maxy - 2, 0, msg);
1051 wclrtoeol(gHostWin);
1052 wmove(gHostWin, maxy - 1, 0);
1053 wrefresh(gHostWin);
1054 BEEP(1);
1055 gNeedToClearMsg = 1;
1056 } /* HostWinMsg */
1057
1058
1059
1060
1061 /* Prompts for a line of input. */
HostWinGetStr(char * str,size_t size)1062 void HostWinGetStr(char *str, size_t size)
1063 {
1064 WGetsParams wgp;
1065 int maxy, maxx;
1066
1067 getmaxyx(gHostWin, maxy, maxx);
1068 DrawStrAt(gHostWin, maxy - 1, 0, "/");
1069 wclrtoeol(gHostWin);
1070 wrefresh(gHostWin);
1071 curs_set(1);
1072 wgp.w = gHostWin;
1073 wgp.sy = maxy - 1;
1074 wgp.sx = 1;
1075 wgp.fieldLen = maxx - 1;
1076 wgp.dst = str;
1077 wgp.dstSize = size;
1078 wgp.useCurrentContents = 0;
1079 wgp.echoMode = wg_RegularEcho;
1080 wgp.history = wg_NoHistory;
1081 (void) wg_Gets(&wgp);
1082 cbreak(); /* wg_Gets turns off cbreak and delay. */
1083
1084 wmove(gHostWin, maxy - 1, 0);
1085 wclrtoeol(gHostWin);
1086 wrefresh(gHostWin);
1087 curs_set(0);
1088 } /* HostWinGetStr */
1089
1090
1091
1092
1093 /*ARGSUSED*/
1094 static void
1095 #if (defined(__GNUC__)) && (__GNUC__ >= 2)
1096 __attribute__ ((noreturn))
1097 #endif
SigIntHostWin(int UNUSED (sig))1098 SigIntHostWin(int UNUSED(sig))
1099 {
1100 LIBNCFTP_USE_VAR(sig);
1101 alarm(0);
1102 #ifdef HAVE_SIGSETJMP
1103 siglongjmp(gHostWinJmp, 1);
1104 #else /* HAVE_SIGSETJMP */
1105 longjmp(gHostWinJmp, 1);
1106 #endif /* HAVE_SIGSETJMP */
1107 } /* SigIntHostWin */
1108
1109
1110
1111 static void
WriteSelectedBMToFile(char * bookmarkName)1112 WriteSelectedBMToFile(char *bookmarkName)
1113 {
1114 FILE *fp;
1115
1116 fp = fopen(gBookmarkSelectionFile, "w");
1117 if (fp == NULL)
1118 return;
1119 (void) fprintf(fp, "%s\n", bookmarkName);
1120 (void) fclose(fp);
1121 } /* WriteSelectedBMToFile */
1122
1123
1124
1125 static void
LaunchNcFTP(char * bookmarkName)1126 LaunchNcFTP(char *bookmarkName)
1127 {
1128 char *av[8];
1129
1130 EndWin();
1131
1132 av[0] = strdup("ncftp");
1133 av[1] = strdup(bookmarkName);
1134 av[2] = NULL;
1135
1136 #ifdef NCFTPPATH
1137 (void) execv(NCFTPPATH, av);
1138 #else
1139 (void) execvp(av[0], av);
1140 #endif
1141 free(av[0]);
1142 free(av[1]);
1143 } /* LaunchNcFTP */
1144
1145
1146
1147
1148
1149 /* Runs the host editor. Another big use for this is to open sites
1150 * that are in your host list.
1151 */
HostWindow(void)1152 int HostWindow(void)
1153 {
1154 int c;
1155 char cmd[256];
1156 volatile BookmarkPtr toOpen;
1157 vsigproc_t si;
1158 int maxy, maxx;
1159 int lmaxy;
1160
1161 si = (sigproc_t) (-1);
1162 if (gWinInit) {
1163 gHostListWin = NULL;
1164 gHostWin = NULL;
1165
1166 gHostWin = newwin(LINES, COLS, 0, 0);
1167 if (gHostWin == NULL)
1168 return (-1);
1169
1170 curs_set(0);
1171 cbreak();
1172
1173 /* Set the clear flag for the first update. */
1174 wclear(gHostWin);
1175 keypad(gHostWin, TRUE); /* For arrow keys. */
1176 #ifdef HAVE_NOTIMEOUT
1177 notimeout(gHostWin, TRUE);
1178 #endif
1179
1180 #ifdef HAVE_SIGSETJMP
1181 if (sigsetjmp(gHostWinJmp, 1) == 0) {
1182 #else /* HAVE_SIGSETJMP */
1183 if (setjmp(gHostWinJmp) == 0) {
1184 #endif /* HAVE_SIGSETJMP */
1185 /* Gracefully cleanup the screen if the user ^C's. */
1186 si = NcSignal(SIGINT, SigIntHostWin);
1187
1188 /* Initialize the page start and select a host to be
1189 * the current one.
1190 */
1191 gHostListWinStart = 0;
1192 gHilitedHost = 0;
1193 if (gNumBookmarks == 0)
1194 gCurHostListItem = NULL;
1195 else
1196 gCurHostListItem = &gBookmarkTable[gHilitedHost];
1197
1198 /* Initially, we don't want to connect to any site in
1199 * the host list.
1200 */
1201 toOpen = NULL;
1202
1203 getmaxyx(gHostWin, maxy, maxx);
1204 WAttr(gHostWin, kBold, 1);
1205 WAddCenteredStr(gHostWin, 0, "NcFTP Bookmark Editor");
1206 WAttr(gHostWin, kBold, 0);
1207
1208 DrawStrAt(gHostWin, 3, 2, "Open selected site: <enter>");
1209 DrawStrAt(gHostWin, 4, 2, "Edit selected site: /ed");
1210 DrawStrAt(gHostWin, 5, 2, "Delete selected site: /del");
1211 DrawStrAt(gHostWin, 6, 2, "Duplicate selected site: /dup");
1212 DrawStrAt(gHostWin, 7, 2, "Add a new site: /new");
1213 DrawStrAt(gHostWin, 9, 2, "Up one: <u>");
1214 DrawStrAt(gHostWin, 10, 2, "Down one: <d>");
1215 DrawStrAt(gHostWin, 11, 2, "Previous page: <p>");
1216 DrawStrAt(gHostWin, 12, 2, "Next page: <n>");
1217 DrawStrAt(gHostWin, 14, 2, "Capital letters selects first");
1218 DrawStrAt(gHostWin, 15, 2, " site starting with the letter.");
1219 DrawStrAt(gHostWin, 17, 2, "Exit the bookmark editor: <x>");
1220
1221 /* Initialize the scrolling host list window. */
1222 if (maxx < 110) {
1223 gHostListWinWide = 0;
1224 gHostListWin = subwin(
1225 gHostWin,
1226 LINES - 7,
1227 40,
1228 3,
1229 COLS - 40 - 2
1230 );
1231 } else {
1232 gHostListWinWide = COLS - 42;
1233 gHostListWin = subwin(
1234 gHostWin,
1235 LINES - 7,
1236 gHostListWinWide,
1237 3,
1238 38
1239 );
1240 }
1241
1242 if (gHostListWin == NULL)
1243 return (-1);
1244 lmaxy = getmaxy(gHostListWin);
1245 gHostListPageSize = lmaxy;
1246 DrawHostList();
1247 wmove(gHostWin, maxy - 1, 0);
1248 UpdateHostWindows(1);
1249
1250 for (;;) {
1251 c = HostWinGetKey();
1252 if (gNeedToClearMsg) {
1253 wmove(gHostWin, maxy - 2, 0);
1254 wclrtoeol(gHostWin);
1255 wrefresh(gHostWin);
1256 }
1257 if ((c >= 'A') && (c <= 'Z')) {
1258 /* isupper can coredump if wgetch returns a meta key. */
1259 HostWinZoomTo(c);
1260 } else if (c == '/') {
1261 /* Get an "extended" command. Sort of like vi's
1262 * :colon commands.
1263 */
1264 HostWinGetStr(cmd, sizeof(cmd));
1265
1266 if (ISTREQ(cmd, "ed"))
1267 HostWinEdit();
1268 else if (ISTREQ(cmd, "dup"))
1269 HostWinDup();
1270 else if (ISTREQ(cmd, "del"))
1271 HostWinDelete();
1272 else if (ISTREQ(cmd, "new"))
1273 HostWinNew();
1274 else
1275 HostWinMsg("Invalid bookmark editor command.");
1276 } else switch(c) {
1277 case 10: /* ^J == newline */
1278 goto enter;
1279 case 13: /* ^M == carriage return */
1280 goto enter;
1281 #ifdef KEY_ENTER
1282 case KEY_ENTER:
1283 Trace(1, " [0x%04X, %s]\n", c, "ENTER");
1284 #endif
1285 enter:
1286 if (gCurHostListItem == NULL)
1287 HostWinMsg("Nothing to open. Try 'open sitename' from the main screen.");
1288 else {
1289 toOpen = (BookmarkPtr) gCurHostListItem;
1290 goto done;
1291 }
1292 break;
1293
1294 case kControl_L:
1295 UpdateHostWindows(1);
1296 break;
1297
1298 case 'u':
1299 case 'k': /* vi up key */
1300 case 'h': /* vi left key */
1301 HostListLineUp();
1302 break;
1303 #ifdef KEY_UP
1304 case KEY_UP:
1305 Trace(1, " [0x%04X, %s]\n", c, "UP");
1306 HostListLineUp();
1307 break;
1308 #endif
1309
1310 #ifdef KEY_LEFT
1311 case KEY_LEFT:
1312 Trace(1, " [0x%04X, %s]\n", c, "LEFT");
1313 HostListLineUp();
1314 break;
1315 #endif
1316
1317 case 'd':
1318 case 'j': /* vi down key */
1319 case 'l': /* vi right key */
1320 HostListLineDown();
1321 break;
1322
1323 #ifdef KEY_DOWN
1324 case KEY_DOWN:
1325 Trace(1, " [0x%04X, %s]\n", c, "DOWN");
1326 HostListLineDown();
1327 break;
1328 #endif
1329
1330 #ifdef KEY_RIGHT
1331 case KEY_RIGHT:
1332 Trace(1, " [0x%04X, %s]\n", c, "RIGHT");
1333 HostListLineDown();
1334 break;
1335 #endif
1336
1337 case 'p':
1338 HostListPageUp();
1339 break;
1340
1341 #ifdef KEY_PPAGE
1342 case KEY_PPAGE:
1343 Trace(1, " [0x%04X, %s]\n", c, "PPAGE");
1344 HostListPageUp();
1345 break;
1346 #endif
1347
1348 case 'n':
1349 HostListPageDown();
1350 break;
1351
1352 #ifdef KEY_NPAGE
1353 case KEY_NPAGE:
1354 Trace(1, " [0x%04X, %s]\n", c, "NPAGE");
1355 HostListPageDown();
1356 break;
1357 #endif
1358
1359 case 'x':
1360 case 'q':
1361 goto done;
1362
1363 default:
1364 HostWinMsg("Invalid key.");
1365 Trace(1, " [0x%04X, %s]\n", c, "<invalid>");
1366 break;
1367 }
1368 }
1369 }
1370 NcSignal(SIGINT, (FTPSigProc) SIG_IGN);
1371 done:
1372 if (gHostListWin != NULL)
1373 delwin(gHostListWin);
1374 if (gHostWin != NULL)
1375 delwin(gHostWin);
1376 gHostListWin = gHostWin = NULL;
1377 if (si != (sigproc_t) (-1))
1378 NcSignal(SIGINT, si);
1379 if (toOpen != (BookmarkPtr) 0) {
1380 /* If the user selected a site to open, connect to it now. */
1381 if (gStandAlone != 0) {
1382 LaunchNcFTP(toOpen->bookmarkName);
1383 /*NOTREACHED*/
1384 Exit(0);
1385 } else if (gBookmarkSelectionFile != NULL) {
1386 WriteSelectedBMToFile(toOpen->bookmarkName);
1387 }
1388 return (kNoErr);
1389 }
1390 }
1391 return (kNoErr);
1392 } /* HostWindow */
1393
1394
1395
1396
1397 main_void_return_t
1398 main(int argc, const char **argv)
1399 {
1400 int result;
1401 int argi;
1402
1403 gStandAlone = 1;
1404 gBookmarkSelectionFile = NULL;
1405
1406 InitUserInfo();
1407 if (LoadBookmarkTable() < 0) {
1408 exit(7);
1409 }
1410 if (argc > 1) {
1411 /* The following hack is used by NcFTP
1412 * to get the number of columns without
1413 * having to link with curses/termcap.
1414 * This simplifies things since the
1415 * system may or may not have a good
1416 * curses implementation, and we don't
1417 * want to complicate NcFTP itself with
1418 * that.
1419 */
1420 argi = 1;
1421 if (strcmp(argv[1], "--dimensions") == 0) {
1422 result = PrintDimensions(0);
1423 exit((result == 0) ? 0 : 1);
1424 } else if (strcmp(argv[1], "--dimensions-terse") == 0) {
1425 result = PrintDimensions(1);
1426 exit((result == 0) ? 0 : 1);
1427 } else if (strcmp(argv[1], "--debug") == 0) {
1428 SetDebug(1);
1429 argi++;
1430 }
1431 /* Requested that we were run from ncftp. */
1432 gStandAlone = 0;
1433 if ((argc > argi) && (argv[argi][0] == '/'))
1434 gBookmarkSelectionFile = (const char *) argv[argi];
1435 if (gNumBookmarks < 1)
1436 exit(7);
1437 }
1438
1439 result = FTPInitLibrary(&gLib);
1440 if (result < 0) {
1441 (void) fprintf(stderr, "ncftp: init library error %d (%s).\n", result, FTPStrError(result));
1442 exit(1);
1443 }
1444
1445 result = FTPInitConnectionInfo(&gLib, &gConn, kDefaultFTPBufSize);
1446 if (result < 0) {
1447 (void) fprintf(stderr, "ncftp: init connection info error %d (%s).\n", result, FTPStrError(result));
1448 exit(1);
1449 }
1450
1451 if (gDebug > 0)
1452 OpenTrace();
1453 InitPrefs();
1454 LoadFirewallPrefs(0);
1455 LoadPrefs();
1456
1457 InitWindows();
1458 Trace(1, "Terminal size is %d columns by %d rows.\n", gScreenWidth, gScreenHeight);
1459 HostWindow();
1460 if (gDebug > 0)
1461 CloseTrace();
1462 EndWin();
1463 exit(0);
1464 } /* main */
1465