X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/2def1ef7c06766912f6eea1a9ab31b492d82173a..475fef2edee9db3c63fc089df76f8e93e3d598cd:/uip/burst.c?ds=inline diff --git a/uip/burst.c b/uip/burst.c index 2c741c7f..71b226c1 100644 --- a/uip/burst.c +++ b/uip/burst.c @@ -8,38 +8,49 @@ */ #include - -static struct swit switches[] = { -#define INPLSW 0 - { "inplace", 0 }, -#define NINPLSW 1 - { "noinplace", 0 }, -#define QIETSW 2 - { "quiet", 0 }, -#define NQIETSW 3 - { "noquiet", 0 }, -#define VERBSW 4 - { "verbose", 0 }, -#define NVERBSW 5 - { "noverbose", 0 }, -#define VERSIONSW 6 - { "version", 0 }, -#define HELPSW 7 - { "help", 0 }, - { NULL, 0 } -}; +#include +#include + +#define BURST_SWITCHES \ + X("inplace", 0, INPLSW) \ + X("noinplace", 0, NINPLSW) \ + X("mime", 0, MIMESW) \ + X("nomime", 0, NMIMESW) \ + X("automime", 0, AUTOMIMESW) \ + X("quiet", 0, QIETSW) \ + X("noquiet", 0, NQIETSW) \ + X("verbose", 0, VERBSW) \ + X("noverbose", 0, NVERBSW) \ + X("version", 0, VERSIONSW) \ + X("help", 0, HELPSW) \ + +#define X(sw, minchars, id) id, +DEFINE_SWITCH_ENUM(BURST); +#undef X + +#define X(sw, minchars, id) { sw, minchars, id }, +DEFINE_SWITCH_ARRAY(BURST, switches); +#undef X struct smsg { - long s_start; - long s_stop; + off_t s_start; + off_t s_stop; }; +/* + * For the MIME parsing routines + */ + +int debugsw = 0; + /* * static prototypes */ -static int find_delim (int, struct smsg *); -static void burst (struct msgs **, int, struct smsg *, int, int, int, char *); -static void cpybrst (FILE *, FILE *, char *, char *, int); +static int find_delim (int, struct smsg *, int *); +static void find_mime_parts (CT, struct smsg *, int *); +static void burst (struct msgs **, int, struct smsg *, int, int, int, + char *, int); +static void cpybrst (FILE *, FILE *, char *, char *, int, int); /* * A macro to check to see if we have reached a message delimiter @@ -55,20 +66,15 @@ static void cpybrst (FILE *, FILE *, char *, char *, int); int main (int argc, char **argv) { - int inplace = 0, quietsw = 0, verbosw = 0; - int msgp = 0, hi, msgnum, numburst; + int inplace = 0, quietsw = 0, verbosw = 0, mimesw = 1; + int hi, msgnum, numburst; char *cp, *maildir, *folder = NULL, buf[BUFSIZ]; - char **argp, **arguments, *msgs[MAXARGS]; + char **argp, **arguments; + struct msgs_array msgs = { 0, 0, NULL }; struct smsg *smsgs; struct msgs *mp; -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex (argv[0], '/'); - - /* read user profile/context */ - context_read(); + if (nmh_init(argv[0], 1)) { return 1; } arguments = getarguments (invo_name, argc, argv, 1); argp = arguments; @@ -86,10 +92,10 @@ main (int argc, char **argv) snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]", invo_name); print_help (buf, switches, 1); - done (1); + done (0); case VERSIONSW: print_version(invo_name); - done (1); + done (0); case INPLSW: inplace++; @@ -98,6 +104,16 @@ main (int argc, char **argv) inplace = 0; continue; + case MIMESW: + mimesw = 2; + continue; + case NMIMESW: + mimesw = 0; + continue; + case AUTOMIMESW: + mimesw = 1; + continue; + case QIETSW: quietsw++; continue; @@ -119,14 +135,14 @@ main (int argc, char **argv) else folder = pluspath (cp); } else { - msgs[msgp++] = cp; + app_msgarg(&msgs, cp); } } if (!context_find ("path")) free (path ("./", TFOLDER)); - if (!msgp) - msgs[msgp++] = "cur"; + if (!msgs.size) + app_msgarg(&msgs, "cur"); if (!folder) folder = getfolder (1); maildir = m_maildir (folder); @@ -135,7 +151,7 @@ main (int argc, char **argv) adios (maildir, "unable to change directory to"); /* read folder and create message structure */ - if (!(mp = folder_read (folder))) + if (!(mp = folder_read (folder, 1))) adios (NULL, "unable to read folder %s", folder); /* check for empty folder */ @@ -143,8 +159,8 @@ main (int argc, char **argv) adios (NULL, "no messages in %s", folder); /* parse all the message ranges/sequences and set SELECTED */ - for (msgnum = 0; msgnum < msgp; msgnum++) - if (!m_convert (mp, msgs[msgnum])) + for (msgnum = 0; msgnum < msgs.size; msgnum++) + if (!m_convert (mp, msgs.msgs[msgnum])) done (1); seq_setprev (mp); /* set the previous-sequence */ @@ -158,11 +174,12 @@ main (int argc, char **argv) /* burst all the SELECTED messages */ for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) { if (is_selected (mp, msgnum)) { - if ((numburst = find_delim (msgnum, smsgs)) >= 1) { + if ((numburst = find_delim (msgnum, smsgs, &mimesw)) >= 1) { if (verbosw) printf ("%d message%s exploded from digest %d\n", numburst, numburst > 1 ? "s" : "", msgnum); - burst (&mp, msgnum, smsgs, numburst, inplace, verbosw, maildir); + burst (&mp, msgnum, smsgs, numburst, inplace, verbosw, + maildir, mimesw); } else { if (numburst == 0) { if (!quietsw) @@ -203,41 +220,92 @@ main (int argc, char **argv) /* * Scan the message and find the beginning and * end of all the messages in the digest. + * + * If requested, see if the message is MIME-formatted and contains any + * message/rfc822 parts; if so, burst those parts. */ static int -find_delim (int msgnum, struct smsg *smsgs) +find_delim (int msgnum, struct smsg *smsgs, int *mimesw) { - int wasdlm, msgp; - long pos; + int wasdlm = 0, msgp; + off_t pos; char c, *msgnam; - int cc; char buffer[BUFSIZ]; FILE *in; + CT content; - if ((in = fopen (msgnam = m_name (msgnum), "r")) == NULL) + msgnam = m_name (msgnum); + + /* + * If mimesw is 1 or 2, try to see if it's got proper MIME formatting. + */ + + if (*mimesw > 0) { + content = parse_mime(msgnam); + if (! content && *mimesw == 2) + return 0; + else if (content) { + smsgs[0].s_start = 0; + smsgs[0].s_stop = content->c_begin - 1; + msgp = 1; + find_mime_parts(content, smsgs, &msgp); + free_content(content); + if (msgp == 1 && *mimesw == 2) { + adios (msgnam, "does not have any message/rfc822 parts"); + } else if (msgp > 1) { + *mimesw = 1; + return (msgp - 1); + } + } + } + + *mimesw = 0; + + if ((in = fopen (msgnam, "r")) == NULL) adios (msgnam, "unable to read message"); for (msgp = 0, pos = 0L; msgp <= MAXFOLDER;) { + /* + * We're either at the beginning of the whole message, or + * we're just past the delimiter of the last message. + * Swallow lines until we get to something that's not a newline + */ while (fgets (buffer, sizeof(buffer), in) && buffer[0] == '\n') pos += (long) strlen (buffer); if (feof (in)) break; - fseek (in, pos, SEEK_SET); + + /* + * Reset to the beginning of the last non-blank line, and save our + * starting position. This is where the encapsulated message + * starts. + */ + fseeko (in, pos, SEEK_SET); smsgs[msgp].s_start = pos; + /* + * Read in lines until we get to a message delimiter. + * + * Previously we checked to make sure the preceeding line and + * next line was a newline. That actually does not comply with + * RFC 934, so make sure we break on a message delimiter even + * if the previous character was NOT a newline. + */ for (c = 0; fgets (buffer, sizeof(buffer), in); c = buffer[0]) { - if (CHECKDELIM(buffer) - && (msgp == 1 || c == '\n') - && ((cc = peekc (in)) == '\n' || cc == EOF)) + if ((wasdlm = CHECKDELIM(buffer))) break; else pos += (long) strlen (buffer); } - wasdlm = CHECKDELIM(buffer); - if (smsgs[msgp].s_start != pos) + /* + * Only count as a new message if we got the message delimiter. + * Swallow a blank line if it was right before the message delimiter. + */ + if (smsgs[msgp].s_start != pos && wasdlm) smsgs[msgp++].s_stop = (c == '\n' && wasdlm) ? pos - 1 : pos; + if (feof (in)) { #if 0 if (wasdlm) { @@ -251,7 +319,45 @@ find_delim (int msgnum, struct smsg *smsgs) } fclose (in); - return (msgp - 1); /* toss "End of XXX Digest" */ + return (msgp - 1); /* return the number of messages burst */ +} + + +/* + * Find any MIME content in the message that is a message/rfc822 and add + * it to the list of messages to burst. + */ + +static void +find_mime_parts (CT content, struct smsg *smsgs, int *msgp) +{ + struct multipart *m; + struct part *part; + + /* + * If we have a message/rfc822, then it's easy. + */ + + if (content->c_type == CT_MESSAGE && + content->c_subtype == MESSAGE_RFC822) { + smsgs[*msgp].s_start = content->c_begin; + smsgs[*msgp].s_stop = content->c_end; + (*msgp)++; + return; + } + + /* + * Otherwise, if we do have multiparts, try all of the sub-parts. + */ + + if (content->c_type == CT_MULTIPART) { + m = (struct multipart *) content->c_ctparams; + + for (part = m->mp_parts; part; part = part->mp_next) + find_mime_parts(part->mp_part, smsgs, msgp); + } + + return; } @@ -261,7 +367,7 @@ find_delim (int msgnum, struct smsg *smsgs) static void burst (struct msgs **mpp, int msgnum, struct smsg *smsgs, int numburst, - int inplace, int verbosw, char *maildir) + int inplace, int verbosw, char *maildir, int mimesw) { int i, j, mode; char *msgnam; @@ -351,16 +457,22 @@ burst (struct msgs **mpp, int msgnum, struct smsg *smsgs, int numburst, i = inplace ? msgnum + numburst : mp->hghmsg; for (j = numburst; j >= (inplace ? 0 : 1); i--, j--) { + char *tempfile; + + if ((tempfile = m_mktemp2(NULL, invo_name, NULL, &out)) == NULL) { + adios(NULL, "unable to create temporary file in %s", + get_temp_dir()); + } + strncpy (f2, tempfile, sizeof(f2)); strncpy (f1, m_name (i), sizeof(f1)); - strncpy (f2, m_mktemp(invo_name, NULL, &out), sizeof(f2)); if (verbosw && i != msgnum) printf ("message %d of digest %d becomes message %d\n", j, msgnum, i); chmod (f2, mode); - fseek (in, smsgs[j].s_start, SEEK_SET); + fseeko (in, smsgs[j].s_start, SEEK_SET); cpybrst (in, out, msgnam, f2, - (int) (smsgs[j].s_stop - smsgs[j].s_start)); + (int) (smsgs[j].s_stop - smsgs[j].s_start), mimesw); fclose (out); if (i == msgnum) { @@ -388,6 +500,7 @@ burst (struct msgs **mpp, int msgnum, struct smsg *smsgs, int numburst, #define S1 0 #define S2 1 #define S3 2 +#define S4 3 /* * Copy a mesage which is being burst out of a digest. @@ -395,11 +508,11 @@ burst (struct msgs **mpp, int msgnum, struct smsg *smsgs, int numburst, */ static void -cpybrst (FILE *in, FILE *out, char *ifile, char *ofile, int len) +cpybrst (FILE *in, FILE *out, char *ifile, char *ofile, int len, int mime) { register int c, state; - for (state = S1; (c = fgetc (in)) != EOF && len > 0; len--) { + for (state = mime ? S4 : S1; (c = fgetc (in)) != EOF && len > 0; len--) { if (c == 0) continue; switch (state) { @@ -440,6 +553,10 @@ cpybrst (FILE *in, FILE *out, char *ifile, char *ofile, int len) break; } break; + + case S4: + fputc (c, out); + break; } }