3 * Copyright (c) 1992-2001 by Mike Gleason.
17 /* How many times they've run this program. */
18 extern int gNumProgramRuns
;
23 /* These correspond to the various timeouts from LibNcFTP. */
24 int gConnTimeout
, gXferTimeout
, gCtrlTimeout
;
26 /* Active or passive FTP? (PORT or PASV?) Or both? */
27 extern int gDataPortMode
, gFwDataPortMode
;
29 /* When the destination file already exists, resume transfer or ask user? */
32 /* "Save a bookmark to this site before closing?" */
35 /* Should we update the bookmark for the user? */
36 int gAutoSaveChangesToExistingBookmarks
;
38 /* "Save your password with the bookmark?" */
41 int gMaySetXtermTitle
;
43 /* Number of seconds between connection attempts. */
46 /* Some messages we only want to bug the user about once, ever. */
47 char gOneTimeMessagesSeen
[256];
49 /* Tune the size of the socket buffer using SO_RCVBUF or SO_SNDBUF? */
52 /* Size of the user log before we trim it. 0 means do not log at all. */
55 /* Use ASCII mode automatically for files with these extensions. */
59 /* Which meter to use. */
60 FTPProgressMeterProc gProgressMeter
;
63 /* Allow us to plug our other products? */
66 /* Do we need to save the prefs, or can we skip it? */
69 extern FTPLibraryInfo gLib
;
70 extern FTPConnectionInfo gConn
;
71 extern char gOurDirectoryPath
[], gUser
[], gVersion
[];
73 PrefOpt gPrefOpts
[] = {
74 { "anonopen", PREFOBSELETE
},
75 { "anonpass", SetAnonPass
, kPrefOptObselete
},
76 { "anon-password", SetAnonPass
, 1 },
77 { "auto-ascii", SetAutoAscii
, 1 },
78 { "auto-resume", SetAutoResume
, 1 },
79 { "autosave-bookmark-changes", SetAutoSaveChangesToExistingBookmarks
, 1 },
80 { "blank-lines", PREFOBSELETE
},
81 { "confirm-close", SetConfirmClose
, 1 },
82 { "connect-timeout", SetConnTimeout
, 1 },
83 { "control-timeout", SetCtrlTimeout
, 1 },
84 { "logsize", SetLogSize
, 1 },
85 { "maxbookmarks", PREFOBSELETE
},
86 { "one-time-messages-seen", SetOneTimeMessages
, 0 },
87 { "pager", SetPager
, 1 },
88 { "passive", SetPassive
, 1 },
89 { "progress-meter", SetProgressMeter
, 1 },
90 { "redial-delay", SetRedialDelay
, 1 },
91 { "remote-msgs", PREFOBSELETE
},
92 { "restore-lcwd", PREFOBSELETE
},
93 { "save-passwords", SetSavePasswords
, 1 },
94 { "show-trailing-space", PREFOBSELETE
},
95 { "show-status-in-xterm-titlebar", SetXtTitle
, 1 },
97 { "so-bufsize", SetSOBufsize
, 1 },
99 { "startup-lcwd", PREFOBSELETE
},
100 { "startup-msgs", PREFOBSELETE
},
101 { "timeout", PREFOBSELETE
},
102 { "total-runs", PREFOBSELETE
},
103 { "total-xfer-hundredths-of-seconds", PREFOBSELETE
},
104 { "total-xfer-kbytes", PREFOBSELETE
},
105 { "trace", PREFOBSELETE
},
106 { "utime", PREFOBSELETE
},
107 { "visual", PREFOBSELETE
},
108 { "xfer-timeout", SetXferTimeout
, 1 },
109 { "yes-i-know-about-NcFTPd", SetNoAds
, 1 },
110 { NULL
, (PrefProc
) 0, kPrefOptInvisible
, },
113 int gNumPrefOpts
= ((int)(sizeof(gPrefOpts
) / sizeof(PrefOpt
)) - 1);
118 SetAnonPass(int UNUSED(t
), const char *const val
, FILE *const fp
)
122 (void) fprintf(fp
, "%s", gLib
.defaultAnonPassword
);
124 (void) STRNCPY(gLib
.defaultAnonPassword
, val
);
131 SetAutoAscii(int UNUSED(t
), const char *const val
, FILE *const fp
)
135 (void) fprintf(fp
, "%s", gAutoAscii
);
137 (void) STRNCPY(gAutoAscii
, val
);
138 if ((gAutoAscii
[0] == '\0') || (ISTREQ(gAutoAscii
, "no")) || (ISTREQ(gAutoAscii
, "off")) || (ISTREQ(gAutoAscii
, "false"))) {
139 gConn
.asciiFilenameExtensions
= NULL
;
141 gConn
.asciiFilenameExtensions
= gAutoAscii
;
149 SetAutoResume(int UNUSED(t
), const char *const val
, FILE *const fp
)
153 (void) fprintf(fp
, "%s", YESNO(gAutoResume
));
155 gAutoResume
= StrToBool(val
);
157 } /* SetAutoResume */
162 SetAutoSaveChangesToExistingBookmarks(int UNUSED(t
), const char *const val
, FILE *const fp
)
166 (void) fprintf(fp
, "%s", YESNO(gAutoSaveChangesToExistingBookmarks
));
168 gAutoSaveChangesToExistingBookmarks
= StrToBool(val
);
170 } /* SetAutoSaveChangesToExistingBookmarks */
175 SetConfirmClose(int UNUSED(t
), const char *const val
, FILE *const fp
)
179 (void) fprintf(fp
, "%s", YESNO(gConfirmClose
));
181 gConfirmClose
= StrToBool(val
);
183 } /* SetConfirmClose */
188 SetConnTimeout(int UNUSED(t
), const char *const val
, FILE *const fp
)
192 (void) fprintf(fp
, "%d", gConnTimeout
);
194 gConn
.connTimeout
= gConnTimeout
= atoi(val
);
196 } /* SetConnTimeout */
201 SetCtrlTimeout(int UNUSED(t
), const char *const val
, FILE *const fp
)
205 (void) fprintf(fp
, "%d", gCtrlTimeout
);
207 gConn
.ctrlTimeout
= gCtrlTimeout
= atoi(val
);
209 } /* SetCtrlTimeout */
214 SetLogSize(int UNUSED(t
), const char *const val
, FILE *const fp
)
218 (void) fprintf(fp
, "%d", gMaxLogSize
);
220 gMaxLogSize
= atoi(val
);
227 SetNoAds(int UNUSED(t
), const char *const val
, FILE *const fp
)
231 (void) fprintf(fp
, "%s", YESNO(gDoNotDisplayAds
));
233 gDoNotDisplayAds
= StrToBool(val
);
240 SetOneTimeMessages(int UNUSED(t
), const char *const val
, FILE *const fp
)
244 (void) fprintf(fp
, "%s", gOneTimeMessagesSeen
);
246 (void) STRNCPY(gOneTimeMessagesSeen
, val
);
248 } /* SetOneTimeMessages */
253 SetPager(int UNUSED(t
), const char *const val
, FILE *const fp
)
257 (void) fprintf(fp
, "%s", gPager
);
259 (void) STRNCPY(gPager
, val
);
266 SetPassive(int UNUSED(t
), const char *const val
, FILE *const fp
)
272 m
= (gFwDataPortMode
>= 0) ? gFwDataPortMode
: gDataPortMode
;
273 if (m
== kSendPortMode
) {
274 (void) fprintf(fp
, "%s", "off");
275 } else if (m
== kPassiveMode
) {
276 (void) fprintf(fp
, "%s", "on");
278 (void) fprintf(fp
, "%s", "optional");
281 if (gFwDataPortMode
>= 0) {
282 gDataPortMode
= gFwDataPortMode
;
285 if (ISTRNEQ(val
, "opt", 3))
286 gDataPortMode
= kFallBackToSendPortMode
;
287 else if (ISTREQ(val
, "on"))
288 gDataPortMode
= kPassiveMode
;
289 else if ((int) isdigit(val
[0]))
290 gDataPortMode
= atoi(val
);
292 gDataPortMode
= kSendPortMode
;
293 gConn
.dataPortMode
= gDataPortMode
;
301 SetProgressMeter(int UNUSED(t
), const char *const val
, FILE *const fp
)
305 if (gProgressMeter
== PrStatBar
) {
306 (void) fprintf(fp
, "%s", "2 (statbar)");
307 } else if (gProgressMeter
== PrPhilBar
) {
308 (void) fprintf(fp
, "%s", "1 (philbar)");
310 (void) fprintf(fp
, "%s", "0 (simple)");
313 if ((val
[0] == '0') || (ISTRNEQ(val
, "simple", 6)))
314 gProgressMeter
= PrSizeAndRateMeter
;
315 else if ((val
[0] == '1') || (ISTRNEQ(val
, "phil", 4)))
316 gProgressMeter
= PrPhilBar
;
318 gProgressMeter
= PrStatBar
;
319 gConn
.progress
= gProgressMeter
;
321 } /* SetProgressMeter */
324 SetProgressMeter(int UNUSED(t
), const char *const UNUSED(val
), FILE *const UNUSED(fp
))
327 LIBNCFTP_USE_VAR(val
);
328 LIBNCFTP_USE_VAR(fp
);
329 } /* SetProgressMeter */
335 SetRedialDelay(int UNUSED(t
), const char *const val
, FILE *const fp
)
341 (void) fprintf(fp
, "%d", gRedialDelay
);
346 gRedialDelay
= atoi(val
);
348 } /* SetRedialDelay */
353 SetSavePasswords(int UNUSED(t
), const char *const val
, FILE *const fp
)
357 if (gSavePasswords
< 0)
358 (void) fprintf(fp
, "%s", "ask");
360 (void) fprintf(fp
, "%s", YESNO(gSavePasswords
));
362 if (ISTREQ(val
, "ask"))
365 gSavePasswords
= StrToBool(val
);
367 } /* SetSavePasswords */
372 SetSOBufsize(int UNUSED(t
), const char *const val
, FILE *const fp
)
376 (void) fprintf(fp
, "%d", gSOBufsize
);
378 (void) fprintf(fp
, "%s", " (use system default)");
380 gConn
.dataSocketRBufSize
= gConn
.dataSocketSBufSize
= gSOBufsize
= atoi(val
);
388 SetXferTimeout(int UNUSED(t
), const char *const val
, FILE *const fp
)
392 (void) fprintf(fp
, "%d", gXferTimeout
);
394 gConn
.xferTimeout
= gXferTimeout
= atoi(val
);
396 } /* SetXferTimeout */
401 SetXtTitle(int UNUSED(t
), const char *const val
, FILE *const fp
)
405 (void) fprintf(fp
, "%s", YESNO(gMaySetXtermTitle
));
407 gMaySetXtermTitle
= StrToBool(val
);
417 PrefOpt
*p
= &gPrefOpts
[t
];
419 (void) printf("%-30s ", p
->varname
);
420 if (p
->proc
!= (PrefProc
) 0)
421 (*p
->proc
)(t
, NULL
, stdout
);
428 /* Modify or display the program's configuration. */
430 Set(const char *const tok1
, const char *const tok2
)
434 if ((tok1
== NULL
) || (ISTREQ(tok1
, "all"))) {
436 for (t
=0; t
<gNumPrefOpts
; t
++) {
437 if (gPrefOpts
[t
].visible
== kPrefOptVisible
)
440 } else if (tok2
== NULL
) {
442 for (t
=0; t
<gNumPrefOpts
; t
++) {
443 if (ISTREQ(tok1
, gPrefOpts
[t
].varname
)) {
444 if (gPrefOpts
[t
].visible
== kPrefOptObselete
) {
445 (void) printf("The \"%s\" option is obselete or not implemented.\n", tok1
);
452 if (t
>= gNumPrefOpts
) {
453 (void) printf("Unknown option \"%s\" -- try \"show all\" to list available options.\n", tok1
);
457 for (t
=0; t
<gNumPrefOpts
; t
++) {
458 if (ISTREQ(tok1
, gPrefOpts
[t
].varname
)) {
459 if (gPrefOpts
[t
].visible
== kPrefOptObselete
) {
460 (void) printf("The \"%s\" option is obselete or not implemented.\n", tok1
);
461 } else if (gPrefOpts
[t
].proc
!= (PrefProc
) 0) {
462 (*gPrefOpts
[t
].proc
)(t
, tok2
, NULL
);
468 if (t
>= gNumPrefOpts
) {
469 (void) printf("Unknown option \"%s\" -- try \"show all\" to list available options.\n", tok1
);
477 HasSeenOneTimeMessage(const char *const msg
)
482 memcpy(buf
, gOneTimeMessagesSeen
, sizeof(buf
));
483 for (a
= buf
; (b
= strtok(a
, ",\n")) != NULL
; a
= NULL
) {
484 if (strcmp(msg
, b
) == 0)
488 } /* HasSeenOneTimeMessage */
494 SetSeenOneTimeMessage(const char *const msg
)
497 if (gOneTimeMessagesSeen
[0] == '\0')
498 STRNCPY(gOneTimeMessagesSeen
, msg
);
500 STRNCAT(gOneTimeMessagesSeen
, ",");
501 STRNCAT(gOneTimeMessagesSeen
, msg
);
503 } /* SetSeenOneTimeMessage */
508 OneTimeMessage(const char *const msg
)
510 if (HasSeenOneTimeMessage(msg
))
512 SetSeenOneTimeMessage(msg
);
514 } /* OneTimeMessage */
520 ProcessPrefsFile(FILE *const fp
)
526 line
[sizeof(line
) - 1] = '\0';
527 while (fgets(line
, sizeof(line
) - 1, fp
) != NULL
) {
528 tok1
= strtok(line
, " =\t\r\n");
529 if ((tok1
== NULL
) || (tok1
[0] == '#'))
531 tok2
= strtok(NULL
, "\r\n");
535 for (t
=0; t
<gNumPrefOpts
; t
++) {
536 if (ISTREQ(tok1
, gPrefOpts
[t
].varname
)) {
537 if (gPrefOpts
[t
].visible
== kPrefOptObselete
) {
538 /* Probably converting an
542 } else if (gPrefOpts
[t
].proc
!= (PrefProc
) 0) {
543 (*gPrefOpts
[t
].proc
)(t
, tok2
, NULL
);
548 } /* ProcessPrefsFile */
553 /* Read the saved configuration settings from a preferences file. */
560 /* As with the firewall preference file, there can be
561 * site-wide preferences and user-specific preferences.
562 * The user pref file is of course kept in the user's
563 * NcFTP home directory.
565 * The way we do this is we first look for a global
566 * preferences file. We then process the user's pref
567 * file, which could override the global prefs. Finally,
568 * we open a "global fixed" prefs file which then
569 * overrides anything the user may have done.
572 fp
= fopen(kGlobalPrefFileName
, FOPEN_READ_TEXT
);
574 /* Opened the global (but user-overridable) prefs file. */
575 ProcessPrefsFile(fp
);
579 if (gOurDirectoryPath
[0] != '\0') {
580 (void) OurDirectoryPath(pathName
, sizeof(pathName
), kPrefFileName
);
582 fp
= fopen(pathName
, FOPEN_READ_TEXT
);
584 /* Try loading the version 2 prefs.
585 * There will be options we no longer recognize, but
586 * we'd like to import the prefs when possible.
589 (void) OurDirectoryPath(pathName
, sizeof(pathName
), kPrefFileNameV2
);
590 fp
= fopen(pathName
, FOPEN_READ_TEXT
);
594 /* Write a new one when we're done. */
597 /* Opened the preferences file. */
598 ProcessPrefsFile(fp
);
603 fp
= fopen(kGlobalFixedPrefFileName
, FOPEN_READ_TEXT
);
605 /* Opened the global (and not overridable) prefs file. */
606 ProcessPrefsFile(fp
);
614 /* Initialize the configuration settings, in case the user does not set them. */
620 /* Set default values. */
622 memset(gOneTimeMessagesSeen
, 0, sizeof(gOneTimeMessagesSeen
));
626 gDataPortMode
= kFallBackToSendPortMode
;
627 gConn
.dataPortMode
= gDataPortMode
;
632 gAutoSaveChangesToExistingBookmarks
= 0;
633 gRedialDelay
= kDefaultRedialDelay
;
634 STRNCPY(gAutoAscii
, "|.txt|.asc|.html|.htm|.css|.xml|.ini|.sh|.pl|.hqx|.cfg|.c|.h|.cpp|.hpp|.bat|.m3u|.pls|");
636 /* PLEASE do not change the default from 0, and please
637 * don't hack out the portion in main.c which displays
638 * a plug every 7th time you run the program. This is
639 * not much to ask for all the work I've put into this
642 gDoNotDisplayAds
= 0;
644 #if (defined(WIN32) || defined(_WINDOWS)) && defined(_CONSOLE)
645 gMaySetXtermTitle
= 1;
647 gMaySetXtermTitle
= 0;
652 gProgressMeter
= PrStatBar
;
655 tok1
= getenv("PAGER");
656 if ((tok1
!= NULL
) && (tok1
[0] != '\0')) {
658 /* I prefer "less", but it doesn't work well here
659 * because it clears the screen after it finishes,
660 * and the default at EOF is to stay in less
661 * instead of exiting.
663 if (strstr(gPager
, "less") != NULL
)
664 (void) STRNCPY(gPager
, "more");
666 (void) STRNCPY(gPager
, tok1
);
668 (void) STRNCPY(gPager
, tok1
);
671 (void) STRNCPY(gPager
, "more");
678 /* After reading the preferences, do some additional initialization. */
682 if (gLib
.defaultAnonPassword
[0] == '\0') {
683 FTPInitializeAnonPassword(&gLib
);
686 if (gFwDataPortMode
>= 0)
687 gConn
.dataPortMode
= gFwDataPortMode
;
688 } /* PostInitPrefs */
693 /* Write the configuration settings to a preferences file. */
703 if (gPrefsDirty
== 0)
704 return; /* Don't need to save -- no changes made. */
706 (void) OurDirectoryPath(pathName
, sizeof(pathName
), kPrefFileName
);
708 (void) sprintf(tName
, "tpref%06u.txt", (unsigned int) getpid());
709 (void) OurDirectoryPath(pathName2
, sizeof(pathName2
), tName
);
711 fp
= fopen(pathName2
, FOPEN_WRITE_TEXT
);
713 perror("could not save preferences file");
715 (void) fprintf(fp
, "%s", "# NcFTP 3 preferences file\n# This file is loaded and overwritten each time NcFTP is run.\n#\n");
716 for (t
=0; t
<gNumPrefOpts
; t
++) {
717 if (gPrefOpts
[t
].visible
!= kPrefOptObselete
) {
718 (void) fprintf(fp
, "%s=", gPrefOpts
[t
].varname
);
719 (*gPrefOpts
[t
].proc
)(t
, NULL
, fp
);
720 (void) fprintf(fp
, "\n");
724 (void) unlink(pathName
);
725 if (rename(pathName2
, pathName
) < 0) {
726 perror("could not finish saving preferences file");
727 (void) unlink(pathName2
);
734 /* This maintains the little counter file that is used by version 3.0
735 * to do things based on how many times the program was run.
738 CheckForNewV3User(void)
747 /* Don't create in root directory. */
748 if (gOurDirectoryPath
[0] != '\0') {
749 (void) OurDirectoryPath(pathName
, sizeof(pathName
), kFirstFileName
);
751 if ((stat(pathName
, &st
) < 0) && (errno
== ENOENT
)) {
755 /* Create a blank one. */
756 fp
= fopen(pathName
, FOPEN_WRITE_TEXT
);
759 (void) fprintf(fp
, "# NcFTP uses this file to mark that you have run it before, and that you do not\n# need any special first-time instructions or setup.\n#\nruns=%d\n", gNumProgramRuns
);
762 fp
= fopen(pathName
, FOPEN_READ_TEXT
);
764 while (fgets(line
, sizeof(line
) - 1, fp
) != NULL
) {
765 if (strncmp(line
, "runs=", 5) == 0) {
766 (void) sscanf(line
+ 5, "%d",
774 /* Increment the count of program runs. */
776 if (gNumProgramRuns
== 1)
779 /* Race condition between other ncftp processes.
780 * This isn't a big deal because this counter isn't
784 fp
= fopen(pathName
, FOPEN_WRITE_TEXT
);
786 (void) fprintf(fp
, "# NcFTP uses this file to mark that you have run it before, and that you do not\n# need any special first-time instructions or setup.\n#\nruns=%d\n", gNumProgramRuns
);
791 } /* CheckForNewV3User */