pop_dropcopy.c
上传用户:dayuan858
上传日期:2007-01-04
资源大小:194k
文件大小:27k
源码类别:

网络编程

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (c) 1989 Regents of the University of California.
  3.  * All rights reserved.  The Berkeley software License Agreement
  4.  * specifies the terms and conditions for redistribution.
  5.  */
  6. /*
  7.  * Copyright (c) 1997 by Qualcomm Incorporated.
  8.  */
  9. /*
  10.  * When adding each line length into the size of the message and the maildrop,
  11.  * increase the character count by one for the <cr> added when sending the
  12.  * message to the mail client.  All lines sent to the client are terminated
  13.  * with a <cr><lf>.
  14.  */
  15. #include <config.h>
  16. #include <errno.h>
  17. #include <stdio.h>
  18. #include <sys/types.h>
  19. #include <ctype.h>
  20. #include <string.h>
  21. #include <flock.h>
  22. #if HAVE_UNISTD_H
  23. # include <unistd.h>
  24. #endif
  25. #if HAVE_SYS_UNISTD_H
  26. # include <sys/unistd.h>
  27. #endif
  28. #ifndef HAVE_INDEX
  29. #  define index(s,c) strchr(s,c)
  30. #  define rindex(s,c) strrchr(s,c)
  31. # endif
  32. #if HAVE_STRINGS_H
  33. # include <strings.h>
  34. #endif
  35. #include <sys/stat.h>
  36. #include <sys/file.h>
  37. #include <pwd.h>
  38. #include <popper.h>
  39. #include <md5.h>
  40. #ifdef MAILOCK
  41. # ifdef HAVE_MAILLOCK
  42. #  include <maillock.h>
  43. # endif
  44. # define MAILUNLOCK() mailunlock()
  45. #else 
  46. # define MAILUNLOCK()
  47. #endif
  48. #define MIN_UIDL_LENGTH 5     /* For no reason */
  49. #define MAX_UIDL_LENGTH 72    /* Including NL, Imposed by rfc1939 */
  50. /* This macro comes from Mark Crispin's c-client code */
  51. /* Validate line
  52.  * Accepts: pointer to candidate string to validate as a From header
  53.  *     return pointer to end of date/time field
  54.  *     return pointer to offset from t of time (hours of ``mmm dd hh:mm'')
  55.  *     return pointer to offset from t of time zone (if non-zero)
  56.  * Returns: t,ti,zn set if valid From string, else ti is NIL
  57.  */
  58. #define VALID(s,x,ti,zn) {
  59.   ti = 0;
  60.   if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') &&
  61.       (s[4] == ' ')) {
  62.     for (x = s + 5; *x && *x != 'n'; x++);
  63.     if (x) {
  64.       if (x - s >= 41) {
  65. for (zn = -1; x[zn] != ' '; zn--);
  66. if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') &&
  67.     (x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') &&
  68.     (x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') &&
  69.     (x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))
  70.   x += zn - 12;
  71.       }
  72.       if (x - s >= 27) {
  73. if (x[-5] == ' ') {
  74.   if (x[-8] == ':') zn = 0,ti = -5;
  75.   else if (x[-9] == ' ') ti = zn = -9;
  76.   else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-')))
  77.     ti = zn = -11;
  78. }
  79. else if (x[-4] == ' ') {
  80.   if (x[-9] == ' ') zn = -4,ti = -9;
  81. }
  82. else if (x[-6] == ' ') {
  83.   if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-')))
  84.     zn = -6,ti = -11;
  85. }
  86. if (ti && !((x[ti - 3] == ':') &&
  87.     (x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') &&
  88.     (x[ti - 3] == ' ') && (x[ti - 7] == ' ') &&
  89.     (x[ti - 11] == ' '))) ti = 0;
  90.       }
  91.     }
  92.   }
  93. }
  94. /* You are not expected to understand this macro, but read the next page if
  95.  * you are not faint of heart.
  96.  *
  97.  * Known formats to the VALID macro are:
  98.  *  From user Wed Dec  2 05:53 1992
  99.  * BSD From user Wed Dec  2 05:53:22 1992
  100.  * SysV From user Wed Dec  2 05:53 PST 1992
  101.  * rn From user Wed Dec  2 05:53:22 PST 1992
  102.  * From user Wed Dec  2 05:53 -0700 1992
  103.  * From user Wed Dec  2 05:53:22 -0700 1992
  104.  * From user Wed Dec  2 05:53 1992 PST
  105.  * From user Wed Dec  2 05:53:22 1992 PST
  106.  * From user Wed Dec  2 05:53 1992 -0700
  107.  * Solaris From user Wed Dec  2 05:53:22 1992 -0700
  108.  *
  109.  * Plus all of the above with `` remote from xxx'' after it. Thank you very
  110.  * much, smail and Solaris, for making my life considerably more complicated.
  111.  */
  112. int newline = 1;
  113. /*
  114.  *  0 for not a from line
  115.  *  1 for is a from line
  116.  */
  117. /* Valid UUCP From lines:
  118.  *
  119.  * From Address [tty] date
  120.  * From [tty] date
  121.  *
  122.  * "From [tty] date" is probably valid but I'm too lazy at this
  123.  * time to add the code.
  124.  *
  125.  */
  126. int
  127. isfromline(cp)
  128. char *cp;
  129. {
  130.     int ti, zn;
  131.     char *x;
  132.     /* If the previous line was not a newline then just return */
  133.     /* From message separators are preceeded by a newline */ 
  134.     if (*cp == 'n') {
  135. newline = 1;
  136. return(0);
  137.     } else if (!newline) {
  138. return(0);
  139.     } else
  140. newline = 0;
  141.     VALID(cp, x, ti, zn);
  142.     return(ti != 0);
  143. }
  144. /* Hashing to a spool directory helps reduce the lookup time for sites
  145.  * with thousands of mail spool files.  Unix uses a linear list to
  146.  * save directory information and the following methods attempt to
  147.  * improve the performance.
  148.  *
  149.  * Method 1 - add the value of the first 4 chars mod 26 and open the
  150.  *       spool file in the directory 'a' - 'z'/user.
  151.  *       Brian Buhrow <buhrow@cats.ucsc.edu>
  152.  *
  153.  * Method 2 - Use the first 2 characters to determine which mail spool
  154.  *       to open.  Eg: /usr/spool/u/s/user.
  155.  *       Larry Schwimmer <rosebud@cyclone.stanford.edu>
  156.  *
  157.  * All these methods require that local mail delivery and client programs
  158.  * use the same algorithm.  Only one method to a customer :-)
  159.  */
  160. #if (HASH_SPOOL == 1)
  161. int
  162. genpath(p)
  163. POP *p;
  164. {
  165.     int seed = 0;
  166.     char dirchar[4];
  167.     if (!p->user || *p->user == '')
  168. return(NULL); /*bogus login name*/
  169.     /*Now, perform the hash*/
  170.     switch(strlen(p->user)) {
  171.    case 1:
  172.    seed = (p->user[0]);
  173.    break;
  174.    case 2:
  175.    seed = (p->user[0] + p->user[1]);
  176.    break;
  177.    case 3:
  178.    seed = (p->user[0] + p->user[1] + p->user[2]);
  179.    break;
  180.    case 4:
  181.    seed = (p->user[0] + p->user[1] + p->user[2]+p->user[3]);
  182.    break;
  183.    default:
  184.    seed = (p->user[0] + p->user[1] + p->user[2]+p->user[3]+p->user[4]);
  185.    break;
  186.     }
  187.     dirchar[0] = '/';
  188.     dirchar[1] = (char)((seed % 26) + 'a');
  189.     dirchar[2] = '/';
  190.     dirchar[3] = '';
  191.     strncpy(p->drop_name, POP_MAILDIR, sizeof(p->drop_name));
  192.     strncat(p->drop_name, dirchar, sizeof(p->drop_name) - strlen(p->drop_name));
  193.     strncat(p->drop_name, p->user, sizeof(p->drop_name) - strlen(p->drop_name));
  194.     return(1);
  195. }
  196. #endif
  197. #if (HASH_SPOOL == 2)
  198. int
  199. genpath(p)
  200. POP *p;
  201. {
  202.     static char pathstr[256];
  203.     if (!p->user || *p->user == '')
  204. return(NULL);
  205.     
  206.     sprintf(pathstr, "/%c/%c/%s",
  207.     *p->user, *(p->user+1) ? *(p->user+1) : *p->user, p->user);
  208.     strncpy(p->drop_name, POP_MAILDIR, sizeof(p->drop_name));
  209.     strncat(p->drop_name, pathstr, sizeof(p->drop_name) - strlen(p->drop_name));
  210.     return(1);
  211. }
  212. #endif
  213. #if (HASH_SPOOL != 1 && HASH_SPOOL != 2)
  214. int
  215. genpath(p)
  216. POP *p;
  217. {
  218.     struct passwd *pwp;
  219. #ifdef HOMEDIRMAIL
  220.     if ((pwp = getpwnam(p->user)) == NULL) {
  221. pop_log(p, POP_FAILURE, "unable to retrieve users password entry");
  222. return(-1);
  223.     }
  224.     strncpy(p->drop_name, pwp->pw_dir, sizeof(p->drop_name));
  225.     strncat(p->drop_name, "/.mail",sizeof(p->drop_name) - strlen(p->drop_name));
  226. #else
  227.     strncpy(p->drop_name, POP_MAILDIR, sizeof(p->drop_name));
  228.     strncat(p->drop_name, "/", sizeof(p->drop_name) - strlen(p->drop_name));
  229.     strncat(p->drop_name, p->user, sizeof(p->drop_name) - strlen(p->drop_name));
  230. #endif
  231.     return(1);
  232. }
  233. #endif /* HASH_SPOOL */
  234. /* Open and check the .user.pop file and gather info before copying over
  235.  * the users mailbox.
  236.  */
  237. int init_dropinfo(p)
  238. POP *p;
  239. {
  240.     MsgInfoList         *   mp;         /* Pointer to message info list */
  241.     int     msg_num; /* Current message number */
  242.     int     nchar;
  243.     int     inheader;
  244.     int     uidl_found;
  245.     int     expecting_trailer;
  246.     int     content_length, content_nchar, cont_len;
  247.     char                    buffer[MAXLINELEN]; /*  Read buffer */
  248.     MD5_CTX     mdContext;
  249.     unsigned char     digest[16];
  250. #ifdef DEBUG
  251.     if(p->debug)
  252. pop_log(p,POP_DEBUG, "Checking for old .%s.pop file", p->user);
  253. #endif
  254.     /*  Allocate memory for message information structures */
  255.     p->mlp = (MsgInfoList *)calloc((unsigned)ALLOC_MSGS,sizeof(MsgInfoList));
  256.     if (p->mlp == NULL){
  257.         return pop_msg (p,POP_FAILURE,
  258.             "Can't build message list for '%s': Out of memory", p->user);
  259.     }
  260.     p->msg_count = 0;
  261.     p->drop_size = 0;
  262. #ifdef NULLKLUDGE
  263.   /* Kludge to get around NULLs at the beginning of the mailspool */
  264.   while ((tempchar = getc(p->drop)) == 0);
  265.   ungetc(tempchar, p->drop);
  266. #endif
  267.     if (fgets(buffer, MAXMSGLINELEN, p->drop) == NULL) {
  268. #ifdef DEBUG
  269. if(p->debug)
  270.     pop_log(p,POP_DEBUG, "Old .%s.pop file not found, errno (%d)",
  271. p->user, errno);
  272. #endif
  273. return(POP_SUCCESS);
  274.     }
  275.     /* Is this an MMDF file? */
  276.     if (*buffer == MMDF_SEP_CHAR) {
  277. p->mmdf_separator = (char *)strdup(buffer);
  278.     } else if (!isfromline(buffer)) {
  279. return pop_msg (p,POP_FAILURE,
  280.   "Unable to process From lines (envelopes), change recognition modes.");
  281.     }
  282.     newline = 1;
  283.     rewind(p->drop);
  284.     inheader = 0;
  285.     msg_num = 0;
  286.     uidl_found = 0;
  287.     expecting_trailer = 0;
  288.     content_length = 0;
  289.     content_nchar = 0;
  290.     cont_len = 0;
  291.     p->msg_count = ALLOC_MSGS;
  292. #ifdef NULLKLUDGE
  293.   /* Kludge to get around NULLs at the beginning of the mailspool */
  294.   while ((tempchar = getc(p->drop)) == 0);
  295.   ungetc(tempchar, p->drop);
  296. #endif
  297.     for (mp=p->mlp - 1; fgets(buffer, MAXMSGLINELEN, p->drop);) {
  298. nchar = strlen(buffer);
  299. if ((content_nchar >= content_length) &&
  300.     (p->mmdf_separator ? !strcmp(p->mmdf_separator, buffer) :
  301.     isfromline(buffer))) {
  302.     if (expecting_trailer) {
  303. /* skip over the MMDF trailer */
  304. expecting_trailer = 0;
  305. continue;
  306.     }
  307.     MD5Init (&mdContext);
  308.     MD5Update(&mdContext,(unsigned char *)buffer,strlen(buffer));
  309.     if (!inheader) {
  310. if (++msg_num > p->msg_count) {
  311.     p->mlp = (MsgInfoList *) realloc(p->mlp,
  312. (p->msg_count += ALLOC_MSGS) * sizeof(MsgInfoList));
  313.     if (p->mlp == NULL){
  314. p->msg_count = 0;
  315. return pop_msg (p, POP_FAILURE,
  316.     "Can't build message list for '%s': Out of memory",
  317.     p->user);
  318.     }
  319.     mp = p->mlp + msg_num - 2;
  320. }
  321. #ifdef DEBUG
  322. if(p->debug && msg_num != 1)
  323.     pop_log(p, POP_DEBUG,
  324.     "Msg %d uidl %s at offset %d is %d octets long and has %u lines.",
  325.     mp->number, mp->uidl_str, mp->offset, mp->length, mp->lines);
  326. else
  327.     pop_log(p,POP_DEBUG, "Found top of first message");
  328. #endif
  329. ++mp;
  330.     } else {
  331. pop_log(p,POP_DEBUG,
  332.     "Msg %d corrupted, ignoring previous header information.",
  333.      mp->number);
  334.     }
  335.     mp->number = msg_num;
  336.     mp->length = 0;
  337.     mp->lines = 0;
  338.     mp->body_lines = 0;
  339.     mp->offset = ftell(p->drop) - nchar;
  340.     mp->del_flag = FALSE;
  341.     mp->retr_flag = FALSE;
  342.     mp->orig_retr_state = FALSE;
  343.     mp->uidl_str = "n";
  344. #ifdef DEBUG
  345.     if(p->debug)
  346. pop_log(p,POP_DEBUG, "Msg %d being added to list", mp->number);
  347. #endif
  348.     inheader = 1;
  349.     uidl_found = 0;
  350.     content_nchar = 0;
  351.     content_length = 0;
  352.     cont_len = 0;
  353.     if (p->mmdf_separator)
  354. expecting_trailer = 1;
  355.     
  356.     continue; /* Don't count message separator in total size */
  357. }
  358. if (inheader) {
  359.     if (*buffer == 'n') {
  360. inheader = 0;
  361. content_length = cont_len;
  362. mp->body_lines = 1;  /* Count newline as the first body line */
  363. if (!uidl_found) {
  364.     char *cp;
  365.     int i;
  366.     MD5Final (digest, &mdContext);
  367.     cp = mp->uidl_str = (char *)malloc((DIG_SIZE * 2) + 2);
  368.     for (i = 0; i < DIG_SIZE; i++, cp+=2) {
  369. sprintf(cp, "%02x", digest[i]);
  370.     }
  371.     *cp++ = 'n';
  372.     *cp   = '';
  373.     mp->length += strlen("X-UIDL: ") + strlen(mp->uidl_str) + 1;
  374.     p->drop_size += strlen("X-UIDL: ") + strlen(mp->uidl_str)+1;
  375. /* New UIDs do not dirty the mailspool if NO_STATUS is set.  They
  376.    are just recalculated each time the popper is run or LMOS is
  377.    set and the mail spool is updated.
  378.  */
  379. #ifndef NO_STATUS
  380.     p->dirty = 1;
  381. #endif
  382. }
  383.     } else if (CONTENT_LENGTH && !strncmp(buffer, "Content-Length:", 15)) {
  384. cont_len = atoi(buffer + 15);
  385. MD5Update(&mdContext,(unsigned char *)buffer,strlen(buffer));
  386. continue; /* not part of the message size */
  387.     } else if (!uidl_found && (!strncasecmp("Received:", buffer, 9) ||
  388.        !strncasecmp("Date:", buffer, 5) ||
  389.        !strncasecmp("Message-Id:",buffer, 11) ||
  390.        !strncasecmp("Subject:",buffer, 8)
  391.        )) {
  392. MD5Update(&mdContext,(unsigned char *)buffer,strlen(buffer));
  393.     } else if (!strncasecmp("X-UIDL:", buffer, 7)) {
  394. if (!uidl_found) {
  395.     char *cp;
  396.     int len;
  397.     /* Skip over header string */
  398.     cp = &buffer[7];
  399.                     while (*cp && (*cp == ' ' || *cp == 't')) cp++;
  400.     if( (len = strlen(cp)) > MIN_UIDL_LENGTH && len < MAX_UIDL_LENGTH ) {
  401. uidl_found++;
  402. mp->uidl_str = (char *)strdup(cp);
  403. mp->length += nchar + 1;
  404. p->drop_size += nchar + 1;
  405.     }
  406. }
  407. continue;  /* Do not include this value in the message size */
  408.     } else if ((strncasecmp(buffer,"Status:",7) == 0)) {
  409. if (index(buffer, 'R') != NULL) {
  410.     mp->retr_flag = TRUE;
  411.     mp->orig_retr_state = TRUE;
  412. }
  413.     }
  414. } else {
  415.     content_nchar += nchar;
  416.     mp->body_lines++;
  417. }
  418. mp->length += nchar + 1;
  419. p->drop_size += nchar + 1;
  420. mp->lines++;
  421.     }
  422.     p->msg_count = msg_num;
  423.     return(POP_SUCCESS);
  424. }
  425. /* 
  426.  *  use to be dropinfo:   Extract information about the POP maildrop and store 
  427.  *  it for use by the other POP routines.
  428.  *
  429.  *  Now, the copy and info collection are done at the same time.
  430.  */
  431. do_drop_copy(p, mfd, dfd)
  432. int mfd, dfd;
  433. POP *p;
  434. {
  435.     char                    buffer[MAXLINELEN];     /*  Read buffer */
  436.     MsgInfoList         *   mp;                     /*  Pointer to message 
  437.                                                         info list */
  438.     int                     nchar;                  /*  Bytes written/read */
  439.     int     inheader;     /*  Header section flag */
  440.     int     uidl_found;     /*  UIDL header flag */
  441.     int     msg_num;
  442.     int     expecting_trailer;
  443.     int     content_length, content_nchar, cont_len;
  444.     MD5_CTX     mdContext;
  445.     unsigned char     digest[16];
  446.     FILE     *mail_drop;     /*  Streams for fids */
  447.     /*  Acquire a stream pointer for the maildrop */
  448.     if ( (mail_drop = fdopen(mfd,"r")) == NULL ) {
  449.         (void)close(mfd) ;
  450.         return pop_msg(p,POP_FAILURE,"Cannot assign stream for %s (%d)",
  451.             p->drop_name, errno);
  452.     }
  453.     rewind (mail_drop);
  454. #ifdef NULLKLUDGE
  455.   /* Kludge to get around NULLs at the beginning of the mailspool */
  456.   while ((tempchar = getc(p->drop)) == 0);
  457.   ungetc(tempchar, p->drop);
  458. #endif
  459.     if (fgets(buffer, MAXMSGLINELEN, mail_drop) == NULL) {
  460. return(POP_SUCCESS);
  461.     }
  462.     /* Is this an MMDF file? */
  463.     if (*buffer == MMDF_SEP_CHAR) {
  464. if (!p->mmdf_separator)
  465.     p->mmdf_separator = (char *)strdup(buffer);
  466.     } else if (!isfromline(buffer)) {
  467. return pop_msg (p,POP_FAILURE,
  468.  "Unable to process From lines (envelopes), change recognition modes.");
  469.     }
  470.     newline = 1;
  471.     rewind (mail_drop);
  472.     /*  Scan the file, loading the message information list with 
  473.         information about each message */
  474.     inheader = 0;
  475.     uidl_found = 0;
  476.     expecting_trailer = 0;
  477.     msg_num = p->msg_count;
  478.     content_length = 0;
  479.     content_nchar = 0;
  480.     cont_len = 0;
  481.     p->msg_count = (((p->msg_count - 1) / ALLOC_MSGS) + 1) * ALLOC_MSGS;
  482. #ifdef NULLKLUDGE
  483.   /* Kludge to get around NULLs at the beginning of the mailspool */
  484.   while ((tempchar = getc(p->drop)) == 0);
  485.   ungetc(tempchar, p->drop);
  486. #endif
  487.     for (mp = p->mlp + msg_num - 1; fgets(buffer,MAXMSGLINELEN,mail_drop);) {
  488. nchar = strlen(buffer);
  489. if (fputs(buffer, p->drop) == EOF) {
  490. #ifdef EDQUOT
  491.     if (errno == EDQUOT)
  492. return pop_msg (p,POP_FAILURE,
  493.     "Unable to copy mail spool file, quota exceeded (%d)",
  494. errno);
  495. #endif
  496.     return pop_msg (p,POP_FAILURE,
  497. "Unable to copy mail spool file to temp pop dropbox %s (%d)",
  498.     p->temp_drop, errno);
  499. }
  500. if ((content_nchar >= content_length) &&
  501.     (p->mmdf_separator ? !strcmp(p->mmdf_separator, buffer) :
  502.     isfromline(buffer))) {
  503.     if (expecting_trailer) {
  504. expecting_trailer = 0;
  505. continue;
  506.     }
  507.     MD5Init (&mdContext);
  508.     MD5Update(&mdContext,(unsigned char *)buffer,strlen(buffer));
  509.     if (!inheader) {
  510. if (++msg_num > p->msg_count) {
  511.     p->mlp=(MsgInfoList *) realloc(p->mlp,
  512. (p->msg_count+=ALLOC_MSGS)*sizeof(MsgInfoList));
  513.     if (p->mlp == NULL) {
  514. (void)close (mfd);
  515. (void)close (dfd);
  516. p->msg_count = 0;
  517. return pop_msg (p,POP_FAILURE,
  518.     "Can't build message list for '%s': Out of memory",
  519. p->user);
  520.     }
  521.     mp = p->mlp + msg_num - 2;
  522. }
  523. #ifdef DEBUG
  524. if(p->debug && msg_num != 1)
  525.     pop_log(p,POP_DEBUG,
  526.     "Msg %d uidl %s at offset %d is %d octets long and has %u lines.",
  527.     mp->number,mp->uidl_str,mp->offset,mp->length,mp->lines);
  528. #endif
  529. ++mp;
  530.     } else {
  531. pop_log(p,POP_DEBUG,
  532.     "Msg %d corrupted, ignoring previous header information.",
  533.      mp->number);
  534.     }
  535.             mp->number = msg_num;
  536.             mp->length = 0;
  537.             mp->lines = 0;
  538.             mp->body_lines = 0;
  539.             mp->offset = ftell(p->drop) - nchar;
  540.             mp->del_flag = FALSE;
  541.             mp->retr_flag = FALSE;
  542.             mp->orig_retr_state = FALSE;
  543.     mp->uidl_str = "n";
  544. #ifdef DEBUG
  545.             if(p->debug)
  546.                 pop_log(p,POP_DEBUG, "Msg %d being added to list", mp->number);
  547. #endif
  548.     inheader = 1;
  549.     content_length = 0;
  550.     content_nchar = 0;
  551.     cont_len = 0;
  552.     uidl_found = 0;
  553.     if (p->mmdf_separator)
  554. expecting_trailer = 1;
  555.     continue; /* Do not include From separator in message size */
  556.         } 
  557. if (inheader) {
  558.     if (*buffer == 'n') {
  559. inheader = 0;
  560. mp->body_lines = 1;
  561. content_length = cont_len;
  562. if (!uidl_found) {
  563.     char *cp;
  564.     int  i;
  565.     MD5Final (digest, &mdContext);
  566.     cp = mp->uidl_str = (char *)malloc((DIG_SIZE * 2) + 2);
  567.     for (i = 0; i < DIG_SIZE; i++, cp+=2) {
  568. sprintf(cp, "%02x", digest[i]);
  569.     }
  570.     *cp++ = 'n';
  571.     *cp   = '';
  572.     mp->length += strlen("X-UIDL: ") + strlen(mp->uidl_str) + 1;
  573.     p->drop_size += strlen("X-UIDL: ") + strlen(mp->uidl_str)+1;
  574. /* New UIDs do not dirty the mailspool if NO_STATUS is set.  They
  575.    are just recalculated each time the popper is run or LMOS is
  576.    set and the mail spool is updated.
  577.  */
  578. #ifndef NO_STATUS
  579.     p->dirty = 1;
  580. #endif
  581. }
  582.     } else if (CONTENT_LENGTH && !strncmp(buffer, "Content-Length:", 15)) {
  583. cont_len = atoi(buffer + 15);
  584. MD5Update(&mdContext,(unsigned char *)buffer,strlen(buffer));
  585. continue;  /* Not included in message size */
  586.     } else if (!uidl_found && (!strncasecmp("Received:", buffer, 9) ||
  587.        !strncasecmp("Date:", buffer, 5) ||
  588.        !strncasecmp("Message-Id:",buffer, 11) ||
  589.        !strncasecmp("Subject:",buffer, 8)
  590.        )) {
  591. MD5Update(&mdContext,(unsigned char *)buffer,strlen(buffer));
  592.     } else if (!strncasecmp("X-UIDL:", buffer, 7)) {
  593. if (!uidl_found) {
  594.     int len;
  595.     char *cp;
  596.     uidl_found++;
  597.     /* Skip over header */
  598.     cp = &buffer[7];
  599.                     while (*cp && (*cp == ' ' || *cp == 't')) cp++;
  600.     if( (len = strlen(cp)) > MIN_UIDL_LENGTH && len < MAX_UIDL_LENGTH ) {
  601. uidl_found++;
  602. mp->uidl_str = (char *)strdup(cp);
  603. mp->length += nchar + 1;
  604. p->drop_size += nchar + 1;
  605.     }
  606. }
  607. continue;  /* Do not include this value in the message size */
  608.     } else if (!strncasecmp(buffer,"Status:",7)) {
  609. if (index(buffer, 'R') != NULL) {
  610.     mp->retr_flag = TRUE;
  611.     mp->orig_retr_state = TRUE;
  612. }
  613.     }
  614. } else {
  615.     content_nchar += nchar;
  616.     mp->body_lines++;
  617. }
  618.         mp->length += nchar + 1;
  619.         p->drop_size += nchar + 1;
  620.         mp->lines++;
  621.     }
  622.     p->msg_count = msg_num;
  623. #ifdef DEBUG
  624.     if(p->debug && msg_num > 0) {
  625.         register    i;
  626.         for (i = 0, mp = p->mlp; i < p->msg_count; i++, mp++)
  627.             pop_log(p,POP_DEBUG,
  628.     "Msg %d uidl %s at offset %d is %d octets long and has %u lines.",
  629.     mp->number,mp->uidl_str,mp->offset,mp->length,mp->lines);
  630.     }
  631. #endif
  632.     if (fflush(p->drop) == EOF)
  633.         return pop_msg(p,POP_FAILURE,"Flush of temp pop dropbox %s failed (%d)",
  634.     p->temp_drop, errno);
  635.     return(POP_SUCCESS);
  636. }
  637. /* 
  638.  *  dropcopy:   Make a temporary copy of the user's mail drop and 
  639.  *  save a stream pointer for it.
  640.  */
  641. pop_dropcopy(p, pwp)
  642. POP     *   p;
  643. struct passwd * pwp;
  644. {
  645.     int                     mfd;                    /*  File descriptor for 
  646.                                                         the user's maildrop */
  647.     int                     dfd;                    /*  File descriptor for 
  648.                                                         the SERVER maildrop */
  649.     FILE     *tf;     /*  The temp file */
  650.     int     tfn;     
  651.     char                    buffer[MAXLINELEN];     /*  Read buffer */
  652.     long                    offset;                 /*  Old/New boundary */
  653.     int                     nchar;                  /*  Bytes written/read */
  654.     struct stat             mybuf;                  /*  For fstat() */
  655.     if (genpath(p) < 0)
  656. return(pop_msg(p, POP_FAILURE, "Unable to create temporary drop name"));
  657.     /*  Create a temporary maildrop into which to copy the updated maildrop */
  658.     (void)sprintf(p->temp_drop, POP_DROP, p->user);
  659. #ifdef DEBUG
  660.     if(p->debug)
  661.         pop_log(p,POP_DEBUG,"Creating temporary maildrop '%s'",
  662.             p->temp_drop);
  663. #endif
  664. #ifdef BULLDB
  665.     if (p->bulldir) {
  666. char bull_db[MAXLINELEN];
  667. #ifdef BULLDBDIR
  668. sprintf(bull_db, "%s/bulldb", BULLDBDIR);
  669. #else
  670. sprintf(bull_db, "%s/bulldb", p->bulldir);
  671. #endif
  672. #ifdef GDBM
  673. if ((p->bull_db = gdbm_open (bull_db, 512, GDBM_WRCREAT, 0600, 0)) == NULL)
  674. #else
  675.         if ((p->bull_db = dbm_open (bull_db, O_RDWR | O_CREAT, 0600)) == NULL) 
  676. #endif
  677. {
  678. pop_log(p,POP_PRIORITY,"[g]dbm_open failed : %s (%d)",sys_errlist[errno],errno);
  679.     return(pop_msg(p, POP_FAILURE,
  680.        "Unable to open Bulletin database, contact your administrator"));
  681. }
  682.     }
  683. #endif
  684.     /* Here we work to make sure the user doesn't cause us to remove or
  685.      * write over existing files by limiting how much work we do while
  686.      * running as root.
  687.      */
  688. #ifdef BINMAIL_IS_SETGID
  689. # if BINMAIL_IS_SETGID > 1
  690.     pwp->pw_gid = (gid_t)BINMAIL_IS_SETGID;
  691. # else
  692.     if (!stat(POP_MAILDIR, &mybuf))
  693. pwp->pw_gid = mybuf.st_gid;
  694. # endif
  695. #endif
  696.     /* Now we run as the user. */
  697.     (void) setgid((GID_T)pwp->pw_gid);
  698.     (void) setgroups(1,(GID_T *)&pwp->pw_gid); /* Set the supplementary groups list */
  699.     (void) setuid((UID_T)pwp->pw_uid);
  700. #ifdef DEBUG
  701.     if(p->debug)pop_log(p,POP_DEBUG,"uid = %d, gid = %d",getuid(),getgid());
  702. #endif
  703.     if ((dfd = open(p->temp_drop, O_RDWR | O_CREAT, 0600)) == -1) {
  704.         pop_log(p, POP_PRIORITY,
  705.             "Unable to open temporary maildrop '%s': %s (%d)",p->temp_drop,
  706.                 (errno < sys_nerr) ? sys_errlist[errno] : "", errno) ;
  707.         return pop_msg(p,POP_FAILURE,
  708. "System error, can't open temporary file, do you own it?");
  709.     }
  710.     fstat(dfd, &mybuf);
  711.     if (mybuf.st_uid != pwp->pw_uid) {
  712. close(dfd);
  713. return(pop_msg(p, POP_FAILURE, "Temporary drop file not owned by %s.",
  714.     p->user));
  715.     }
  716. #ifdef NeXT
  717.     if (mybuf.st_mode & (0x7)) {
  718. #else
  719.     if (mybuf.st_mode & (S_IWOTH | S_IROTH)) {
  720. #endif
  721. close(dfd);
  722. return(pop_msg(p, POP_FAILURE,
  723.   "Your temporary file %s is accessable by others.  This must be fixed",
  724.     p->temp_drop));
  725.     }
  726.     /* Make sure the mailspool is not a hard link */
  727.     if (mybuf.st_nlink != 1) {
  728. close(dfd);
  729. return(pop_msg(p, POP_FAILURE,
  730.     "Your temporary file appears to have more than one link."));
  731.     }
  732.     /* If the temporary popdrop is not empty, revert to regular mode. */
  733.     if (mybuf.st_size != 0)
  734. p->server_mode = 0;
  735. #if defined(S_ISREG)
  736.     /* Make sure the file is not a symbolic link reference */
  737.     lstat(p->temp_drop, &mybuf);
  738.     if (!S_ISREG(mybuf.st_mode)) {
  739. close(dfd);
  740. return pop_msg(p, POP_FAILURE,
  741. "Your temporary drop file %s is not type 'regular file'", p->temp_drop);
  742.     }
  743. #endif
  744.     /*  Lock the temporary maildrop */
  745.     if ( flock (dfd, LOCK_EX|LOCK_NB) == -1 ) {
  746. switch(errno) {
  747.     case EWOULDBLOCK:
  748. return pop_msg(p,POP_FAILURE,
  749.      "%s lock busy!  Is another session active? (%d)",
  750. p->temp_drop, errno);
  751. /* NOTREACHED */
  752.     default:
  753. return pop_msg(p,POP_FAILURE,"flock: '%s': %s (%d)",
  754.     p->temp_drop, (errno < sys_nerr) ? sys_errlist[errno] : "", errno);
  755. /* NOTREACHED */
  756. }
  757.     }
  758.     
  759. #ifndef KEEP_TEMP_DROP
  760.     /* check for race conditions involving unlink.  See pop_updt.c */
  761.     /* s-dorner@uiuc.edu, 12/91 */
  762.     {
  763.       struct stat byName, byFd;
  764.       if (stat(p->temp_drop, &byName) || fstat(dfd, &byFd) ||
  765.   byName.st_ino != byFd.st_ino)
  766.       {
  767.         return pop_msg(p,POP_FAILURE,
  768. "Maildrop being unlocked; try again.");
  769.       }
  770.     }
  771. #endif
  772.     
  773.     /* If in server mode and the temporary popdrop has any data in it
  774.        then revert back to the original way of dealing with pop drops.
  775.      */
  776.     /*  Acquire a stream pointer for the temporary maildrop */
  777.     if ( (p->drop = fdopen(dfd,"r+")) == NULL ) {
  778.         (void)close(dfd) ;
  779.         return pop_msg(p,POP_FAILURE,"Cannot assign stream for %s (%d)",
  780.             p->temp_drop, errno);
  781.     }
  782.     if (!p->server_mode) {
  783. /* In server mode this file is used as a process lock and a temporary
  784.    copy file later on */
  785. if (init_dropinfo(p) != POP_SUCCESS)
  786.     return(POP_FAILURE);
  787. /* Sync with stdio */
  788. (void)fseek(p->drop, 0L, SEEK_END);
  789. offset = ftell(p->drop);
  790.     }
  791. #ifdef MAILOCK
  792.     /*  Lock the maildrop */
  793.     if (maillock(p->user,1) != 0)
  794.             return pop_msg(p,POP_FAILURE, "maillock: '%s'", p->temp_drop);
  795. #endif
  796.     /*  Open the user's maildrop, If this fails,  no harm in assuming empty */
  797.     if ((mfd = open(p->drop_name, O_RDWR)) > 0) {
  798.         /* Lock the maildrop */
  799.         if (flock (mfd,LOCK_EX) == -1)
  800. {
  801.             (void)close(mfd) ;
  802.     MAILUNLOCK();
  803.             return pop_msg(p,POP_FAILURE, "flock: '%s': %s (%d)", p->temp_drop,
  804.                 (errno < sys_nerr) ? sys_errlist[errno] : "", errno);
  805.         }
  806. if (!p->server_mode) {
  807.     /* New routine to copy and get dropbox info all at the same time */
  808.     nchar = do_drop_copy(p, mfd, dfd);
  809.     if ( nchar != POP_SUCCESS ) {
  810. /* pop_dropcopy has integrated the info gathering pass into
  811.    the copy pass so now the information of the dropfile is
  812.    inconsistant if there is an error.  Now we exit instead
  813.    of trying to continue with what is available.
  814. */
  815. (void)ftruncate(dfd, (OFF_T)offset) ;
  816. return(nchar);
  817.     } else {
  818. /* Mail transferred!  Zero the mail drop NOW,  that we
  819.    do not have to do gymnastics to figure out what's new
  820.    and what is old later */
  821. (void)ftruncate(mfd, (OFF_T)0) ;
  822.     }
  823.     /*  Close the actual mail drop */
  824.     (void)close (mfd);
  825. } else {
  826.     /* Save the temporary drop FILE and fid values */
  827.     p->hold = p->drop;
  828.     if ((p->drop = fdopen(mfd,"r+")) == NULL) {
  829. pop_msg(p,POP_FAILURE,"Cannot assign stream for %s (%d)",
  830.     p->drop_name, errno);
  831. goto bailout;
  832.     }
  833.     if (init_dropinfo(p) != POP_SUCCESS)
  834. goto bailout;
  835.     dfd = mfd;
  836. }
  837.     } 
  838.     /* Recalculate offset */
  839.     (void)fseek(p->drop, 0L, SEEK_END);
  840.     offset = ftell(p->drop);
  841.     if ((p->bulldir != NULL) && (pop_bull(p, pwp) != POP_SUCCESS)) {
  842. /* Return pop drop back to what it was before the bulletins */
  843. (void)ftruncate(dfd, (OFF_T)offset);
  844.     }
  845. #ifdef BULLDB
  846.     if(p->bulldir != NULL && p->bull_db != NULL) {
  847. #ifdef GDBM
  848.         gdbm_close(p->bull_db);
  849. #else
  850.         dbm_close(p->bull_db);
  851. #endif
  852. p->bull_db = NULL;
  853.     }
  854. #endif
  855.     (void)fseek(p->drop, 0L, SEEK_END);
  856.     p->spool_end = ftell(p->drop);
  857.     MAILUNLOCK();
  858.     if (p->server_mode)
  859.         flock(mfd, LOCK_UN);
  860.     return(POP_SUCCESS);
  861.  bailout:
  862.     MAILUNLOCK();
  863.     flock(mfd, LOCK_UN);
  864.     flock(dfd, LOCK_UN);
  865.     close(mfd);
  866.     close(dfd);
  867.     return( POP_FAILURE );
  868. }