home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume32 / mush / patch05c < prev    next >
Text File  |  1992-10-18  |  41KB  |  1,647 lines

  1. Newsgroups: comp.sources.misc
  2. From: bart@zigzag.z-code.com (Bart Schaefer)
  3. Subject:  v32i103:  mush - Mail User's Shell, Patch05c/3
  4. Message-ID: <1992Oct16.141355.6946@sparky.imd.sterling.com>
  5. X-Md4-Signature: a106ba48c83eda60dc3249295e5224a4
  6. Date: Fri, 16 Oct 1992 14:13:55 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: bart@zigzag.z-code.com (Bart Schaefer)
  10. Posting-number: Volume 32, Issue 103
  11. Archive-name: mush/patch05c
  12. Environment: UNIX
  13. Patch-To: mush: Volume 18, Issue 58-79
  14.  
  15. This is Part 03 of Official Patch #5 for Mush 7.2.  This is a shar of new
  16. files in the Mush 7.2 distribution, NOT a diff.  DO NOT feed this file to
  17. patch!  Save this message to a file in your mush source directory and
  18. extract the contents with:
  19.  
  20.     sh file
  21.  
  22. You don't actually need any of these files unless you are using DOT_LOCK
  23. or POP3_SUPPORT.  See README.
  24.  
  25. #!/bin/sh
  26. # shar:    Shell Archiver  (v1.22+)
  27. #
  28. #    Run the following text with /bin/sh to create:
  29. #      README-7.2.5
  30. #      pop.h
  31. #      pop.c
  32. #      pmush.c
  33. #      xcreat.c
  34. #
  35. echo "x - extracting README-7.2.5 (Text)"
  36. sed 's/^X//' << 'SHAR_EOF' > README-7.2.5 &&
  37. X
  38. XThis is release 7.2.5 of the Mail User's Shell (mush).
  39. X
  40. XMush was last posted as a complete package at release 7.2.2.  Before that,
  41. Xthe last complete posting was 7.1.1.  If your version of mush is older
  42. Xthan 7.2.2, refer to README-7.0 and README-7.1 for lists of other changes.
  43. XSee README-7.2.0 for changes from 7.1.1 to 7.2.  Patch 3 was bugfixes only;
  44. Xthere was no README-7.2.3.  See README-7.2.4 for a list of changes in both
  45. Xpatch 3 and patch 4.
  46. X
  47. XChanges in compilation:
  48. X
  49. X    POP3_SUPPORT
  50. X    Enable POP client mode by compiling with this defined.  See README.
  51. X
  52. X    New files to support POP and DOT_LOCK have been added to the makefiles.
  53. X
  54. XNew/changed commands:
  55. X
  56. X    See the $metamail variable for changes in print/type/etc.
  57. X
  58. XNew/changed variables:
  59. X
  60. X    metamail
  61. X    If $metamail is set to the pathname (and arguments) of a MIME
  62. X    decoder (such as the "metamail" program), Mush will recognize
  63. X    MIME messages and "page" them through that decoder instead of
  64. X    through the regular $pager.
  65. X
  66. XTool mode changes:
  67. X
  68. X    Bug fixes only, see below.
  69. X
  70. XBugs fixed in Patch #5:
  71. X
  72. X  * Better parsing of double-quoted tokens in addresses
  73. X
  74. X  * Unsetenv allocates a new copy of the environment on first call
  75. X
  76. X  * Doesn't attempt to init tty if there isn't one
  77. X
  78. X  * #define CURSES in config.h (as opposed to in CFLAGS) should work
  79. X
  80. X  * On AIX, curses mode won't dump core
  81. X
  82. X  * Recognize more date formats, and store dates to resolution in seconds
  83. X    for more accurate date sorting
  84. X
  85. X  * Tool mode "sort" menu "by value of sort variable" works now
  86. X
  87. X  * Better handling of X.400 addresses (heuristic for distinguishing them
  88. X    from file names has been improved)
  89. X
  90. X  * Tool mode "save" pullright directory-walking menus work in all contexts
  91. X    (I hope)
  92. X
  93. X  * Moved that silly piece of code that was setting $realname to the
  94. X    spool folder path
  95. X
  96. X  * Code to init all hostname aliases for $hostname finally works right in
  97. X    all cases
  98. X
  99. X  * Many improvements to DOT_LOCK; NFS "secure" lockfile creation
  100. X
  101. X  * ~user/$variable parses correctly and expands $variable
  102. X
  103. X  * Some compilation fixes for SGI IRIX
  104. X
  105. X  * Child-process management for pager process improved
  106. X
  107. X  * Support for POSIX_UTIME fixed
  108. X
  109. X  * "saveopts" of variables, aliases, etc. with embedded quotes of mixed
  110. X    types does appropriate quoting of its output
  111. SHAR_EOF
  112. chmod 0644 README-7.2.5 || echo "restore of README-7.2.5 fails"
  113. set `wc -c README-7.2.5`;Sum=$1
  114. if test "$Sum" != "2290"
  115. then echo original size 2290, current size $Sum;fi
  116. echo "x - extracting pop.h (Text)"
  117. sed 's/^X//' << 'SHAR_EOF' > pop.h &&
  118. X/*
  119. X * pop.h: Header file for the "pop.c" client POP3 protocol
  120. X * implementation.
  121. X */
  122. X
  123. X#ifdef POP3_SUPPORT
  124. X
  125. X#include <stdio.h>
  126. X
  127. X#define GETLINE_MAX 1024    /* a pretty arbitrary value */
  128. X
  129. Xextern char pop_error[];
  130. Xextern int pop_debug;
  131. X
  132. Xtypedef struct _PopServer {
  133. X     int file, data;
  134. X     char buffer[GETLINE_MAX], *dp;
  135. X} *PopServer;
  136. X
  137. X/*
  138. X * Valid flags for the pop_open function.
  139. X */
  140. X
  141. X#define POP_NO_KERBEROS    (1<<0)
  142. X#define POP_NO_HESIOD    (1<<1)
  143. X#define POP_NO_GETPASS     (1<<2)
  144. X
  145. Xextern PopServer pop_open();
  146. Xextern int pop_stat();
  147. Xextern int pop_list();
  148. Xextern char *pop_retrieve();
  149. Xextern int pop_delete();
  150. Xextern int pop_noop();
  151. Xextern int pop_last();
  152. Xextern int pop_reset();
  153. Xextern int pop_quit();
  154. Xextern void pop_close();
  155. X
  156. X#endif /* POP3_SUPPORT */
  157. SHAR_EOF
  158. chmod 0644 pop.h || echo "restore of pop.h fails"
  159. set `wc -c pop.h`;Sum=$1
  160. if test "$Sum" != "748"
  161. then echo original size 748, current size $Sum;fi
  162. echo "x - extracting pop.c (Text)"
  163. sed 's/^X//' << 'SHAR_EOF' > pop.c &&
  164. X/*
  165. X * pop.c: client routines for talking to a POP3-protocol post-office
  166. X * server
  167. X *
  168. X * Jonathan Kamens
  169. X * August 13, 1991
  170. X */
  171. X
  172. X#ifdef POP3_SUPPORT
  173. X
  174. X#include <sys/types.h>
  175. X#include <netinet/in.h>
  176. X#include <sys/socket.h>
  177. X#include "pop.h"
  178. X
  179. Xextern int errno;
  180. X
  181. X#ifdef KERBEROS
  182. X#include <krb.h>
  183. X#include <des.h>
  184. X#ifdef sun
  185. X#include <malloc.h>
  186. X#else /* !sun */
  187. Xextern char *
  188. Xmalloc( /* unsigned */ );
  189. Xextern void 
  190. Xfree( /* char * */ );
  191. X#endif /* sun */
  192. X#endif /* KERBEROS */
  193. X
  194. X#ifdef HESIOD
  195. X#include <hesiod.h>
  196. X/*
  197. X * It really shouldn't be necessary to put this declaration here, but
  198. X * the version of hesiod.h that Athena has installed in release 7.2
  199. X * doesn't declare this function; I don't know if the 7.3 version of
  200. X * hesiod.h does.
  201. X */
  202. Xextern struct servent *
  203. Xhes_getservbyname( /* char *, char * */ );
  204. X#endif /* HESIOD */
  205. X
  206. X#include <pwd.h>
  207. X#include <string.h>
  208. X#include <strings.h>
  209. X
  210. Xextern char *
  211. Xstrstr( /* char *, char * */ );
  212. X
  213. X#include <netdb.h>
  214. X#include <errno.h>
  215. X#include <stdio.h>
  216. X
  217. Xextern char *sys_errlist[];
  218. X#define strerror(eno)    sys_errlist[eno]
  219. X
  220. Xextern char *
  221. Xgetenv( /* char * */ );
  222. Xextern char *
  223. Xgetlogin( /* void */ );
  224. Xextern char *
  225. Xgetpass( /* char * */ );
  226. Xextern int 
  227. Xgetuid( /* void */ );
  228. Xextern void 
  229. Xbzero( /* char *, int */ ), bcopy( /* char *, char *, int */ );
  230. Xextern int 
  231. Xsocket( /* int, int, int */ );
  232. Xextern int 
  233. Xconnect( /* int, struct sockaddr *, int */ );
  234. Xextern int 
  235. Xclose( /* int */ );
  236. Xextern int 
  237. Xread( /* int, char *, int */ ), write( /* int, char *, int */ );
  238. Xextern int 
  239. Xatoi( /* char * */ );
  240. X
  241. X#if !(defined(vax) && defined(__GNUC__))
  242. Xextern int 
  243. Xfprintf( /* FILE *, char *, ... */ );
  244. X#endif /* !(vax && __GNUC__) */
  245. X
  246. X#ifdef KERBEROS
  247. Xextern int 
  248. Xkrb_sendauth( /* long, int, KTEXT, char *, char *, char *, u_long, MSG_DAT **,
  249. X        CREDENTIALS *, Key_schedule, struct sockaddr_in *,
  250. X        struct sockaddr_in *, char * */ );
  251. Xextern char *
  252. Xkrb_realmofhost( /* char * */ );
  253. X#endif /* KERBEROS */
  254. X
  255. Xextern int h_errno;
  256. X
  257. Xstatic int socket_connection();
  258. Xstatic char *getline();
  259. Xstatic int sendline();
  260. Xstatic int fullwrite();
  261. Xstatic int getok();
  262. Xstatic int gettermination();
  263. X
  264. X#define ERROR_MAX 80    /* a pretty arbitrary size */
  265. X#define POP_PORT 110
  266. X#define KPOP_PORT 1109
  267. X#define POP_SERVICE "pop"
  268. X#define KPOP_SERVICE "kpop"
  269. X
  270. Xchar pop_error[ERROR_MAX];
  271. Xint pop_debug = 0;
  272. X
  273. X/*
  274. X * Function: pop_open(char *host, char *username, char *password,
  275. X *               int flags)
  276. X *
  277. X * Purpose: Establishes a connection with a post-office server, and
  278. X *     completes the authorization portion of the session.
  279. X *
  280. X * Arguments:
  281. X *     host    The server host with which the connection should be
  282. X *         established.  Optional.  If omitted, internal
  283. X *         heuristics will be used to determine the server host,
  284. X *         if possible.
  285. X *     username
  286. X *         The username of the mail-drop to access.  Optional.
  287. X *         If omitted, internal heuristics will be used to
  288. X *         determine the username, if possible.
  289. X *     password
  290. X *         The password to use for authorization.  If omitted,
  291. X *         internal heuristics will be used to determine the
  292. X *         password, if possible.
  293. X *     flags    A bit mask containing flags controlling certain
  294. X *         functions of the routine.  Valid flags are defined in
  295. X *         the file pop.h
  296. X *
  297. X * Return value: Upon successful establishment of a connection, a
  298. X *     non-null PopServer will be returned.  Otherwise, null will be
  299. X *     returned, and the string variable pop_error will contain an
  300. X *     explanation of the error.
  301. X */
  302. XPopServer 
  303. Xpop_open(host, username, password, flags)
  304. Xchar *host, *username, *password;
  305. Xint flags;
  306. X{
  307. X    int sock;
  308. X    PopServer server;
  309. X
  310. X    /* Determine the user name */
  311. X    if (!username) {
  312. X    username = getenv("USER");
  313. X    if (!(username && *username)) {
  314. X        username = getlogin();
  315. X        if (!(username && *username)) {
  316. X        struct passwd *passwd;
  317. X
  318. X        passwd = getpwuid(getuid());
  319. X        if (passwd && passwd->pw_name && *passwd->pw_name) {
  320. X            username = passwd->pw_name;
  321. X        } else {
  322. X            strcpy(pop_error, "Could not determine username");
  323. X            return (0);
  324. X        }
  325. X        }
  326. X    }
  327. X    }
  328. X    /* Determine the mail host */
  329. X#ifdef HESIOD
  330. X    if ((!host) && (!(flags & POP_NO_HESIOD))) {
  331. X    struct hes_postoffice *office;
  332. X
  333. X    office = hes_getmailhost(username);
  334. X    if (office && office->po_type && (!strcmp(office->po_type, "POP"))
  335. X        && office->po_name && *office->po_name && office->po_host
  336. X        && *office->po_host) {
  337. X        host = office->po_host;
  338. X        username = office->po_name;
  339. X    }
  340. X    }
  341. X#endif
  342. X    if (!host) {
  343. X    host = getenv("MAILHOST");
  344. X    if (!host) {
  345. X        strcpy(pop_error, "Could not determine POP server");
  346. X        return (0);
  347. X    }
  348. X    }
  349. X    /* Determine the password */
  350. X#ifdef KERBEROS
  351. X#define DONT_NEED_PASSWORD (! (flags & POP_NO_KERBEROS))
  352. X#else
  353. X#define DONT_NEED_PASSWORD 0
  354. X#endif
  355. X
  356. X    /* Modified to return password if possible -- Bart */
  357. X    if ((!password || !*password) && (!DONT_NEED_PASSWORD)) {
  358. X    if (!(flags & POP_NO_GETPASS)) {
  359. X        char *p = getpass("Enter POP password:");
  360. X        if (p && password)
  361. X        (void) strcpy(password, p);
  362. X        password = p;
  363. X    }
  364. X    if (!password) {
  365. X        strcpy(pop_error, "Could not determine POP password");
  366. X        return (0);
  367. X    }
  368. X    }
  369. X    if (password)
  370. X    flags |= POP_NO_KERBEROS;
  371. X    else
  372. X    password = username;
  373. X
  374. X    sock = socket_connection(host, flags);
  375. X    if (sock == -1)
  376. X    return (0);
  377. X
  378. X    server = (PopServer) malloc(sizeof(struct _PopServer));
  379. X    if (!server) {
  380. X    strcpy(pop_error, "Out of memory in pop_open");
  381. X    return (0);
  382. X    }
  383. X    server->file = sock;
  384. X    server->data = 0;
  385. X    server->dp = server->buffer;
  386. X
  387. X    if (getok(server))
  388. X    return (0);
  389. X
  390. X    /*
  391. X     * I really shouldn't use the pop_error variable like this, but.... 
  392. X     */
  393. X    if (strlen(username) > ERROR_MAX - 6) {
  394. X    pop_close(server);
  395. X    strcpy(pop_error,
  396. X        "Username too long; recompile pop.c with larger ERROR_MAX");
  397. X    return (0);
  398. X    }
  399. X    sprintf(pop_error, "USER %s", username);
  400. X
  401. X    if (sendline(server, pop_error) || getok(server)) {
  402. X    return (0);
  403. X    }
  404. X    if (strlen(password) > ERROR_MAX - 6) {
  405. X    pop_close(server);
  406. X    strcpy(pop_error,
  407. X        "Password too long; recompile pop.c with larger ERROR_MAX");
  408. X    return (0);
  409. X    }
  410. X    sprintf(pop_error, "PASS %s", password);
  411. X
  412. X    if (sendline(server, pop_error) || getok(server)) {
  413. X    return (0);
  414. X    }
  415. X    return (server);
  416. X}
  417. X
  418. X/*
  419. X * Function: pop_stat
  420. X *
  421. X * Purpose: Issue the STAT command to the server and return (in the
  422. X *     value parameters) the number of messages in the maildrop and
  423. X *     the total size of the maildrop.
  424. X *
  425. X * Return value: 0 on success, or non-zero with an error in pop_error
  426. X *     in failure.
  427. X *
  428. X * Side effects: Closes the connection on failure.
  429. X */
  430. Xint 
  431. Xpop_stat(server, count, size)
  432. XPopServer server;
  433. Xint *count, *size;
  434. X{
  435. X    char *fromserver;
  436. X
  437. X    if (sendline(server, "STAT") || (!(fromserver = getline(server))))
  438. X    return (-1);
  439. X
  440. X    if (strncmp(fromserver, "+OK ", 4)) {
  441. X    strcpy(pop_error, "Unexpected response from POP server in pop_stat");
  442. X    pop_close();
  443. X    return (-1);
  444. X    }
  445. X    *count = atoi(&fromserver[4]);
  446. X
  447. X    fromserver = index(&fromserver[4], ' ');
  448. X    if (!fromserver) {
  449. X    strcpy(pop_error,
  450. X        "Badly formatted response from server in pop_stat");
  451. X    pop_close(server);
  452. X    return (-1);
  453. X    }
  454. X    *size = atoi(fromserver + 1);
  455. X
  456. X    return (0);
  457. X}
  458. X
  459. X/*
  460. X * Function: pop_list
  461. X *
  462. X * Purpose: Performs the POP "list" command and returns (in value
  463. X *     parameters) two malloc'd zero-terminated arrays -- one of
  464. X *     message IDs, and a parallel one of sizes.
  465. X *
  466. X * Arguments:
  467. X *     server    The pop connection to talk to.
  468. X *     message    The number of the one message about which to get
  469. X *         information, or 0 to get information about all
  470. X *         messages.
  471. X *
  472. X * Return value: 0 on success, non-zero with error in pop_error on
  473. X *     failure.
  474. X *
  475. X * Side effects: Closes the connection on error.
  476. X */
  477. Xint 
  478. Xpop_list(server, message, IDs, sizes)
  479. XPopServer server;
  480. Xint message, **IDs, **sizes;
  481. X{
  482. X    int how_many, i;
  483. X    char *fromserver;
  484. X
  485. X    if (message)
  486. X    how_many = 1;
  487. X    else {
  488. X    int count, size;
  489. X
  490. X    if (pop_stat(server, &count, &size))
  491. X        return (-1);
  492. X    how_many = count;
  493. X    }
  494. X
  495. X    *IDs = (int *) malloc((how_many + 1) * sizeof(int));
  496. X    *sizes = (int *) malloc((how_many + 1) * sizeof(int));
  497. X    if (!(*IDs && *sizes)) {
  498. X    strcpy(pop_error, "Out of memory in pop_list");
  499. X    pop_close(server);
  500. X    return (-1);
  501. X    }
  502. X    if (message) {
  503. X    sprintf(pop_error, "LIST %d", message);
  504. X    if (sendline(server, pop_error)) {
  505. X        free((char *) *IDs);
  506. X        free((char *) *sizes);
  507. X        return (-1);
  508. X    }
  509. X    if (!(fromserver = getline(server))) {
  510. X        free((char *) *IDs);
  511. X        free((char *) *sizes);
  512. X        return (-1);
  513. X    }
  514. X    if (strncmp(fromserver, "+OK ", 4)) {
  515. X        if (!strncmp(fromserver, "-ERR", 4))
  516. X        strncpy(pop_error, fromserver, ERROR_MAX);
  517. X        else
  518. X        strcpy(pop_error,
  519. X            "Unexpected response from server in pop_list");
  520. X        free((char *) *IDs);
  521. X        free((char *) *sizes);
  522. X        pop_close(server);
  523. X        return (-1);
  524. X    }
  525. X    (*IDs)[0] = atoi(&fromserver[4]);
  526. X    fromserver = index(&fromserver[4], ' ');
  527. X    if (!fromserver) {
  528. X        strcpy(pop_error,
  529. X            "Badly formatted response from server in pop_list");
  530. X        free((char *) *IDs);
  531. X        free((char *) *sizes);
  532. X        pop_close(server);
  533. X        return (-1);
  534. X    }
  535. X    (*sizes)[0] = atoi(fromserver);
  536. X    (*IDs)[1] = (*sizes)[1] = 0;
  537. X    return (0);
  538. X    } else {
  539. X    if (sendline(server, "LIST") || getok(server)) {
  540. X        free((char *) *IDs);
  541. X        free((char *) *sizes);
  542. X        return (-1);
  543. X    }
  544. X    for (i = 0; i < how_many; i++) {
  545. X        if (!(fromserver = getline(server))) {
  546. X        free((char *) *IDs);
  547. X        free((char *) *sizes);
  548. X        return (-1);
  549. X        }
  550. X        (*IDs)[i] = atoi(fromserver);
  551. X        fromserver = index(fromserver, ' ');
  552. X        if (!fromserver) {
  553. X        strcpy(pop_error,
  554. X            "Badly formatted response from server in pop_list");
  555. X        free((char *) *IDs);
  556. X        free((char *) *sizes);
  557. X        pop_close(server);
  558. X        return (-1);
  559. X        }
  560. X        (*sizes)[i] = atoi(fromserver);
  561. X    }
  562. X    if (gettermination(server)) {
  563. X        free((char *) *IDs);
  564. X        free((char *) *sizes);
  565. X        return (-1);
  566. X    }
  567. X    (*IDs)[i] = (*sizes)[i] = 0;
  568. X    return (0);
  569. X    }
  570. X}
  571. X
  572. X/*
  573. X * Function: pop_retrieve
  574. X *
  575. X * Purpose: Retrieve a specified message from the maildrop.
  576. X *
  577. X * Arguments:
  578. X *     server    The server to retrieve from.
  579. X *     message    The message number to retrieve.
  580. X *
  581. X * Return value: A string pointing to the message, if successful, or
  582. X *     null with pop_error set if not.
  583. X *
  584. X * Side effects: Closes the connection on error.
  585. X */
  586. Xchar *
  587. Xpop_retrieve(server, message)
  588. XPopServer server;
  589. Xint message;
  590. X{
  591. X    int *IDs, *sizes;
  592. X    char *ptr, *cp;
  593. X
  594. X    if (pop_list(server, message, &IDs, &sizes))
  595. X    return (0);
  596. X
  597. X    sprintf(pop_error, "RETR %d", message);
  598. X    if (sendline(server, pop_error) || getok(server)) {
  599. X    return (0);
  600. X    }
  601. X    cp = ptr = (char *) malloc(sizes[0]+1);
  602. X    free((char *) IDs);
  603. X    free((char *) sizes);
  604. X
  605. X    if (!ptr) {
  606. X    strcpy(pop_error, "Out of memory in pop_retrieve");
  607. X    pop_close(server);
  608. X    return (0);
  609. X    }
  610. X    *cp = '\0';
  611. X
  612. X    while (1) {
  613. X    char *fromserver = getline(server);
  614. X    int size;
  615. X
  616. X    if (!fromserver) {
  617. X        free(ptr);
  618. X        pop_close(server);
  619. X        return (0);
  620. X    }
  621. X    if (fromserver[0] == '.') {
  622. X        if (!fromserver[1]) {
  623. X        return (ptr);
  624. X        }
  625. X        fromserver++;
  626. X    }
  627. X    size = strlen(fromserver);
  628. X    bcopy(fromserver, cp, size + 1);
  629. X    cp += size;
  630. X    *cp++ = '\n';
  631. X    *cp = '\0';
  632. X    }
  633. X}
  634. X
  635. X/* Function: pop_delete
  636. X *
  637. X * Purpose: Delete a specified message.
  638. X *
  639. X * Arguments:
  640. X *     server    Server from which to delete the message.
  641. X *     message    Message to delete.
  642. X *
  643. X * Return value: 0 on success, non-zero with error in pop_error
  644. X *     otherwise.
  645. X */
  646. Xint 
  647. Xpop_delete(server, message)
  648. XPopServer server;
  649. Xint message;
  650. X{
  651. X    sprintf(pop_error, "DELE %d", message);
  652. X
  653. X    if (sendline(server, pop_error) || getok(server)) {
  654. X    pop_close(server);
  655. X    return (-1);
  656. X    }
  657. X    return (0);
  658. X}
  659. X
  660. X/*
  661. X * Function: pop_noop
  662. X *
  663. X * Purpose: Send a noop command to the server.
  664. X *
  665. X * Argument:
  666. X *     server    The server to send to.
  667. X *
  668. X * Return value: 0 on success, non-zero with error in pop_error
  669. X *     otherwise.
  670. X *
  671. X * Side effects: Closes connection on error.
  672. X */
  673. Xint 
  674. Xpop_noop(server)
  675. XPopServer server;
  676. X{
  677. X    if (sendline(server, "NOOP") || getok(server))
  678. X    return (-1);
  679. X
  680. X    return (0);
  681. X}
  682. X
  683. X/*
  684. X * Function: pop_last
  685. X *
  686. X * Purpose: Find out the highest seen message from the server.
  687. X *
  688. X * Arguments:
  689. X *     server    The server.
  690. X *
  691. X * Return value: If successful, the highest seen message, which is
  692. X *     greater than or equal to 0.  Otherwise, a negative number with
  693. X *     the error explained in pop_error.
  694. X *
  695. X * Side effects: Closes the connection on error.
  696. X */
  697. Xint 
  698. Xpop_last(server)
  699. XPopServer server;
  700. X{
  701. X    char *fromserver;
  702. X
  703. X    if (sendline(server, "LAST"))
  704. X    return (-1);
  705. X
  706. X    if (!(fromserver = getline(server)))
  707. X    return (-1);
  708. X
  709. X    if (!strncmp(fromserver, "-ERR", 4)) {
  710. X    strncpy(pop_error, fromserver, ERROR_MAX);
  711. X    pop_close(server);
  712. X    return (-1);
  713. X    } else if (strncmp(fromserver, "+OK", 3)) {
  714. X    strcpy(pop_error, "Unexpected response from server in pop_last");
  715. X    pop_close(server);
  716. X    return (-1);
  717. X    } else {
  718. X    return (atoi(&fromserver[4]));
  719. X    }
  720. X}
  721. X
  722. X/*
  723. X * Function: pop_reset
  724. X *
  725. X * Purpose: Reset the server to its initial connect state
  726. X *
  727. X * Arguments:
  728. X *     server    The server.
  729. X *
  730. X * Return value: 0 for success, non-0 with error in pop_error
  731. X *     otherwise.
  732. X *
  733. X * Side effects: Closes the connection on error.
  734. X */
  735. Xint 
  736. Xpop_reset(server)
  737. XPopServer server;
  738. X{
  739. X    if (sendline(server, "RSET") || getok(server)) {
  740. X    pop_close(server);
  741. X    return (-1);
  742. X    }
  743. X    return (0);
  744. X}
  745. X
  746. X/*
  747. X * Function: pop_quit
  748. X *
  749. X * Purpose: Quit the connection to the server,
  750. X *
  751. X * Arguments:
  752. X *     server    The server to quit.
  753. X *
  754. X * Return value: 0 for success, non-zero otherwise with error in
  755. X *     pop_error.
  756. X *
  757. X * Side Effects: The PopServer passed in is unuseable after this
  758. X *     function is called, even if an error occurs.
  759. X */
  760. Xint 
  761. Xpop_quit(server)
  762. XPopServer server;
  763. X{
  764. X    int ret = 0;
  765. X
  766. X    if (sendline(server, "QUIT") || getok(server))
  767. X    ret = -1;
  768. X
  769. X    close(server->file);
  770. X    free((char *) server);
  771. X
  772. X    return (ret);
  773. X}
  774. X
  775. X/*
  776. X * Function: socket_connection
  777. X *
  778. X * Purpose: Opens the network connection with the mail host, without
  779. X *     doing any sort of I/O with it or anything.
  780. X *
  781. X * Arguments:
  782. X *     host    The host to which to connect.
  783. X *    flags    Option flags.
  784. X *     
  785. X * Return value: A file descriptor indicating the connection, or -1
  786. X *     indicating failure, in which case an error has been copied
  787. X *     into pop_error.
  788. X */
  789. Xstatic int 
  790. Xsocket_connection(host, flags)
  791. Xchar *host;
  792. Xint flags;
  793. X{
  794. X    struct hostent *hostent;
  795. X    struct servent *servent;
  796. X    struct sockaddr_in addr;
  797. X    char found_port = 0;
  798. X    char *service;
  799. X    int sock;
  800. X
  801. X#ifdef KERBEROS
  802. X    KTEXT ticket;
  803. X    MSG_DAT msg_data;
  804. X    CREDENTIALS cred;
  805. X    Key_schedule schedule;
  806. X    int rem;
  807. X
  808. X#endif
  809. X
  810. X    int try_count = 0;
  811. X
  812. X    do {
  813. X    hostent = gethostbyname(host);
  814. X    try_count++;
  815. X    if ((!hostent) && ((h_errno != TRY_AGAIN) || (try_count == 5))) {
  816. X        strcpy(pop_error, "Could not determine POP server's address");
  817. X        return (-1);
  818. X    }
  819. X    } while (!hostent);
  820. X
  821. X    bzero((char *) &addr, sizeof(addr));
  822. X    addr.sin_family = AF_INET;
  823. X
  824. X#ifdef KERBEROS
  825. X    service = (flags & POP_NO_KERBEROS) ? POP_SERVICE : KPOP_SERVICE;
  826. X#else
  827. X    service = POP_SERVICE;
  828. X#endif
  829. X
  830. X#ifdef HESIOD
  831. X    if (!(flags & POP_NO_HESIOD)) {
  832. X    servent = hes_getservbyname(service, "tcp");
  833. X    if (servent) {
  834. X        addr.sin_port = servent->s_port;
  835. X        found_port = 1;
  836. X    }
  837. X    }
  838. X#endif
  839. X    if (!found_port) {
  840. X    servent = getservbyname(service, "tcp");
  841. X    if (servent) {
  842. X        addr.sin_port = servent->s_port;
  843. X    } else {
  844. X#ifdef KERBEROS
  845. X        addr.sin_port = htons((flags & POP_NO_KERBEROS) ?
  846. X            POP_PORT : KPOP_PORT);
  847. X#else
  848. X        addr.sin_port = htons(POP_PORT);
  849. X#endif
  850. X    }
  851. X    }
  852. X#define SOCKET_ERROR "Could not create socket for POP connection: "
  853. X
  854. X    sock = socket(PF_INET, SOCK_STREAM, 0);
  855. X    if (sock < 0) {
  856. X    strcpy(pop_error, SOCKET_ERROR);
  857. X    strncat(pop_error, strerror(errno),
  858. X        ERROR_MAX - sizeof(SOCKET_ERROR));
  859. X    return (-1);
  860. X
  861. X    }
  862. X    while (*hostent->h_addr_list) {
  863. X    bcopy(*hostent->h_addr_list, (char *) &addr.sin_addr,
  864. X        hostent->h_length);
  865. X    if (!connect(sock, (struct sockaddr *) & addr, sizeof(addr)))
  866. X        break;
  867. X    hostent->h_addr_list++;
  868. X    }
  869. X
  870. X#define CONNECT_ERROR "Could not connect to POP server: "
  871. X
  872. X    if (!*hostent->h_addr_list) {
  873. X    (void) close(sock);
  874. X    strcpy(pop_error, CONNECT_ERROR);
  875. X    strncat(pop_error, strerror(errno),
  876. X        ERROR_MAX - sizeof(CONNECT_ERROR));
  877. X    return (-1);
  878. X
  879. X    }
  880. X#ifdef KERBEROS
  881. X    if (!(flags & POP_NO_KERBEROS)) {
  882. X    ticket = (KTEXT) malloc(sizeof(KTEXT_ST));
  883. X    rem = krb_sendauth(0L, sock, ticket, "pop", hostent->h_name,
  884. X        (char *) krb_realmofhost(hostent->h_name),
  885. X        (unsigned long) 0, &msg_data, &cred, schedule,
  886. X        (struct sockaddr_in *) 0,
  887. X        (struct sockaddr_in *) 0,
  888. X        "KPOPV0.1");
  889. X    free((char *) ticket);
  890. X    if (rem != KSUCCESS) {
  891. X#define KRB_ERROR "Kerberos error connecting to POP server: "
  892. X        strcpy(pop_error, KRB_ERROR);
  893. X        strncat(pop_error, krb_err_txt[rem],
  894. X            ERROR_MAX - sizeof(KRB_ERROR));
  895. X        (void) close(sock);
  896. X        return (-1);
  897. X    }
  898. X    }
  899. X#endif    /* KERBEROS */
  900. X
  901. X    return (sock);
  902. X}/* socket_connection */
  903. X
  904. X/*
  905. X * Function: getline
  906. X *
  907. X * Purpose: Get a line of text from the connection and return a
  908. X *     pointer to it.  The carriage return and linefeed at the end of
  909. X *     the line are stripped, but periods at the beginnings of lines
  910. X *     are NOT dealt with in any special way.
  911. X *
  912. X * Arguments:
  913. X *     server    The server from which to get the line of text.
  914. X *
  915. X * Returns: A non-null pointer if successful, or a null pointer on any
  916. X *     error, with an error message copied into pop_error.
  917. X *
  918. X * Notes: The line returned is overwritten with each call to getline.
  919. X *
  920. X * Side effects: Closes the connection on error.
  921. X */
  922. Xstatic char *
  923. Xgetline(server)
  924. XPopServer server;
  925. X{
  926. X#define GETLINE_ERROR "Error reading from server: "
  927. X
  928. X    int ret;
  929. X
  930. X    if (server->data) {
  931. X    char *cp = strstr(server->dp, "\r\n");
  932. X
  933. X    if (cp) {
  934. X        char *found;
  935. X
  936. X        *cp = '\0';
  937. X        server->data -= (&cp[2] - server->dp);
  938. X        found = server->dp;
  939. X        server->dp = &cp[2];
  940. X
  941. X        if (pop_debug)
  942. X        fprintf(stderr, "<<< %s\n", found);
  943. X        return (found);
  944. X    } else {
  945. X        bcopy(server->dp, server->buffer, server->data);
  946. X        server->dp = server->buffer;
  947. X    }
  948. X    } else {
  949. X    server->dp = server->buffer;
  950. X    }
  951. X
  952. X    while (server->data < GETLINE_MAX) {
  953. X    ret = read(server->file, &server->buffer[server->data],
  954. X        GETLINE_MAX - server->data);
  955. X    if (ret < 0) {
  956. X        strcpy(pop_error, GETLINE_ERROR);
  957. X        strncat(pop_error, strerror(errno),
  958. X            GETLINE_MAX - sizeof(GETLINE_ERROR));
  959. X        pop_close(server);
  960. X        return (0);
  961. X    } else if (ret == 0) {
  962. X        strcpy(pop_error, "Unexpected EOF from server in getline");
  963. X        pop_close(server);
  964. X        return (0);
  965. X    } else {
  966. X        char *cp = strstr(server->buffer, "\r\n");
  967. X
  968. X        server->data += ret;
  969. X
  970. X        if (cp) {
  971. X        *cp = '\0';
  972. X        server->data -= (&cp[2] - server->dp);
  973. X        server->dp = &cp[2];
  974. X
  975. X        if (pop_debug)
  976. X            fprintf(stderr, "<<< %s\n", server->buffer);
  977. X        return (server->buffer);
  978. X        }
  979. X    }
  980. X    }
  981. X
  982. X    strcpy(pop_error, "Line too long reading from server; compile pop.c with larger GETLINE_MAX");
  983. X    pop_close(server);
  984. X    return (0);
  985. X}
  986. X
  987. X/*
  988. X * Function: sendline
  989. X *
  990. X * Purpose: Sends a line of text to the POP server.  The line of text
  991. X *     passed into this function should NOT have the carriage return
  992. X *     and linefeed on the end of it.  Periods at beginnings of lines
  993. X *     will NOT be treated specially by this function.
  994. X *
  995. X * Arguments:
  996. X *     server    The server to which to send the text.
  997. X *     line    The line of text to send.
  998. X *
  999. X * Return value: Upon successful completion, a value of 0 will be
  1000. X *     returned.  Otherwise, a non-zero value will be returned, and
  1001. X *     an error will be copied into pop_error.
  1002. X *
  1003. X * Side effects: Closes the connection on error.
  1004. X */
  1005. Xstatic int 
  1006. Xsendline(server, line)
  1007. XPopServer server;
  1008. Xchar *line;
  1009. X{
  1010. X#define SENDLINE_ERROR "Error writing to POP server: "
  1011. X    int ret;
  1012. X
  1013. X    ret = fullwrite(server->file, line, strlen(line));
  1014. X    if (ret >= 0) {    /* 0 indicates that a blank line was written */
  1015. X    ret = fullwrite(server->file, "\r\n", 2);
  1016. X    }
  1017. X    if (ret < 0) {
  1018. X    pop_close(server);
  1019. X    strcpy(pop_error, SENDLINE_ERROR);
  1020. X    strncat(pop_error, strerror(errno),
  1021. X        ERROR_MAX - sizeof(SENDLINE_ERROR));
  1022. X    return (ret);
  1023. X    }
  1024. X    if (pop_debug)
  1025. X    fprintf(stderr, ">>> %s\n", line);
  1026. X
  1027. X    return (0);
  1028. X}
  1029. X
  1030. X/*
  1031. X * Procedure: fullwrite
  1032. X *
  1033. X * Purpose: Just like write, but keeps trying until the entire string
  1034. X *     has been written.
  1035. X *
  1036. X * Return value: Same as write.  Pop_error is not set.
  1037. X */
  1038. Xstatic int 
  1039. Xfullwrite(fd, buf, nbytes)
  1040. Xint fd;
  1041. Xchar *buf;
  1042. Xint nbytes;
  1043. X{
  1044. X    char *cp;
  1045. X    int ret;
  1046. X
  1047. X    cp = buf;
  1048. X    while ((ret = write(fd, cp, nbytes)) > 0) {
  1049. X    cp += ret;
  1050. X    nbytes -= ret;
  1051. X    }
  1052. X
  1053. X    return (ret);
  1054. X}
  1055. X
  1056. X/*
  1057. X * Procedure getok
  1058. X *
  1059. X * Purpose: Reads a line from the server.  If the return indicator is
  1060. X *     positive, return with a zero exit status.  If not, return with
  1061. X *     a negative exit status.
  1062. X *
  1063. X * Arguments:
  1064. X *     server    The server to read from.
  1065. X * 
  1066. X * Returns: 0 for success, else for failure and puts error in pop_error.
  1067. X *
  1068. X * Side effects: Closes the connection on error.
  1069. X */
  1070. Xstatic int 
  1071. Xgetok(server)
  1072. XPopServer server;
  1073. X{
  1074. X    char *fromline;
  1075. X
  1076. X    if (!(fromline = getline(server))) {
  1077. X    return (-1);
  1078. X    }
  1079. X    if (!strncmp(fromline, "+OK", 3))
  1080. X    return (0);
  1081. X    else if (!strncmp(fromline, "-ERR", 4)) {
  1082. X    strncpy(pop_error, fromline, ERROR_MAX);
  1083. X    pop_error[ERROR_MAX - 1] = '\0';
  1084. X    pop_close(server);
  1085. X    return (-1);
  1086. X    } else {
  1087. X    strcpy(pop_error,
  1088. X        "Unknown response from server; expecting +OK or -ERR");
  1089. X    pop_close(server);
  1090. X    return (-1);
  1091. X    }
  1092. X}
  1093. X
  1094. X/*
  1095. X * Function: gettermination
  1096. X *
  1097. X * Purpose: Gets the next line and verifies that it is a termination
  1098. X *     line (nothing but a dot).
  1099. X *
  1100. X * Return value: 0 on success, non-zero with pop_error set on error.
  1101. X *
  1102. X * Side effects: Closes the connection on error.
  1103. X */
  1104. Xstatic int 
  1105. Xgettermination(server)
  1106. XPopServer server;
  1107. X{
  1108. X    char *fromserver;
  1109. X
  1110. X    fromserver = getline(server);
  1111. X    if (!fromserver)
  1112. X    return (-1);
  1113. X
  1114. X    if (strcmp(fromserver, ".")) {
  1115. X    strcpy(pop_error,
  1116. X        "Unexpected response from server in gettermination");
  1117. X    pop_close(server);
  1118. X    return (-1);
  1119. X    }
  1120. X    return (0);
  1121. X}
  1122. X
  1123. X/*
  1124. X * Function pop_close
  1125. X *
  1126. X * Purpose: Close a pop connection, sending a "RSET" command to try to
  1127. X *     preserve any changes that were made and a "QUIT" command to
  1128. X *     try to get the server to quit, but ignoring any responses that
  1129. X *     are received.
  1130. X *
  1131. X * Side effects: The server is unuseable after this function returns.
  1132. X *     Changes made to the maildrop since the session was started (or
  1133. X *     since the last pop_reset) may be lost.
  1134. X */
  1135. Xvoid 
  1136. Xpop_close(server)
  1137. XPopServer server;
  1138. X{
  1139. X    sendline(server, "RSET");
  1140. X    sendline(server, "QUIT");
  1141. X
  1142. X    close(server->file);
  1143. X    free((char *) server);
  1144. X
  1145. X    return;
  1146. X}
  1147. X
  1148. X#endif /* POP3_SUPPORT */
  1149. SHAR_EOF
  1150. chmod 0644 pop.c || echo "restore of pop.c fails"
  1151. set `wc -c pop.c`;Sum=$1
  1152. if test "$Sum" != "22450"
  1153. then echo original size 22450, current size $Sum;fi
  1154. echo "x - extracting pmush.c (Text)"
  1155. sed 's/^X//' << 'SHAR_EOF' > pmush.c &&
  1156. X/**************************************************************************
  1157. XNAME: Brian Buhrow
  1158. XDATE: September 17, 1991
  1159. XPURPOSE: This file contains the interface between the Mush program and the
  1160. X    POP post-office calls which put mail into the system mailbox.  Mail
  1161. X    will be placed in the user's mailbox when Mush is first fired up and
  1162. X    will be checked periodically as Mush is run.
  1163. X    Note that these routines will only be called if the pre-processor
  1164. X    variable POP3_SUPPORT is defined.
  1165. X**************************************************************************/
  1166. X
  1167. X#ifdef POP3_SUPPORT
  1168. X
  1169. X#include "config.h"
  1170. X#include "mush.h"
  1171. X#include "pop.h"
  1172. X
  1173. X/*
  1174. X * strstr - find first occurrence of wanted in s
  1175. X */
  1176. X
  1177. Xchar *                /* found string, or NULL if none */
  1178. Xstrstr(s, wanted)
  1179. Xchar *s;
  1180. Xchar *wanted;
  1181. X{
  1182. X    char *scan;
  1183. X    long len;
  1184. X    char firstc;
  1185. X
  1186. X    /*
  1187. X     * The odd placement of the two tests is so "" is findable.
  1188. X     * Also, we inline the first char for speed.
  1189. X     * The ++ on scan has been moved down for optimization.
  1190. X     */
  1191. X    firstc = *wanted;
  1192. X    len = strlen(wanted);
  1193. X    for (scan = s; *scan != firstc || strncmp(scan, wanted, len) != 0; )
  1194. X    if (*scan++ == '\0')
  1195. X        return NULL;
  1196. X    return scan;
  1197. X}
  1198. X
  1199. X/* This routine forms the header line for the From and Date functions below.
  1200. X * It was written by John Kammens for use by UCSC's version of UCBmail running
  1201. X * on the ATHENA system.
  1202. X */
  1203. Xstatic char *
  1204. Xheader(msg, tag)
  1205. Xchar *msg, *tag;
  1206. X{
  1207. X    char *val, *ptr, *eoh;
  1208. X
  1209. X    val = malloc(strlen(tag) + 3);
  1210. X    if (!val)
  1211. X    return (0);
  1212. X
  1213. X    sprintf(val, "\n%s:", tag);
  1214. X
  1215. X    eoh = strstr(msg, "\n\n");
  1216. X    if (!eoh)
  1217. X    eoh = (char *) index(msg, '\0');
  1218. X
  1219. X    ptr = strstr(msg, tag);
  1220. X
  1221. X    if ((!ptr) || (ptr > eoh)) {
  1222. X    sprintf(val, "%s:", tag);
  1223. X    if (!strncmp(val, msg, strlen(val)))
  1224. X        ptr = msg;
  1225. X    else
  1226. X        ptr = 0;
  1227. X    }
  1228. X    if (!ptr) {
  1229. X    free(val);
  1230. X    return (0);
  1231. X    }
  1232. X    ptr += strlen(val);
  1233. X
  1234. X    while (*ptr && ((*ptr == ' ') || (*ptr == '\t')))
  1235. X    ptr++;
  1236. X
  1237. X    eoh = (char *) index(ptr, '\n');
  1238. X    if (!eoh)
  1239. X    eoh = (char *) index(ptr, '\0');
  1240. X
  1241. X    val = realloc(val, (eoh - ptr) + 1);
  1242. X    strncpy(val, ptr, (eoh - ptr));
  1243. X    val[eoh - ptr] = '\0';
  1244. X
  1245. X    return (val);
  1246. X}
  1247. X
  1248. X/* This routine comes up with the Unix Date line to insert into the mail
  1249. X * file.  It was written by John Kammens for use with UCSC's UCBMail on
  1250. X * Athena.
  1251. X *
  1252. X * Modified to get rid of dependence on that hideous B-news yacc parser.
  1253. X * Mush already has a perfectly good date parser, let's use it.  -- Bart
  1254. X */
  1255. Xstatic char *
  1256. Xdate(msg)
  1257. Xchar *msg;
  1258. X{
  1259. X    char *real = 0, *machine = 0;
  1260. X    long t;
  1261. X    int size;
  1262. X
  1263. X    real = header(msg, "Date");
  1264. X
  1265. X    if (real) {
  1266. X    machine = parse_date(real);
  1267. X    free(real);
  1268. X    if (machine) {
  1269. X        machine = date_to_ctime(machine);
  1270. X    }
  1271. X    }
  1272. X    if (!machine) {
  1273. X    t = time((long *)0);
  1274. X    machine = ctime(&t);
  1275. X    }
  1276. X    size = strlen(machine);
  1277. X    machine[size - 1] = '\0';    /* get rid of newline */
  1278. X    real = malloc(size);
  1279. X    if (!real)
  1280. X    return 0;
  1281. X    strcpy(real, machine);
  1282. X
  1283. X    return real;
  1284. X}
  1285. X
  1286. X/* This routine comes up with the Unix From line to insert into the mail
  1287. X * file.  It was written by John Kammens for use with UCSC's UCBMail on
  1288. X * Athena.
  1289. X *
  1290. X * Modified to use get_name_n_addr() so we don't depend on regexec()
  1291. X * being available, which it usually isn't. -- Bart
  1292. X */
  1293. Xstatic char *
  1294. Xfrom_line(msg)
  1295. Xchar *msg;
  1296. X{
  1297. X    char *real = header(msg, "From"), *real2;
  1298. X    char addr[256];
  1299. X
  1300. X    if (real) {
  1301. X    addr[0] = 0;
  1302. X    (void) get_name_n_addr(real, NULL, addr);
  1303. X    if (addr[0]) {
  1304. X        (void) bang_form(real, addr);
  1305. X        return real;
  1306. X    }
  1307. X    }
  1308. X
  1309. X    if (!real)
  1310. X    real = malloc(8);
  1311. X    if (!real)
  1312. X    return 0;
  1313. X    strcpy(real, "unknown");
  1314. X    return real;
  1315. X}
  1316. X
  1317. X/* Retrieves mail from the system post office using the POP interface
  1318. X * routines as put together by John Kammens for the UCBmail program under
  1319. X * ATHENA.  This routine will be called both when Mush begins executing to
  1320. X * check for new mail and when Mush is executing to see if new mail has
  1321. X * arrived during the Mush session.
  1322. X */
  1323. Xstatic void 
  1324. Xloadmail()
  1325. X{
  1326. X    PopServer postinfo;
  1327. X    int msgcount, msgsize, i, flags = 0;
  1328. X    char mailbox[MAXPATHLEN], *msgptr, *dateline, *fromline;
  1329. X    FILE *mfstream;
  1330. X    struct stat mfstat;
  1331. X    static char pass[64];
  1332. X
  1333. X    *mailbox = (char) NULL;    /* Clear string */
  1334. X    strcat(mailbox, getenv("HOME"));
  1335. X    strcat(mailbox, "/");
  1336. X    strcat(mailbox, MAILFILE);
  1337. X    /* Get info about post drop */
  1338. X    if (pass[0])
  1339. X    flags = POP_NO_GETPASS;
  1340. X    if (!(postinfo = pop_open(NULL, login, pass, flags))) {
  1341. X    fprintf(stderr, "Error opening connection with post office: %s\n",
  1342. X        pop_error);
  1343. X    return;
  1344. X    }
  1345. X    if (pop_stat(postinfo, &msgcount, &msgsize)) {
  1346. X    fprintf(stderr, "Error collecting status from post office: %s\n",
  1347. X        pop_error);
  1348. X    pop_close(postinfo);
  1349. X    return;
  1350. X    }
  1351. X    if (!msgcount) {
  1352. X    pop_quit(postinfo);
  1353. X    return;
  1354. X    }
  1355. X    /* Begin loading mailbox */
  1356. X    if (stat(mailbox, &mfstat)) {
  1357. X    if (errno == ENOENT) {
  1358. X        close(open(mailbox, O_WRONLY | O_CREAT | O_EXCL, 0600));
  1359. X    }
  1360. X    }
  1361. X    if (!(mfstream = fopen(mailbox, "a"))) {
  1362. X    perror("Error opening mailbox in loadmail");
  1363. X    pop_close(postinfo);
  1364. X    return;
  1365. X    }
  1366. X    for (i = 1; i <= msgcount; i++) {    /* Load new messages */
  1367. X    msgptr = pop_retrieve(postinfo, i);
  1368. X    dateline = date(msgptr);
  1369. X    fromline = from_line(msgptr);
  1370. X    if (fprintf(mfstream, "\nFrom %s %s\n%s", fromline, dateline, msgptr)
  1371. X        < (strlen(fromline) + strlen(dateline) + strlen(msgptr))) {
  1372. X        fprintf(stderr, "Error writing mailbox file\n");
  1373. X        pop_close(postinfo);
  1374. X        cleanup(-1);
  1375. X    }
  1376. X    free(dateline);
  1377. X    free(fromline);
  1378. X    free(msgptr);
  1379. X    if (pop_delete(postinfo, i)) {
  1380. X        fprintf(stderr, "Error deleting message from post office: %s\n",
  1381. X            pop_error);
  1382. X    }
  1383. X    }
  1384. X    if (fclose(mfstream) == EOF) {
  1385. X    perror("Error closing mailbox file in loadmail");
  1386. X    pop_close(postinfo);
  1387. X    return;
  1388. X    }
  1389. X    if (pop_quit(postinfo)) {
  1390. X    fprintf(stderr, "Error closing post office: %s\n", pop_error);
  1391. X    }
  1392. X    return;
  1393. X}
  1394. X
  1395. X/* This routine merely calls loadmail to get mail initially from the post
  1396. X * office.  There is no forking, and it is intended to be used when Mush is
  1397. X * first started.
  1398. X */
  1399. Xvoid
  1400. Xpopgetmail()
  1401. X{
  1402. X    loadmail();
  1403. X}
  1404. X
  1405. X/* This function calls loadmail, after first forking, releasing stdin,
  1406. X * stdout and stderr and ignoring any signals that might be generated.
  1407. X * This function is invoked by the sigalrm signal.  The parent resets
  1408. X * the alarm and returns.
  1409. X */
  1410. Xvoid 
  1411. Xpopchkmail()
  1412. X{
  1413. X    static int cpid = 0, numtries = 0;
  1414. X
  1415. X    if (cpid > 0) {
  1416. X    if (!kill(cpid, 0)) {
  1417. X        numtries++;
  1418. X        if (numtries > 10) {
  1419. X        kill(cpid, SIGKILL);
  1420. X        }
  1421. X        return;
  1422. X    } else {
  1423. X        numtries = 0;
  1424. X    }
  1425. X    }
  1426. X    if (!(cpid = fork())) {
  1427. X    /* Ignore several signals for workability */
  1428. X    signal(SIGCONT, SIG_IGN);
  1429. X    signal(SIGQUIT, SIG_IGN);
  1430. X    signal(SIGTSTP, SIG_IGN);
  1431. X    signal(SIGSTOP, SIG_IGN);
  1432. X    signal(SIGTERM, SIG_IGN);
  1433. X    signal(SIGIO, SIG_IGN);
  1434. X    signal(SIGPIPE, SIG_IGN);
  1435. X    loadmail();
  1436. X    _exit(0);
  1437. X    } else {
  1438. X    if (cpid == -1) {
  1439. X        fprintf(stderr, "Unable to fork in popchkmail\n");
  1440. X    }
  1441. X    return;
  1442. X    }
  1443. X}
  1444. X
  1445. X#endif    /* POP3_SUPPORT */
  1446. SHAR_EOF
  1447. chmod 0644 pmush.c || echo "restore of pmush.c fails"
  1448. set `wc -c pmush.c`;Sum=$1
  1449. if test "$Sum" != "6973"
  1450. then echo original size 6973, current size $Sum;fi
  1451. echo "x - extracting xcreat.c (Text)"
  1452. sed 's/^X//' << 'SHAR_EOF' > xcreat.c &&
  1453. X/************************************************************************
  1454. X *    secure exclusive creat/lock    v1.4 1992/04/27            *
  1455. X *    (works even across NFS, which O_EXCL does *not*)        *
  1456. X *                                    *
  1457. X *    Created 1990-1992, S.R. van den Berg, The Netherlands        *
  1458. X *            berg@pool.informatik.rwth-aachen.de        *
  1459. X *            berg@physik.tu-muenchen.de            *
  1460. X *                                    *
  1461. X *    This file is donated to the public domain.            *
  1462. X *                                    *
  1463. X *    Cleaned up 1992, Bart Schaefer, Z-Code Software Corp.        *
  1464. X *            schaefer@z-code.com                *
  1465. X *            schaefer@cse.ogi.edu                *
  1466. X *        Cleanup includes reformatting for readability,        *
  1467. X *        more comments, and using some file-name macros        *
  1468. X *        that Mush defines (removed calls to strpbrk()        *
  1469. X *        and avoided malloc()ing when max. size known).        *
  1470. X *        Also added XCTEST standalone test program mode.        *
  1471. X *                                    *
  1472. X *    Usage: int xcreat(char *filename, int mode)            *
  1473. X *                                    *
  1474. X *    returns  0:success  -1:lock busy                *
  1475. X *                                    *
  1476. X *        sets errno on failure                    *
  1477. X *                                    *
  1478. X *    To remove a `lockfile', simply unlink it.            *
  1479. X *                                    *
  1480. X ************************************************************************/
  1481. X
  1482. X#include "mush.h"    /* For OS-specific include files and macros */
  1483. X
  1484. X#ifdef XCTEST_LOUDLY
  1485. X#ifndef XCTEST
  1486. X#define XCTEST
  1487. X#endif /* XCTEST */
  1488. X#endif /* XCTEST_LOUDLY */
  1489. X
  1490. X#ifdef XCTEST
  1491. X#define hostname()    "xctest"
  1492. X#else
  1493. Xextern char **ourname;
  1494. X#define hostname()    ourname[0]
  1495. X#endif /* XCTEST */
  1496. X
  1497. X#ifdef DECLARE_ERRNO
  1498. Xextern int errno;
  1499. X#endif /* DECLARE_ERRNO */
  1500. X
  1501. X#ifndef O_SYNC
  1502. X#define O_SYNC        0
  1503. X#endif
  1504. X#ifndef    O_CREAT
  1505. X#define    copen(path,type,mode)    creat(path,mode)
  1506. X#else
  1507. X#define copen(path,type,mode)    open(path,type,mode)
  1508. X#endif
  1509. X
  1510. X#define UNIQ_PREFIX    '_'        /* Any unlikely character works */
  1511. X#define charsULTOAN    4        /* # of chars output by ultoan() */
  1512. X
  1513. X#ifndef MAXNAMLEN
  1514. X#if defined(BSD) || defined(IRIX4) || defined(HPUX)
  1515. X#define MAXNAMLEN    (MAXPATHLEN/2)    /* Any fairly large number works */
  1516. X#else /* !SYSV */
  1517. X#define MAXNAMLEN    14        /* 14 is SysVr3 standard */
  1518. X#endif /* BSD */
  1519. X#endif /* MAXNAMLEN */
  1520. X
  1521. X#define HOSTNAMElen    (MAXNAMLEN-charsULTOAN-1)
  1522. X
  1523. X/* Define a bit rotation to generate pseudo-unique numbers in "sequence" */
  1524. X#define bitsSERIAL    (6*charsULTOAN)
  1525. X#define maskSERIAL    ((1L<<bitsSERIAL)-1)
  1526. X#define rotbSERIAL    2
  1527. X#define mrotbSERIAL    ((1L<<rotbSERIAL)-1)
  1528. X
  1529. X#define XCserialize(n,r) \
  1530. X    ((u_long) maskSERIAL&((u_long)(r)<<bitsSERIAL-mrotbSERIAL)+(u_long)(n))
  1531. X
  1532. X/* Generate an almost-unique 4-character string from an unsigned long */
  1533. Xstatic 
  1534. Xultoan(val, dest)
  1535. Xunsigned long val;
  1536. Xchar *dest;    /* convert to a number */
  1537. X{
  1538. X    register i;    /* within the set [0-9A-Za-z-_] */
  1539. X
  1540. X#ifdef XCTEST_LOUDLY
  1541. X    printf("Converting %lu to ascii.\n", val);
  1542. X#endif /* XCTEST_LOUDLY */
  1543. X
  1544. X    do {
  1545. X    i = val & 0x3f;
  1546. X    *dest++ = i+(i < 10? '0' :
  1547. X            i < 10+26? 'A'-10 :
  1548. X            i < 10+26+26? 'a'-10-26 :
  1549. X            i == 10+26+26 ? '-'-10-26-26 :
  1550. X            '_'-10-26-27);
  1551. X    }
  1552. X    while (val >>= 6);
  1553. X    *dest = '\0';
  1554. X}
  1555. X
  1556. X/* create unique file name */
  1557. Xstatic
  1558. Xunique(full, p, mode)
  1559. Xchar *full;
  1560. Xchar *p;
  1561. Xint mode;
  1562. X{
  1563. X    unsigned long retry = 3;
  1564. X    int i;
  1565. X
  1566. X    do {
  1567. X#ifdef XCTEST_LOUDLY
  1568. X    printf("Using PID = %d:  ", getpid());
  1569. X#endif /* XCTEST_LOUDLY */
  1570. X    ultoan(XCserialize(getpid(),retry), p + 1);
  1571. X    *p = UNIQ_PREFIX;
  1572. X    strncat(p, hostname(), HOSTNAMElen);
  1573. X    } /* casually check if it already exists (highly unlikely) */
  1574. X    while (0 > (i = copen(full, O_WRONLY|O_CREAT|O_EXCL|O_SYNC, mode)) &&
  1575. X        errno == EEXIST && retry--);
  1576. X    if (i < 0)
  1577. X    return 0;
  1578. X    close(i);
  1579. X    return 1;
  1580. X}
  1581. X
  1582. X/* rename MUST fail if already existent */
  1583. Xstatic 
  1584. Xmyrename(old, newn)
  1585. Xchar *old, *newn;
  1586. X{
  1587. X    int i, serrno;
  1588. X    struct stat stbuf;
  1589. X
  1590. X#ifdef XCTEST_LOUDLY
  1591. X    printf("Renaming %s to %s\n", old, newn);
  1592. X#endif /* XCTEST_LOUDLY */
  1593. X
  1594. X    link(old, newn);
  1595. X    serrno = errno;
  1596. X    i = stat(old, &stbuf);
  1597. X    unlink(old);
  1598. X    errno = serrno;
  1599. X    return stbuf.st_nlink == 2 ? i : -1;
  1600. X}
  1601. X
  1602. X/* an NFS secure exclusive file open */
  1603. Xxcreat(name, mode)
  1604. Xchar *name;
  1605. Xint mode;
  1606. X{
  1607. X    char buf[MAXPATHLEN];
  1608. X    char *p, *q;
  1609. X    int j = -2, i;
  1610. X
  1611. X    q = rindex(name, '/');
  1612. X    if (q)
  1613. X    i = q - name;
  1614. X    else {
  1615. X    i = 0;    /* Creating in the current directory */
  1616. X    }
  1617. X    p = strncpy(buf, name, i);
  1618. X    if (unique(p, p + i, mode))
  1619. X    j = myrename(p, name);    /* try and rename it, fails if nonexclusive */
  1620. X    free(p);
  1621. X    return j;
  1622. X}
  1623. X
  1624. X#ifdef XCTEST
  1625. X
  1626. Xmain(argc, argv)
  1627. Xint argc;
  1628. Xchar **argv;
  1629. X{
  1630. X    if (argc > 1)
  1631. X    exit(xcreat(argv[1], 0444) < 0);
  1632. X}
  1633. X
  1634. X#endif /* XCTEXT */
  1635. SHAR_EOF
  1636. chmod 0644 xcreat.c || echo "restore of xcreat.c fails"
  1637. set `wc -c xcreat.c`;Sum=$1
  1638. if test "$Sum" != "4396"
  1639. then echo original size 4396, current size $Sum;fi
  1640. exit 0
  1641.  
  1642. -- 
  1643. Bart Schaefer                                     schaefer@zigzag.z-code.com
  1644. Z-Code Software Corp.                             schaefer@z-code.com
  1645.  
  1646. exit 0 # Just in case...
  1647.