headermatch/headermatch.c

127 lines
3.0 KiB (Stored with Git LFS)
C

/********
headermatch checks an rfc822 message on standard input for a matching
header, and exits 0 if finds a match, and 1 otherwise.
The header to match by default is "X-Spam-Flag: YES".
If a command line argument is given, its text is used
as the sorting header rather than "X-Spam-Flag: YES".
Note that standard input must be able to be mmaped(*) for the testing to
succeed - this will be the case when qmail-local is doing the delivery.
If mmap fails then headermatch exits with status 100.
(*) mmap was used so that there are no local buffers used in the program, so
that the program logic is very simple.
Copyright (C) 2006 Charlie Brady
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
***********/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <unistd.h>
#include <errno.h>
error(const char* s)
{
write(2, s, strlen(s));
write(2, "\n", 1);
}
char * find_str(const char* s, const long len, const char* pattern)
{
char* sptr;
size_t plen;
long slen;
char p;
if (*pattern == 0) return 0;
slen = len;
plen = strlen(pattern);
for (sptr = (char *)s; (p = *pattern) != 0; ++sptr, --slen)
{
if (*sptr == '\n')
{
sptr++;
slen--;
if (*sptr == '\n')
{
return 0;
}
if (slen < plen)
{
return 0;
}
if (!memcmp(sptr, pattern, (size_t)plen))
{
return sptr;
}
}
}
return 0;
}
int main(int argc, char **argv)
{
struct stat st;
char *message;
int fstat_ret;
char *end_of_headers;
char *spam_header = "X-Spam-Flag: YES";
size_t spam_header_len;
size_t message_len;
if (argc > 1)
{
spam_header = argv[1];
}
if (fstat_ret = fstat(0,&st))
{
error("Could not fstat standard input");
exit(111);
}
message_len = st.st_size;
spam_header_len = strlen(spam_header);
if (message_len < spam_header_len)
{
exit(99);
}
if (message_len > 0xffffffff)
{
error("Input file too big");
exit(100);
}
message = mmap(0,message_len,PROT_READ,MAP_SHARED,0,0);
if (message + 1)
{
if (!memcmp(message, spam_header, spam_header_len))
{
munmap(message, message_len);
exit(0);
}
if (find_str(message, message_len, spam_header))
{
munmap(message, message_len);
exit(0);
}
munmap(message, message_len);
exit(99);
}
error("MMap failed");
exit(100);
}