jepeway@utkcs2.cs.utk.edu (Chris Jepeway) (10/20/88)
I'm trying to get POP running under MH v6r6. The POP server is a Vax 8200 running Ultrix 2.2, and the clients are Sun 3/60's and 3/260's running Sun-OS 3.5. The trouble I'm having is that the POP server on the Vax thinks the entire contents of /var/spool/mail/whoever is a single message. Here's the Vax's mtstailor file-- mmdfldir: /var/spool/mail servers: localhost \01localnet mmdelim1:\nFrom\ mmdelim2:\nFrom\ The characters after the final slashes on the mmdelim lines are spaces. I can't figure what's going on, but trust that someone else has a solution. Thanks Ever, C. Jepeway
dempsey@handel.colostate.edu. (Steve Dempsey) (10/25/88)
In article <598@utkcs2.cs.utk.edu> jepeway@utkcs2.cs.utk.edu (Chris Jepeway) writes: >I'm trying to get POP running under MH v6r6. >The POP server is a Vax 8200 running Ultrix 2.2, >and the clients are Sun 3/60's and 3/260's >running Sun-OS 3.5. The trouble I'm having >is that the POP server on the Vax thinks >the entire contents of /var/spool/mail/whoever >is a single message. Here's the Vax's mtstailor file-- > >mmdfldir: /var/spool/mail >servers: localhost \01localnet >mmdelim1:\nFrom\ >mmdelim2:\nFrom\ The obvious answer! It really *SHOULD* work this way, right? > >The characters after the final slashes on the mmdelim >lines are spaces. I can't figure what's going on, >but trust that someone else has a solution. > >Thanks Ever, >C. Jepeway [I've been rather hesitant to post a rogue patch to such a large and popular software package, but figure there must be MANY (hundreds of, even) people out there who could *really* use this (!) ] The above configuration would seem to be technically correct. The problem with MH is that the POP server is normally used to handle mailboxes created by the POP delivery agent (mail comes in addressed to user@pop). This is when those 'mmdelim'' strings are inserted into the maildrop file. The normal V7 mailbox format says that new messages begin with a line that looks like: From sender[@wherever] FORMATTED_DATE\n Unfortunately, the part of the POP server that reads maildrops is not set up to handle this. Lines are read from the file using fgets(3S), which will never be able to deal with a line that looks like: [anything or NULL]\n[data][anything else to be ignores] as was attempted above. The newline not being at the end is the kicker. Unless you know how simple-minded the maildrop reader is, it is not ovbious why `mmdelim: \nFrom ' fails. I cannot imagine that nobody ever thought about using POP this way before! When I discovered MH, it was the *instant* solution to all our mail problems. Or so I thought. This odd behavior of the POP server was the only flaw, and I set out to fix it immediately. Since we have sources, I was able to discover how the old 4.[23]BSD mailer handled the message delimiter. The solution I came up with involved duplication of a few of the MH library routines with minor changes, and borrowing some of the BSD code to detect the beginning of a new message. Because the problem is almost trivial, and the borrowed code is nothing fancy, I decided that I would just grab the parts I needed to make the POP server work. If I had not been lazy, the necessary code could have been implemented in about 10 lines of C, but I thought I might as well do it the right way, and use some robust(?) code. The following is a context diff between the new and old versions of .../mh-6.6/support/pop/popser.c. Part of the change is almost a duplication of mbx_read() routine, and the rest is to parse the beginning of a new message. With this patch, the postoffice (POP server) is able to read /usr/spool/mail/whoever properly with no other changes to the delivery agent or any other part of MH. We've been using this for several weeks without a hitch. It's really been the answer to our mail problems. Before MH, things were VERY difficult, and now mail is a breeze. Just for the record, I've included the options I used on the server and one of the clients. I've no no experience with generating patches, so please excuse the raw diff. It should not be difficult to install, but if you have trouble, I can mail out the entire file to those who request it. P.S I also have managed to get a client version of MH6.6 running under HPUX V5.17. This also is a relatively small patch that I'd be willing to mail to interested parties. The official update will be submitted when I find the time to really clean it up .... some day. ------------------------------------------------------------------------------- /\ \Steve Dempsey, Center For \steved@longs.LANCE.ColoState.Edu \/ _|/ _ _\Computer Assisted Engineering\dempsey@handel.CS.ColoState.Edu /\ | (_) | |_(_)\Colorado State University \...!ncar!handel!dempsey /_/_/(_/\_/ V \_ \Fort Collins, CO 80523 \(303)-491-0630 ------------------------------- Options --------------------------------------- Server is a VAX780 running 4.3XINU [BSD+NFS]. Client is a VS2000 running Ultrix2.2, both use same options. version: MH 6.6 #1[UCI] (ics) of Tue May 24 15:51:53 PDT 1988 options: [BSD42] [BSD43] [BERK] [TTYD] [DUMB] [MHE] [NETWORK] [BIND] [RPATHS] [ATZ] [SBACKUP='"#"'] [DPOP] [MHRC] [RPOP] [OVERHEAD] [WHATNOW] [SENDMTS] [SMTP] [POP] [BPOP] -------------------------------- Diffs ---------------------------------------- <- popser.c -> popser.c.orig 646c646 < if ((i = pmbx_read (dp, pos, &rp, debug)) <= 0) --- > if ((i = mbx_read (dp, pos, &rp, debug)) <= 0) 1359,1762d1358 < < /* dropsbr.c - read from a mailbox - pop server version */ < < /* ALMOST IDENTICAL to mbx_read */ < < int pmbx_read (fp, pos, drops, noisy) < register FILE *fp; < register long pos; < struct drop **drops; < int noisy; < { < register int len, < size; < long ld1, < ld2; < register char *bp; < char buffer[BUFSIZ]; < register struct drop *cp, < *dp, < *ep, < *pp; < < /* get drop storage */ < pp = (struct drop *) calloc ((unsigned) (len = MAXFOLDER), sizeof *dp); < < if (debug) < padvise (NULLCP, LOG_DEBUG, "pmbx_read (%d, %ld, %d, %d)", < fp, pos,drops,noisy); < < if (pp == NULL) { < if (noisy) < admonish (NULLCP, "unable to allocate drop storage"); < return NOTOK; < } < < /* get sizes of msg delimiters */ < ld1 = (long) strlen (mmdlm1); < ld2 = (long) strlen (mmdlm2); < < /* rewind drop file */ < (void) fseek (fp, pos, 0); < < if (debug) < padvise (NULLCP, LOG_DEBUG, "rewind maildrop"); < < /* read a buffer */ < for (ep = (dp = pp) + len - 1; fgets (buffer, sizeof buffer, fp);) { < size = 0; < < /* if beginning of msg then mark it */ < < if (p_ishead(buffer)) /*(strcmp (buffer, mmdlm1) == 0)*/ { < /* (don't) inc pos to msg start, mark it */ < /*pos += ld1;*/ < dp -> d_start = pos; < pos += strlen(buffer); /* inc pos after marking head */ < } < else { < /* didn't find it; mark it anyway */ < dp -> d_start = pos, pos += (long) strlen (buffer); < < /* count newlines and inc size if any found */ < for (bp = buffer; *bp; bp++, size++) < if (*bp == '\n') < size++; < } < < /* read more lines... */ < while (fgets (buffer, sizeof buffer, fp) != NULL) < < /* found end? */ < if (p_ishead(buffer)) /*(strcmp (buffer, mmdlm2) == 0)*/ { < < /* out of loop */ < (void) fseek (fp, pos, 0); < break; < < } < else { < /* add buffer size to pos */ < pos += (long) strlen (buffer); < < /* count newlines.... */ < for (bp = buffer; *bp; bp++, size++) < if (*bp == '\n') < size++; < } < < if (dp -> d_start != pos) { < /* do this if pos was actually incremented; got some text */ < dp -> d_id = 0; < dp -> d_size = size; /* save the stuff we got */ < dp -> d_stop = pos; < dp++; < } < < /* (don't) advance pos */ < /* pos += ld2; */ < < /* need more storage.... */ < if (dp >= ep) { < register int curlen = dp - pp; < < cp = (struct drop *) realloc ((char *) pp, < (unsigned) (len += MAXFOLDER) * sizeof *pp); < if (cp == NULL) { < if (noisy) < admonish (NULLCP, "unable to allocate drop storage"); < free ((char *) pp); < return 0; < } < dp = cp + curlen, ep = (pp = cp) + len - 1; < } < } < < /* return unused stuff */ < if (dp == pp) < free ((char *) pp); < else < *drops = pp; < return (dp - pp); < } < < /* < * The remainder of this file adapted from: < * < * head.c 5.2 (Berkeley) 6/21/85 < */ < < struct p_hdline { < char *l_from; /* The name of the sender */ < char *l_tty; /* His tty string (if any) */ < char *l_date; /* The entire date string */ < }; < < /* < * < * See if position in a file is a mail header. < * Return true if yes. Note the extreme pains to < * accommodate all funny formats. < */ < < #define NOSTR ((char *) 0) /* Null string pointer */ < < p_ishead(buffer) < char buffer[]; < { < register char *cp; < struct p_hdline hl; < char linebuf[BUFSIZ]; < char parbuf[BUFSIZ]; < < char * p_copyin(); < char * p_copy(); < < strcpy(linebuf,buffer); < cp = linebuf; < < if (linebuf[0]=='F') < padvise (NULLCP, LOG_DEBUG, "ishead: '%s'",linebuf); < < if (strncmp("From ", cp, 5) != 0) < return(0); < < padvise (NULLCP, LOG_DEBUG, "Fromline..."); < < /* get full header */ < p_parse(cp, &hl, parbuf); < < if (hl.l_from == NOSTR || hl.l_date == NOSTR) { < padvise (NULLCP, LOG_DEBUG, "Fromline...NODATE"); < return(0); < } < < if (!p_isdate(hl.l_date)) { < padvise (NULLCP, LOG_DEBUG, "Fromline...BADDATE %s", < hl.l_date); < return(0); < } < < /* I guess we got it! */ < padvise (NULLCP, LOG_DEBUG, "got a head.. "); < < return(1); < } < < /* < * Split a headline into its useful components. < * Copy the line into dynamic string space, then set < * pointers into the copied line in the passed headline < * structure. Actually, it scans. < */ < < p_parse(line, hl, pbuf) < char line[], pbuf[]; < struct p_hdline *hl; < { < register char *cp, *dp; < char *sp; < char word[BUFSIZ]; < char * p_nextword(); < < hl->l_from = NOSTR; < hl->l_tty = NOSTR; < hl->l_date = NOSTR; < cp = line; < sp = pbuf; < < /* < * Skip the first "word" of the line, which should be "From" < * anyway. < */ < cp = p_nextword(cp, word); < dp = p_nextword(cp, word); < if (!(strcmp(word, "")==0)) < hl->l_from = p_copyin(word, &sp); < < /* UNLIKELY */ < if (strncmp(dp, "tty", 3) == 0) { < cp = p_nextword(dp, word); < hl->l_tty = p_copyin(word, &sp); < if (cp != NOSTR) < hl->l_date = p_copyin(cp, &sp); < } < < /* USUAL */ < else < if (dp != NOSTR) < hl->l_date = p_copyin(dp, &sp); < } < < /* < * Copy the string on the left into the string on the right < * and bump the right (reference) string pointer by the length. < * Thus, dynamically allocate space in the right string, copying < * the left string into it. < */ < < char * < p_copyin(src, space) < char src[]; < char **space; < { < register char *cp, *top; < register int s; < < s = strlen(src); < cp = *space; < top = cp; < strcpy(cp, src); < cp += s + 1; < *space = cp; < return(top); < } < < /* < * Collect a liberal (space, tab delimited) word into the word buffer < * passed. Also, return a pointer to the next word following that, < * or (empty) if none follow. < */ < < char * < p_nextword(wp, wbuf) < char wp[], wbuf[]; < { < register char *cp, *cp2; < < if ((cp = wp) == NOSTR) { < p_copy("", wbuf); < return(NOSTR); < } < cp2 = wbuf; < while (!any(*cp, " \t") && *cp != '\0') < if (*cp == '"') { < *cp2++ = *cp++; < while (*cp != '\0' && *cp != '"') < *cp2++ = *cp++; < if (*cp == '"') < *cp2++ = *cp++; < } else < *cp2++ = *cp++; < *cp2 = '\0'; < while (any(*cp, " \t")) < cp++; < if (*cp == '\0') < return(NOSTR); < return(cp); < } < < /* < * Copy str1 to str2, return pointer to null in str2. < */ < < char * < p_copy(str1, str2) < char *str1, *str2; < { < register char *s1, *s2; < < s1 = str1; < s2 = str2; < while (*s1) < *s2++ = *s1++; < *s2 = 0; < return(s2); < } < < #define L 1 /* A lower case char */ < #define S 2 /* A space */ < #define D 3 /* A digit */ < #define O 4 /* An optional digit or space */ < #define C 5 /* A colon */ < #define N 6 /* A new line */ < #define U 7 /* An upper case char */ < < /*example T h u S e p 2 9 1 5 : 2 0 : 1 9 1 9 8 8 */ < char p_ctypes[] = {U,L,L,S,U,L,L,S,O,D,S,D,D,C,D,D,C,D,D,S,D,D,D,D,0}; < < /* example T h u S e p 2 9 1 5 : 2 0 : 1 9 M S T 1 9 8 8 */ < char p_tmztyp[] = {U,L,L,S,U,L,L,S,O,D,S,D,D,C,D,D,C,D,D,S,U,U,U,S,D,D,D,D,0}; < < p_isdate(date) < char date[]; < { < register char *cp; < < cp = date; < if (p_cmatch(cp, p_ctypes)) < return(1); < < return(p_cmatch(cp, p_tmztyp)); < } < < /* < * Match the given string against the given template. < * Return 1 if they match, 0 if they don't < */ < < p_cmatch(str, temp) < char str[], temp[]; < { < register char *cp, *tp; < register int c; < < cp = str; < tp = temp; < while (*cp != '\0' && *tp != 0) { < c = *cp++; < switch (*tp++) { < case L: < if (c < 'a' || c > 'z') < return(0); < break; < < case U: < if (c < 'A' || c > 'Z') < return(0); < break; < < case S: < if (c != ' ') < return(0); < break; < < case D: < if (!isdigit(c)) < return(0); < break; < < case O: < if (c != ' ' && !isdigit(c)) < return(0); < break; < < case C: < if (c != ':') < return(0); < break; < < case N: < if (c != '\n') < return(0); < break; < } < } < if ((*cp != '\0' && *cp != '\n') || *tp != 0) < return(0); < return(1); < } < < any(ch, str) < char *str; < { < register char *f; < register c; < < f = str; < c = ch; < while (*f) < if (c == *f++) < return(1); < return(0); < } <