1 /* pref.c
2 *
3 * Copyright (c) 1992-2016 by Mike Gleason.
4 * All rights reserved.
5 *
6 */
7
8 #include "syshdrs.h"
9 #ifdef PRAGMA_HDRSTOP
10 # pragma hdrstop
11 #endif
12
13 #ifdef ncftp
14 #include "progress.h"
15 #endif
16
17 #include "pref.h"
18 #include "util.h"
19
20 /* How many times they've run this program. */
21 extern int gNumProgramRuns;
22
23 /* Their $PAGER. */
24 char gPager[128];
25
26 /* These correspond to the various timeouts from LibNcFTP. */
27 int gConnTimeout, gXferTimeout, gCtrlTimeout;
28
29 /* Active or passive FTP? (PORT or PASV?) Or both? */
30 extern int gDataPortMode, gFwDataPortMode;
31
32 /* When the destination file already exists, resume transfer or ask user? */
33 int gAutoResume;
34
35 /* "Save a bookmark to this site before closing?" */
36 int gConfirmClose;
37
38 /* Should we update the bookmark for the user? */
39 int gAutoSaveChangesToExistingBookmarks;
40
41 /* "Save your password with the bookmark?" */
42 int gSavePasswords;
43
44 int gMaySetXtermTitle;
45
46 /* Number of seconds between connection attempts. */
47 int gRedialDelay;
48
49 /* Some messages we only want to bug the user about once, ever. */
50 char gOneTimeMessagesSeen[256];
51
52 /* Tune the size of the socket buffer using SO_RCVBUF or SO_SNDBUF? */
53 int gSOBufsize;
54
55 /* Size of the user log before we trim it. 0 means do not log at all. */
56 int gMaxLogSize;
57
58 /* Use ASCII mode automatically for files with these extensions. */
59 char gAutoAscii[512];
60
61 #ifdef ncftp
62 /* Which meter to use. */
63 FTPProgressMeterProc gProgressMeter;
64 #endif
65
66 /* Allow us to plug our other products? */
67 int gDoNotDisplayAds;
68
69 /* Do we need to save the prefs, or can we skip it? */
70 int gPrefsDirty = 0;
71
72 extern FTPLibraryInfo gLib;
73 extern FTPConnectionInfo gConn;
74 extern char gOurDirectoryPath[];
75
76 PrefOpt gPrefOpts[] = {
77 { "anonopen", PREFOBSELETE },
78 { "anonpass", SetAnonPass, kPrefOptObselete },
79 { "anon-password", SetAnonPass, 1 },
80 { "auto-ascii", SetAutoAscii, 1 },
81 { "auto-resume", SetAutoResume, 1 },
82 { "autosave-bookmark-changes", SetAutoSaveChangesToExistingBookmarks, 1 },
83 { "blank-lines", PREFOBSELETE },
84 { "confirm-close", SetConfirmClose, 1 },
85 { "connect-timeout", SetConnTimeout, 1 },
86 { "control-timeout", SetCtrlTimeout, 1 },
87 { "logsize", SetLogSize, 1 },
88 { "maxbookmarks", PREFOBSELETE },
89 { "one-time-messages-seen", SetOneTimeMessages, 0 },
90 { "pager", SetPager, 1 },
91 { "passive", SetPassive, 1 },
92 { "progress-meter", SetProgressMeter, 1 },
93 { "redial-delay", SetRedialDelay, 1 },
94 { "remote-msgs", PREFOBSELETE },
95 { "restore-lcwd", PREFOBSELETE },
96 { "save-passwords", SetSavePasswords, 1 },
97 { "show-trailing-space", PREFOBSELETE },
98 { "show-status-in-xterm-titlebar", SetXtTitle, 1 },
99 #ifdef SO_RCVBUF
100 { "so-bufsize", SetSOBufsize, 1 },
101 #endif
102 { "startup-lcwd", PREFOBSELETE },
103 { "startup-msgs", PREFOBSELETE },
104 { "timeout", PREFOBSELETE },
105 { "total-runs", PREFOBSELETE },
106 { "total-xfer-hundredths-of-seconds", PREFOBSELETE },
107 { "total-xfer-kbytes", PREFOBSELETE },
108 { "trace", PREFOBSELETE },
109 { "utime", PREFOBSELETE },
110 { "visual", PREFOBSELETE },
111 { "xfer-timeout", SetXferTimeout, 1 },
112 { "yes-i-know-about-NcFTPd", SetNoAds, 1 },
113 { NULL, (PrefProc) 0, kPrefOptInvisible, },
114 };
115
116 int gNumPrefOpts = ((int)(sizeof(gPrefOpts) / sizeof(PrefOpt)) - 1);
117
118
119
120 void
SetAnonPass(const char * const val,FILE * const fp)121 SetAnonPass(const char *const val, FILE *const fp)
122 {
123 if (fp != NULL) {
124 (void) fprintf(fp, "%s", gLib.defaultAnonPassword);
125 } else {
126 (void) STRNCPY(gLib.defaultAnonPassword, val);
127 }
128 } /* SetAnonPass */
129
130
131
132 void
SetAutoAscii(const char * const val,FILE * const fp)133 SetAutoAscii(const char *const val, FILE *const fp)
134 {
135 if (fp != NULL) {
136 (void) fprintf(fp, "%s", gAutoAscii);
137 } else {
138 (void) STRNCPY(gAutoAscii, val);
139 if ((gAutoAscii[0] == '\0') || (ISTREQ(gAutoAscii, "no")) || (ISTREQ(gAutoAscii, "off")) || (ISTREQ(gAutoAscii, "false"))) {
140 gConn.asciiFilenameExtensions = NULL;
141 } else {
142 gConn.asciiFilenameExtensions = gAutoAscii;
143 }
144 }
145 } /* SetAutoAscii */
146
147
148
149 void
SetAutoResume(const char * const val,FILE * const fp)150 SetAutoResume(const char *const val, FILE *const fp)
151 {
152 if (fp != NULL) {
153 (void) fprintf(fp, "%s", YESNO(gAutoResume));
154 } else {
155 gAutoResume = StrToBool(val);
156 }
157 } /* SetAutoResume */
158
159
160
161 void
SetAutoSaveChangesToExistingBookmarks(const char * const val,FILE * const fp)162 SetAutoSaveChangesToExistingBookmarks(const char *const val, FILE *const fp)
163 {
164 if (fp != NULL) {
165 (void) fprintf(fp, "%s", YESNO(gAutoSaveChangesToExistingBookmarks));
166 } else {
167 gAutoSaveChangesToExistingBookmarks = StrToBool(val);
168 }
169 } /* SetAutoSaveChangesToExistingBookmarks */
170
171
172
173 void
SetConfirmClose(const char * const val,FILE * const fp)174 SetConfirmClose(const char *const val, FILE *const fp)
175 {
176 if (fp != NULL) {
177 (void) fprintf(fp, "%s", YESNO(gConfirmClose));
178 } else {
179 gConfirmClose = StrToBool(val);
180 }
181 } /* SetConfirmClose */
182
183
184
185 void
SetConnTimeout(const char * const val,FILE * const fp)186 SetConnTimeout(const char *const val, FILE *const fp)
187 {
188 if (fp != NULL) {
189 (void) fprintf(fp, "%d", gConnTimeout);
190 } else {
191 gConn.connTimeout = (unsigned int) atoi(val);
192 gConnTimeout = atoi(val);
193 }
194 } /* SetConnTimeout */
195
196
197
198 void
SetCtrlTimeout(const char * const val,FILE * const fp)199 SetCtrlTimeout(const char *const val, FILE *const fp)
200 {
201 if (fp != NULL) {
202 (void) fprintf(fp, "%d", gCtrlTimeout);
203 } else {
204 gConn.ctrlTimeout = (unsigned int) atoi(val);
205 gCtrlTimeout = atoi(val);
206 }
207 } /* SetCtrlTimeout */
208
209
210
211 void
SetLogSize(const char * const val,FILE * const fp)212 SetLogSize(const char *const val, FILE *const fp)
213 {
214 if (fp != NULL) {
215 (void) fprintf(fp, "%d", gMaxLogSize);
216 } else {
217 gMaxLogSize = atoi(val);
218 }
219 } /* SetLogSize */
220
221
222
223 void
SetNoAds(const char * const val,FILE * const fp)224 SetNoAds(const char *const val, FILE *const fp)
225 {
226 if (fp != NULL) {
227 (void) fprintf(fp, "%s", YESNO(gDoNotDisplayAds));
228 } else {
229 gDoNotDisplayAds = StrToBool(val);
230 }
231 } /* SetNoAds */
232
233
234
235 void
SetOneTimeMessages(const char * const val,FILE * const fp)236 SetOneTimeMessages(const char *const val, FILE *const fp)
237 {
238 if (fp != NULL) {
239 (void) fprintf(fp, "%s", gOneTimeMessagesSeen);
240 } else {
241 (void) STRNCPY(gOneTimeMessagesSeen, val);
242 }
243 } /* SetOneTimeMessages */
244
245
246
247 void
SetPager(const char * const val,FILE * const fp)248 SetPager(const char *const val, FILE *const fp)
249 {
250 if (fp != NULL) {
251 (void) fprintf(fp, "%s", gPager);
252 } else {
253 (void) STRNCPY(gPager, val);
254 }
255 } /* SetPager */
256
257
258
259 void
SetPassive(const char * const val,FILE * const fp)260 SetPassive(const char *const val, FILE *const fp)
261 {
262 int m;
263
264 if (fp != NULL) {
265 m = (gFwDataPortMode >= 0) ? gFwDataPortMode : gDataPortMode;
266 if (m == kSendPortMode) {
267 (void) fprintf(fp, "%s", "off");
268 } else if (m == kPassiveMode) {
269 (void) fprintf(fp, "%s", "on");
270 } else {
271 (void) fprintf(fp, "%s", "optional");
272 }
273 } else {
274 if (gFwDataPortMode >= 0) {
275 gDataPortMode = gFwDataPortMode;
276 return;
277 }
278 if (ISTRNEQ(val, "opt", 3))
279 gDataPortMode = kFallBackToSendPortMode;
280 else if (ISTREQ(val, "on"))
281 gDataPortMode = kPassiveMode;
282 else if (isdigit((int) val[0]))
283 gDataPortMode = atoi(val);
284 else
285 gDataPortMode = kSendPortMode;
286 gConn.dataPortMode = gDataPortMode;
287 }
288 } /* SetPassive */
289
290
291
292 #ifdef ncftp
293 void
SetProgressMeter(const char * const val,FILE * const fp)294 SetProgressMeter(const char *const val, FILE *const fp)
295 {
296 if (fp != NULL) {
297 if (gProgressMeter == PrStatBar) {
298 (void) fprintf(fp, "%s", "2 (statbar)");
299 } else if (gProgressMeter == PrPhilBar) {
300 (void) fprintf(fp, "%s", "1 (philbar)");
301 } else {
302 (void) fprintf(fp, "%s", "0 (simple)");
303 }
304 } else {
305 if ((val[0] == '0') || (ISTRNEQ(val, "simple", 6)))
306 gProgressMeter = PrSizeAndRateMeter;
307 else if ((val[0] == '1') || (ISTRNEQ(val, "phil", 4)))
308 gProgressMeter = PrPhilBar;
309 else
310 gProgressMeter = PrStatBar;
311 gConn.progress = gProgressMeter;
312 }
313 } /* SetProgressMeter */
314 #else
315 void
SetProgressMeter(const char * const UNUSED (val),FILE * const UNUSED (fp))316 SetProgressMeter(const char *const UNUSED(val), FILE *const UNUSED(fp))
317 {
318 LIBNCFTP_USE_VAR(val);
319 LIBNCFTP_USE_VAR(fp);
320 } /* SetProgressMeter */
321 #endif
322
323
324
325 void
SetRedialDelay(const char * const val,FILE * const fp)326 SetRedialDelay(const char *const val, FILE *const fp)
327 {
328 int i;
329
330 if (fp != NULL) {
331 (void) fprintf(fp, "%d", gRedialDelay);
332 } else {
333 i = atoi(val);
334 if (i < 10)
335 i = 10;
336 gRedialDelay = atoi(val);
337 }
338 } /* SetRedialDelay */
339
340
341
342 void
SetSavePasswords(const char * const val,FILE * const fp)343 SetSavePasswords(const char *const val, FILE *const fp)
344 {
345 if (fp != NULL) {
346 if (gSavePasswords < 0)
347 (void) fprintf(fp, "%s", "ask");
348 else
349 (void) fprintf(fp, "%s", YESNO(gSavePasswords));
350 } else {
351 if (ISTREQ(val, "ask"))
352 gSavePasswords = -1;
353 else
354 gSavePasswords = StrToBool(val);
355 }
356 } /* SetSavePasswords */
357
358
359
360 void
SetSOBufsize(const char * const val,FILE * const fp)361 SetSOBufsize(const char *const val, FILE *const fp)
362 {
363 if (fp != NULL) {
364 (void) fprintf(fp, "%d", gSOBufsize);
365 if (gSOBufsize <= 0)
366 (void) fprintf(fp, "%s", " (use system default)");
367 } else {
368 gConn.dataSocketRBufSize = gConn.dataSocketSBufSize = (size_t) atoi(val);
369 gSOBufsize = atoi(val);
370 }
371 } /* SetSOBufsize */
372
373
374
375
376 void
SetXferTimeout(const char * const val,FILE * const fp)377 SetXferTimeout(const char *const val, FILE *const fp)
378 {
379 if (fp != NULL) {
380 (void) fprintf(fp, "%d", gXferTimeout);
381 } else {
382 gConn.xferTimeout = (unsigned int) atoi(val);
383 gXferTimeout = atoi(val);
384 }
385 } /* SetXferTimeout */
386
387
388
389 void
SetXtTitle(const char * const val,FILE * const fp)390 SetXtTitle(const char *const val, FILE *const fp)
391 {
392 if (fp != NULL) {
393 (void) fprintf(fp, "%s", YESNO(gMaySetXtermTitle));
394 } else {
395 gMaySetXtermTitle = StrToBool(val);
396 }
397 } /* SetXtTitle */
398
399
400
401
402 static void
Show1(int t)403 Show1(int t)
404 {
405 PrefOpt *p = &gPrefOpts[t];
406
407 (void) printf("%-30s ", p->varname);
408 if (p->proc != (PrefProc) 0)
409 (*p->proc)(NULL, stdout);
410 (void) printf("\n");
411 } /* Show1 */
412
413
414
415
416 /* Modify or display the program's configuration. */
417 void
Set(const char * const tok1,const char * const tok2)418 Set(const char *const tok1, const char *const tok2)
419 {
420 int t;
421
422 if ((tok1 == NULL) || (ISTREQ(tok1, "all"))) {
423 /* Show all. */
424 for (t=0; t<gNumPrefOpts; t++) {
425 if (gPrefOpts[t].visible == kPrefOptVisible)
426 Show1(t);
427 }
428 } else if (tok2 == NULL) {
429 /* Show one. */
430 for (t=0; t<gNumPrefOpts; t++) {
431 if (ISTREQ(tok1, gPrefOpts[t].varname)) {
432 if (gPrefOpts[t].visible == kPrefOptObselete) {
433 (void) printf("The \"%s\" option is obselete or not implemented.\n", tok1);
434 } else {
435 Show1(t);
436 }
437 break;
438 }
439 }
440 if (t >= gNumPrefOpts) {
441 (void) printf("Unknown option \"%s\" -- try \"show all\" to list available options.\n", tok1);
442 }
443 } else {
444 /* Set one. */
445 for (t=0; t<gNumPrefOpts; t++) {
446 if (ISTREQ(tok1, gPrefOpts[t].varname)) {
447 if (gPrefOpts[t].visible == kPrefOptObselete) {
448 (void) printf("The \"%s\" option is obselete or not implemented.\n", tok1);
449 } else if (gPrefOpts[t].proc != (PrefProc) 0) {
450 (*gPrefOpts[t].proc)(tok2, NULL);
451 gPrefsDirty++;
452 }
453 break;
454 }
455 }
456 if (t >= gNumPrefOpts) {
457 (void) printf("Unknown option \"%s\" -- try \"show all\" to list available options.\n", tok1);
458 }
459 }
460 } /* Set */
461
462
463
464 int
HasSeenOneTimeMessage(const char * const msg)465 HasSeenOneTimeMessage(const char *const msg)
466 {
467 char buf[256];
468 char *a, *b;
469
470 memcpy(buf, gOneTimeMessagesSeen, sizeof(buf));
471 for (a = buf; (b = strtok(a, ",\n")) != NULL; a = NULL) {
472 if (strcmp(msg, b) == 0)
473 return (1);
474 }
475 return (0);
476 } /* HasSeenOneTimeMessage */
477
478
479
480
481 void
SetSeenOneTimeMessage(const char * const msg)482 SetSeenOneTimeMessage(const char *const msg)
483 {
484 gPrefsDirty++;
485 if (gOneTimeMessagesSeen[0] == '\0')
486 STRNCPY(gOneTimeMessagesSeen, msg);
487 else {
488 STRNCAT(gOneTimeMessagesSeen, ",");
489 STRNCAT(gOneTimeMessagesSeen, msg);
490 }
491 } /* SetSeenOneTimeMessage */
492
493
494
495 int
OneTimeMessage(const char * const msg)496 OneTimeMessage(const char *const msg)
497 {
498 if (HasSeenOneTimeMessage(msg))
499 return (0);
500 SetSeenOneTimeMessage(msg);
501 return (1);
502 } /* OneTimeMessage */
503
504
505
506
507 void
ProcessPrefsFile(FILE * const fp)508 ProcessPrefsFile(FILE *const fp)
509 {
510 char line[1024];
511 char *tok1, *tok2;
512 int t;
513
514 line[sizeof(line) - 1] = '\0';
515 while (fgets(line, sizeof(line) - 1, fp) != NULL) {
516 tok1 = strtok(line, " =\t\r\n");
517 if ((tok1 == NULL) || (tok1[0] == '#'))
518 continue;
519 tok2 = strtok(NULL, "\r\n");
520 if (tok2 == NULL)
521 continue;
522
523 for (t=0; t<gNumPrefOpts; t++) {
524 if (ISTREQ(tok1, gPrefOpts[t].varname)) {
525 if (gPrefOpts[t].visible == kPrefOptObselete) {
526 /* Probably converting an
527 * old 2.4.2 file.
528 */
529 gPrefsDirty++;
530 } else if (gPrefOpts[t].proc != (PrefProc) 0) {
531 (*gPrefOpts[t].proc)(tok2, NULL);
532 }
533 }
534 }
535 }
536 } /* ProcessPrefsFile */
537
538
539
540
541 /* Read the saved configuration settings from a preferences file. */
542 void
LoadPrefs(void)543 LoadPrefs(void)
544 {
545 FILE *fp;
546 char pathName[256];
547
548 /* As with the firewall preference file, there can be
549 * site-wide preferences and user-specific preferences.
550 * The user pref file is of course kept in the user's
551 * NcFTP home directory.
552 *
553 * The way we do this is we first look for a global
554 * preferences file. We then process the user's pref
555 * file, which could override the global prefs. Finally,
556 * we open a "global fixed" prefs file which then
557 * overrides anything the user may have done.
558 */
559
560 fp = fopen(kGlobalPrefFileName, FOPEN_READ_TEXT);
561 if (fp != NULL) {
562 /* Opened the global (but user-overridable) prefs file. */
563 ProcessPrefsFile(fp);
564 (void) fclose(fp);
565 }
566
567 if (gOurDirectoryPath[0] != '\0') {
568 (void) OurDirectoryPath(pathName, sizeof(pathName), kPrefFileName);
569
570 fp = fopen(pathName, FOPEN_READ_TEXT);
571 if (fp == NULL) {
572 /* Try loading the version 2 prefs.
573 * There will be options we no longer recognize, but
574 * we'd like to import the prefs when possible.
575 */
576 gPrefsDirty++;
577 (void) OurDirectoryPath(pathName, sizeof(pathName), kPrefFileNameV2);
578 fp = fopen(pathName, FOPEN_READ_TEXT);
579 }
580
581 if (fp == NULL) {
582 /* Write a new one when we're done. */
583 gPrefsDirty++;
584 } else {
585 /* Opened the preferences file. */
586 ProcessPrefsFile(fp);
587 (void) fclose(fp);
588 }
589 }
590
591 fp = fopen(kGlobalFixedPrefFileName, FOPEN_READ_TEXT);
592 if (fp != NULL) {
593 /* Opened the global (and not overridable) prefs file. */
594 ProcessPrefsFile(fp);
595 (void) fclose(fp);
596 }
597 } /* LoadPrefs */
598
599
600
601
602 /* Initialize the configuration settings, in case the user does not set them. */
603 void
InitPrefs(void)604 InitPrefs(void)
605 {
606 char *tok1;
607
608 /* Set default values. */
609 gPager[0] = '\0';
610 memset(gOneTimeMessagesSeen, 0, sizeof(gOneTimeMessagesSeen));
611 gXferTimeout = 3600;
612 gConnTimeout = 20;
613 gCtrlTimeout = 135;
614 gDataPortMode = kFallBackToSendPortMode;
615 gConn.dataPortMode = gDataPortMode;
616 gAutoResume = 0;
617 gSOBufsize = 0;
618 gMaxLogSize = 10240;
619 gConfirmClose = 0;
620 gAutoSaveChangesToExistingBookmarks = 0;
621 gRedialDelay = kDefaultRedialDelay;
622 STRNCPY(gAutoAscii, "|.txt|.asc|.html|.htm|.css|.xml|.ini|.pl|.hqx|.cfg|.c|.h|.cpp|.hpp|.bat|.m3u|.pls|");
623
624 /* PLEASE do not change the default from 0, and please
625 * don't hack out the portion in main.c which displays
626 * a plug every 7th time you run the program. This is
627 * not much to ask for all the work I've put into this
628 * since 1991.
629 */
630 gDoNotDisplayAds = 0;
631
632 #if ( (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__) )\
633 && defined(_CONSOLE)
634 gMaySetXtermTitle = 1;
635 #else
636 gMaySetXtermTitle = 0;
637 #endif
638
639 gSavePasswords = -1;
640 #ifdef ncftp
641 gProgressMeter = PrStatBar;
642 #endif
643
644 tok1 = getenv("PAGER");
645 if ((tok1 != NULL) && (tok1[0] != '\0')) {
646 #ifdef HAVE_STRSTR
647 /* I prefer "less", but it doesn't work well here
648 * because it clears the screen after it finishes,
649 * and the default at EOF is to stay in less
650 * instead of exiting.
651 */
652 if (strstr(gPager, "less") != NULL)
653 (void) STRNCPY(gPager, "more");
654 else
655 (void) STRNCPY(gPager, tok1);
656 #else
657 (void) STRNCPY(gPager, tok1);
658 #endif
659 } else {
660 (void) STRNCPY(gPager, "more");
661 }
662 } /* InitPrefs */
663
664
665
666
667 /* After reading the preferences, do some additional initialization. */
668 void
PostInitPrefs(void)669 PostInitPrefs(void)
670 {
671 if (gLib.defaultAnonPassword[0] == '\0') {
672 FTPInitializeAnonPassword(&gLib);
673 gPrefsDirty++;
674 }
675 if (gFwDataPortMode >= 0)
676 gConn.dataPortMode = gFwDataPortMode;
677 } /* PostInitPrefs */
678
679
680
681
682 /* Write the configuration settings to a preferences file. */
683 void
SavePrefs(void)684 SavePrefs(void)
685 {
686 char pathName[256];
687 char pathName2[256];
688 char tName[32];
689 int t;
690 FILE *fp;
691
692 if (gPrefsDirty == 0)
693 return; /* Don't need to save -- no changes made. */
694
695 (void) OurDirectoryPath(pathName, sizeof(pathName), kPrefFileName);
696
697 (void) sprintf(tName, "tpref%06u.txt", (unsigned int) getpid());
698 (void) OurDirectoryPath(pathName2, sizeof(pathName2), tName);
699
700 fp = fopen(pathName2, FOPEN_WRITE_TEXT);
701 if (fp == NULL) {
702 perror("could not save preferences file");
703 } else {
704 (void) fprintf(fp, "%s", "# NcFTP 3 preferences file\n# This file is loaded and overwritten each time NcFTP is run.\n#\n");
705 for (t=0; t<gNumPrefOpts; t++) {
706 if (gPrefOpts[t].visible != kPrefOptObselete) {
707 (void) fprintf(fp, "%s=", gPrefOpts[t].varname);
708 (*gPrefOpts[t].proc)(NULL, fp);
709 (void) fprintf(fp, "\n");
710 }
711 }
712 (void) fclose(fp);
713 (void) unlink(pathName);
714 if (rename(pathName2, pathName) < 0) {
715 perror("could not finish saving preferences file");
716 (void) unlink(pathName2);
717 };
718 }
719 } /* SavePrefs */
720
721
722
723 /* This maintains the little counter file that is used by version 3.0
724 * to do things based on how many times the program was run.
725 */
726 void
CheckForNewV3User(void)727 CheckForNewV3User(void)
728 {
729 FILE *fp;
730 struct stat st;
731 char pathName[256];
732 char line[256];
733
734 gNumProgramRuns = 0;
735
736 /* Don't create in root directory. */
737 if (gOurDirectoryPath[0] != '\0') {
738 (void) OurDirectoryPath(pathName, sizeof(pathName), kFirstFileName);
739
740 if ((stat(pathName, &st) < 0) && (errno == ENOENT)) {
741 gNumProgramRuns = 1;
742 gPrefsDirty++;
743
744 /* Create a blank one. */
745 fp = fopen(pathName, FOPEN_WRITE_TEXT);
746 if (fp == NULL)
747 return;
748 (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);
749 (void) fclose(fp);
750 } else {
751 fp = fopen(pathName, FOPEN_READ_TEXT);
752 if (fp != NULL) {
753 while (fgets(line, sizeof(line) - 1, fp) != NULL) {
754 if (strncmp(line, "runs=", 5) == 0) {
755 (void) sscanf(line + 5, "%d",
756 &gNumProgramRuns);
757 break;
758 }
759 }
760 (void) fclose(fp);
761 }
762
763 /* Increment the count of program runs. */
764 gNumProgramRuns++;
765 if (gNumProgramRuns == 1)
766 gPrefsDirty++;
767
768 /* Race condition between other ncftp processes.
769 * This isn't a big deal because this counter isn't
770 * critical.
771 */
772
773 fp = fopen(pathName, FOPEN_WRITE_TEXT);
774 if (fp != NULL) {
775 (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);
776 (void) fclose(fp);
777 }
778 }
779 }
780 } /* CheckForNewV3User */
781