PageRenderTime 55ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/ncftp-3.2.5/ncftp/bookmark.c

#
C | 904 lines | 658 code | 141 blank | 105 comment | 228 complexity | 22585005550b7987186b99a8544baeb5 MD5 | raw file
Possible License(s): AGPL-3.0
  1. /* bookmark.c
  2. *
  3. * Copyright (c) 1992-2005 by Mike Gleason.
  4. * All rights reserved.
  5. *
  6. */
  7. #include "syshdrs.h"
  8. #ifdef PRAGMA_HDRSTOP
  9. # pragma hdrstop
  10. #endif
  11. #include "bookmark.h"
  12. #include "util.h"
  13. /*
  14. * The ~/.ncftp/bookmarks file contains a list of sites
  15. * the user wants to remember.
  16. *
  17. * Unlike previous versions of the program, we now open/close
  18. * the file every time we need it; That way we can have
  19. * multiple ncftp processes changing the file. There is still
  20. * a possibility that two different processes could be modifying
  21. * the file at the same time.
  22. */
  23. Bookmark gBm;
  24. int gLoadedBm = 0;
  25. int gBookmarkMatchMode = 0;
  26. int gNumBookmarks = 0;
  27. BookmarkPtr gBookmarkTable = NULL;
  28. extern char gOurDirectoryPath[];
  29. /* Converts a pre-loaded Bookmark structure into a RFC 1738
  30. * Uniform Resource Locator.
  31. */
  32. void
  33. BookmarkToURL(BookmarkPtr bmp, char *url, size_t urlsize)
  34. {
  35. char pbuf[32];
  36. /* //<user>:<password>@<host>:<port>/<url-path> */
  37. /* Note that if an absolute path is given,
  38. * you need to escape the first entry, i.e. /pub -> %2Fpub
  39. */
  40. (void) Strncpy(url, "ftp://", urlsize);
  41. if (bmp->user[0] != '\0') {
  42. (void) Strncat(url, bmp->user, urlsize);
  43. if (bmp->pass[0] != '\0') {
  44. (void) Strncat(url, ":", urlsize);
  45. (void) Strncat(url, "PASSWORD", urlsize);
  46. }
  47. (void) Strncat(url, "@", urlsize);
  48. }
  49. (void) Strncat(url, bmp->name, urlsize);
  50. if (bmp->port != 21) {
  51. (void) sprintf(pbuf, ":%u", (unsigned int) bmp->port);
  52. (void) Strncat(url, pbuf, urlsize);
  53. }
  54. if (bmp->dir[0] == '/') {
  55. /* Absolute URL path, must escape first slash. */
  56. (void) Strncat(url, "/%2F", urlsize);
  57. (void) Strncat(url, bmp->dir + 1, urlsize);
  58. (void) Strncat(url, "/", urlsize);
  59. } else if (bmp->dir[0] != '\0') {
  60. (void) Strncat(url, "/", urlsize);
  61. (void) Strncat(url, bmp->dir, urlsize);
  62. (void) Strncat(url, "/", urlsize);
  63. }
  64. } /* BookmarkToURL */
  65. void
  66. SetBookmarkDefaults(BookmarkPtr bmp)
  67. {
  68. (void) memset(bmp, 0, sizeof(Bookmark));
  69. bmp->xferType = 'I';
  70. bmp->xferMode = 'S'; /* Use FTP protocol default as ours too. */
  71. bmp->hasSIZE = kCommandAvailabilityUnknown;
  72. bmp->hasMDTM = kCommandAvailabilityUnknown;
  73. bmp->hasUTIME = kCommandAvailabilityUnknown;
  74. bmp->hasPASV = kCommandAvailabilityUnknown;
  75. bmp->isUnix = 1;
  76. bmp->lastCall = (time_t) 0;
  77. bmp->deleted = 0;
  78. } /* SetBookmarkDefaults */
  79. /* Used when converting hex strings to integral types. */
  80. static int
  81. HexCharToNibble(int c)
  82. {
  83. switch (c) {
  84. case '0':
  85. case '1':
  86. case '2':
  87. case '3':
  88. case '4':
  89. case '5':
  90. case '6':
  91. case '7':
  92. case '8':
  93. case '9':
  94. return (c - '0');
  95. case 'a':
  96. case 'b':
  97. case 'c':
  98. case 'd':
  99. case 'e':
  100. case 'f':
  101. return (c - 'a' + 10);
  102. case 'A':
  103. case 'B':
  104. case 'C':
  105. case 'D':
  106. case 'E':
  107. case 'F':
  108. return (c - 'A' + 10);
  109. }
  110. return (-1); /* Error. */
  111. } /* HexCharToNibble */
  112. /* Fills in a Bookmark structure based off of a line from the NcFTP
  113. * "bookmarks" file.
  114. */
  115. int
  116. ParseHostLine(char *line, BookmarkPtr bmp)
  117. {
  118. char token[128];
  119. char pass[128];
  120. char *s, *d;
  121. char *tokenend;
  122. long L;
  123. int i;
  124. int result;
  125. int n, n1, n2;
  126. SetBookmarkDefaults(bmp);
  127. s = line;
  128. tokenend = token;
  129. tokenend += sizeof(token);
  130. --tokenend;
  131. result = -1;
  132. for (i=1; ; i++) {
  133. if (*s == '\0')
  134. break;
  135. /* Some tokens may need to have a comma in them. Since this is a
  136. * field delimiter, these fields use \, to represent a comma, and
  137. * \\ for a backslash. This chunk gets the next token, paying
  138. * attention to the escaped stuff.
  139. */
  140. for (d = token; *s != '\0'; ) {
  141. if ((*s == '\\') && (s[1] != '\0')) {
  142. if (d < tokenend)
  143. *d++ = s[1];
  144. s += 2;
  145. } else if (*s == ',') {
  146. ++s;
  147. break;
  148. } else if ((*s == '$') && (s[1] != '\0') && (s[2] != '\0')) {
  149. n1 = HexCharToNibble(s[1]);
  150. n2 = HexCharToNibble(s[2]);
  151. if ((n1 >= 0) && (n2 >= 0)) {
  152. n = (n1 << 4) | n2;
  153. if (d < tokenend)
  154. *(unsigned char *)d++ = (unsigned char) n;
  155. }
  156. s += 3;
  157. } else {
  158. if (d < tokenend)
  159. *d++ = *s;
  160. ++s;
  161. }
  162. }
  163. *d = '\0';
  164. switch(i) {
  165. case 1: (void) STRNCPY(bmp->bookmarkName, token); break;
  166. case 2: (void) STRNCPY(bmp->name, token); break;
  167. case 3: (void) STRNCPY(bmp->user, token); break;
  168. case 4: (void) STRNCPY(bmp->pass, token); break;
  169. case 5: (void) STRNCPY(bmp->acct, token); break;
  170. case 6: (void) STRNCPY(bmp->dir, token);
  171. result = 0; /* Good enough to have these fields. */
  172. break;
  173. case 7:
  174. if (token[0] != '\0')
  175. bmp->xferType = (int) token[0];
  176. break;
  177. case 8:
  178. /* Most of the time, we won't have a port. */
  179. if (token[0] == '\0')
  180. bmp->port = (unsigned int) kDefaultFTPPort;
  181. else
  182. bmp->port = (unsigned int) atoi(token);
  183. break;
  184. case 9:
  185. (void) sscanf(token, "%lx", &L);
  186. bmp->lastCall = (time_t) L;
  187. break;
  188. case 10: bmp->hasSIZE = atoi(token); break;
  189. case 11: bmp->hasMDTM = atoi(token); break;
  190. case 12: bmp->hasPASV = atoi(token); break;
  191. case 13: bmp->isUnix = atoi(token);
  192. result = 3; /* Version 3 had all fields to here. */
  193. break;
  194. case 14: (void) STRNCPY(bmp->lastIP, token); break;
  195. case 15: (void) STRNCPY(bmp->comment, token); break;
  196. case 16:
  197. case 17:
  198. case 18:
  199. case 19:
  200. break;
  201. case 20: bmp->xferMode = token[0];
  202. result = 7; /* Version 7 has all fields to here. */
  203. break;
  204. case 21: bmp->hasUTIME = atoi(token);
  205. break;
  206. case 22: (void) STRNCPY(bmp->ldir, token);
  207. result = 8; /* Version 8 has all fields to here. */
  208. break;
  209. default:
  210. result = 99; /* Version >8 ? */
  211. goto done;
  212. }
  213. }
  214. done:
  215. /* Decode password, if it was base-64 encoded. */
  216. if (strncmp(bmp->pass, kPasswordMagic, kPasswordMagicLen) == 0) {
  217. FromBase64(pass, bmp->pass + kPasswordMagicLen, strlen(bmp->pass + kPasswordMagicLen), 1);
  218. (void) STRNCPY(bmp->pass, pass);
  219. }
  220. return (result);
  221. } /* ParseHostLine */
  222. void
  223. CloseBookmarkFile(FILE *fp)
  224. {
  225. if (fp != NULL)
  226. (void) fclose(fp);
  227. } /* CloseBookmarkFile */
  228. int
  229. GetNextBookmark(FILE *fp, Bookmark *bmp)
  230. {
  231. char line[512];
  232. while (FGets(line, sizeof(line), fp) != NULL) {
  233. if (ParseHostLine(line, bmp) >= 0)
  234. return (0);
  235. }
  236. return (-1);
  237. } /* GetNextBookmark */
  238. /* Opens a NcFTP 2.x or 3.x style bookmarks file, and sets the file pointer
  239. * so that it is ready to read the first data line.
  240. */
  241. FILE *
  242. OpenBookmarkFile(int *numBookmarks0)
  243. {
  244. char pathName[256], path2[256];
  245. char line[256];
  246. FILE *fp;
  247. int version;
  248. int numBookmarks;
  249. Bookmark junkbm;
  250. if (gOurDirectoryPath[0] == '\0')
  251. return NULL; /* Don't create in root directory. */
  252. (void) OurDirectoryPath(pathName, sizeof(pathName), kBookmarkFileName);
  253. fp = fopen(pathName, FOPEN_READ_TEXT);
  254. if (fp == NULL) {
  255. /* See if it exists under the old name. */
  256. (void) OurDirectoryPath(path2, sizeof(path2), kOldBookmarkFileName);
  257. if (rename(path2, pathName) == 0) {
  258. /* Rename succeeded, now open it. */
  259. fp = fopen(pathName, FOPEN_READ_TEXT);
  260. if (fp == NULL)
  261. return NULL;
  262. }
  263. return NULL; /* Okay to not have one yet. */
  264. }
  265. #if (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__)
  266. #else
  267. (void) chmod(pathName, 00600);
  268. #endif
  269. if (FGets(line, sizeof(line), fp) == NULL) {
  270. (void) fprintf(stderr, "%s: invalid format.\n", pathName);
  271. (void) fclose(fp);
  272. return NULL;
  273. }
  274. /* Sample line we're looking for:
  275. * "NcFTP bookmark-file version: 8"
  276. */
  277. version = -1;
  278. (void) sscanf(line, "%*s %*s %*s %d", &version);
  279. if (version < kBookmarkMinVersion) {
  280. if (version < 0) {
  281. (void) fprintf(stderr, "%s: invalid format, or bad version.\n", pathName);
  282. (void) fclose(fp);
  283. return NULL;
  284. }
  285. (void) STRNCPY(path2, pathName);
  286. (void) sprintf(line, ".v%d", version);
  287. (void) STRNCAT(path2, line);
  288. (void) rename(pathName, path2);
  289. (void) fprintf(stderr, "%s: old version.\n", pathName);
  290. (void) fclose(fp);
  291. return NULL;
  292. }
  293. /* Sample line we're looking for:
  294. * "Number of entries: 28" or "# # # 1"
  295. */
  296. numBookmarks = -1;
  297. /* At the moment, we can't trust the number stored in the
  298. * file. It's there for future use.
  299. */
  300. if (FGets(line, sizeof(line), fp) == NULL) {
  301. (void) fprintf(stderr, "%s: invalid format.\n", pathName);
  302. (void) fclose(fp);
  303. return NULL;
  304. }
  305. if (numBookmarks0 == (int *) 0) {
  306. /* If the caller doesn't care how many bookmarks are *really*
  307. * in the file, then we can return now.
  308. */
  309. return(fp);
  310. }
  311. /* Otherwise, we have to read through the whole file because
  312. * unfortunately the header line can't be trusted.
  313. */
  314. for (numBookmarks = 0; ; numBookmarks++) {
  315. if (GetNextBookmark(fp, &junkbm) < 0)
  316. break;
  317. }
  318. /* Now we have to re-open and re-position the file.
  319. * We don't use rewind() because it doesn't always work.
  320. * This introduces a race condition, but the bookmark
  321. * functionality wasn't designed to be air-tight.
  322. */
  323. CloseBookmarkFile(fp);
  324. fp = fopen(pathName, FOPEN_READ_TEXT);
  325. if (fp == NULL)
  326. return (NULL);
  327. if (FGets(line, sizeof(line), fp) == NULL) {
  328. (void) fprintf(stderr, "%s: invalid format.\n", pathName);
  329. (void) fclose(fp);
  330. return NULL;
  331. }
  332. if (FGets(line, sizeof(line), fp) == NULL) {
  333. (void) fprintf(stderr, "%s: invalid format.\n", pathName);
  334. (void) fclose(fp);
  335. return NULL;
  336. }
  337. /* NOW we're done. */
  338. *numBookmarks0 = numBookmarks;
  339. return (fp);
  340. } /* OpenBookmarkFile */
  341. /* Looks for a saved bookmark by the abbreviation given. */
  342. int
  343. GetBookmark(const char *const bmabbr, Bookmark *bmp)
  344. {
  345. FILE *fp;
  346. char line[512];
  347. Bookmark byHostName;
  348. Bookmark byHostAbbr;
  349. Bookmark byBmAbbr;
  350. size_t byBmNameFlag = 0;
  351. size_t byBmAbbrFlag = 0;
  352. size_t byHostNameFlag = 0;
  353. size_t byHostAbbrFlag = 0;
  354. int result = -1;
  355. int exactMatch = 0;
  356. size_t bmabbrLen;
  357. char *cp;
  358. char bmabbrtrunc[sizeof(bmp->bookmarkName)];
  359. fp = OpenBookmarkFile(NULL);
  360. if (fp == NULL)
  361. return (-1);
  362. memset(&byHostName, 0, sizeof(Bookmark));
  363. memset(&byHostAbbr, 0, sizeof(Bookmark));
  364. memset(&byBmAbbr, 0, sizeof(Bookmark));
  365. STRNCPY(bmabbrtrunc, bmabbr);
  366. bmabbrLen = strlen(bmabbr);
  367. while (FGets(line, sizeof(line), fp) != NULL) {
  368. if (ParseHostLine(line, bmp) < 0)
  369. continue;
  370. if (ISTREQ(bmp->bookmarkName, bmabbrtrunc)) {
  371. /* Exact match, done. */
  372. byBmNameFlag = bmabbrLen;
  373. exactMatch = 1;
  374. break;
  375. } else if (ISTRNEQ(bmp->bookmarkName, bmabbr, bmabbrLen)) {
  376. /* Remember this one, it matched an abbreviated
  377. * bookmark name.
  378. */
  379. byBmAbbr = *bmp;
  380. byBmAbbrFlag = bmabbrLen;
  381. } else if (ISTREQ(bmp->name, bmabbr)) {
  382. /* Remember this one, it matched a full
  383. * host name.
  384. */
  385. byHostName = *bmp;
  386. byHostNameFlag = bmabbrLen;
  387. } else if ((cp = strchr(bmp->name, '.')) != NULL) {
  388. /* See if it matched part of the hostname. */
  389. if (ISTRNEQ(bmp->name, "ftp", 3)) {
  390. cp = cp + 1;
  391. } else if (ISTRNEQ(bmp->name, "www", 3)) {
  392. cp = cp + 1;
  393. } else {
  394. cp = bmp->name;
  395. }
  396. if (ISTRNEQ(cp, bmabbr, bmabbrLen)) {
  397. /* Remember this one, it matched a full
  398. * host name.
  399. */
  400. byHostAbbr = *bmp;
  401. byHostAbbrFlag = bmabbrLen;
  402. }
  403. }
  404. }
  405. if (gBookmarkMatchMode == 0) {
  406. /* Only use a bookmark when the exact
  407. * bookmark name was used.
  408. */
  409. if (exactMatch != 0) {
  410. result = 0;
  411. }
  412. } else {
  413. /* Pick the best match, if any. */
  414. if (byBmNameFlag != 0) {
  415. /* *bmp is already set. */
  416. result = 0;
  417. } else if (byBmAbbrFlag != 0) {
  418. result = 0;
  419. *bmp = byBmAbbr;
  420. } else if (byHostNameFlag != 0) {
  421. result = 0;
  422. *bmp = byHostName;
  423. } else if (byHostAbbrFlag != 0) {
  424. result = 0;
  425. *bmp = byHostAbbr;
  426. }
  427. }
  428. if (result != 0)
  429. memset(bmp, 0, sizeof(Bookmark));
  430. CloseBookmarkFile(fp);
  431. return (result);
  432. } /* GetBookmark */
  433. static int
  434. BookmarkSortProc(const void *a, const void *b)
  435. {
  436. return (ISTRCMP((*(const Bookmark *)a).bookmarkName, (*(const Bookmark *)b).bookmarkName));
  437. } /* BookmarkSortProc */
  438. static int
  439. BookmarkSearchProc(const void *key, const void *b)
  440. {
  441. return (ISTRCMP((const char *) key, (*(const Bookmark *)b).bookmarkName));
  442. } /* BookmarkSearchProc */
  443. BookmarkPtr
  444. SearchBookmarkTable(const char *key)
  445. {
  446. return ((BookmarkPtr) bsearch(key, gBookmarkTable, (size_t) gNumBookmarks, sizeof(Bookmark), BookmarkSearchProc));
  447. } /* SearchBookmarkTable */
  448. void
  449. SortBookmarks(void)
  450. {
  451. if ((gBookmarkTable == NULL) || (gNumBookmarks < 2))
  452. return;
  453. /* Sorting involves swapping entire Bookmark structures.
  454. * Normally the proper thing to do is to use an array
  455. * of pointers to Bookmarks and sort them, but even
  456. * these days a large bookmark list can be sorted in
  457. * the blink of an eye.
  458. */
  459. qsort(gBookmarkTable, (size_t) gNumBookmarks, sizeof(Bookmark), BookmarkSortProc);
  460. } /* SortBookmarks */
  461. int
  462. LoadBookmarkTable(void)
  463. {
  464. int i, nb;
  465. FILE *infp;
  466. infp = OpenBookmarkFile(&nb);
  467. if (infp == NULL) {
  468. nb = 0;
  469. }
  470. if ((nb != gNumBookmarks) && (gBookmarkTable != NULL)) {
  471. /* Re-loading the table from disk. */
  472. gBookmarkTable = (Bookmark *) realloc(gBookmarkTable, (size_t) (nb + 1) * sizeof(Bookmark));
  473. memset(gBookmarkTable, 0, (nb + 1) * sizeof(Bookmark));
  474. } else {
  475. gBookmarkTable = calloc((size_t) (nb + 1), (size_t) sizeof(Bookmark));
  476. }
  477. if (gBookmarkTable == NULL) {
  478. CloseBookmarkFile(infp);
  479. return (-1);
  480. }
  481. for (i=0; i<nb; i++) {
  482. if (GetNextBookmark(infp, gBookmarkTable + i) < 0) {
  483. break;
  484. }
  485. }
  486. gNumBookmarks = i;
  487. CloseBookmarkFile(infp);
  488. SortBookmarks();
  489. return (0);
  490. } /* LoadBookmarkTable */
  491. /* Some characters need to be escaped so the file is editable and can
  492. * be parsed correctly the next time it is read.
  493. */
  494. static char *
  495. BmEscapeTok(char *dst, size_t dsize, char *src)
  496. {
  497. char *dlim = dst + dsize - 1;
  498. char *dst0 = dst;
  499. int c;
  500. while ((c = *src) != '\0') {
  501. src++;
  502. if ((c == '\\') || (c == ',') || (c == '$')) {
  503. /* These need to be escaped. */
  504. if ((dst + 1) < dlim) {
  505. *dst++ = '\\';
  506. *dst++ = (char) c;
  507. }
  508. } else if (!isprint(c)) {
  509. /* Escape non-printing characters. */
  510. if ((dst + 2) < dlim) {
  511. (void) sprintf(dst, "$%02x", c);
  512. dst += 3;
  513. }
  514. } else {
  515. if (dst < dlim)
  516. *dst++ = (char) c;
  517. }
  518. }
  519. *dst = '\0';
  520. return (dst0);
  521. } /* BmEscapeTok */
  522. /* Converts a Bookmark into a text string, and writes it to the saved
  523. * bookmarks file.
  524. */
  525. static int
  526. WriteBmLine(Bookmark *bmp, FILE *outfp, int savePassword)
  527. {
  528. char tok[256];
  529. char pass[160];
  530. if (fprintf(outfp, "%s", bmp->bookmarkName) < 0) return (-1) ;/*1*/
  531. if (fprintf(outfp, ",%s", BmEscapeTok(tok, sizeof(tok), bmp->name)) < 0) return (-1) ;/*2*/
  532. if (fprintf(outfp, ",%s", BmEscapeTok(tok, sizeof(tok), bmp->user)) < 0) return (-1) ;/*3*/
  533. if ((bmp->pass[0] != '\0') && (savePassword == 1)) {
  534. (void) memcpy(pass, kPasswordMagic, kPasswordMagicLen);
  535. ToBase64(pass + kPasswordMagicLen, bmp->pass, strlen(bmp->pass), 1);
  536. if (fprintf(outfp, ",%s", pass) < 0) return (-1) ;/*4*/
  537. } else {
  538. if (fprintf(outfp, ",%s", "") < 0) return (-1) ;/*4*/
  539. }
  540. if (fprintf(outfp, ",%s", BmEscapeTok(tok, sizeof(tok), bmp->acct)) < 0) return (-1) ;/*5*/
  541. if (fprintf(outfp, ",%s", BmEscapeTok(tok, sizeof(tok), bmp->dir)) < 0) return (-1) ;/*6*/
  542. if (fprintf(outfp, ",%c", bmp->xferType) < 0) return (-1) ;/*7*/
  543. if (fprintf(outfp, ",%u", (unsigned int) bmp->port) < 0) return (-1) ;/*8*/
  544. if (fprintf(outfp, ",%lu", (unsigned long) bmp->lastCall) < 0) return (-1) ;/*9*/
  545. if (fprintf(outfp, ",%d", bmp->hasSIZE) < 0) return (-1) ;/*10*/
  546. if (fprintf(outfp, ",%d", bmp->hasMDTM) < 0) return (-1) ;/*11*/
  547. if (fprintf(outfp, ",%d", bmp->hasPASV) < 0) return (-1) ;/*12*/
  548. if (fprintf(outfp, ",%d", bmp->isUnix) < 0) return (-1) ;/*13*/
  549. if (fprintf(outfp, ",%s", bmp->lastIP) < 0) return (-1) ;/*14*/
  550. if (fprintf(outfp, ",%s", BmEscapeTok(tok, sizeof(tok), bmp->comment)) < 0) return (-1) ;/*15*/
  551. if (fprintf(outfp, ",%s", "") < 0) return (-1) ;/*16*/
  552. if (fprintf(outfp, ",%s", "") < 0) return (-1) ;/*17*/
  553. if (fprintf(outfp, ",%s", "") < 0) return (-1) ;/*18*/
  554. if (fprintf(outfp, ",%s", "") < 0) return (-1) ;/*19*/
  555. if (fprintf(outfp, ",%c", bmp->xferMode) < 0) return (-1) ;/*20*/
  556. if (fprintf(outfp, ",%d", bmp->hasUTIME) < 0) return (-1) ;/*21*/
  557. if (fprintf(outfp, ",%s", BmEscapeTok(tok, sizeof(tok), bmp->ldir)) < 0) return (-1) ;/*22*/
  558. if (fprintf(outfp, "\n") < 0) return (-1) ;
  559. if (fflush(outfp) < 0) return (-1);
  560. return (0);
  561. } /* WriteBmLine */
  562. static int
  563. SwapBookmarkFiles(void)
  564. {
  565. char pidStr[32];
  566. char pathName[256], path2[256];
  567. (void) OurDirectoryPath(path2, sizeof(path2), kBookmarkFileName);
  568. (void) OurDirectoryPath(pathName, sizeof(pathName), kTmpBookmarkFileName);
  569. #if (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__) && !defined(getpid)
  570. # define getpid _getpid
  571. #endif
  572. (void) sprintf(pidStr, "-%u.txt", (unsigned int) getpid());
  573. (void) STRNCAT(pathName, pidStr);
  574. (void) remove(path2);
  575. if (rename(pathName, path2) < 0) {
  576. return (-1);
  577. }
  578. return (0);
  579. } /* SwapBookmarkFiles */
  580. /* Saves a Bookmark structure into the bookmarks file. */
  581. FILE *
  582. OpenTmpBookmarkFile(int nb)
  583. {
  584. FILE *outfp;
  585. char pidStr[32];
  586. char pathName[256], path2[256];
  587. if (gOurDirectoryPath[0] == '\0')
  588. return (NULL); /* Don't create in root directory. */
  589. (void) OurDirectoryPath(path2, sizeof(path2), kBookmarkFileName);
  590. (void) OurDirectoryPath(pathName, sizeof(pathName), kTmpBookmarkFileName);
  591. (void) sprintf(pidStr, "-%u.txt", (unsigned int) getpid());
  592. (void) STRNCAT(pathName, pidStr);
  593. outfp = fopen(pathName, FOPEN_WRITE_TEXT);
  594. if (outfp == NULL) {
  595. (void) fprintf(stderr, "Could not save bookmark.\n");
  596. perror(pathName);
  597. return (NULL);
  598. }
  599. #if (defined(WIN32) || defined(_WINDOWS)) && !defined(__CYGWIN__)
  600. #else
  601. (void) chmod(pathName, 00600);
  602. #endif
  603. if (nb > 0) {
  604. if (fprintf(outfp, "NcFTP bookmark-file version: %d\nNumber of bookmarks: %d\n", kBookmarkVersion, nb) < 0) {
  605. (void) fprintf(stderr, "Could not save bookmark.\n");
  606. perror(pathName);
  607. (void) fclose(outfp);
  608. return (NULL);
  609. }
  610. } else {
  611. if (fprintf(outfp, "NcFTP bookmark-file version: %d\nNumber of bookmarks: ??\n", kBookmarkVersion) < 0) {
  612. (void) fprintf(stderr, "Could not save bookmark.\n");
  613. perror(pathName);
  614. (void) fclose(outfp);
  615. return (NULL);
  616. }
  617. }
  618. return (outfp);
  619. } /* OpenTmpBookmarkFile */
  620. int
  621. SaveBookmarkTable(void)
  622. {
  623. int i;
  624. FILE *outfp;
  625. int nb;
  626. if ((gNumBookmarks < 1) || (gBookmarkTable == NULL))
  627. return (0); /* Nothing to save. */
  628. /* Get a count of live bookmarks. */
  629. for (i=0, nb=0; i<gNumBookmarks; i++) {
  630. if (gBookmarkTable[i].deleted == 0)
  631. nb++;
  632. }
  633. outfp = OpenTmpBookmarkFile(nb);
  634. if (outfp == NULL) {
  635. return (-1);
  636. }
  637. for (i=0; i<gNumBookmarks; i++) {
  638. if (gBookmarkTable[i].deleted == 0) {
  639. if (WriteBmLine(gBookmarkTable + i, outfp, 1) < 0) {
  640. CloseBookmarkFile(outfp);
  641. return (-1);
  642. }
  643. }
  644. }
  645. CloseBookmarkFile(outfp);
  646. if (SwapBookmarkFiles() < 0) {
  647. return (-1);
  648. }
  649. return (0);
  650. } /* SaveBookmarkTable */
  651. /* Saves a Bookmark structure into the bookmarks file. */
  652. int
  653. PutBookmark(Bookmark *bmp, int savePassword)
  654. {
  655. FILE *infp, *outfp;
  656. char line[256];
  657. char bmAbbr[64];
  658. int replaced = 0;
  659. size_t len;
  660. outfp = OpenTmpBookmarkFile(0);
  661. if (outfp == NULL)
  662. return (-1);
  663. (void) STRNCPY(bmAbbr, bmp->bookmarkName);
  664. (void) STRNCAT(bmAbbr, ",");
  665. len = strlen(bmAbbr);
  666. /* This may fail the first time we ever save a bookmark. */
  667. infp = OpenBookmarkFile(NULL);
  668. if (infp != NULL) {
  669. while (FGets(line, sizeof(line), infp) != NULL) {
  670. if (strncmp(line, bmAbbr, len) == 0) {
  671. /* Replace previous entry. */
  672. if (WriteBmLine(bmp, outfp, savePassword) < 0) {
  673. (void) fprintf(stderr, "Could not save bookmark.\n");
  674. perror("reason");
  675. (void) fclose(outfp);
  676. }
  677. replaced = 1;
  678. } else {
  679. if (fprintf(outfp, "%s\n", line) < 0) {
  680. (void) fprintf(stderr, "Could not save bookmark.\n");
  681. perror("reason");
  682. (void) fclose(outfp);
  683. return (-1);
  684. }
  685. }
  686. }
  687. CloseBookmarkFile(infp);
  688. }
  689. if (replaced == 0) {
  690. /* Add it as a new bookmark. */
  691. if (WriteBmLine(bmp, outfp, savePassword) < 0) {
  692. (void) fprintf(stderr, "Could not save bookmark.\n");
  693. perror("reason");
  694. (void) fclose(outfp);
  695. return (-1);
  696. }
  697. }
  698. if (fclose(outfp) < 0) {
  699. (void) fprintf(stderr, "Could not save bookmark.\n");
  700. perror("reason");
  701. return (-1);
  702. }
  703. if (SwapBookmarkFiles() < 0) {
  704. (void) fprintf(stderr, "Could not rename bookmark file.\n");
  705. perror("reason");
  706. return (-1);
  707. }
  708. return (0);
  709. } /* PutBookmark */
  710. /* Tries to generate a bookmark abbreviation based off of the hostname. */
  711. void
  712. DefaultBookmarkName(char *dst, size_t siz, char *src)
  713. {
  714. char str[128];
  715. const char *token;
  716. const char *cp;
  717. (void) STRNCPY(str, src);
  718. /* Pick the first "significant" part of the hostname. Usually
  719. * this is the first word in the name, but if it's something like
  720. * ftp.unl.edu, we would want to choose "unl" and not "ftp."
  721. */
  722. token = str;
  723. if ((token = strtok(str, ".")) == NULL)
  724. token = str;
  725. else if ((ISTRNEQ(token, "ftp", 3)) || (ISTRNEQ(token, "www", 3))) {
  726. if ((token = strtok(NULL, ".")) == NULL)
  727. token = "";
  728. }
  729. for (cp = token; ; cp++) {
  730. if (*cp == '\0') {
  731. /* Token was all digits, like an IP address perhaps. */
  732. token = "";
  733. }
  734. if (!isdigit((int) *cp))
  735. break;
  736. }
  737. (void) Strncpy(dst, token, siz);
  738. } /* DefaultBookmarkName */
  739. int
  740. AddNewItemToBookmarkTable(void)
  741. {
  742. int nb;
  743. BookmarkPtr newTable, bmp;
  744. if (gBookmarkTable == NULL)
  745. return (-1);
  746. nb = gNumBookmarks + 1;
  747. newTable = (BookmarkPtr) realloc(gBookmarkTable, (size_t) (nb) * sizeof(Bookmark));
  748. if (newTable == NULL)
  749. return (-1);
  750. gBookmarkTable = newTable;
  751. gNumBookmarks = nb;
  752. bmp = &newTable[nb - 1];
  753. SetBookmarkDefaults(bmp);
  754. return (nb - 1);
  755. } /* AddNewItemToBookmarkTable */
  756. void
  757. DisposeBookmarkTable(void)
  758. {
  759. if (gBookmarkTable != NULL) {
  760. free(gBookmarkTable);
  761. gBookmarkTable = NULL;
  762. }
  763. } /* DisposeBookmarkTable */