/* * Copyright 1998-2002 Ben Smithurst * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Splits a mbox into its individual messages. */ #include "misc.h" const char rcsid[] = "$BCPS: src/mailutils/mail-split.c,v 1.29 2003/01/19 19:18:25 ben Exp $"; int split_maildir(int, char *, FILE *); int split_file(FILE *, FILE *); void usage(void); char *prefix, *suffix; int fflag; int main(int argc, char *argv[]) { int ch; /* defaults */ prefix = "%n-"; suffix = ""; fflag = 0; while ((ch = getopt(argc, argv, "fp:s:")) != -1) switch (ch) { case 'f': fflag = 1; break; case 'p': prefix = optarg; break; case 's': suffix = optarg; break; default: usage(); /* NOTREACHED */ } argc -= optind; argv += optind; return (process(argv, split_file, split_maildir) ? 0 : 1); } int split_maildir(int reset, char *fn, FILE *in_fp) { if (reset) warnx("useless on Maildir %s", curfile); return (RET_NOCHANGE); } /* * Expands the given prefix, number and suffix into `buf', which has * room for `size' characters including NUL. %N in prefix or suffix * expands to the value of `curfile', %n to the last part of `curfile' * (i.e. from the character after the last slash onwards, or the entire * string if it doesn't contain any slashes.) */ int fn_expand(char *buf, int size, char *prefix, char *suffix, int num) { char numbuf[32]; char *b, *p; int len, i; int plen, slen, nlen, nblen, numlen; snprintf(numbuf, sizeof numbuf, "%06d", num); numlen = strlen(numbuf); plen = strlen(prefix); slen = strlen(suffix); nlen = strlen(curfile); if ((b = strrchr(curfile, '/')) == NULL) { b = curfile; nblen = nlen; } else { b++; nblen = strlen(b); } /* Do the expansion */ len = 0; for (i = 0; i < 3; i++) { /* Second time through the loop, just copy the number */ if (i == 1) { if (len + numlen >= size) return (0); strcpy(buf + len, numbuf); len += numlen; continue; } /* * First time through (i == 0), process the prefix, otherwise * (must be third time) process suffix. */ for (p = (i ? suffix : prefix); *p != '\0'; p++) switch (*p) { case '%': switch (*++p) { case 'n': if (len + nblen >= size) return (0); strcpy(buf + len, b); len += nblen; break; case 'N': if (len + nlen >= size) return (0); strcpy(buf + len, curfile); len += nlen; break; case '\0': p--; /* So that for() loop sees \0 */ /* FALLTHROUGH */ case '%': if (len + 1 >= size) return (0); buf[len++] = '%'; break; default: if (len + 2 >= size) return (0); buf[len++] = '%'; buf[len++] = *p; break; } break; default: if (len + numlen >= size) return (0); buf[len++] = *p; break; } } buf[len] = '\0'; return (1); } int split_file(FILE *in, FILE *junk) { FILE *out; char *line, filename[MAXPATHLEN]; int e, fd, from_line, num; size_t len; mode_t mask; /* Set a restrictive umask since files containing mail are created */ mask = umask(077); num = 0; from_line = 0; out = NULL; while ((line = gl_getline(in)) != NULL) { len = strlen(line); chop(line, len); if (is_from(line, 1)) { num++; from_line = 1; if (out) { fclose(out); out = NULL; } /* * build the new filename, increase num until * a unique name is found. */ for (;;) { /* Do expansion */ if (!fn_expand(filename, sizeof filename, prefix, suffix, num)) { warnx("fn_expand failed"); umask(mask); return (RET_LOCALERROR); } /* Attempt to create file */ fd = open(filename, O_WRONLY|O_CREAT|O_EXCL, 0600); if (fd >= 0) break; /* EEXIST is ok, anything else isn't. */ if (errno != EEXIST) { e = errno; umask(mask); errno = e; return (RET_ERROR); } /* Protect against overflow. */ if (num == INT_MAX) { warnx("couldn't get unique name"); umask(mask); return (RET_LOCALERROR); } num++; } if ((out = fdopen(fd, "w")) == NULL) { e = errno; umask(mask); errno = e; return (RET_ERROR); } } else from_line = 0; if (out && (fflag || !from_line)) fprintf(out, "%s\n", line); } gl_destroy(in); if (out != NULL) fclose(out); umask(mask); return (RET_NOCHANGE); } void usage(void) { fprintf(stderr, "usage: mail-split [-f] [-p prefix] [-s suffix]\n" " [files ...]\n"); exit(EX_USAGE); }