/******** 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 #include #include #include #include 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); }