--- vdelivermail.c.orig Mon Oct 20 20:59:57 2003 +++ vdelivermail.c Sat Nov 1 11:21:15 2003 @@ -62,6 +62,7 @@ #define FILE_SIZE 156 char hostname[FILE_SIZE]; char loop_buf[FILE_SIZE]; +char spam_buf[FILE_SIZE]; #define MSG_BUF_SIZE 5000 char msgbuf[MSG_BUF_SIZE]; @@ -90,6 +91,10 @@ void usernotfound(void); int is_loop_match( char *dt, char *address); int deliver_quota_warning(const char *dir, const char *q); +#ifdef SPAM_THRESHOLD +int is_spam(int threshold); +int is_spam_match(char *xsl, int threshold); +#endif static char local_file[156]; static char local_file_new[156]; @@ -257,7 +262,7 @@ /* check for wildcard if there's no match */ if(tmpstr == NULL) { - for(i=strlen(TheUser);i >= 0 && j != 1;--i) { + for(i=strlen(TheUser);i > 0 && j != 1;--i) { if(TheUser[i-1]=='-') { tmpuser[0] = '\0'; strncat(tmpuser,TheUser,i); @@ -444,6 +449,7 @@ int inject = 0; FILE *fs; char tmp_file[256]; + int pim[2]; /* check if the email is looping to this user */ if ( is_looping( address ) == 1 ) { @@ -631,6 +637,51 @@ } } +#ifdef SPAMC + /* fork the SpamAssassin client - patch by Alex Dupre */ + if (!pipe(pim)) { + pid = vfork(); + switch (pid) { + case -1: + close(pim[0]); + close(pim[1]); + break; + case 0: + close(pim[0]); + dup2(pim[1], 1); + close(pim[1]); + if (execl(SPAMC, SPAMC, "-u", maildir_to_email(address), 0) == -1) { + while ((file_count = read(0, msgbuf, MSG_BUF_SIZE)) > 0) + write(1, msgbuf, file_count); + _exit(0); + } + } + close(pim[1]); + dup2(pim[0], 0); + close(pim[0]); + } +#ifdef SPAM_THRESHOLD + /* silently delete message if spam level > SPAM_THRESHOLD */ + if (is_spam(SPAM_THRESHOLD) == 1) { + close(write_fd); + if (unlink(local_file) != 0) { + printf("unlink failed %s errno = %d\n", local_file, errno); + return(errno); + } + return(0); + } + +#ifdef MAKE_SEEKABLE + if (!Seekable(0)) + MakeSeekable(stdin); +#endif + + if (lseek(0, 0L, SEEK_SET) < 0) { + printf("lseek errno=%d\n", errno); + return(errno); + } +#endif +#endif /* read it in chunks and write it to the new file */ while((file_count=read(0,msgbuf,MSG_BUF_SIZE))>0) { @@ -881,6 +932,9 @@ if (strncmp(loop_buf, "Delivered-To: ", 14) == 0 && is_loop_match(loop_buf, address)==1 ) { + /* seek to the end of stdin */ + fseek(stdin, 0L, SEEK_END); + /* return the loop found */ return(1); @@ -919,6 +973,8 @@ * looping not found value */ if ( found == 0 ) { + /* seek to the end of stdin */ + fseek(stdin, 0L, SEEK_END); /* return not found looping message value */ return(0); } @@ -1335,3 +1391,96 @@ return(1); } +#ifdef SPAM_THRESHOLD +/* Check for a spam message + * This is done by checking for a matching line + * in the email headers for X-Spam-Level: which + * we put in each spam email + * + * Return 1 if spam + * Return 0 if not spam + * Return -1 on error + */ +int is_spam(int threshold) +{ + int i; + int found; + +#ifdef MAKE_SEEKABLE + if (!Seekable(0)) + MakeSeekable(stdin); +#endif + + if ( lseek(0, 0L, SEEK_SET) < 0 ) { + printf("lseek errno=%d\n", errno); + return(errno); + } + + while (fgets(spam_buf, sizeof(spam_buf), stdin) != NULL){ + + /* if we find the line, return error (looping) */ + if (strncmp(spam_buf, "X-Spam-Level: ", 14) == 0 && + is_spam_match(spam_buf, threshold) ==1) { + + /* seek to the end of stdin */ + fseek(stdin, 0L, SEEK_END); + + /* return the spam found */ + return(1); + + /* check for the start of the body, we only need + * to check the headers. + */ + } else { + + /* walk through the charaters in the body */ + for (i = 0, found = 0; spam_buf[i] != 0 && found == 0; ++i) { + switch(spam_buf[i]) { + + /* skip blank spaces and new lines */ + case ' ': + case '\n': + case '\t': + case '\r': + break; + + /* found a non blank, so we are still + * in the headers + */ + default: + + /* set the found non blank char flag */ + found = 1; + break; + } + } + + /* if the line only had blanks, then it is the + * delimiting line between the headers and the + * body. We don't need to check the body for + * the X-Spam-Level: line. Hence, we + * are done with our search and can return the + * spam not found value + */ + if (found == 0) { + /* seek to the end of stdin */ + fseek(stdin, 0L, SEEK_END); + /* return not found spam message value */ + return(0); + } + } + } + + /* if we get here then the there is either no body + * or the logic above failed and we scanned + * the whole email, headers and body. + */ + return(0); +} + +int is_spam_match(char *xsl, int threshold) +{ + if (strlen(xsl) - strlen("X-Spam-Level: ") > threshold) return(1); + else return(0); +} +#endif