home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Mail / qpopper-2.4-MIHS / pop_dropcopy.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-12  |  26.8 KB  |  996 lines

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