a new filter for multipart/base64 encoded messages
Peter Englmaier <[email protected]> Wed, 02 Jul 2003 16:07:54 +0200
| Newsgroups | gmane.mail.procmail.devel |
|---|---|
| Message-ID | <[email protected]> |
--fUYQa+Pmc3FrFX/N
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Hi,
I just wrote this little tool for decoding base64 encoded multipart
messages. I use this with procmail to find out if it contains
spam. The procmail code is as follows:
:0 f
* ^Content-Type: multipart/alternative
| base64-decoder
What it does is basically decoding each base64 encoded attachment
it encounters, leaving everything else untouched. The usual spam
checkers can then filter based on its contents.
A sample spam message is included which can be successfully decoded
with this tool. If anybody would like to hack on it and improve it,
I would like to get a copy. Perhaps procmail should include something
like this internally? Would be more efficient. Warning: the program
has not been tested a lot so far. It should probably do more tests
to ensure it won't decode images and such.
Best, Peter.
P.s.: The tool needs the program mimencode from the metamail package.
--fUYQa+Pmc3FrFX/N
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="base64-decoder.c"
// Filter email message and decode base64 attachments
// (c) by Peter Englmaier, 2003. GPL license.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void parsepart(char *endoffile);
int main()
{
parsepart(NULL);
return 0;
}
// parse a multi-part section of the input
void parsepart(char *endoffile)
{
char *buffer, *boundary, *pos, *tfile=NULL, cmd[100];
FILE *tfp;
int mode=0, decode64=0, mime=0, multi=0, size=1000;
buffer=malloc(size);
boundary=malloc(size);
if (!buffer || !boundary) {
fprintf(stdout,"Out of memory\n");
exit(1);
}
while (fgets(buffer, size, stdin)) {
if (endoffile!=NULL && strstr(buffer, endoffile)!=NULL) {
// fprintf(stderr, "**** Detected boundary-return from parsepart\n");
if (tfile) {
// fprintf(stderr, "**** closing temp file and decoding to stdout\n");
fclose(tfp);
sprintf(cmd, "mimencode -u %s", tfile);
fflush(stdout);
system(cmd);
unlink(tfile);
fprintf(stdout,"\n");
}
fprintf(stdout,"%s",buffer);
break;
}
switch (mode) {
case 0:// header
if (buffer[0]=='\n') { // end of header?
// fprintf(stderr, "**** detected body\n");
mode=1+multi; // switch to body mode
}
char *header1="Content-Length: ";
if (strncmp(buffer, header1, strlen(header1))==0) {
break;
}
header1="Lines: ";
if (strncmp(buffer, header1, strlen(header1))==0) {
break;
}
header1="Content-Transfer-Encoding: base64";
if (strncmp(buffer, header1, strlen(header1))==0) {
decode64=1;
// fprintf(stderr,"***base64 encoding detected\n");
sprintf(buffer, "Content-Transfer-Encoding: quoted-printable\n");
}
header1="Content-type: multipart/alternative";
if (strncmp(buffer, header1, strlen(header1))==0) {
multi=1;
// fprintf(stderr, "**** detected multipart \n");
}
if (multi) {
header1=" boundary=";
pos=strstr(buffer, header1);
if (pos!=NULL) {
if (1==sscanf(pos, " boundary=\"%[^\"]\"", boundary)) {
// fprintf(stderr,"**** Seen boundary >>%s<<\n", boundary);
}
}
}
fprintf(stdout,"%s",buffer);
break;
case 1: //body
if (decode64) {
if (tfile==NULL) {
tfile=tmpnam(NULL);
tfp=fopen(tfile, "w");
}
fprintf(tfp, "%s", buffer);
} else {
fprintf(stdout,"%s", buffer);
}
break;
case 2: //body
fprintf(stdout,"%s", buffer);
parsepart(boundary);
}
}
if (buffer) free(buffer);
if (boundary) free(boundary);
return;
}
--fUYQa+Pmc3FrFX/N
Content-Type: application/x-gzip
Content-Disposition: attachment; filename="sample.spam.gz"
Content-Transfer-Encoding: base64
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
--fUYQa+Pmc3FrFX/N--