⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 passthrough.c

📁 一个C语言写的快速贝叶斯垃圾邮件过滤工具
💻 C
字号:
/* $Id: passthrough.c,v 1.39 2006/05/29 14:38:29 relson Exp $ *//*****************************************************************************NAME:   passthrough.c -- handle writing out message in passthrough ('-p') mode.******************************************************************************/#include "common.h"#include <assert.h>#include <ctype.h>#include <errno.h>#include <stdlib.h>#ifdef HAVE_SYSLOG_H#include <syslog.h>#endif#include "passthrough.h"#include "bogofilter.h"#include "bogoreader.h"		/* for is_eol() */#include "fgetsl.h"#include "format.h"#include "textblock.h"#include "xmalloc.h"#include "mysetvbuf.h"#include "lexer.h" /* need have_body */static const char *eol = NULL;char msg_register[256];static char msg_bogofilter[256];static char msg_spam_header[256];size_t msg_register_size = sizeof(msg_register);/* Function Definitions */static void cleanup_exit(ex_t exitcode, int killfiles)    __attribute__ ((noreturn));static void cleanup_exit(ex_t exitcode, int killfiles) {    if (fpo) {	output_cleanup();    }    if (killfiles && outfname[0] != '\0') unlink(outfname);    exit(exitcode);}#define	ISSPACE(ch)	(isspace(ch) || (ch == '\b'))/* check for non-empty blank line */static bool is_blank_line(const char *line, size_t len){    if (have_body)	return len == 0;    while (len-- > 0) {	byte ch = *line++;	if (!ISSPACE(ch))	    return false;    }    return true;}/** check if the line we're looking at is a header/body delimiter */static bool is_hb_delim(const char *line, size_t len, bool strict_body){    if (strict_body)	return len == 0;    return is_blank_line(line, len);}static int read_mem(char **out, void *in) {    textdata_t **text = in;    if ((*text)->next) {	int s = (*text)->size;	*out = (char *)(*text)->data;	*text = (*text)->next;	return s;    }    return 0;}static int read_seek(char **out, void *in) {    static char buf[4096];    FILE *inf = in;    static int carry[2] = { -1, -1 }; /* carry over bytes */    int s, i;    char *b = buf;    int cap = sizeof(buf);    for (i = 0; i < (int)sizeof(carry) && carry[i] != -1 ; i++) {	buf[i] = carry[i];	carry[i] = -1;    }    b += i;    cap -= i;    s = xfgetsl(b, cap, inf, true);    if (s == EOF) {       if (i) s = i;    } else {	s += i;    }    /* we must take care that on overlong lines, the \n doesn't appear     * at the beginning of the buffer, so we pull two characters out and      * store them in the carry array */    if (s && buf[s-1] != '\n') {	int c = 2;	if (c > s) c = s;	s -= c;	for (i = 0; i < c ; i++) {	    carry[i] = (unsigned char)buf[s+i];	}    }    *out = buf;    return s;}typedef int (*readfunc_t)(char **, void *);static bool write_header(rc_t status, readfunc_t rf, void *rfarg){    ssize_t rd;    char   *out;    bool hadlf = true;    bool seen_subj = false;    int bogolen = strlen(spam_header_name);    const char *subjstr = "Subject:";    int subjlen = strlen(subjstr);    /* print headers */    while ((rd = rf(&out, rfarg)) > 0)    {	if (eol == NULL) {	    if (memcmp(out+rd-1, NL, 1) == 0)		eol = NL;	    if (rd >=2 && memcmp(out+rd-2, CRLF, 2) == 0)		eol = CRLF;	}	/* skip over spam_header_name ("X-Bogosity:") lines */	while (rd >= bogolen && 	       memcmp(out, spam_header_name, bogolen) == 0) {	    while (((rd = rf(&out, rfarg)) > 0) && 		   (out[0] == ' ' || out[0] == '\t') )		/* empty loop */ ;	}	/* detect end of headers */	if (is_eol(out, rd) ||	    is_hb_delim(out, rd, have_body))	    /* check for non-empty blank line */	    break;	/* rewrite "Subject: " line */	if (!seen_subj && rd >= subjlen) {	    const char *tag = NULL;	    if (status == RC_SPAM && spam_subject_tag != NULL)		tag = spam_subject_tag;	    if (status == RC_UNSURE && unsure_subject_tag != NULL)		tag = unsure_subject_tag;	    if (tag != NULL && strncasecmp(out, subjstr, subjlen) == 0) {		seen_subj = true;		(void) fprintf(fpo, "%.*s %s", subjlen, out, tag);		if (out[subjlen] != ' ')		    fputc(' ', fpo);		(void) fwrite(out + subjlen, 1, rd - subjlen, fpo);		continue;	    }	}	hadlf = (out[rd-1] == '\n');	(void) fwrite(out, 1, rd, fpo);	if (ferror(fpo)) cleanup_exit(EX_ERROR, 1);    }    if (eol == NULL)	/* special treatment of empty input */	eol = NL;    if (!hadlf)	(void)fputs(eol, fpo);    return seen_subj;}static void write_body(readfunc_t rf, void *rfarg){    ssize_t rd;    char   *out;    int hadlf = 1;    /* If the message terminated early (without body or blank     * line between header and body), enforce a blank line to     * prevent anything past us from choking. */    (void)fputs(eol, fpo);    /* print body */    while ((rd = rf(&out, rfarg)) > 0)    {	(void) fwrite(out, 1, rd, fpo);	hadlf = (out[rd-1] == '\n');	if (ferror(fpo)) cleanup_exit(EX_ERROR, 1);    }    if (!hadlf) (void) fputs(eol, fpo);}static void build_spam_header(void){    if (passthrough || verbose || terse) {	typedef char *formatter(char *buff, size_t size);	formatter *fcn = terse ? format_terse : format_header;	(*fcn)(msg_spam_header, sizeof(msg_spam_header));    }}void write_message(rc_t status){    readfunc_t rf = NULL;	/* assignment to quench warning */    void *rfarg = 0;		/* assignment to quench warning */    textdata_t *text;    bool seen_subj = false;    build_spam_header();    if (!passthrough)	eol = NL;    else    {	eol = NULL;	/* initialize */	switch (passmode) {	    case PASS_MEM:		rf = read_mem;		text = textblock_head();		rfarg = &text;		break;	    case PASS_SEEK:		rf = read_seek;		rfarg = fpin;		rewind(rfarg);		break;	    default:		abort();	}	seen_subj = write_header(status, rf, rfarg);    }    /* print spam-status at the end of the header     * then mark the beginning of the message body */    if (passthrough || verbose || terse)	fprintf(fpo, "%s%s", msg_spam_header, eol);    if (passthrough || verbose || Rtable) {	verbose += passthrough;	print_stats( fpo );	verbose -= passthrough;    }    if (passthrough && !seen_subj) {	if (status == RC_SPAM && spam_subject_tag != NULL)	    (void) fprintf(fpo, "Subject: %s%s", spam_subject_tag, eol);	if (status == RC_UNSURE && unsure_subject_tag != NULL)	    (void) fprintf(fpo, "Subject: %s%s", unsure_subject_tag, eol);    }    if (passthrough) 	write_body(rf, rfarg);    if (passthrough || verbose || Rtable) {	if (fflush(fpo) || ferror(fpo))	    cleanup_exit(EX_ERROR, 1);    }    return;}void write_log_message(rc_t status){#ifdef HAVE_SYSLOG_H    format_log_header(msg_bogofilter, sizeof(msg_bogofilter));    switch (run_type) {    case RUN_NORMAL:	syslog(LOG_INFO, "%s\n", msg_bogofilter);	break;    case RUN_UPDATE:	if (status == RC_UNSURE || msg_register[0] == '\0')	    syslog(LOG_INFO, "%s\n", msg_bogofilter);	else {	    syslog(LOG_INFO, "%s, %s\n", msg_bogofilter, msg_register);	    msg_register[0] = '\0';	}	break;    default:	syslog(LOG_INFO, "%s", msg_register);	msg_register[0] = '\0';    }    closelog();#endif}/* we need to take care not to fclose() a shared file descriptor, if, * for instance we've fdopen()ed STDOUT_FILENO, becase we'd prevent * other streams accessing the same file descriptor from flushing their * caches. Prominent symptom: t.bogodir failure. */static bool fpo_mayclose;	/* if output_cleanup can close the file */void output_setup(void){    assert(fpo == NULL);    if (*outfname && passthrough) {	fpo = fopen(outfname,"wt");	fpo_mayclose = true;    } else {	fpo = fdopen(STDOUT_FILENO, "wt");	fpo_mayclose = false;    }    if (fpo == NULL) {	if (*outfname)	    fprintf(stderr, "Cannot open %s: %s\n",		    outfname, strerror(errno));	else	    fprintf(stderr, "Cannot fdopen STDOUT: %s\n", strerror(errno));	exit(EX_ERROR);    }    /* if we're not in passthrough mode, set line buffered mode just in     * case some program that calls uses waits for our output in -T mode */    if (!passthrough) {	mysetvbuf(fpo, NULL, _IOLBF, BUFSIZ);    }}void output_cleanup(void) {    int rc;    rc = fflush(fpo);    if (fpo_mayclose)	rc |= fclose(fpo);    fpo = NULL;    if (rc)	cleanup_exit(EX_ERROR, 1);}void passthrough_setup(void){    /* check if the input is seekable, if it is, we don't need to buffer     * things in memory => configure passmode accordingly     */    if (!passthrough)	return;    passmode = PASS_MEM;    if (passmode == PASS_MEM)	textblock_init();    if (DEBUG_GENERAL(2)) {	const char *m;	switch (passmode) {	case PASS_MEM:  m = "cache in memory"; break;	case PASS_SEEK: m = "rewind and reread file"; break;	default:        m = "unknown"; break;	}	fprintf(dbgout, "passthrough mode: %s\n", m);    }}int passthrough_keepopen(void){    return passthrough && passmode == PASS_SEEK ;}void passthrough_cleanup(void){    if (!passthrough)	return;    switch (passmode) {    case PASS_MEM:	textblock_free();	break;    case PASS_SEEK: default:	break;    }}/* End */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -