nsb@THUMPER.BELLCORE.COM (Nathaniel Borenstein) (08/01/90)
I've gotten several requests for the "eatmail" program I referenced in a previous post. Since it hasn't yet made it onto a patch, and since it is very short, I thought I'd post it here. You only need two files, Imakefile and eatmail.c -- I put them in a directory called contrib/eatmail. The Imakefile looks like this: LOCALINCLUDES = -I${BASEDIR}/include/ams OBJS = eatmail.o LIBS= \ ${BASEDIR}/lib/libmail.a \ ${BASEDIR}/lib/liberrors.a \ ${UTILLIB} NormalObjectRule() ProgramTarget(eatmail, ${OBJS}, ${LIBS} , ) DependTarget() And eatmail.c looks like this: /* This includes most of the code from ams/libs/ms/cvtold.c, so a better eventual solution would be to modularize it; unfortunately, the biggest differences are things I was able to remove to shrink the size of the eatmail binary, but which are really needed by the message server... */ #include <stdio.h> #include <sys/param.h> #include <sys/stat.h> #include <andrewos.h> /* sys/types.h sys/file.h sys/time.h */ #include <system.h> /* #include <ms.h> */ #include <mserrno.h> #include <mailconf.h> #include <ctype.h> #include <parseadd.h> #include <pwd.h> extern char *malloc(), *index(); extern int errno; extern FILE *fopen(); extern char *getenv(), *getprofile(); char home[1+MAXPATHLEN]; long mserrcode; #undef AMS_RETURN_ERRCODE #define AMS_RETURN_ERRCODE(x,y,z) return(-1); main() { char SpoolFileName[1 + MAXPATHLEN], SourceDir[1+MAXPATHLEN], *SpoolFile; int numfound = 0, errcode; struct passwd *pswd; CheckAMSConfiguration(); pswd = getpwuid(getuid()); if (!pswd) { fprintf(stderr, "Cannot get your password file entry\n"); exit(-1); } strcpy(home, pswd->pw_dir); SpoolFile = getenv("MAIL"); if (SpoolFile == NULL || *SpoolFile == '\0') SpoolFile = getprofile("mailboxfile"); if (SpoolFile == NULL || *SpoolFile == '\0') { sprintf(SpoolFileName, "%s/%s", AMS_MailBoxPrefix, pswd->pw_name); } else { strcpy(SpoolFileName, SpoolFile); } sprintf(SourceDir, "%s/Mailbox", home); if (ConvertIncomingMail(SpoolFileName, SourceDir, &numfound)) { fprintf(stderr, "Error: Could not move mail from %s to %s\n", SpoolFileName, SourceDir); exit(-1); } exit(0); } /* * Remove the mail lock, and note that we no longer * have it locked. */ static int rmlock(name, lockFD) char name[]; int lockFD; { struct stat statb; if (lockFD >= 0) close(lockFD); if (stat(name, &statb) < 0) return(-1); if ((statb.st_mode & S_IFMT) != S_IFREG) { errno = EISDIR; return(-1); } if (unlink(name)) { #if SY_B4x != 0 return(truncate(name, 0)); #else /* SY_B4x */ return 0; #endif /* SY_B4x */ } return(0); } /* * Lock the specified mail file by setting the file mailfile.lock. * We must, of course, be careful to rmlock the lock file by a call * to unlock before we stop. The algorithm used here is to see if * the lock exists, and if it does, return an error. * * Attempt to set the lock by creating the temporary file, * then doing a link/unlink. If it fails, return -1 else 0 */ static int lock(file, lockedFile, lockedFDp) char *file, *lockedFile; int *lockedFDp; { register int f, g; char locktmp[1+MAXPATHLEN]; /* Usable lock temporary */ char *s; s = rindex(file, '/'); if (*s != '/') return -1; strcpy(lockedFile, SpoolMailLockDir); strcat(lockedFile, s); strcat(lockedFile, ".lock"); g = open(lockedFile, osi_O_READLOCK, 0); if (g < 0) return -1; if (osi_ExclusiveLockNoBlock(g) != 0) { close(g); return -1; } strcpy(locktmp, SpoolMailLockTemp); mktemp(locktmp); rmlock(locktmp, -1); f = creat(locktmp, 0); if (f < 0) { close(g); return(-1); } close(f); if (link(locktmp, lockedFile) < 0) { rmlock(locktmp, g); return(-1); } rmlock(locktmp, -1); *lockedFDp = g; return(0); } static int SetHoldFromFile(fname, holdP) char *fname; int *holdP; {/* Set or unset ``hold'' as in the file ``fname''. */ FILE *fp; char InBuf[300]; char *sp, *scmd; int DoSet, errsave; errno = 0; fp = fopen(fname, "r"); if (fp == NULL) { if (errno == ENOENT) return 0; if (errno == 0) errno = ENOMEM; AMS_RETURN_ERRCODE(errno, EIN_FOPEN, EVIA_CONVERTINCOMING); } for (;;) { NextLine: sp = fgets(InBuf, sizeof(InBuf), fp); if (sp == NULL) break; while (*sp != '\0' && isspace(*sp)) ++sp; scmd = sp; while (*sp != '\0' && !isspace(*sp)) ++sp; *sp++ = '\0'; if (strcmp(scmd, "set") == 0) DoSet = 1; else if (strcmp(scmd, "unset") == 0) DoSet = 0; else continue; for (;;) { while (*sp != '\0' && isspace(*sp)) ++sp; if (*sp == '\0') goto NextLine; scmd = sp; while (*sp != '\0' && !isspace(*sp)) ++sp; *sp++ = '\0'; if (strcmp(scmd, "hold") == 0) *holdP = DoSet; } } if (ferror(fp)) { errsave = errno; (void) fclose(fp); if (errsave == 0) errsave = ENOMEM; AMS_RETURN_ERRCODE(errno, EIN_READ, EVIA_CONVERTINCOMING); } (void) fclose(fp); } static int CheckMailrcHold() {/* Check whether the ~/.mailrc or /usr/lib/Mail.rc file has set the ``hold'' variable; return 0 if it isn't set, or an mserrcode. */ static int HoldVal = -1; int RC, TempVal; char MyMailrc[1+MAXPATHLEN]; if (HoldVal >= 0) return HoldVal; TempVal = 0; RC = SetHoldFromFile("/usr/lib/Mail.rc", &TempVal); if (RC != 0) return RC; sprintf(MyMailrc, "%s/.mailrc", home); RC = SetHoldFromFile(MyMailrc, &TempVal); if (RC != 0) return RC; HoldVal = TempVal; /* Got it all right. */ if (HoldVal != 0) { AMS_RETURN_ERRCODE(EMSHOLDSET, EIN_PARAMCHECK, EVIA_CONVERTINCOMING); } return 0; } #define FALSE 0 #define TRUE 1 #define buffsize 1024 #define MAXTRIES 25 int ConvertIncomingMail(MailSpoolFile, MailDir, FilesReadIn) char *MailSpoolFile, *MailDir; int *FilesReadIn; { FILE *fp; int wfd = 0, i, errsave, tfd, AnyWrittenToThisOne, LockFD; short FileOpen, ReadyToStartAgain; struct stat statbuf; char buffer[buffsize], FName[1+MAXPATHLEN], CurLock[1+MAXPATHLEN]; *FilesReadIn = 0; if ((stat(MailDir, &statbuf)) == -1){ if (errno == ENOENT) { return(0); } AMS_RETURN_ERRCODE(errno, EIN_STAT, EVIA_CONVERTINCOMING); } if ((stat(MailSpoolFile, &statbuf)) == -1){ if (errno == ENOENT) { return(0); } AMS_RETURN_ERRCODE(errno, EIN_STAT, EVIA_CONVERTINCOMING); } if (statbuf.st_size <= 0){ return(0); } errsave = CheckMailrcHold(); if (errsave != 0) return(errsave); if (AMS_StrictStandaloneLocking && (lock(MailSpoolFile, CurLock, &LockFD)) != 0){ AMS_RETURN_ERRCODE(errno, EIN_UCBMAILLOCK, EVIA_CONVERTINCOMING); } if ((fp = fopen(MailSpoolFile, "r")) == NULL){ if (AMS_StrictStandaloneLocking) rmlock(CurLock, LockFD); AMS_RETURN_ERRCODE(errno, EIN_OPEN, EVIA_CONVERTINCOMING); } FileOpen = FALSE; ReadyToStartAgain = 0; AnyWrittenToThisOne = 0; while (TRUE) { if (fgets(buffer, buffsize, fp) == NULL) { errsave = errno; if (feof(fp)) break; /* Done reading */ fclose(fp); if (AMS_StrictStandaloneLocking) rmlock(CurLock, LockFD); AMS_RETURN_ERRCODE(errsave, EIN_READ, EVIA_CONVERTINCOMING); } if (ReadyToStartAgain && FileOpen && (AMS_DemandSeparatingCharacter || IsNewFrom(buffer)) && AnyWrittenToThisOne) { (*FilesReadIn)++; if (vclose(wfd)) { fclose(fp); if (AMS_StrictStandaloneLocking) rmlock(CurLock, LockFD); AMS_RETURN_ERRCODE(errno, EIN_VCLOSE, EVIA_CONVERTINCOMING); } FileOpen = FALSE; } if (!FileOpen){ for (i=0; i<MAXTRIES; ++i) { sprintf(FName, "%s/%s", MailDir, ams_genid(1)); wfd = open(FName, O_CREAT|O_EXCL|O_WRONLY, 0600); if (wfd < 0) continue; if (osi_ExclusiveLockNoBlock(wfd)) { errsave = errno; close(wfd); if (errsave == EWOULDBLOCK) { continue; } AMS_RETURN_ERRCODE(errsave, EIN_FLOCK, EVIA_CONVERTINCOMING); } break; /* flock succeeded */ } if (wfd < 0) { errsave = errno; fclose(fp); if (AMS_StrictStandaloneLocking) rmlock(CurLock, LockFD); AMS_RETURN_ERRCODE(errsave, EIN_VMOPEN, EVIA_CONVERTINCOMING); } FileOpen = TRUE; AnyWrittenToThisOne = 0; } if (AMS_DemandSeparatingCharacter) { if ((buffer[0] == AMS_SeparatingCharacter) && (AnyWrittenToThisOne != 0)) { ReadyToStartAgain = 1; } else { writeall(wfd, buffer, strlen(buffer)); AnyWrittenToThisOne = 1; ReadyToStartAgain = 0; } } else { ReadyToStartAgain = (buffer[0] == '\n') ? 1 : 0; writeall(wfd, buffer, strlen(buffer)); AnyWrittenToThisOne = 1; } } if (FileOpen){ (*FilesReadIn)++; if (vclose(wfd)) { errsave = errno; fclose(fp); if (AMS_StrictStandaloneLocking) rmlock(CurLock, LockFD); AMS_RETURN_ERRCODE(errsave, EIN_VCLOSE, EVIA_CONVERTINCOMING); } } if ((tfd = creat(MailSpoolFile, 666)) < 0){ fprintf(stderr, "Could not Zero-out %s (%d)...continuing anyway", MailSpoolFile, errno); } else { close(tfd); /* Just creating it, that's all */ } fclose(fp); if (AMS_StrictStandaloneLocking) rmlock(CurLock, LockFD); return(0); } static int IsNewFrom(line) char *line; { PARSED_ADDRESS *ListHead = NULL; struct tm TmBuf; char *addr, *date, *space; /* First pass, very simple */ if (strncmp(line, "From", 4)) { return(0); } if (line[4] != ' ' && (!AMS_AllowColonInSeparatingFrom || line[4] != ':')) return(0); addr = index(line, ' '); if (!addr) return(0); while (*addr && isspace(*addr)) ++addr; if (!*addr) return(0); space = index(addr, ' '); if (!space) return(0); *space = '\0'; date = space+1; if (AMS_CheckAddressInSeparatingFrom && *addr != '@' && ParseAddressList(addr, &ListHead) != PA_OK) { *space = ' '; return(0); } if (ListHead) FreeAddressList(ListHead); *space = ' '; /* if (AMS_CheckDateInSeparatingFrom && parsedateheader(date, &TmBuf, 1, 1, 1, 0)) return(0); */ if (AMS_CheckDateInSeparatingFrom) { fprintf(stderr, "Can't check date in separating from\n"); return(-1); } return(1); }