- Rearrange reactos.dff according to rosapps rearrange.
[reactos.git] / rosapps / applications / net / ncftp / ncftp / pref.c
1 /* pref.c
2 *
3 * Copyright (c) 1992-2001 by Mike Gleason.
4 * All rights reserved.
5 *
6 */
7
8 #include "syshdrs.h"
9
10 #ifdef ncftp
11 #include "progress.h"
12 #endif
13
14 #include "pref.h"
15 #include "util.h"
16
17 /* How many times they've run this program. */
18 extern int gNumProgramRuns;
19
20 /* Their $PAGER. */
21 char gPager[128];
22
23 /* These correspond to the various timeouts from LibNcFTP. */
24 int gConnTimeout, gXferTimeout, gCtrlTimeout;
25
26 /* Active or passive FTP? (PORT or PASV?) Or both? */
27 extern int gDataPortMode, gFwDataPortMode;
28
29 /* When the destination file already exists, resume transfer or ask user? */
30 int gAutoResume;
31
32 /* "Save a bookmark to this site before closing?" */
33 int gConfirmClose;
34
35 /* Should we update the bookmark for the user? */
36 int gAutoSaveChangesToExistingBookmarks;
37
38 /* "Save your password with the bookmark?" */
39 int gSavePasswords;
40
41 int gMaySetXtermTitle;
42
43 /* Number of seconds between connection attempts. */
44 int gRedialDelay;
45
46 /* Some messages we only want to bug the user about once, ever. */
47 char gOneTimeMessagesSeen[256];
48
49 /* Tune the size of the socket buffer using SO_RCVBUF or SO_SNDBUF? */
50 int gSOBufsize;
51
52 /* Size of the user log before we trim it. 0 means do not log at all. */
53 int gMaxLogSize;
54
55 /* Use ASCII mode automatically for files with these extensions. */
56 char gAutoAscii[512];
57
58 #ifdef ncftp
59 /* Which meter to use. */
60 FTPProgressMeterProc gProgressMeter;
61 #endif
62
63 /* Allow us to plug our other products? */
64 int gDoNotDisplayAds;
65
66 /* Do we need to save the prefs, or can we skip it? */
67 int gPrefsDirty = 0;
68
69 extern FTPLibraryInfo gLib;
70 extern FTPConnectionInfo gConn;
71 extern char gOurDirectoryPath[], gUser[], gVersion[];
72
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 },
96 #ifdef SO_RCVBUF
97 { "so-bufsize", SetSOBufsize, 1 },
98 #endif
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, },
111 };
112
113 int gNumPrefOpts = ((int)(sizeof(gPrefOpts) / sizeof(PrefOpt)) - 1);
114
115
116
117 void
118 SetAnonPass(int UNUSED(t), const char *const val, FILE *const fp)
119 {
120 LIBNCFTP_USE_VAR(t);
121 if (fp != NULL) {
122 (void) fprintf(fp, "%s", gLib.defaultAnonPassword);
123 } else {
124 (void) STRNCPY(gLib.defaultAnonPassword, val);
125 }
126 } /* SetAnonPass */
127
128
129
130 void
131 SetAutoAscii(int UNUSED(t), const char *const val, FILE *const fp)
132 {
133 LIBNCFTP_USE_VAR(t);
134 if (fp != NULL) {
135 (void) fprintf(fp, "%s", gAutoAscii);
136 } else {
137 (void) STRNCPY(gAutoAscii, val);
138 if ((gAutoAscii[0] == '\0') || (ISTREQ(gAutoAscii, "no")) || (ISTREQ(gAutoAscii, "off")) || (ISTREQ(gAutoAscii, "false"))) {
139 gConn.asciiFilenameExtensions = NULL;
140 } else {
141 gConn.asciiFilenameExtensions = gAutoAscii;
142 }
143 }
144 } /* SetAutoAscii */
145
146
147
148 void
149 SetAutoResume(int UNUSED(t), const char *const val, FILE *const fp)
150 {
151 LIBNCFTP_USE_VAR(t);
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
162 SetAutoSaveChangesToExistingBookmarks(int UNUSED(t), const char *const val, FILE *const fp)
163 {
164 LIBNCFTP_USE_VAR(t);
165 if (fp != NULL) {
166 (void) fprintf(fp, "%s", YESNO(gAutoSaveChangesToExistingBookmarks));
167 } else {
168 gAutoSaveChangesToExistingBookmarks = StrToBool(val);
169 }
170 } /* SetAutoSaveChangesToExistingBookmarks */
171
172
173
174 void
175 SetConfirmClose(int UNUSED(t), const char *const val, FILE *const fp)
176 {
177 LIBNCFTP_USE_VAR(t);
178 if (fp != NULL) {
179 (void) fprintf(fp, "%s", YESNO(gConfirmClose));
180 } else {
181 gConfirmClose = StrToBool(val);
182 }
183 } /* SetConfirmClose */
184
185
186
187 void
188 SetConnTimeout(int UNUSED(t), const char *const val, FILE *const fp)
189 {
190 LIBNCFTP_USE_VAR(t);
191 if (fp != NULL) {
192 (void) fprintf(fp, "%d", gConnTimeout);
193 } else {
194 gConn.connTimeout = gConnTimeout = atoi(val);
195 }
196 } /* SetConnTimeout */
197
198
199
200 void
201 SetCtrlTimeout(int UNUSED(t), const char *const val, FILE *const fp)
202 {
203 LIBNCFTP_USE_VAR(t);
204 if (fp != NULL) {
205 (void) fprintf(fp, "%d", gCtrlTimeout);
206 } else {
207 gConn.ctrlTimeout = gCtrlTimeout = atoi(val);
208 }
209 } /* SetCtrlTimeout */
210
211
212
213 void
214 SetLogSize(int UNUSED(t), const char *const val, FILE *const fp)
215 {
216 LIBNCFTP_USE_VAR(t);
217 if (fp != NULL) {
218 (void) fprintf(fp, "%d", gMaxLogSize);
219 } else {
220 gMaxLogSize = atoi(val);
221 }
222 } /* SetLogSize */
223
224
225
226 void
227 SetNoAds(int UNUSED(t), const char *const val, FILE *const fp)
228 {
229 LIBNCFTP_USE_VAR(t);
230 if (fp != NULL) {
231 (void) fprintf(fp, "%s", YESNO(gDoNotDisplayAds));
232 } else {
233 gDoNotDisplayAds = StrToBool(val);
234 }
235 } /* SetNoAds */
236
237
238
239 void
240 SetOneTimeMessages(int UNUSED(t), const char *const val, FILE *const fp)
241 {
242 LIBNCFTP_USE_VAR(t);
243 if (fp != NULL) {
244 (void) fprintf(fp, "%s", gOneTimeMessagesSeen);
245 } else {
246 (void) STRNCPY(gOneTimeMessagesSeen, val);
247 }
248 } /* SetOneTimeMessages */
249
250
251
252 void
253 SetPager(int UNUSED(t), const char *const val, FILE *const fp)
254 {
255 LIBNCFTP_USE_VAR(t);
256 if (fp != NULL) {
257 (void) fprintf(fp, "%s", gPager);
258 } else {
259 (void) STRNCPY(gPager, val);
260 }
261 } /* SetPager */
262
263
264
265 void
266 SetPassive(int UNUSED(t), const char *const val, FILE *const fp)
267 {
268 int m;
269
270 LIBNCFTP_USE_VAR(t);
271 if (fp != NULL) {
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");
277 } else {
278 (void) fprintf(fp, "%s", "optional");
279 }
280 } else {
281 if (gFwDataPortMode >= 0) {
282 gDataPortMode = gFwDataPortMode;
283 return;
284 }
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);
291 else
292 gDataPortMode = kSendPortMode;
293 gConn.dataPortMode = gDataPortMode;
294 }
295 } /* SetPassive */
296
297
298
299 #ifdef ncftp
300 void
301 SetProgressMeter(int UNUSED(t), const char *const val, FILE *const fp)
302 {
303 LIBNCFTP_USE_VAR(t);
304 if (fp != NULL) {
305 if (gProgressMeter == PrStatBar) {
306 (void) fprintf(fp, "%s", "2 (statbar)");
307 } else if (gProgressMeter == PrPhilBar) {
308 (void) fprintf(fp, "%s", "1 (philbar)");
309 } else {
310 (void) fprintf(fp, "%s", "0 (simple)");
311 }
312 } else {
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;
317 else
318 gProgressMeter = PrStatBar;
319 gConn.progress = gProgressMeter;
320 }
321 } /* SetProgressMeter */
322 #else
323 void
324 SetProgressMeter(int UNUSED(t), const char *const UNUSED(val), FILE *const UNUSED(fp))
325 {
326 LIBNCFTP_USE_VAR(t);
327 LIBNCFTP_USE_VAR(val);
328 LIBNCFTP_USE_VAR(fp);
329 } /* SetProgressMeter */
330 #endif
331
332
333
334 void
335 SetRedialDelay(int UNUSED(t), const char *const val, FILE *const fp)
336 {
337 int i;
338
339 LIBNCFTP_USE_VAR(t);
340 if (fp != NULL) {
341 (void) fprintf(fp, "%d", gRedialDelay);
342 } else {
343 i = atoi(val);
344 if (i < 10)
345 i = 10;
346 gRedialDelay = atoi(val);
347 }
348 } /* SetRedialDelay */
349
350
351
352 void
353 SetSavePasswords(int UNUSED(t), const char *const val, FILE *const fp)
354 {
355 LIBNCFTP_USE_VAR(t);
356 if (fp != NULL) {
357 if (gSavePasswords < 0)
358 (void) fprintf(fp, "%s", "ask");
359 else
360 (void) fprintf(fp, "%s", YESNO(gSavePasswords));
361 } else {
362 if (ISTREQ(val, "ask"))
363 gSavePasswords = -1;
364 else
365 gSavePasswords = StrToBool(val);
366 }
367 } /* SetSavePasswords */
368
369
370
371 void
372 SetSOBufsize(int UNUSED(t), const char *const val, FILE *const fp)
373 {
374 LIBNCFTP_USE_VAR(t);
375 if (fp != NULL) {
376 (void) fprintf(fp, "%d", gSOBufsize);
377 if (gSOBufsize <= 0)
378 (void) fprintf(fp, "%s", " (use system default)");
379 } else {
380 gConn.dataSocketRBufSize = gConn.dataSocketSBufSize = gSOBufsize = atoi(val);
381 }
382 } /* SetSOBufsize */
383
384
385
386
387 void
388 SetXferTimeout(int UNUSED(t), const char *const val, FILE *const fp)
389 {
390 LIBNCFTP_USE_VAR(t);
391 if (fp != NULL) {
392 (void) fprintf(fp, "%d", gXferTimeout);
393 } else {
394 gConn.xferTimeout = gXferTimeout = atoi(val);
395 }
396 } /* SetXferTimeout */
397
398
399
400 void
401 SetXtTitle(int UNUSED(t), const char *const val, FILE *const fp)
402 {
403 LIBNCFTP_USE_VAR(t);
404 if (fp != NULL) {
405 (void) fprintf(fp, "%s", YESNO(gMaySetXtermTitle));
406 } else {
407 gMaySetXtermTitle = StrToBool(val);
408 }
409 } /* SetXtTitle */
410
411
412
413
414 static void
415 Show1(int t)
416 {
417 PrefOpt *p = &gPrefOpts[t];
418
419 (void) printf("%-30s ", p->varname);
420 if (p->proc != (PrefProc) 0)
421 (*p->proc)(t, NULL, stdout);
422 (void) printf("\n");
423 } /* Show1 */
424
425
426
427
428 /* Modify or display the program's configuration. */
429 void
430 Set(const char *const tok1, const char *const tok2)
431 {
432 int t;
433
434 if ((tok1 == NULL) || (ISTREQ(tok1, "all"))) {
435 /* Show all. */
436 for (t=0; t<gNumPrefOpts; t++) {
437 if (gPrefOpts[t].visible == kPrefOptVisible)
438 Show1(t);
439 }
440 } else if (tok2 == NULL) {
441 /* Show one. */
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);
446 } else {
447 Show1(t);
448 }
449 break;
450 }
451 }
452 if (t >= gNumPrefOpts) {
453 (void) printf("Unknown option \"%s\" -- try \"show all\" to list available options.\n", tok1);
454 }
455 } else {
456 /* Set one. */
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);
463 gPrefsDirty++;
464 }
465 break;
466 }
467 }
468 if (t >= gNumPrefOpts) {
469 (void) printf("Unknown option \"%s\" -- try \"show all\" to list available options.\n", tok1);
470 }
471 }
472 } /* Set */
473
474
475
476 int
477 HasSeenOneTimeMessage(const char *const msg)
478 {
479 char buf[256];
480 char *a, *b;
481
482 memcpy(buf, gOneTimeMessagesSeen, sizeof(buf));
483 for (a = buf; (b = strtok(a, ",\n")) != NULL; a = NULL) {
484 if (strcmp(msg, b) == 0)
485 return (1);
486 }
487 return (0);
488 } /* HasSeenOneTimeMessage */
489
490
491
492
493 void
494 SetSeenOneTimeMessage(const char *const msg)
495 {
496 gPrefsDirty++;
497 if (gOneTimeMessagesSeen[0] == '\0')
498 STRNCPY(gOneTimeMessagesSeen, msg);
499 else {
500 STRNCAT(gOneTimeMessagesSeen, ",");
501 STRNCAT(gOneTimeMessagesSeen, msg);
502 }
503 } /* SetSeenOneTimeMessage */
504
505
506
507 int
508 OneTimeMessage(const char *const msg)
509 {
510 if (HasSeenOneTimeMessage(msg))
511 return (0);
512 SetSeenOneTimeMessage(msg);
513 return (1);
514 } /* OneTimeMessage */
515
516
517
518
519 void
520 ProcessPrefsFile(FILE *const fp)
521 {
522 char line[1024];
523 char *tok1, *tok2;
524 int t;
525
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] == '#'))
530 continue;
531 tok2 = strtok(NULL, "\r\n");
532 if (tok2 == NULL)
533 continue;
534
535 for (t=0; t<gNumPrefOpts; t++) {
536 if (ISTREQ(tok1, gPrefOpts[t].varname)) {
537 if (gPrefOpts[t].visible == kPrefOptObselete) {
538 /* Probably converting an
539 * old 2.4.2 file.
540 */
541 gPrefsDirty++;
542 } else if (gPrefOpts[t].proc != (PrefProc) 0) {
543 (*gPrefOpts[t].proc)(t, tok2, NULL);
544 }
545 }
546 }
547 }
548 } /* ProcessPrefsFile */
549
550
551
552
553 /* Read the saved configuration settings from a preferences file. */
554 void
555 LoadPrefs(void)
556 {
557 FILE *fp;
558 char pathName[256];
559
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.
564 *
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.
570 */
571
572 fp = fopen(kGlobalPrefFileName, FOPEN_READ_TEXT);
573 if (fp != NULL) {
574 /* Opened the global (but user-overridable) prefs file. */
575 ProcessPrefsFile(fp);
576 (void) fclose(fp);
577 }
578
579 if (gOurDirectoryPath[0] != '\0') {
580 (void) OurDirectoryPath(pathName, sizeof(pathName), kPrefFileName);
581
582 fp = fopen(pathName, FOPEN_READ_TEXT);
583 if (fp == NULL) {
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.
587 */
588 gPrefsDirty++;
589 (void) OurDirectoryPath(pathName, sizeof(pathName), kPrefFileNameV2);
590 fp = fopen(pathName, FOPEN_READ_TEXT);
591 }
592
593 if (fp == NULL) {
594 /* Write a new one when we're done. */
595 gPrefsDirty++;
596 } else {
597 /* Opened the preferences file. */
598 ProcessPrefsFile(fp);
599 (void) fclose(fp);
600 }
601 }
602
603 fp = fopen(kGlobalFixedPrefFileName, FOPEN_READ_TEXT);
604 if (fp != NULL) {
605 /* Opened the global (and not overridable) prefs file. */
606 ProcessPrefsFile(fp);
607 (void) fclose(fp);
608 }
609 } /* LoadPrefs */
610
611
612
613
614 /* Initialize the configuration settings, in case the user does not set them. */
615 void
616 InitPrefs(void)
617 {
618 char *tok1;
619
620 /* Set default values. */
621 gPager[0] = '\0';
622 memset(gOneTimeMessagesSeen, 0, sizeof(gOneTimeMessagesSeen));
623 gXferTimeout = 3600;
624 gConnTimeout = 20;
625 gCtrlTimeout = 135;
626 gDataPortMode = kFallBackToSendPortMode;
627 gConn.dataPortMode = gDataPortMode;
628 gAutoResume = 0;
629 gSOBufsize = 0;
630 gMaxLogSize = 10240;
631 gConfirmClose = 1;
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|");
635
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
640 * since 1991.
641 */
642 gDoNotDisplayAds = 0;
643
644 #if (defined(WIN32) || defined(_WINDOWS)) && defined(_CONSOLE)
645 gMaySetXtermTitle = 1;
646 #else
647 gMaySetXtermTitle = 0;
648 #endif
649
650 gSavePasswords = -1;
651 #ifdef ncftp
652 gProgressMeter = PrStatBar;
653 #endif
654
655 tok1 = getenv("PAGER");
656 if ((tok1 != NULL) && (tok1[0] != '\0')) {
657 #ifdef HAVE_STRSTR
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.
662 */
663 if (strstr(gPager, "less") != NULL)
664 (void) STRNCPY(gPager, "more");
665 else
666 (void) STRNCPY(gPager, tok1);
667 #else
668 (void) STRNCPY(gPager, tok1);
669 #endif
670 } else {
671 (void) STRNCPY(gPager, "more");
672 }
673 } /* InitPrefs */
674
675
676
677
678 /* After reading the preferences, do some additional initialization. */
679 void
680 PostInitPrefs(void)
681 {
682 if (gLib.defaultAnonPassword[0] == '\0') {
683 FTPInitializeAnonPassword(&gLib);
684 gPrefsDirty++;
685 }
686 if (gFwDataPortMode >= 0)
687 gConn.dataPortMode = gFwDataPortMode;
688 } /* PostInitPrefs */
689
690
691
692
693 /* Write the configuration settings to a preferences file. */
694 void
695 SavePrefs(void)
696 {
697 char pathName[256];
698 char pathName2[256];
699 char tName[32];
700 int t;
701 FILE *fp;
702
703 if (gPrefsDirty == 0)
704 return; /* Don't need to save -- no changes made. */
705
706 (void) OurDirectoryPath(pathName, sizeof(pathName), kPrefFileName);
707
708 (void) sprintf(tName, "tpref%06u.txt", (unsigned int) getpid());
709 (void) OurDirectoryPath(pathName2, sizeof(pathName2), tName);
710
711 fp = fopen(pathName2, FOPEN_WRITE_TEXT);
712 if (fp == NULL) {
713 perror("could not save preferences file");
714 } else {
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");
721 }
722 }
723 (void) fclose(fp);
724 (void) unlink(pathName);
725 if (rename(pathName2, pathName) < 0) {
726 perror("could not finish saving preferences file");
727 (void) unlink(pathName2);
728 };
729 }
730 } /* SavePrefs */
731
732
733
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.
736 */
737 void
738 CheckForNewV3User(void)
739 {
740 FILE *fp;
741 struct stat st;
742 char pathName[256];
743 char line[256];
744
745 gNumProgramRuns = 0;
746
747 /* Don't create in root directory. */
748 if (gOurDirectoryPath[0] != '\0') {
749 (void) OurDirectoryPath(pathName, sizeof(pathName), kFirstFileName);
750
751 if ((stat(pathName, &st) < 0) && (errno == ENOENT)) {
752 gNumProgramRuns = 1;
753 gPrefsDirty++;
754
755 /* Create a blank one. */
756 fp = fopen(pathName, FOPEN_WRITE_TEXT);
757 if (fp == NULL)
758 return;
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);
760 (void) fclose(fp);
761 } else {
762 fp = fopen(pathName, FOPEN_READ_TEXT);
763 if (fp != NULL) {
764 while (fgets(line, sizeof(line) - 1, fp) != NULL) {
765 if (strncmp(line, "runs=", 5) == 0) {
766 (void) sscanf(line + 5, "%d",
767 &gNumProgramRuns);
768 break;
769 }
770 }
771 (void) fclose(fp);
772 }
773
774 /* Increment the count of program runs. */
775 gNumProgramRuns++;
776 if (gNumProgramRuns == 1)
777 gPrefsDirty++;
778
779 /* Race condition between other ncftp processes.
780 * This isn't a big deal because this counter isn't
781 * critical.
782 */
783
784 fp = fopen(pathName, FOPEN_WRITE_TEXT);
785 if (fp != NULL) {
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);
787 (void) fclose(fp);
788 }
789 }
790 }
791 } /* CheckForNewV3User */