qsf-1.2.7/0000755000076400007640000000000010665021416010123 5ustar awawqsf-1.2.7/README0000644000076400007640000000661110664537024011015 0ustar awawIntroduction ************ This is the README for `qsf', a quick spam filter. QSF uses a database of "tokens" taken from previous emails to determine whether any given email is likely to be spam or not. If an email is miscategorised, simply send the email back to QSF with the appropriate parameters to modify the database and make it more accurate. Note that `qsf' works well with either its own backend databases, GDBM, SQLite, or MySQL. GDBM and SQLite are fast but the builtin database reduces dependencies on other libraries, whereas MySQL can be harder to set up. If you use the MySQL backend, "make test" may fail. Read the documentation in the "MYSQL BACKEND" part of the manual for information on how to use `qsf' with MySQL. Also, it has been reported that MySQL 4.1.x works much better with QSF than 4.0.x or the 3.23.x series. Documentation ************* A manual page is included in this distribution. If you prefer plain text, then look at `doc/quickref.txt' for a text version. Dependencies ************ The internal binary tree and list databases have no dependencies. The GDBM backend requires GDBM: http://www.gnu.org/software/gdbm/ The MySQL backend requires MySQL: http://www.mysql.com/ The SQLite backend requires SQLite: http://www.sqlite.org/ (version 2.x). Note that if you try to compile MySQL support but the MySQL libraries cannot be found, make sure you have the MySQL development package installed. You may also need to install the "zlib-devel" package. Compilation *********** To compile the package, type "sh ./configure", which should generate a Makefile for your system. You may then type "make" to build everything. You may need GNU `make' for compilation to work properly. See the file `doc/INSTALL' for more about the `configure' script. Developers note that you can do "./configure --enable-debugging" to cause debugging support to be built in. Also note that doing "make index" will generate an HTML code index (using `ctags' and `cproto'); this index lists all files used, all functions defined, and all TODOs marked in the code. Memory allocation tracing (MALLOC_TRACE) may cause a crash if the allocation log file gets too large (>2GB usually). This is a bug in the C library; unfortunately it cannot be fixed in `qsf'. There are some extra shell scripts in the "extra/" directory, which can help with generation of statistics. Read the scripts for full details. Author ****** This package is copyright (C) 2007 Andrew Wood, and is being distributed under the terms of the Artistic License 2.0. For more details, see the file `doc/COPYING'. You can contact me by email at andrew.wood@ivarch.com or by using the contact form on my web page at http://www.ivarch.com/. Suggestions and patches have been received from the following people: Tom Parker Dr Kelly A. Parker Vesselin Mladenov Glyn Faulkner Mark Reynolds Ondrej Suchy Sam Roberts Scott Allen Karsten Kankowski M. Kolbl Micha Holzmann Jef Poskanzer Clemens Fischer Nelson A. de Oliveira Michal Vitecek Tommy Pettersson The `qsf' home page is at: http://www.ivarch.com/programs/qsf/ The latest version can always be found here. ----------------------------------------------------------------------------- qsf-1.2.7/src/0000755000076400007640000000000010665021416010712 5ustar awawqsf-1.2.7/src/include/0000755000076400007640000000000010665021416012335 5ustar awawqsf-1.2.7/src/include/message.h0000644000076400007640000000426510554714162014145 0ustar awaw/* * Message handling prototypes and structures. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #ifndef _MESSAGE_H #define _MESSAGE_H 1 #ifndef _OPTIONS_H #include "options.h" #endif #define MAX_MESSAGE_SIZE 512*1024 struct msg_s; typedef struct msg_s *msg_t; struct msg_s { /* structure describing an email message */ char *original; /* the original message, in full */ long original_size; /* the length of the full original message */ char *sender; /* email address from "From:" header */ char *envsender; /* email address of envelope sender */ int num_headers; /* number of header lines */ char **header; /* the header lines */ char *body; /* the original message body */ long body_size; /* the size of the original message body */ char *content; /* decoded content of message */ long content_size; /* the size of the decoded content */ long content_alloced; /* size of block allocated */ char *textcontent; /* decoded content of message, no HTML */ long text_size; /* the size of the decoded non-HTML content */ long *wordpos; /* positions of words in decoded non-HTML */ int *wordlength; /* the length of each word */ long num_words; /* size of the above array (no. of words) */ int num_images; /* the number of image attachments found */ char *_bound[8]; /* content boundaries */ int _bdepth; /* current boundary nesting depth */ char _in_header; /* in message header */ char _encoding; /* current content encoding type */ char _nottext; /* set if current content is not text */ long _pos; /* decoding position */ }; msg_t msg_parse(opts_t); void msg_spamsubject(msg_t, char *); void msg_spamheader(msg_t, char *, double); void msg_spamratingheader(msg_t, double, double); void msg_spamlevelheader(msg_t, double, double); void msg_dump(msg_t); void msg_free(msg_t); char *msg_from_base64(char *, long *); char *msg_from_qp(char *, long *); char *msg_decode_rfc2047(char *, long *); int msg_addcontent(opts_t, msg_t, char *, long); msg_t msg_alloc(opts_t); int msg_read(opts_t, msg_t); int msg_headers_store(opts_t, msg_t); #endif /* _MESSAGE_H */ /* EOF */ qsf-1.2.7/src/include/md5.h0000644000076400007640000000063010466704356013204 0ustar awaw#ifndef MD5_H #define MD5_H #include typedef uint32_t uint32; struct MD5Context { uint32 buf[4]; uint32 bits[2]; unsigned char in[64]; }; extern void MD5Init(); extern void MD5Update(); extern void MD5Final(); extern void MD5Transform(); /* * This is needed to make RSAREF happy on some MS-DOS compilers. */ typedef struct MD5Context MD5_CTX; #endif /* !MD5_H */ qsf-1.2.7/src/include/log.h0000644000076400007640000000045010554714163013273 0ustar awaw/* * Functions for logging. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #ifndef _LOG_H #define _LOG_H 1 void log_level(int); void log_add(int, char *, ...); void log_dump(char *); void log_errdump(char *); void log_free(void); #endif /* _LOG_H */ /* EOF */ qsf-1.2.7/src/include/database.h0000644000076400007640000000205410554714164014261 0ustar awaw/* * Database handling prototypes, structures, and constants. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #ifndef _DATABASE_H #define _DATABASE_H 1 typedef enum { QDB_NEW, QDB_READONLY, QDB_READWRITE } qdb_open_t; struct qdb_s; typedef struct qdb_s *qdb_t; struct qdbint_s; typedef struct qdbint_s *qdbint_t; typedef struct { unsigned char *data; int size; } qdb_datum; qdb_t qdb_open(const char *, qdb_open_t); int qdb_fd(qdb_t); char *qdb_type(qdb_t); void qdb_close(qdb_t); qdb_datum qdb_fetch(qdb_t, qdb_datum); int qdb_store(qdb_t, qdb_datum, qdb_datum); int qdb_delete(qdb_t, qdb_datum); qdb_datum qdb_firstkey(qdb_t); qdb_datum qdb_nextkey(qdb_t, qdb_datum); void qdb_optimise(qdb_t); char *qdb_error(void); void qdb_unlock(qdb_t); void qdb_relock(qdb_t); void qdb_restore_start(qdb_t); void qdb_restore_end(qdb_t); /* * Common library functions for backends to use. */ int qdb_int__lock(int, int, int *); void qdb_int__sig_block(void); void qdb_int__sig_unblock(void); #endif /* _DATABASE_H */ /* EOF */ qsf-1.2.7/src/include/options.h0000644000076400007640000000617710554714165014223 0ustar awaw/* * Global program option structure and the parsing function prototype. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #ifndef _OPTIONS_H #define _OPTIONS_H 1 struct opts_s; typedef struct opts_s *opts_t; typedef enum { ACTION_NONE, ACTION_TEST, ACTION_MARK_SPAM, ACTION_MARK_NONSPAM, ACTION_TRAIN, ACTION_PRUNE, ACTION_DUMP, ACTION_RESTORE, ACTION_TOKENS, ACTION_BENCHMARK, ACTION_MERGE, ACTION__MAX } action_t; struct opts_s { /* structure describing run-time options */ char *program_name; /* name the program is running as */ char *database; /* location of the database file */ char *globaldb; /* location of global database */ char *globaldb2; /* location of 2nd global database */ char *plainmap; /* location of plaintext map */ void *dbr1; /* first db handle, if any */ void *dbr2; /* second db handle, if any */ void *dbr3; /* third db handle, if any */ void *plaindata; /* plaintext working data */ int db1weight; /* weighting multiplier for db 1 */ int db2weight; /* weighting multiplier for db 2 */ int db3weight; /* weighting multiplier for db 3 */ void *dbw; /* db handle to write to, if any */ void *inbuf; /* stdin replacement, if any */ long inbufsize; /* size of stdin replacement */ unsigned char modify_subject; /* whether to modify subject line */ unsigned char no_header; /* set if not to add an X-Spam line */ unsigned char add_rating; /* set if adding X-Spam-Rating line */ unsigned char add_stars; /* set if adding X-Spam-Level line */ unsigned char no_filter; /* set if we're not filtering */ double threshold; /* spam threshold (default 0.9) */ unsigned char allowlist; /* set if allow-list is enabled */ unsigned char denylist; /* set if deny-list is enabled */ unsigned char modifydenylist; /* set if acting on the deny-list */ unsigned int weight; /* weighting to use when marking */ unsigned char noautoprune; /* set if we've not to auto-prune */ unsigned char showprune; /* show verbose prune indicator */ unsigned int loglevel; /* logging level (default 0) */ unsigned int min_token_count; /* min tokens before giving a score */ unsigned long prune_max; /* max tokens to prune at once */ char *subject_marker; /* string to add to subject if spam */ char *header_marker; /* string to set X-Spam header to if spam */ char *mergefrom; /* database to merge data from */ char *emailonly; /* email address to use in -e mode */ char *emailonly2; /* extra email address for -e */ int argc; /* number of non-option arguments */ action_t action; /* what action we are to take */ char **argv; /* array of non-option arguments */ }; extern opts_t opts_parse(int, char **); extern void opts_free(opts_t); #endif /* _OPTIONS_H */ /* EOF */ qsf-1.2.7/src/include/spam.h0000644000076400007640000000164110554714166013460 0ustar awaw/* * Spam handling prototypes, structures, and constants. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #ifndef _SPAM_H #define _SPAM_H 1 #ifndef _OPTIONS_H #include "options.h" #endif #ifndef _MESSAGE_H #include "message.h" #endif enum { SPAM, NONSPAM }; #define TOKEN_CHARS "0123456789" \ "abcdefghijklmnopqrstuvwxyz" \ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ "_'.$£-!" double spam_check(opts_t, msg_t); int spam_update(opts_t, msg_t, int); int spam_dumptokens(opts_t, msg_t); int spam_db_dump(opts_t); int spam_db_restore(opts_t); int spam_db_prune(opts_t); int spam_db_merge(opts_t); int spam_train(opts_t); int spam_benchmark(opts_t); int spam_allowlist_manage(opts_t); int spam_denylist_manage(opts_t); void spam_plaintext_update(opts_t, char *, int, char *, int); void spam_plaintext_free(opts_t); #endif /* _SPAM_H */ /* EOF */ qsf-1.2.7/src/include/mailbox.h0000644000076400007640000000075310554714167014157 0ustar awaw/* * Functions for reading messages from a mailbox. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #ifndef _MAILBOX_H #define _MAILBOX_H 1 #ifndef _OPTIONS_H #include "options.h" #endif #ifndef _STDIO_H #include #endif struct mbox_s; typedef struct mbox_s *mbox_t; mbox_t mbox_scan(opts_t, FILE *); void mbox_free(mbox_t mbox); size_t mbox_count(mbox_t mbox); int mbox_select(opts_t, mbox_t, FILE *, size_t); #endif /* _MAILBOX_H */ /* EOF */ qsf-1.2.7/src/library.c0000644000076400007640000000563210664772303012537 0ustar awaw/* * Some small library functions. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include #include #include /* * Find the start of the first occurrence of the substring "needle" of * length "needlelen" in the memory area "haystack" of length "haystacklen". * Returns a pointer to the start of the beginning of the substring, or NULL * if not found. */ char *minimemmem(char *haystack, long haystacklen, char *needle, long needlelen) { char *found; if (haystack == NULL) return NULL; if (haystacklen < 1) return NULL; if (needle == NULL) return haystack; if (needlelen < 1) return haystack; while (haystacklen > needlelen) { found = memchr(haystack, needle[0], haystacklen); if (found == NULL) return NULL; haystacklen -= (found - haystack); if (haystacklen < needlelen) return NULL; haystack = found; if (memcmp(haystack, needle, needlelen) == 0) return haystack; haystack++; haystacklen--; } return NULL; } #ifndef HAVE_GETOPT char *minioptarg = NULL; int minioptind = 0; int miniopterr = 1; int minioptopt = 0; /* * Minimalist getopt() clone, which handles short options only and doesn't * permute argv[]. */ int minigetopt(int argc, char **argv, char *optstring) { static int nextchar = 0; int optchar; int i; if ((minioptind == 0) && (argc > 0)) minioptind++; if ((nextchar > 0) && (argv[minioptind][nextchar] == 0)) { minioptind++; nextchar = 0; } if (minioptind >= argc) return -1; /* * End of options if arg doesn't start with "-" */ if (argv[minioptind][0] != '-') return -1; /* * End of options if arg is just "-" */ if (argv[minioptind][1] == 0) return -1; /* * End of options if arg is "--", but don't include the "--" in the * non-option arguments */ if ((argv[minioptind][1] == '-') && (argv[minioptind][2] == 0)) { minioptind++; return -1; } if (nextchar == 0) nextchar = 1; optchar = argv[minioptind][nextchar++]; for (i = 0; optstring[i] != 0 && optstring[i] != optchar; i++) { } if (optstring[i] == 0) { minioptopt = optchar; if (miniopterr) fprintf(stderr, "%s: invalid option -- %c\n", argv[0], optchar); return '?'; } if (optstring[i + 1] != ':') { minioptarg = NULL; return optchar; } /* * At this point we've got an option that takes an argument. */ /* * Next character isn't 0, so the argument is within this array * element (i.e. "-dFOO"). */ if (argv[minioptind][nextchar] != 0) { minioptarg = &(argv[minioptind][nextchar]); nextchar = 0; minioptind++; return optchar; } /* * Argument is in the next array element (i.e. "-d FOO"). */ nextchar = 0; minioptind++; if (minioptind >= argc) { fprintf(stderr, "%s: option `-%c' requires an argument\n", argv[0], optchar); return ':'; } minioptarg = argv[minioptind++]; return optchar; } #endif /* HAVE_GETOPT */ /* EOF */ qsf-1.2.7/src/md5.c0000644000076400007640000001701110664772303011552 0ustar awaw/* * This code implements the MD5 message-digest algorithm. * The algorithm is due to Ron Rivest. This code was * written by Colin Plumb in 1993, no copyright is claimed. * This code is in the public domain; do with it what you wish. * * Equivalent code is available from RSA Data Security, Inc. * This code has been tested against that, and is equivalent, * except that you don't need to include two pages of legalese * with every copy. * * To compute the message digest of a chunk of bytes, declare an * MD5Context structure, pass it to MD5Init, call MD5Update as * needed on buffers full of bytes, and then call MD5Final, which * will fill a supplied 16-byte array with the digest. */ #include /* for memcpy() */ #include "md5.h" #include "config.h" #ifndef IS_BIG_ENDIAN #define byteReverse(buf, len) /* Nothing */ #else /* * Note: this code is harmless on little-endian machines. */ void byteReverse(unsigned char *buf, unsigned longs) { uint32 t; do { t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | ((unsigned) buf[1] << 8 | buf[0]); *(uint32 *) buf = t; buf += 4; } while (--longs); } #endif /* * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious * initialization constants. */ void MD5Init(struct MD5Context *ctx) { ctx->buf[0] = 0x67452301; ctx->buf[1] = 0xefcdab89; ctx->buf[2] = 0x98badcfe; ctx->buf[3] = 0x10325476; ctx->bits[0] = 0; ctx->bits[1] = 0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ void MD5Update(struct MD5Context *ctx, unsigned char *buf, unsigned int len) { uint32 t; /* Update bitcount */ t = ctx->bits[0]; if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) ctx->bits[1]++; /* Carry from low to high */ ctx->bits[1] += len >> 29; t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ /* Handle any leading odd-sized chunks */ if (t) { unsigned char *p = (unsigned char *) ctx->in + t; t = 64 - t; if (len < t) { memcpy(p, buf, len); return; } memcpy(p, buf, t); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (uint32 *) ctx->in); buf += t; len -= t; } /* Process data in 64-byte chunks */ while (len >= 64) { memcpy(ctx->in, buf, 64); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (uint32 *) ctx->in); buf += 64; len -= 64; } /* Handle any remaining bytes of data. */ memcpy(ctx->in, buf, len); } /* * Final wrapup - pad to 64-byte boundary with the bit pattern * 1 0* (64-bit count of bits processed, MSB-first) */ void MD5Final(unsigned char digest[16], struct MD5Context *ctx) { unsigned count; unsigned char *p; /* Compute number of bytes mod 64 */ count = (ctx->bits[0] >> 3) & 0x3F; /* Set the first char of padding to 0x80. This is safe since there is always at least one byte free */ p = ctx->in + count; *p++ = 0x80; /* Bytes of padding needed to make 64 bytes */ count = 64 - 1 - count; /* Pad out to 56 mod 64 */ if (count < 8) { /* Two lots of padding: Pad the first block to 64 bytes */ memset(p, 0, count); byteReverse(ctx->in, 16); MD5Transform(ctx->buf, (uint32 *) ctx->in); /* Now fill the next block with 56 bytes */ memset(ctx->in, 0, 56); } else { /* Pad block to 56 bytes */ memset(p, 0, count - 8); } byteReverse(ctx->in, 14); /* Append length in bits and transform */ ((uint32 *) ctx->in)[14] = ctx->bits[0]; ((uint32 *) ctx->in)[15] = ctx->bits[1]; MD5Transform(ctx->buf, (uint32 *) ctx->in); byteReverse((unsigned char *) ctx->buf, 4); memcpy(digest, ctx->buf, 16); memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ } /* The four core functions - F1 is optimized somewhat */ /* #define F1(x, y, z) (x & y | ~x & z) */ #define F1(x, y, z) (z ^ (x & (y ^ z))) #define F2(x, y, z) F1(z, x, y) #define F3(x, y, z) (x ^ y ^ z) #define F4(x, y, z) (y ^ (x | ~z)) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f, w, x, y, z, data, s) \ ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to * reflect the addition of 16 longwords of new data. MD5Update blocks * the data and converts bytes into longwords for this routine. */ void MD5Transform(uint32 buf[4], uint32 in[16]) { register uint32 a, b, c, d; a = buf[0]; b = buf[1]; c = buf[2]; d = buf[3]; MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); buf[0] += a; buf[1] += b; buf[2] += c; buf[3] += d; } /* EOF */ qsf-1.2.7/src/db/0000755000076400007640000000000010665021416011277 5ustar awawqsf-1.2.7/src/db/obtree.c0000644000076400007640000004237010664772303012740 0ustar awaw/* * Old binary tree database backend. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "database.h" #include "log.h" #ifdef USING_OBTREE #include #include #include #include #include #include #include #include #ifdef HAVE_FCNTL #include #endif #define BT_RECORD_SIZE sizeof(struct bt_record) #define BT_TOKEN_MAX 36 typedef unsigned long bt_ul; struct bt_record { /* single binary tree record */ bt_ul lower; /* offset of "lower" token */ bt_ul higher; /* offset of "higher" token */ unsigned char token[BT_TOKEN_MAX]; /* RATS: ignore - 0-term. token */ long data[2]; /* token data (i.e. the counts) */ }; typedef struct bt_record *bt_record_t; struct qdbint_s { /* database state */ int fd; /* file descriptor of database file */ bt_ul size; /* total size of database */ #ifdef HAVE_FCNTL int lockcount; /* number of times lock asked for */ int locktype; /* type of lock to use (read or write) */ #endif int gotheadoffs; /* flag, set once head offset read */ bt_ul head_offset; /* offset of head record of tree */ }; static char *bt_lasterror = ""; #ifdef HAVE_FCNTL /* * Obtain / release a read or write lock on the database. Returns nonzero on * error, and blocks until a lock can be obtained. */ static int dbbt_lock(qdbint_t db, int lock_type) { int ret; ret = qdb_int__lock(db->fd, lock_type, &(db->lockcount)); if (ret != 0) { bt_lasterror = strerror(errno); return 1; } return 0; } #endif /* HAVE_FCNTL */ /* * Analogue of fread(). */ static int dbbt_chunkread(void *ptr, int size, int nmemb, int fd) { int numread, togo, got; for (numread = 0; nmemb > 0; nmemb--, numread++) { for (togo = size; togo > 0;) { got = read(fd, ptr, togo); /* RATS: ignore (OK) */ if (got <= 0) return numread; togo -= got; ptr = (void *) (((char *) ptr) + got); } } return numread; } /* * Analogue of fwrite(). */ static int dbbt_chunkwrite(void *ptr, int size, int nmemb, int fd) { int numwritten, togo, written; for (numwritten = 0; nmemb > 0; nmemb--, numwritten++) { for (togo = size; togo > 0;) { written = write(fd, ptr, togo); if (written <= 0) return numwritten; togo -= written; ptr = (void *) (((char *) ptr) + written); } } return numwritten; } /* * Read a record from the database at the given offset into the given record * structure, returning nonzero on failure. */ static int dbbt_read_record(qdbint_t db, bt_ul offset, bt_record_t record) { int got; if (lseek(db->fd, offset, SEEK_SET) == (off_t) - 1) { bt_lasterror = strerror(errno); return 1; } got = dbbt_chunkread(record, BT_RECORD_SIZE, 1, db->fd); if (got < 1) { bt_lasterror = strerror(errno); return 1; } record->token[BT_TOKEN_MAX - 1] = 0; return 0; } /* * Write a record to the database at the given offset, returning nonzero on * failure. */ static int dbbt_write_record(qdbint_t db, bt_ul offset, bt_record_t record) { if (lseek(db->fd, offset, SEEK_SET) == (off_t) - 1) { bt_lasterror = strerror(errno); return 1; } if (dbbt_chunkwrite(record, BT_RECORD_SIZE, 1, db->fd) < 1) { bt_lasterror = strerror(errno); return 1; } return 0; } /* * Find the given token in the database and fill in the given record * structure if found, also filling in the offset of the record (or 0 if not * found) and the offset of the parent record (0 if none). * * Returns -1 if the token looked for was "lower" than its parent or +1 if * "higher", or 0 if there was no parent record (i.e. this is the first * record). */ static int dbbt_find_token(qdbint_t db, qdb_datum key, bt_record_t record, bt_ul * offset, bt_ul * parent) { int hilow = 0; int x; *offset = 0; *parent = 0; if (db == NULL) return 0; if (db->size < 2 * sizeof(long)) return 0; if (!db->gotheadoffs) { lseek(db->fd, 0, SEEK_SET); dbbt_chunkread(offset, sizeof(*offset), 1, db->fd); db->head_offset = *offset; db->gotheadoffs = 1; } else { *offset = db->head_offset; } while (*offset > 0) { int len; if (dbbt_read_record(db, *offset, record)) { *offset = 0; break; } x = strncmp((char *) (record->token), (char *) (key.data), key.size); len = strlen((char *) (record->token)); if (len < key.size) { x = -1; } else if (len > key.size) { x = 1; } if (x == 0) { return hilow; } else if (x < 0) { *parent = *offset; hilow = -1; *offset = record->lower; } else { *parent = *offset; hilow = 1; *offset = record->higher; } } return hilow; } /* * Return nonzero if the given file is of this database type. */ int qdb_obtree_identify(const char *file) { if (file == NULL) return 0; if (strncasecmp(file, "obtree:", 7) == 0) return 1; return 0; } /* * Open the given database in the given way (new database, read-only, or * read-write); return a qdbint_t or NULL on error. */ qdbint_t qdb_obtree_open(const char *file, qdb_open_t method) { qdbint_t db; int fd = -1; #ifdef HAVE_FCNTL int locktype = F_RDLCK; #endif int forced_type = 0; if (strncasecmp(file, "obtree:", 7) == 0) { file += 7; forced_type = 1; } switch (method) { case QDB_NEW: fd = open(file, /* RATS: ignore (no race) */ O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd < 0) bt_lasterror = strerror(errno); #ifdef HAVE_FCNTL locktype = F_WRLCK; #endif break; case QDB_READONLY: fd = open(file, /* RATS: ignore (no race) */ O_RDONLY); if (fd < 0) bt_lasterror = strerror(errno); break; case QDB_READWRITE: fd = open(file, /* RATS: ignore (no race) */ O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd < 0) bt_lasterror = strerror(errno); #ifdef HAVE_FCNTL locktype = F_WRLCK; #endif break; default: break; } if (fd < 0) return NULL; db = calloc(1, sizeof(*db)); if (db == NULL) { bt_lasterror = strerror(errno); close(fd); return NULL; } db->size = lseek(fd, 0, SEEK_END); db->fd = fd; #ifdef HAVE_FCNTL db->locktype = locktype; if (dbbt_lock(db, locktype)) { close(fd); free(db); return NULL; } #endif /* * Complain at the user to stop using this backend if it wasn't * specifically chosen. */ if (!forced_type) { log_add(0, "%s", _("WARNING: Using deprecated obtree backend!")); log_add(0, "%s", _("WARNING: Dump, delete, and restore your")); log_add(0, "%s", _("WARNING: databases to upgrade them to the")); log_add(0, "%s", _("WARNING: new format and stop this warning.")); } else { log_add(1, "%s", _("warning: obtree backend is deprecated")); } /* * If the database has zero size and we're writing to it, assume * it's new and don't complain. */ if ((db->size == 0) && (method != QDB_READONLY)) return db; /* * We now do some simple checks to make sure that the file is a * database of the format we're expecting. */ /* * If it's shorter than 2 long ints, it's not a valid database. */ if (db->size < 2 * sizeof(long)) { bt_lasterror = _("invalid database (too small)"); close(fd); free(db); return NULL; } /* * If its size, discounting the two longs at the start, isn't a * multiple of our record size, it's not a valid database. */ if (((db->size - 2 * sizeof(long)) % BT_RECORD_SIZE) != 0) { bt_lasterror = _("invalid database (irregular size)"); close(fd); free(db); return NULL; } /* * If the first long int (the "head offset") is larger than the size * of the file, this isn't a valid database. */ { bt_ul offset = db->size + 1; lseek(fd, 0, SEEK_SET); dbbt_chunkread(&offset, sizeof(offset), 1, fd); if (offset > db->size) { bt_lasterror = _("invalid database (bad head offset)"); close(fd); free(db); return NULL; } lseek(fd, 0, SEEK_SET); } return db; } /* * Close the given database. */ void qdb_obtree_close(qdbint_t db) { if (db == NULL) return; #ifdef HAVE_FCNTL while (db->lockcount > 0) dbbt_lock(db, F_UNLCK); #endif close(db->fd); free(db); } /* * Fetch a value from the database. The datum returned needs its val.data * free()ing after use. If val.data is NULL, no value was found for the * given key. */ qdb_datum qdb_obtree_fetch(qdbint_t db, qdb_datum key) { struct bt_record record; unsigned long offset, parent; qdb_datum val; val.data = NULL; val.size = 0; if (db == NULL) return val; if (key.size >= BT_TOKEN_MAX) key.size = BT_TOKEN_MAX - 1; dbbt_find_token(db, key, &record, &offset, &parent); if (offset == 0) return val; val.size = 2 * sizeof(long); val.data = calloc(1, val.size); if (val.data == NULL) { val.size = 0; return val; } ((long *) val.data)[0] = record.data[0]; ((long *) val.data)[1] = record.data[1]; return val; } /* * Return a file descriptor for the given database, or -1 on error. */ int qdb_obtree_fd(qdbint_t db) { if (db == NULL) return -1; return db->fd; } /* * Store the given key with the given value into the database, replacing any * existing value for that key. Returns nonzero on error. */ int qdb_obtree_store(qdbint_t db, qdb_datum key, qdb_datum val) { struct bt_record record, head; unsigned long offset, parent, nextfree; int x; if (db == NULL) return 1; memset(&head, 0, BT_RECORD_SIZE); memset(&record, 0, BT_RECORD_SIZE); if (key.size >= BT_TOKEN_MAX) key.size = BT_TOKEN_MAX - 1; x = dbbt_find_token(db, key, &record, &offset, &parent); memcpy(record.token, key.data, key.size); record.token[key.size] = 0; record.data[0] = ((long *) val.data)[0]; record.data[1] = ((long *) val.data)[1]; qdb_int__sig_block(); /* * Record exists - overwrite it. */ if (offset > 0) { if (dbbt_write_record(db, offset, &record)) { qdb_int__sig_unblock(); return 1; } qdb_int__sig_unblock(); return 0; } record.lower = 0; record.higher = 0; /* * Database has just been created, so fill in the header and write * this record as the first one. */ if (db->size <= sizeof(offset)) { if (lseek(db->fd, 0, SEEK_SET) == (off_t) - 1) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } offset = 2 * sizeof(offset); if (dbbt_chunkwrite(&offset, sizeof(offset), 1, db->fd) < 1) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } db->gotheadoffs = 0; offset = 0; if (dbbt_chunkwrite(&offset, sizeof(offset), 1, db->fd) < 1) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } head.lower = (2 * sizeof(offset)) + BT_RECORD_SIZE; if (dbbt_chunkwrite(&head, BT_RECORD_SIZE, 1, db->fd) < 1) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } if (dbbt_chunkwrite(&record, BT_RECORD_SIZE, 1, db->fd) < 1) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } db->size = lseek(db->fd, 0, SEEK_CUR); qdb_int__sig_unblock(); return 0; } /* * Get offset of next free space block. */ if (lseek(db->fd, sizeof(offset), SEEK_SET) == (off_t) - 1) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } if (dbbt_chunkread(&offset, sizeof(offset), 1, db->fd) < 1) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } offset &= 0x7FFFFFFF; /* * If offset is 0 or we can't read from that offset, it's a new * block at the end of the file, otherwise we take the next free * offset from there and store it in the core free pointer, and then * use that free offset. */ if (lseek(db->fd, offset, SEEK_SET) == (off_t) - 1) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } if ((offset == 0) || (dbbt_chunkread(&nextfree, sizeof(nextfree), 1, db->fd) < 1) ) { offset = lseek(db->fd, 0, SEEK_END); nextfree = 0x80000000; } if (lseek(db->fd, sizeof(offset), SEEK_SET) == (off_t) - 1) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } if (dbbt_chunkwrite(&nextfree, sizeof(nextfree), 1, db->fd) < 0) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } if (dbbt_write_record(db, offset, &record)) { qdb_int__sig_unblock(); return 1; } /* * Now attach the new record to its parent, if applicable. */ if (parent > 0) { if (dbbt_read_record(db, parent, &record)) { qdb_int__sig_unblock(); return 1; } if (x < 0) { record.lower = offset; } else { record.higher = offset; } if (dbbt_write_record(db, parent, &record)) { qdb_int__sig_unblock(); return 1; } } qdb_int__sig_unblock(); return 0; } /* * Return the "first" key in the database, suitable for using with repeated * calls to qdb_nextkey() to walk through every key in the database. */ qdb_datum qdb_obtree_firstkey(qdbint_t db) { struct bt_record record; qdb_datum key; key.data = NULL; key.size = 0; if (lseek(db->fd, 2 * sizeof(unsigned long), SEEK_SET) == (off_t) - 1) return key; if (dbbt_chunkread(&record, BT_RECORD_SIZE, 1, db->fd) < 1) { return key; } record.token[BT_TOKEN_MAX - 1] = 0; key.data = (unsigned char *) strdup((char *) (record.token)); key.size = strlen((char *) (record.token)); return key; } /* * Return the "next" key in the database, or key.data=NULL when all keys * have been returned. */ qdb_datum qdb_obtree_nextkey(qdbint_t db, qdb_datum key) { struct bt_record record; unsigned long offset, parent; qdb_datum newkey; newkey.data = NULL; newkey.size = 0; if (key.data == NULL) { return newkey; } dbbt_find_token(db, key, &record, &offset, &parent); if (offset < 1) { return newkey; } if (lseek(db->fd, offset + BT_RECORD_SIZE, SEEK_SET) == (off_t) - 1) { return newkey; } do { if (dbbt_chunkread(&record, BT_RECORD_SIZE, 1, db->fd) < 1) { return newkey; } } while (record.lower & 0x80000000); record.token[BT_TOKEN_MAX - 1] = 0; newkey.data = (unsigned char *) strdup((char *) (record.token)); newkey.size = strlen((char *) (record.token)); return newkey; } /* * Reposition the given record in the binary tree, by finding an existing * record to link it to. Returns nonzero on error. */ static int qdb_obtree_delete__reposition(qdbint_t db, unsigned long offset, char *token) { struct bt_record record; unsigned long offs, parent; qdb_datum key; int x; key.data = (unsigned char *) token; key.size = strlen(token); x = dbbt_find_token(db, key, &record, &offs, &parent); if (parent < 1) return 1; if (dbbt_read_record(db, parent, &record)) return 1; if (x < 0) { record.lower = offset; } else { record.higher = offset; } if (dbbt_write_record(db, parent, &record)) return 1; return 0; } /* * Delete the given key from the database. Returns nonzero on error. */ int qdb_obtree_delete(qdbint_t db, qdb_datum key) { struct bt_record record, recparent, reclower, rechigher; unsigned long offset, parent, nextfree; int x; if (db == NULL) return 1; if (key.size < 1) return 1; x = dbbt_find_token(db, key, &record, &offset, &parent); if (offset < 1) return 1; /* * Get a copy of the lower and higher records, if any. */ if (record.lower > 0) { if (dbbt_read_record(db, record.lower, &reclower)) return 1; } if (record.higher > 0) { if (dbbt_read_record(db, record.higher, &rechigher)) return 1; } qdb_int__sig_block(); /* * Remove the link to this record from its parent. */ if (parent > 0) { if (dbbt_read_record(db, parent, &recparent)) { qdb_int__sig_unblock(); return 1; } if (x < 0) { recparent.lower = 0; } else { recparent.higher = 0; } if (dbbt_write_record(db, parent, &recparent)) { qdb_int__sig_unblock(); return 1; } } /* * Re-attach any children of this record to the database. */ if (record.lower > 0) qdb_obtree_delete__reposition(db, record.lower, (char *) (reclower.token)); if (record.higher > 0) qdb_obtree_delete__reposition(db, record.higher, (char *) (rechigher.token)); /* * Now we add this record's offset to the head of the "free records" * linked list. */ if (lseek(db->fd, sizeof(offset), SEEK_SET) == (off_t) - 1) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } nextfree = 0x80000000; if (dbbt_chunkread(&nextfree, sizeof(nextfree), 1, db->fd) < 0) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } if (lseek(db->fd, sizeof(offset), SEEK_SET) == (off_t) - 1) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } offset |= 0x80000000; if (dbbt_chunkwrite(&offset, sizeof(offset), 1, db->fd) < 0) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } offset &= 0x7FFFFFFF; if (lseek(db->fd, offset, SEEK_SET) == (off_t) - 1) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } if (dbbt_chunkwrite(&nextfree, sizeof(nextfree), 1, db->fd) < 1) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } qdb_int__sig_unblock(); return 0; } /* * Temporarily release the lock on the database. */ void qdb_obtree_unlock(qdbint_t db) { #ifdef HAVE_FCNTL dbbt_lock(db, F_UNLCK); #endif } /* * Reassert the lock on the database. */ void qdb_obtree_relock(qdbint_t db) { #ifdef HAVE_FCNTL dbbt_lock(db, db->locktype); #endif db->gotheadoffs = 0; } /* * Return a string describing the last database error to occur. */ char *qdb_obtree_error(void) { return bt_lasterror; } #endif /* USING_OBTREE */ /* EOF */ qsf-1.2.7/src/db/list.c0000644000076400007640000003617210664772303012436 0ustar awaw/* * In-memory flat list database backend. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "database.h" #include "log.h" #ifdef USING_LIST #include #include #include #include #include #include #include #include #include #ifdef HAVE_FCNTL #include #endif #ifdef HAVE_UTIME #include #include #endif #include #define ML_TOKEN_MAX 36 /* maximum token length */ #define ML_INCSIZE 10000 /* increments by which array size grows */ #define ML_ADDITIONBUF 1000 /* size of addition buffer */ struct mh_record_s { char token[ML_TOKEN_MAX]; /* RATS: ignore - 0-term. token */ uint32_t data[3]; /* token data (i.e. the counts) */ }; struct qdbint_s { int fd; long size; #ifdef HAVE_FCNTL int lockcount; /* number of times lock asked for */ int locktype; /* type of lock to use (read or write) */ #endif char *filename; /* filename of database */ int modified; /* flag, set if db modified at all */ int restoring; /* flag, set if no qsort on store */ struct mh_record_s *array; /* array holding all list entries */ long array_len; /* highest used index + 1 */ long array_alloced; /* size of array */ long walk_index; /* current index for ..._nextkey() */ struct mh_record_s *addition; /* array holding all list entries */ long addition_len; /* highest used index + 1 */ }; static char *mh_lasterror = ""; #ifdef HAVE_FCNTL /* * Obtain / release a read or write lock on the database. Returns nonzero on * error, and blocks until a lock can be obtained. */ static int dbl_lock(qdbint_t db, int lock_type) { int ret; ret = qdb_int__lock(db->fd, lock_type, &(db->lockcount)); if (ret != 0) { mh_lasterror = strerror(errno); return 1; } return 0; } #endif /* HAVE_FCNTL */ /* * Analogue of fread(). */ static int dbl_chunkread(void *ptr, int size, int nmemb, int fd) { int numread, togo, got; for (numread = 0; nmemb > 0; nmemb--, numread++) { for (togo = size; togo > 0;) { got = read(fd, ptr, togo); /* RATS: ignore (OK) */ if (got <= 0) return numread; togo -= got; ptr = (void *) (((char *) ptr) + got); } } return numread; } /* * Analogue of fwrite(). */ static int dbl_chunkwrite(void *ptr, int size, int nmemb, int fd) { int numwritten, togo, written; for (numwritten = 0; nmemb > 0; nmemb--, numwritten++) { for (togo = size; togo > 0;) { written = write(fd, ptr, togo); if (written <= 0) return numwritten; togo -= written; ptr = (void *) (((char *) ptr) + written); } } return numwritten; } /* * Read a single long integer from the database and return it, converting * from network byte order. */ static long dbl_longread(qdbint_t db) { uint32_t val; val = 0; dbl_chunkread(&val, sizeof(val), 1, db->fd); return ntohl(val); } /* * Write a single long integer to the database, converting to network byte * order. Returns nonzero on error. */ static int dbl_longwrite(qdbint_t db, long val) { uint32_t newval; newval = htonl(val); return dbl_chunkwrite(&newval, sizeof(newval), 1, db->fd) == 1 ? 0 : -1; } /* * Comparison function to compare two database records' tokens. */ static int dbl_compare(const void *a, const void *b) { if (a == NULL) return -1; if (b == NULL) return 1; if (((struct mh_record_s *) a)->token[0] == 0) return 1; if (((struct mh_record_s *) b)->token[0] == 0) return -1; return strncmp(((struct mh_record_s *) a)->token, ((struct mh_record_s *) b)->token, ML_TOKEN_MAX); } /* * Return a file descriptor for the given database, or -1 on error. */ int qdb_list_fd(qdbint_t db) { if (db == NULL) return -1; return db->fd; } /* * Return nonzero if the given file is of this database type. */ int qdb_list_identify(const char *file) { int fd; char buf[8]; /* RATS: ignore (checked) */ if (file == NULL) return 0; if (strncasecmp(file, "list:", 5) == 0) return 1; fd = open(file, O_RDONLY); if (fd < 0) return 0; if (dbl_chunkread(buf, 4, 1, fd) < 1) { close(fd); return 0; } close(fd); if (strncmp(buf, "QSF2", 4) == 0) return 1; return 0; } /* * Open the given database in the given way (new database, read-only, or * read-write); return a qdbint_t or NULL on error. */ qdbint_t qdb_list_open(const char *file, qdb_open_t method) { qdbint_t db; int fd = -1; #ifdef HAVE_FCNTL int locktype = F_RDLCK; #endif if (strncasecmp(file, "list:", 5) == 0) file += 5; switch (method) { case QDB_NEW: fd = open(file, /* RATS: ignore (no race) */ O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd < 0) mh_lasterror = strerror(errno); #ifdef HAVE_FCNTL locktype = F_WRLCK; #endif break; case QDB_READONLY: fd = open(file, /* RATS: ignore (no race) */ O_RDONLY); if (fd < 0) mh_lasterror = strerror(errno); break; case QDB_READWRITE: fd = open(file, /* RATS: ignore (no race) */ O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd < 0) mh_lasterror = strerror(errno); #ifdef HAVE_FCNTL locktype = F_WRLCK; #endif break; default: break; } if (fd < 0) return NULL; db = calloc(1, sizeof(*db)); if (db == NULL) { mh_lasterror = strerror(errno); close(fd); return NULL; } db->filename = strdup(file); db->fd = fd; #ifdef HAVE_FCNTL db->locktype = locktype; #endif db->modified = 0; db->array = NULL; db->array_len = 0; db->array_alloced = 0; db->addition_len = 0; db->addition = calloc(ML_ADDITIONBUF, sizeof(struct mh_record_s)); if (db->addition == NULL) { mh_lasterror = strerror(errno); close(fd); free(db->filename); free(db); return NULL; } #ifdef HAVE_FCNTL if (dbl_lock(db, db->locktype)) { close(db->fd); if (db->filename) free(db->filename); if (db->addition) free(db->addition); free(db); return NULL; } #endif db->size = lseek(db->fd, 0, SEEK_END); if (db->size == (off_t) - 1) db->size = 0; /* * If this is a new database, and it's not readonly, write our * header to it and return. */ if ((db->size <= 8) && (method != QDB_READONLY)) { lseek(db->fd, 0, SEEK_SET); dbl_chunkwrite("QSF2", 4, 1, db->fd); dbl_longwrite(db, 0); db->size = 8; db->modified = 1; return db; } lseek(db->fd, 4, SEEK_SET); db->array_len = dbl_longread(db); if ((db->array_len < 0) || (db->array_len > 10000000)) { mh_lasterror = _("invalid database (array size out of range)"); #ifdef HAVE_FCNTL dbl_lock(db, F_UNLCK); #endif close(db->fd); if (db->filename) free(db->filename); if (db->addition) free(db->addition); free(db); return NULL; } db->array_alloced = db->array_len + ML_INCSIZE; db->array = calloc(db->array_alloced, sizeof(struct mh_record_s)); if (db->array == NULL) { mh_lasterror = strerror(errno); #ifdef HAVE_FCNTL dbl_lock(db, F_UNLCK); #endif close(db->fd); if (db->filename) free(db->filename); if (db->addition) free(db->addition); free(db); return NULL; } if (dbl_chunkread (db->array, sizeof(struct mh_record_s), db->array_len, db->fd) < db->array_len) { mh_lasterror = _("invalid database (file truncated)"); #ifdef HAVE_FCNTL dbl_lock(db, F_UNLCK); #endif close(db->fd); if (db->filename) free(db->filename); free(db->array); if (db->addition) free(db->addition); free(db); return NULL; } qsort(db->array, db->array_len, sizeof(struct mh_record_s), dbl_compare); return db; } /* * Extend the array by "amount" items. Returns nonzero on error. */ static int qdb_list__extendarray(qdbint_t db, long amount) { long origlen, origalloced; void *ptr; origlen = db->array_len; db->array_len += amount; if (db->array_len < db->array_alloced) return 0; origalloced = db->array_alloced; while (db->array_alloced < db->array_len) { db->array_alloced += ML_INCSIZE; } if (db->array == NULL) { ptr = calloc(db->array_alloced, sizeof(struct mh_record_s)); } else { ptr = realloc(db->array, /* RATS: ignore (OK) */ db->array_alloced * sizeof(struct mh_record_s)); } if (ptr == NULL) { mh_lasterror = strerror(errno); db->array_len = origlen; db->array_alloced = origalloced; return 1; } db->array = ptr; return 0; } /* * Dump the addition list on to the end of the array, and re-sort the array. * Returns nonzero on error. */ static int qdb_list__dumpaddition(qdbint_t db) { if (db->addition_len == 0) return 0; if (qdb_list__extendarray(db, db->addition_len)) return 1; memcpy(&(db->array[db->array_len - db->addition_len]), db->addition, db->addition_len * sizeof(struct mh_record_s)); db->addition_len = 0; if (!db->restoring) { qsort(db->array, db->array_len, sizeof(struct mh_record_s), dbl_compare); } return 0; } /* * Save any changes that were made to the database. This function only * stores the data, it doesn't free memory or update timestamps. Returns * nonzero on error. */ static int qdb_list__savedb(qdbint_t db) { unsigned long newsize; /* * Append the addition list to the array. */ if (qdb_list__dumpaddition(db)) return 1; /* * Write the contents of the array first. */ lseek(db->fd, 8, SEEK_SET); if (dbl_chunkwrite (db->array, sizeof(struct mh_record_s), db->array_len, db->fd) < db->array_len) { return 1; } newsize = lseek(db->fd, 0, SEEK_CUR); /* * Now store the new size of the array. */ lseek(db->fd, 4, SEEK_SET); if (dbl_longwrite(db, db->array_len)) return 1; /* * Finally, truncate the database (if it's got smaller). */ if (ftruncate(db->fd, newsize) != 0) { log_add(0, "%s: failed to truncate database: %s", db->filename, strerror(errno)); } return 0; } /* * Close the given database. */ void qdb_list_close(qdbint_t db) { if (db == NULL) return; if (db->modified) { qdb_int__sig_block(); qdb_list__savedb(db); qdb_int__sig_unblock(); } if (db->array) free(db->array); if (db->addition) free(db->addition); #ifdef HAVE_FCNTL while (db->lockcount > 0) dbl_lock(db, F_UNLCK); #endif close(db->fd); if (db->modified && db->filename) { #ifdef HAVE_UTIME struct utimbuf utb; utb.actime = time(NULL); utb.modtime = time(NULL); utime(db->filename, &utb); #endif } if (db->filename) free(db->filename); free(db); } /* * Search the array for the given token. Returns a pointer to the array * entry or NULL on failure. */ static struct mh_record_s *dbl_search(qdbint_t db, qdb_datum key) { struct mh_record_s search; struct mh_record_s *val; if (db == NULL) return NULL; if (key.data == NULL) return NULL; memset(search.token, 0, ML_TOKEN_MAX); strncpy(search.token, (char *) (key.data), (key.size > ML_TOKEN_MAX) ? ML_TOKEN_MAX : key.size); if (db->addition_len > 0) { val = bsearch((void *) (&search), (void *) db->addition, db->addition_len, sizeof(struct mh_record_s), dbl_compare); if (val != NULL) return val; } if (db->array == NULL) return NULL; return bsearch((void *) (&search), (void *) db->array, db->array_len, sizeof(struct mh_record_s), dbl_compare); } /* * Fetch a value from the database. The datum returned needs its val.data * free()ing after use. If val.data is NULL, no value was found for the * given key. */ qdb_datum qdb_list_fetch(qdbint_t db, qdb_datum key) { struct mh_record_s *result; qdb_datum val; val.data = NULL; val.size = 0; result = dbl_search(db, key); if (result == NULL) return val; val.size = 3 * sizeof(long); val.data = calloc(1, val.size); if (val.data == NULL) { val.size = 0; return val; } ((long *) val.data)[0] = ntohl(result->data[0]); ((long *) val.data)[1] = ntohl(result->data[1]); ((long *) val.data)[2] = ntohl(result->data[2]); return val; } /* * Store the given key with the given value into the database, replacing any * existing value for that key. Returns nonzero on error. */ int qdb_list_store(qdbint_t db, qdb_datum key, qdb_datum val) { struct mh_record_s *result; if (db == NULL) return 1; if ((key.data == NULL) || (val.data == NULL)) return 1; db->modified = 1; if (db->restoring) { result = NULL; } else { result = dbl_search(db, key); } if (result != NULL) { result->data[0] = htonl(((long *) val.data)[0]); result->data[1] = htonl(((long *) val.data)[1]); result->data[2] = htonl(((long *) val.data)[2]); } else { db->addition_len++; result = &(db->addition[db->addition_len - 1]); memset(result, 0, sizeof(struct mh_record_s)); strncpy(result->token, (char *) (key.data), (key.size > ML_TOKEN_MAX) ? ML_TOKEN_MAX : key.size); result->data[0] = htonl(((long *) val.data)[0]); result->data[1] = htonl(((long *) val.data)[1]); result->data[2] = htonl(((long *) val.data)[2]); if (db->addition_len >= ML_ADDITIONBUF) { if (qdb_list__dumpaddition(db)) return 1; } else if (!db->restoring) { qsort(db->addition, db->addition_len, sizeof(struct mh_record_s), dbl_compare); } } return 0; } /* * Delete the given key from the database. Returns nonzero on error. */ int qdb_list_delete(qdbint_t db, qdb_datum key) { struct mh_record_s *result; long src, dst; if (db == NULL) return 1; if (key.data == NULL) return 1; if (qdb_list__dumpaddition(db)) return 1; result = dbl_search(db, key); if (result == NULL) return 0; db->modified = 1; result->token[0] = 0; for (src = 0, dst = 0; src < db->array_len; src++) { if (db->array[src].token[0] == 0) continue; if (src != dst) memcpy(&(db->array[dst]), &(db->array[src]), sizeof(struct mh_record_s)); dst++; } db->array_len = dst; return 0; } /* * Return the "next" key in the database, or key.data=NULL when all keys * have been returned. */ qdb_datum qdb_list_nextkey(qdbint_t db, qdb_datum key) { qdb_datum newkey; char keystr[ML_TOKEN_MAX + 1]; /* RATS: ignore */ newkey.data = NULL; newkey.size = 0; db->walk_index++; while ((db->walk_index < db->array_len) && (db->array[db->walk_index].token[0] == 0) ) { db->walk_index++; } if (db->walk_index >= db->array_len) return newkey; if (db->array[db->walk_index].token[0] == 0) return newkey; memset(keystr, 0, sizeof(keystr)); strncpy(keystr, db->array[db->walk_index].token, ML_TOKEN_MAX); newkey.data = (unsigned char *) strdup((char *) keystr); newkey.size = strlen((char *) keystr); return newkey; } /* * Return the "first" key in the database, suitable for using with repeated * calls to qdb_nextkey() to walk through every key in the database. */ qdb_datum qdb_list_firstkey(qdbint_t db) { qdb_datum key; qdb_list__dumpaddition(db); db->walk_index = -1; key.data = NULL; key.size = 0; return qdb_list_nextkey(db, key); } /* * Return a string describing the last database error to occur. */ char *qdb_list_error(void) { return mh_lasterror; } /* * Tell the database that a restore operation is starting. */ void qdb_list_restore_start(qdbint_t db) { db->restoring = 1; } /* * Tell the database that a restore operation is ending. */ void qdb_list_restore_end(qdbint_t db) { qdb_list__dumpaddition(db); qsort(db->array, db->array_len, sizeof(struct mh_record_s), dbl_compare); db->restoring = 0; } #endif /* USING_LIST */ /* EOF */ qsf-1.2.7/src/db/main.c0000644000076400007640000003230010664772303012374 0ustar awaw/* * Main entry point for database functions. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "database.h" #include #include #include #include #ifdef HAVE_FCNTL #include #endif #ifdef USING_OBTREE int qdb_obtree_identify(const char *); qdbint_t qdb_obtree_open(const char *, qdb_open_t); int qdb_obtree_fd(qdbint_t); void qdb_obtree_close(qdbint_t); qdb_datum qdb_obtree_fetch(qdbint_t, qdb_datum); int qdb_obtree_store(qdbint_t, qdb_datum, qdb_datum); int qdb_obtree_delete(qdbint_t, qdb_datum); qdb_datum qdb_obtree_firstkey(qdbint_t); qdb_datum qdb_obtree_nextkey(qdbint_t, qdb_datum); char *qdb_obtree_error(void); void qdb_obtree_unlock(qdbint_t); void qdb_obtree_relock(qdbint_t); #endif /* USING_OBTREE */ #ifdef USING_BTREE int qdb_btree_identify(const char *); qdbint_t qdb_btree_open(const char *, qdb_open_t); int qdb_btree_fd(qdbint_t); void qdb_btree_close(qdbint_t); qdb_datum qdb_btree_fetch(qdbint_t, qdb_datum); int qdb_btree_store(qdbint_t, qdb_datum, qdb_datum); int qdb_btree_delete(qdbint_t, qdb_datum); qdb_datum qdb_btree_firstkey(qdbint_t); qdb_datum qdb_btree_nextkey(qdbint_t, qdb_datum); void qdb_btree_optimise(qdbint_t); char *qdb_btree_error(void); void qdb_btree_unlock(qdbint_t); void qdb_btree_relock(qdbint_t); #endif /* USING_BTREE */ #ifdef USING_LIST int qdb_list_identify(const char *); qdbint_t qdb_list_open(const char *, qdb_open_t); int qdb_list_fd(qdbint_t); void qdb_list_close(qdbint_t); qdb_datum qdb_list_fetch(qdbint_t, qdb_datum); int qdb_list_store(qdbint_t, qdb_datum, qdb_datum); int qdb_list_delete(qdbint_t, qdb_datum); qdb_datum qdb_list_firstkey(qdbint_t); qdb_datum qdb_list_nextkey(qdbint_t, qdb_datum); char *qdb_list_error(void); void qdb_list_restore_start(qdbint_t); void qdb_list_restore_end(qdbint_t); #endif /* USING_LIST */ #ifdef USING_GDBM int qdb_gdbm_identify(const char *); qdbint_t qdb_gdbm_open(const char *, qdb_open_t); int qdb_gdbm_fd(qdbint_t); void qdb_gdbm_close(qdbint_t); qdb_datum qdb_gdbm_fetch(qdbint_t, qdb_datum); int qdb_gdbm_store(qdbint_t, qdb_datum, qdb_datum); int qdb_gdbm_delete(qdbint_t, qdb_datum); qdb_datum qdb_gdbm_firstkey(qdbint_t); qdb_datum qdb_gdbm_nextkey(qdbint_t, qdb_datum); void qdb_gdbm_optimise(qdbint_t); char *qdb_gdbm_error(void); #endif /* USING_GDBM */ #ifdef USING_MYSQL int qdb_mysql_identify(const char *); qdbint_t qdb_mysql_open(const char *, qdb_open_t); int qdb_mysql_fd(qdbint_t); void qdb_mysql_close(qdbint_t); qdb_datum qdb_mysql_fetch(qdbint_t, qdb_datum); int qdb_mysql_store(qdbint_t, qdb_datum, qdb_datum); int qdb_mysql_delete(qdbint_t, qdb_datum); qdb_datum qdb_mysql_firstkey(qdbint_t); qdb_datum qdb_mysql_nextkey(qdbint_t, qdb_datum); char *qdb_mysql_error(void); #endif /* USING_MYSQL */ #ifdef USING_SQLITE int qdb_sqlite_identify(const char *); qdbint_t qdb_sqlite_open(const char *, qdb_open_t); int qdb_sqlite_fd(qdbint_t); void qdb_sqlite_close(qdbint_t); qdb_datum qdb_sqlite_fetch(qdbint_t, qdb_datum); int qdb_sqlite_store(qdbint_t, qdb_datum, qdb_datum); int qdb_sqlite_delete(qdbint_t, qdb_datum); qdb_datum qdb_sqlite_firstkey(qdbint_t); qdb_datum qdb_sqlite_nextkey(qdbint_t, qdb_datum); char *qdb_sqlite_error(void); void qdb_sqlite_unlock(qdbint_t); void qdb_sqlite_relock(qdbint_t); #endif /* USING_SQLITE */ struct qdbtype_s { char *name; int (*_identify) (const char *); qdbint_t(*_open) (const char *, qdb_open_t); int (*_fd) (qdbint_t); void (*_close) (qdbint_t); qdb_datum(*_fetch) (qdbint_t, qdb_datum); int (*_store) (qdbint_t, qdb_datum, qdb_datum); int (*_delete) (qdbint_t, qdb_datum); qdb_datum(*_firstkey) (qdbint_t); qdb_datum(*_nextkey) (qdbint_t, qdb_datum); char *(*_error) (void); void (*_optimise) (qdbint_t); /* optional */ void (*_unlock) (qdbint_t); /* optional */ void (*_relock) (qdbint_t); /* optional */ void (*_restore_start) (qdbint_t); /* optional */ void (*_restore_end) (qdbint_t); /* optional */ }; struct qdb_s { struct qdbtype_s *type; int typeindex; struct qdbint_s *data; }; static struct qdbtype_s qdb__backends[] = { #ifdef USING_LIST { "list", qdb_list_identify, qdb_list_open, qdb_list_fd, qdb_list_close, qdb_list_fetch, qdb_list_store, qdb_list_delete, qdb_list_firstkey, qdb_list_nextkey, qdb_list_error, NULL, /* optimise */ NULL, /* unlock */ NULL, /* relock */ qdb_list_restore_start, qdb_list_restore_end}, #endif #ifdef USING_BTREE { "btree", qdb_btree_identify, qdb_btree_open, qdb_btree_fd, qdb_btree_close, qdb_btree_fetch, qdb_btree_store, qdb_btree_delete, qdb_btree_firstkey, qdb_btree_nextkey, qdb_btree_error, qdb_btree_optimise, qdb_btree_unlock, qdb_btree_relock, NULL, /* restore_start */ NULL}, /* restore_end */ #endif #ifdef USING_OBTREE { "obtree", qdb_obtree_identify, qdb_obtree_open, qdb_obtree_fd, qdb_obtree_close, qdb_obtree_fetch, qdb_obtree_store, qdb_obtree_delete, qdb_obtree_firstkey, qdb_obtree_nextkey, qdb_obtree_error, NULL, /* optimise */ qdb_obtree_unlock, qdb_obtree_relock, NULL, /* restore_start */ NULL}, /* restore_end */ #endif #ifdef USING_GDBM { "GDBM", qdb_gdbm_identify, qdb_gdbm_open, qdb_gdbm_fd, qdb_gdbm_close, qdb_gdbm_fetch, qdb_gdbm_store, qdb_gdbm_delete, qdb_gdbm_firstkey, qdb_gdbm_nextkey, qdb_gdbm_error, qdb_gdbm_optimise, NULL, /* unlock */ NULL, /* relock */ NULL, /* restore_start */ NULL}, /* restore_end */ #endif #ifdef USING_MYSQL { "MySQL", qdb_mysql_identify, qdb_mysql_open, qdb_mysql_fd, qdb_mysql_close, qdb_mysql_fetch, qdb_mysql_store, qdb_mysql_delete, qdb_mysql_firstkey, qdb_mysql_nextkey, qdb_mysql_error, NULL, /* optimise */ NULL, /* unlock */ NULL, /* relock */ NULL, /* restore_start */ NULL}, /* restore_end */ #endif #ifdef USING_SQLITE { "sqlite", qdb_sqlite_identify, qdb_sqlite_open, qdb_sqlite_fd, qdb_sqlite_close, qdb_sqlite_fetch, qdb_sqlite_store, qdb_sqlite_delete, qdb_sqlite_firstkey, qdb_sqlite_nextkey, qdb_sqlite_error, NULL, /* optimise */ qdb_sqlite_unlock, qdb_sqlite_relock, NULL, /* restore_start */ NULL}, /* restore_end */ #endif {NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; static int qdb__lastbackend = 0; /* * Return a file descriptor for the given database, or -1 on error. */ int qdb_fd(qdb_t db) { if (db == NULL) return -1; qdb__lastbackend = db->typeindex; return db->type->_fd(db->data); } /* * Return a string describing the type of the given database, or "(none)" on * error. The string should NOT be free()d. */ char *qdb_type(qdb_t db) { if (db == NULL) return "(none)"; return db->type->name; } /* * Open the given database in the given way (new database, read-only, or * read-write); return a qdb_t or NULL on error. */ qdb_t qdb_open(const char *file, qdb_open_t method) { int type, i; qdb_t db; type = -1; for (i = 0; type == -1 && qdb__backends[i].name != NULL; i++) { if (qdb__backends[i]._identify(file)) type = i; } /* * If no valid type was determined, fall back to obtree if the file * already exists, list if not (providing they are both compiled * in). If neither is compiled in, fall back to the first available * backend in the list. */ if (type == -1) { char *usetype = NULL; FILE *fptr; #ifdef USING_LIST usetype = "list"; #endif #ifdef USING_OBTREE fptr = fopen(file, "rb"); if (fptr) { fclose(fptr); usetype = "obtree"; } #endif if (usetype) { for (i = 0; type == -1 && qdb__backends[i].name != NULL; i++) { if (strcmp(qdb__backends[i].name, usetype) == 0) type = i; } } if (type == -1) type = 0; } qdb__lastbackend = type; db = calloc(1, sizeof(*db)); if (db == NULL) { return NULL; } db->type = &(qdb__backends[type]); db->typeindex = type; db->data = db->type->_open(file, method); if (db->data == NULL) { free(db); return NULL; } return db; } /* * Close the given database. */ void qdb_close(qdb_t db) { if (db == NULL) return; qdb__lastbackend = db->typeindex; db->type->_close(db->data); free(db); } /* * NOTE: From here on down, we take copies of "key" and "val" qdb_datum * objects before sending them on to the backend. For some reason OpenBSD * corrupts the key and val if we just pass them on, but if we pass on * copies, it's OK. */ /* * Fetch a value from the database. The datum returned needs its val.data * free()ing after use. If val.data is NULL, no value was found for the * given key. */ qdb_datum qdb_fetch(qdb_t db, qdb_datum key) { qdb_datum keycopy; if (db == NULL) { qdb_datum val; val.data = NULL; val.size = 0; return val; } if (key.data == NULL) { qdb_datum val; val.data = NULL; val.size = 0; return val; } keycopy = key; qdb__lastbackend = db->typeindex; return db->type->_fetch(db->data, keycopy); } /* * Store the given key with the given value into the database, replacing any * existing value for that key. Returns nonzero on error. */ int qdb_store(qdb_t db, qdb_datum key, qdb_datum val) { qdb_datum keycopy, valcopy; if (db == NULL) return 1; if ((key.data == NULL) || (val.data == NULL)) return 1; keycopy = key; valcopy = val; qdb__lastbackend = db->typeindex; return db->type->_store(db->data, keycopy, valcopy); } /* * Delete the given key from the database. Returns nonzero on error. */ int qdb_delete(qdb_t db, qdb_datum key) { qdb_datum keycopy; if (db == NULL) return 1; if (key.data == NULL) return 1; keycopy = key; qdb__lastbackend = db->typeindex; return db->type->_delete(db->data, keycopy); } /* * Return the "first" key in the database, suitable for using with repeated * calls to qdb_nextkey() to walk through every key in the database. */ qdb_datum qdb_firstkey(qdb_t db) { qdb__lastbackend = db->typeindex; return db->type->_firstkey(db->data); } /* * Return the "next" key in the database, or key.data=NULL when all keys * have been returned. */ qdb_datum qdb_nextkey(qdb_t db, qdb_datum key) { qdb_datum keycopy; keycopy = key; qdb__lastbackend = db->typeindex; return db->type->_nextkey(db->data, keycopy); } /* * Reorganise the database for better efficiency. */ void qdb_optimise(qdb_t db) { qdb__lastbackend = db->typeindex; if (db->type->_optimise == NULL) return; db->type->_optimise(db->data); } /* * Return a string describing the last database error to occur. */ char *qdb_error(void) { return qdb__backends[qdb__lastbackend]._error(); } /* * Temporarily release the lock on the database. */ void qdb_unlock(qdb_t db) { qdb__lastbackend = db->typeindex; if (db->type->_unlock == NULL) return; db->type->_unlock(db->data); } /* * Reassert the lock on the database. */ void qdb_relock(qdb_t db) { qdb__lastbackend = db->typeindex; if (db->type->_relock == NULL) return; db->type->_relock(db->data); } /* * Tell the database that a restore operation is starting. */ void qdb_restore_start(qdb_t db) { qdb__lastbackend = db->typeindex; if (db->type->_restore_start == NULL) return; db->type->_restore_start(db->data); } /* * Tell the database that a restore operation is ending. */ void qdb_restore_end(qdb_t db) { qdb__lastbackend = db->typeindex; if (db->type->_restore_end == NULL) return; db->type->_restore_end(db->data); } /* * Utility functions that can be used by the back-end follow. */ /* * Block common interrupt signals, so a user doesn't accidentally kill this * process while it's doing something critical to data integrity. */ void qdb_int__sig_block(void) { #ifdef SIGHUP signal(SIGHUP, SIG_IGN); /* RATS: ignore (OK) */ #endif #ifdef SIGINT signal(SIGINT, SIG_IGN); /* RATS: ignore (OK) */ #endif #ifdef SIGQUIT signal(SIGQUIT, SIG_IGN); /* RATS: ignore (OK) */ #endif #ifdef SIGTERM signal(SIGTERM, SIG_IGN); /* RATS: ignore (OK) */ #endif } /* * Unblock previously blocked signals. */ void qdb_int__sig_unblock(void) { #ifdef SIGHUP signal(SIGHUP, SIG_DFL); /* RATS: ignore (OK) */ #endif #ifdef SIGINT signal(SIGINT, SIG_DFL); /* RATS: ignore (OK) */ #endif #ifdef SIGQUIT signal(SIGQUIT, SIG_DFL); /* RATS: ignore (OK) */ #endif #ifdef SIGTERM signal(SIGTERM, SIG_DFL); /* RATS: ignore (OK) */ #endif } /* * Obtain / release a read or write lock on the database. Returns zero on * success, 1 on error. Blocks until a lock can be obtained. Keeps track of * the number of times locked, so we don't accidentally try to lock a file * descriptor twice. */ int qdb_int__lock(int fd, int lock_type, int *lockcount) { #ifdef HAVE_FCNTL struct flock lock; int lockdummy = 0; if (lockcount == NULL) lockcount = &lockdummy; if ((lock_type == F_UNLCK) && (*lockcount > 1)) { *lockcount = (*lockcount) - 1; return 0; } else if ((lock_type != F_UNLCK) && (*lockcount > 0)) { *lockcount = (*lockcount) + 1; return 0; } lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 0; lock.l_type = lock_type; if (fcntl(fd, F_SETLKW, &lock)) { return 1; } if (lock_type == F_UNLCK) { *lockcount = (*lockcount) - 1; } else { *lockcount = (*lockcount) + 1; } #endif /* HAVE_FCNTL */ return 0; } /* EOF */ qsf-1.2.7/src/db/gdbm.c0000644000076400007640000001235610664772303012372 0ustar awaw/* * Make our db functions a wrapper for GDBM. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "database.h" #ifdef USING_GDBM #include #include #include #include #include #ifdef HAVE_FCNTL #include #endif #include #include struct qdbint_s { GDBM_FILE dbf; #ifndef HAVE_GDBM_FDESC int fd; #endif /* !HAVE_GDBM_FDESC */ }; /* * Return a file descriptor for the given database, or -1 on error. */ int qdb_gdbm_fd(qdbint_t db) { if (db == NULL) return -1; if (db->dbf == NULL) return -1; #ifdef HAVE_GDBM_FDESC return gdbm_fdesc(db->dbf); #else /* !HAVE_GDBM_FDESC */ return db->fd; #endif /* HAVE_GDBM_FDESC */ } /* * Return nonzero if the given file is of this database type. */ int qdb_gdbm_identify(const char *file) { FILE *fptr; unsigned char buf[8]; /* RATS: ignore (checked) */ if (file == NULL) return 0; if (strncasecmp(file, "gdbm:", 5) == 0) return 1; fptr = fopen(file, "rb"); if (fptr == NULL) return 0; if (fread(buf, 4, 1, fptr) < 1) { fclose(fptr); return 0; } fclose(fptr); buf[4] = 0; if ((buf[0] == 0x13) && (buf[1] == 0x57) && (buf[2] == 0x9a) && (buf[3] == 0xce) ) return 1; if ((buf[3] == 0x13) && (buf[2] == 0x57) && (buf[1] == 0x9a) && (buf[0] == 0xce) ) return 1; if (strncmp((char *) buf, "GDBM", 4) == 0) return 1; return 0; } /* * Open the given database in the given way (new database, read-only, or * read-write); return a qdbint_t or NULL on error. */ qdbint_t qdb_gdbm_open(const char *file, qdb_open_t method) { GDBM_FILE dbf = NULL; qdbint_t db; int tries; if (strncasecmp(file, "gdbm:", 5) == 0) file += 5; for (tries = 0; tries < 60 && dbf == NULL; tries++) { switch (method) { case QDB_NEW: dbf = gdbm_open((char *) file, 512, GDBM_NEWDB, S_IRUSR | S_IWUSR, NULL); break; case QDB_READONLY: dbf = gdbm_open((char *) file, 512, GDBM_READER, S_IRUSR, NULL); break; case QDB_READWRITE: dbf = gdbm_open((char *) file, 512, GDBM_WRCREAT, S_IRUSR | S_IWUSR, NULL); break; default: break; } if (dbf != NULL) break; switch (gdbm_errno) { case GDBM_CANT_BE_READER: case GDBM_CANT_BE_WRITER: sleep(1); break; default: return NULL; } } if (dbf == NULL) return NULL; db = calloc(1, sizeof(*db)); if (db == NULL) { gdbm_close(dbf); return NULL; } #ifndef HAVE_GDBM_FDESC db->fd = open(file, O_RDONLY); #endif /* !HAVE_GDBM_FDESC */ db->dbf = dbf; return db; } /* * Close the given database. */ void qdb_gdbm_close(qdbint_t db) { if (db == NULL) return; #ifndef HAVE_GDBM_FDESC if (db->fd >= 0) close(db->fd); #endif /* !HAVE_GDBM_FDESC */ gdbm_close(db->dbf); free(db); } /* * Fetch a value from the database. The datum returned needs its val.data * free()ing after use. If val.data is NULL, no value was found for the * given key. */ qdb_datum qdb_gdbm_fetch(qdbint_t db, qdb_datum key) { datum gkey, gval; qdb_datum val; if (db == NULL) { val.data = NULL; val.size = 0; return val; } if (key.data == NULL) { val.data = NULL; val.size = 0; return val; } gkey.dptr = (char *) (key.data); gkey.dsize = key.size; gval = gdbm_fetch(db->dbf, gkey); val.data = (unsigned char *) (gval.dptr); val.size = gval.dsize; return val; } /* * Store the given key with the given value into the database, replacing any * existing value for that key. Returns nonzero on error. */ int qdb_gdbm_store(qdbint_t db, qdb_datum key, qdb_datum val) { datum gkey, gval; if (db == NULL) return 1; if ((key.data == NULL) || (val.data == NULL)) return 1; gkey.dptr = (char *) (key.data); gkey.dsize = key.size; gval.dptr = (char *) (val.data); gval.dsize = val.size; return gdbm_store(db->dbf, gkey, gval, GDBM_REPLACE); } /* * Delete the given key from the database. Returns nonzero on error. */ int qdb_gdbm_delete(qdbint_t db, qdb_datum key) { datum gkey; if (db == NULL) return 1; if (key.data == NULL) return 1; gkey.dptr = (char *) (key.data); gkey.dsize = key.size; return gdbm_delete(db->dbf, gkey); } /* * Return the "first" key in the database, suitable for using with repeated * calls to qdb_nextkey() to walk through every key in the database. */ qdb_datum qdb_gdbm_firstkey(qdbint_t db) { datum gkey; qdb_datum key; gkey = gdbm_firstkey(db->dbf); key.data = (unsigned char *) (gkey.dptr); key.size = gkey.dsize; return key; } /* * Return the "next" key in the database, or key.data=NULL when all keys * have been returned. */ qdb_datum qdb_gdbm_nextkey(qdbint_t db, qdb_datum key) { datum gkey, newgkey; qdb_datum newkey; gkey.dptr = (char *) (key.data); gkey.dsize = key.size; newgkey = gdbm_nextkey(db->dbf, gkey); newkey.data = (unsigned char *) (newgkey.dptr); newkey.size = newgkey.dsize; return newkey; } /* * Reorganise the database for better efficiency. */ void qdb_gdbm_optimise(qdbint_t db) { gdbm_reorganize(db->dbf); } /* * Return a string describing the last database error to occur. */ char *qdb_gdbm_error(void) { return (char *) gdbm_strerror(gdbm_errno); } #endif /* USING_GDBM */ /* EOF */ qsf-1.2.7/src/db/btree.c0000644000076400007640000005722310664772303012564 0ustar awaw/* * Binary tree database backend. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "database.h" #include "log.h" #ifdef USING_BTREE #include #include #include #include #include #include #include #include #ifdef HAVE_FCNTL #include #endif #ifdef HAVE_MMAP #include #endif #ifdef HAVE_UTIME #include #include #endif #define BT_RECORD_SIZE sizeof(struct bt_record) #define BT_TOKEN_MAX 36 typedef unsigned long bt_ul; struct bt_record { /* single binary tree record */ bt_ul lower; /* offset of "lower" token */ bt_ul higher; /* offset of "higher" token */ unsigned char token[BT_TOKEN_MAX]; /* RATS: ignore - 0-term. token */ long data[3]; /* token data (i.e. the counts) */ }; typedef struct bt_record *bt_record_t; struct qdbint_s { /* database state */ int fd; /* file descriptor of database file */ bt_ul size; /* total size of database */ #ifdef HAVE_FCNTL int lockcount; /* number of times lock asked for */ int locktype; /* type of lock to use (read or write) */ #endif int gotheadoffs; /* flag, set once head offset read */ bt_ul head_offset; /* offset of head record of tree */ #ifdef HAVE_MMAP unsigned char *data; /* mmap()ed database data */ bt_ul filepos; /* current file pointer */ #endif char *filename; /* filename of database */ int modified; /* flag, set if db modified at all */ }; static char *bt_lasterror = ""; #ifdef HAVE_FCNTL /* * Obtain / release a read or write lock on the database. Returns nonzero on * error, and blocks until a lock can be obtained. */ static int dbbt_lock(qdbint_t db, int lock_type) { int ret; ret = qdb_int__lock(db->fd, lock_type, &(db->lockcount)); if (ret != 0) { bt_lasterror = strerror(errno); return 1; } return 0; } #endif /* HAVE_FCNTL */ static off_t dbbt_lseek(qdbint_t db, off_t offset, int whence) { #ifdef HAVE_MMAP if ((db->data == 0) || (db->filepos < 0) || (whence != SEEK_SET)) { db->filepos = lseek(db->fd, offset, whence); } else { db->filepos = offset; } return db->filepos; #else return lseek(db->fd, offset, whence); #endif } /* * Analogue of fread(). */ static int dbbt_chunkread_raw(void *ptr, int size, int nmemb, int fd) { int numread, togo, got; for (numread = 0; nmemb > 0; nmemb--, numread++) { for (togo = size; togo > 0;) { got = read(fd, ptr, togo); /* RATS: ignore (OK) */ if (got <= 0) return numread; togo -= got; ptr = (void *) (((char *) ptr) + got); } } return numread; } /* * Analogue of fwrite(). */ static int dbbt_chunkwrite_raw(void *ptr, int size, int nmemb, int fd) { int numwritten, togo, written; for (numwritten = 0; nmemb > 0; nmemb--, numwritten++) { for (togo = size; togo > 0;) { written = write(fd, ptr, togo); if (written <= 0) return numwritten; togo -= written; ptr = (void *) (((char *) ptr) + written); } } return numwritten; } /* * Analogue of fread(), using memory mapped data if possible. */ static int dbbt_chunkread(void *ptr, int size, int nmemb, qdbint_t db) { #ifdef HAVE_MMAP long available, copyable, tocopy; if ((db->data == 0) || (db->filepos < 0)) { return dbbt_chunkread_raw(ptr, size, nmemb, db->fd); } if (size < 1) return 0; available = db->size - db->filepos; if (available <= 0) return 0; copyable = available / size; if (copyable < nmemb) nmemb = copyable; tocopy = nmemb * size; memcpy(ptr, db->data + db->filepos, tocopy); db->filepos += tocopy; return nmemb; #else /* !HAVE_MMAP */ return dbbt_chunkread_raw(ptr, size, nmemb, db->fd); #endif /* HAVE_MMAP */ } /* * Analogue of fwrite(), using memory mapped data if possible, remapping * after extending the file if not. */ static int dbbt_chunkwrite(void *ptr, int size, int nmemb, qdbint_t db) { #ifdef HAVE_MMAP long available, copyable, tocopy; db->modified = 1; if ((db->data == 0) || (db->filepos < 0)) return dbbt_chunkwrite_raw(ptr, size, nmemb, db->fd); if (size < 1) return 0; available = db->size - db->filepos; copyable = available / size; if (copyable < nmemb) { int retval; munmap(db->data, db->size); db->data = 0; lseek(db->fd, db->filepos, SEEK_SET); retval = dbbt_chunkwrite_raw(ptr, size, nmemb, db->fd); db->size = lseek(db->fd, 0, SEEK_END); db->data = mmap(NULL, db->size, PROT_READ | PROT_WRITE, MAP_SHARED, db->fd, 0); if (db->data == MAP_FAILED) db->data = 0; db->filepos = db->size; return retval; } else { tocopy = nmemb * size; memcpy(db->data + db->filepos, ptr, tocopy); db->filepos += tocopy; return nmemb; } #else /* !HAVE_MMAP */ return dbbt_chunkwrite_raw(ptr, size, nmemb, db->fd); #endif /* HAVE_MMAP */ } /* * Read a record from the database at the given offset into the given record * structure, returning nonzero on failure. */ static int dbbt_read_record(qdbint_t db, bt_ul offset, bt_record_t record) { int got; if (dbbt_lseek(db, offset, SEEK_SET) == (off_t) - 1) { bt_lasterror = strerror(errno); return 1; } got = dbbt_chunkread(record, BT_RECORD_SIZE, 1, db); if (got < 1) { bt_lasterror = strerror(errno); return 1; } record->token[BT_TOKEN_MAX - 1] = 0; return 0; } /* * Write a record to the database at the given offset, returning nonzero on * failure. */ static int dbbt_write_record(qdbint_t db, bt_ul offset, bt_record_t record) { if (dbbt_lseek(db, offset, SEEK_SET) == (off_t) - 1) { bt_lasterror = strerror(errno); return 1; } if (dbbt_chunkwrite(record, BT_RECORD_SIZE, 1, db) < 1) { bt_lasterror = strerror(errno); return 1; } return 0; } /* * Find the given token in the database and fill in the given record * structure if found, also filling in the offset of the record (or 0 if not * found) and the offset of the parent record (0 if none). * * Returns -1 if the token looked for was "lower" than its parent or +1 if * "higher", or 0 if there was no parent record (i.e. this is the first * record). */ static int dbbt_find_token(qdbint_t db, qdb_datum key, bt_record_t record, bt_ul * offset, bt_ul * parent) { int hilow = 0; int x; *offset = 0; *parent = 0; if (db == NULL) return 0; if (db->size < 2 * sizeof(long)) return 0; if (!db->gotheadoffs) { dbbt_lseek(db, 4, SEEK_SET); dbbt_chunkread(offset, sizeof(*offset), 1, db); db->head_offset = *offset; db->gotheadoffs = 1; } else { *offset = db->head_offset; } while (*offset > 0) { int len; if (dbbt_read_record(db, *offset, record)) { *offset = 0; break; } x = strncmp((char *) (record->token), (char *) (key.data), key.size); len = strlen((char *) (record->token)); if (len < key.size) { x = -1; } else if (len > key.size) { x = 1; } if (x == 0) { return hilow; } else if (x < 0) { *parent = *offset; hilow = -1; *offset = record->lower; } else { *parent = *offset; hilow = 1; *offset = record->higher; } } return hilow; } /* * Mark the block at the given offset as free space by adding it to the head * of the free space list. Returns nonzero on error. */ static int dbbt_markfree(qdbint_t db, bt_ul offset) { bt_ul nextfree, storeoffs; /* * Read the "next free" offset from the free space head block */ if (dbbt_lseek(db, 4 + sizeof(offset), SEEK_SET) == (off_t) - 1) { bt_lasterror = strerror(errno); return 1; } nextfree = 0x80000000; if (dbbt_chunkread(&nextfree, sizeof(nextfree), 1, db) < 0) { bt_lasterror = strerror(errno); return 1; } /* * Write the given offset as the new "next free" offset */ if (dbbt_lseek(db, 4 + sizeof(offset), SEEK_SET) == (off_t) - 1) { bt_lasterror = strerror(errno); return 1; } storeoffs = offset; storeoffs |= 0x80000000; if (dbbt_chunkwrite(&storeoffs, sizeof(offset), 1, db) < 0) { bt_lasterror = strerror(errno); return 1; } /* * Write the old "next free" offset into the block being freed */ if (dbbt_lseek(db, offset, SEEK_SET) == (off_t) - 1) { bt_lasterror = strerror(errno); return 1; } if (dbbt_chunkwrite(&nextfree, sizeof(nextfree), 1, db) < 1) { bt_lasterror = strerror(errno); return 1; } return 0; } /* * Return nonzero if the given file is of this database type. */ int qdb_btree_identify(const char *file) { FILE *fptr; unsigned char buf[8]; /* RATS: ignore (checked) */ if (file == NULL) return 0; if (strncasecmp(file, "btree:", 6) == 0) return 1; fptr = fopen(file, "rb"); if (fptr == NULL) return 0; if (fread(buf, 4, 1, fptr) < 1) { fclose(fptr); return 0; } fclose(fptr); if (strncmp((char *) buf, "QSF1", 4) == 0) return 1; return 0; } /* * Open the given database in the given way (new database, read-only, or * read-write); return a qdbint_t or NULL on error. */ qdbint_t qdb_btree_open(const char *file, qdb_open_t method) { qdbint_t db; int fd = -1; #ifdef HAVE_FCNTL int locktype = F_RDLCK; #endif if (strncasecmp(file, "btree:", 6) == 0) file += 6; switch (method) { case QDB_NEW: fd = open(file, /* RATS: ignore (no race) */ O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd < 0) bt_lasterror = strerror(errno); #ifdef HAVE_FCNTL locktype = F_WRLCK; #endif break; case QDB_READONLY: fd = open(file, /* RATS: ignore (no race) */ O_RDONLY); if (fd < 0) bt_lasterror = strerror(errno); break; case QDB_READWRITE: fd = open(file, /* RATS: ignore (no race) */ O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd < 0) bt_lasterror = strerror(errno); #ifdef HAVE_FCNTL locktype = F_WRLCK; #endif break; default: break; } if (fd < 0) return NULL; db = calloc(1, sizeof(*db)); if (db == NULL) { bt_lasterror = strerror(errno); close(fd); return NULL; } db->filename = strdup(file); db->fd = fd; db->modified = 0; #ifdef HAVE_FCNTL db->locktype = locktype; if (dbbt_lock(db, locktype)) { close(fd); if (db->filename) free(db->filename); free(db); return NULL; } #endif db->size = dbbt_lseek(db, 0, SEEK_END); /* * If this is a new database, and it's not readonly, write our * header to it and return. */ if ((db->size < 5) && (method != QDB_READONLY)) { dbbt_lseek(db, 0, SEEK_SET); dbbt_chunkwrite_raw("QSF1", 4, 1, db->fd); db->size = 4; db->modified = 1; #ifdef HAVE_MMAP db->filepos = 0; db->data = mmap(NULL, db->size, PROT_READ | (method == QDB_READONLY ? 0 : PROT_WRITE), MAP_SHARED, db->fd, 0); if (db->data == MAP_FAILED) db->data = 0; #endif return db; } /* * We now do some simple checks to make sure that the file is a * database of the format we're expecting. */ /* * If it's shorter than 4 bytes plus 2 long ints, it's not a valid * database. */ if (db->size < 4 + 2 * sizeof(long)) { bt_lasterror = _("invalid database (too small)"); close(fd); if (db->filename) free(db->filename); free(db); return NULL; } /* * If its size, discounting the two longs at the start, isn't a * multiple of our record size, it's not a valid database. */ if (((db->size - (4 + 2 * sizeof(long))) % BT_RECORD_SIZE) != 0) { bt_lasterror = _("invalid database (irregular size)"); close(fd); if (db->filename) free(db->filename); free(db); return NULL; } /* * If the first long int (the "head offset") is larger than the size * of the file, this isn't a valid database. */ { bt_ul offset = db->size + 1; dbbt_lseek(db, 4, SEEK_SET); dbbt_chunkread(&offset, sizeof(offset), 1, db); if (offset > db->size) { bt_lasterror = _("invalid database (bad head offset)"); close(fd); if (db->filename) free(db->filename); free(db); return NULL; } dbbt_lseek(db, 4, SEEK_SET); } #ifdef HAVE_MMAP db->data = mmap(NULL, db->size, PROT_READ | (method == QDB_READONLY ? 0 : PROT_WRITE), MAP_SHARED, db->fd, 0); if (db->data == MAP_FAILED) db->data = 0; #endif return db; } /* * Close the given database. */ void qdb_btree_close(qdbint_t db) { if (db == NULL) return; #ifdef HAVE_MMAP if (db->data) munmap(db->data, db->size); #endif #ifdef HAVE_FCNTL while (db->lockcount > 0) dbbt_lock(db, F_UNLCK); #endif close(db->fd); if (db->modified && db->filename) { #ifdef HAVE_UTIME struct utimbuf utb; utb.actime = time(NULL); utb.modtime = time(NULL); utime(db->filename, &utb); #endif } if (db->filename) free(db->filename); free(db); } /* * Fetch a value from the database. The datum returned needs its val.data * free()ing after use. If val.data is NULL, no value was found for the * given key. */ qdb_datum qdb_btree_fetch(qdbint_t db, qdb_datum key) { struct bt_record record; unsigned long offset, parent; qdb_datum val; val.data = NULL; val.size = 0; if (db == NULL) return val; if (key.size >= BT_TOKEN_MAX) key.size = BT_TOKEN_MAX - 1; dbbt_find_token(db, key, &record, &offset, &parent); if (offset == 0) return val; val.size = 3 * sizeof(long); val.data = calloc(1, val.size); if (val.data == NULL) { val.size = 0; return val; } ((long *) val.data)[0] = record.data[0]; ((long *) val.data)[1] = record.data[1]; ((long *) val.data)[2] = record.data[2]; return val; } /* * Return a file descriptor for the given database, or -1 on error. */ int qdb_btree_fd(qdbint_t db) { if (db == NULL) return -1; return db->fd; } /* * Store the given key with the given value into the database, replacing any * existing value for that key. Returns nonzero on error. */ int qdb_btree_store(qdbint_t db, qdb_datum key, qdb_datum val) { struct bt_record record, head; unsigned long offset, parent, nextfree; int x; if (db == NULL) return 1; memset(&head, 0, BT_RECORD_SIZE); memset(&record, 0, BT_RECORD_SIZE); if (key.size >= BT_TOKEN_MAX) key.size = BT_TOKEN_MAX - 1; x = dbbt_find_token(db, key, &record, &offset, &parent); memcpy(record.token, key.data, key.size); record.token[key.size] = 0; record.data[0] = ((long *) val.data)[0]; record.data[1] = ((long *) val.data)[1]; if (val.size > 2 * sizeof(long)) record.data[2] = ((long *) val.data)[2]; qdb_int__sig_block(); /* * Record exists - overwrite it. */ if (offset > 0) { if (dbbt_write_record(db, offset, &record)) { qdb_int__sig_unblock(); return 1; } qdb_int__sig_unblock(); return 0; } record.lower = 0; record.higher = 0; /* * Database has just been created, so fill in the header and write * this record as the first one. */ if (db->size <= 4 + sizeof(offset)) { if (dbbt_lseek(db, 4, SEEK_SET) == (off_t) - 1) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } offset = 4 + 2 * sizeof(offset); if (dbbt_chunkwrite(&offset, sizeof(offset), 1, db) < 1) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } db->gotheadoffs = 0; offset = 0; if (dbbt_chunkwrite(&offset, sizeof(offset), 1, db) < 1) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } head.lower = (4 + 2 * sizeof(offset)) + BT_RECORD_SIZE; if (dbbt_chunkwrite(&head, BT_RECORD_SIZE, 1, db) < 1) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } if (dbbt_chunkwrite(&record, BT_RECORD_SIZE, 1, db) < 1) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } db->size = dbbt_lseek(db, 0, SEEK_CUR); qdb_int__sig_unblock(); return 0; } /* * Get offset of next free space block. */ if (dbbt_lseek(db, 4 + sizeof(offset), SEEK_SET) == (off_t) - 1) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } if (dbbt_chunkread(&offset, sizeof(offset), 1, db) < 1) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } offset &= 0x7FFFFFFF; /* * If offset is 0 or we can't read from that offset, it's a new * block at the end of the file, otherwise we take the next free * offset from there and store it in the core free pointer, and then * use that free offset. */ if (dbbt_lseek(db, offset, SEEK_SET) == (off_t) - 1) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } if ((offset < 5) || (dbbt_chunkread(&nextfree, sizeof(nextfree), 1, db) < 1) ) { offset = dbbt_lseek(db, 0, SEEK_END); nextfree = 0x80000000; } if (dbbt_lseek(db, 4 + sizeof(offset), SEEK_SET) == (off_t) - 1) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } if (dbbt_chunkwrite(&nextfree, sizeof(nextfree), 1, db) < 0) { bt_lasterror = strerror(errno); qdb_int__sig_unblock(); return 1; } if (dbbt_write_record(db, offset, &record)) { qdb_int__sig_unblock(); return 1; } /* * Now attach the new record to its parent, if applicable. */ if (parent > 0) { if (dbbt_read_record(db, parent, &record)) { qdb_int__sig_unblock(); return 1; } if (x < 0) { record.lower = offset; } else { record.higher = offset; } if (dbbt_write_record(db, parent, &record)) { qdb_int__sig_unblock(); return 1; } } qdb_int__sig_unblock(); return 0; } /* * Return the "first" key in the database, suitable for using with repeated * calls to qdb_nextkey() to walk through every key in the database. */ qdb_datum qdb_btree_firstkey(qdbint_t db) { struct bt_record record; qdb_datum newkey; newkey.data = NULL; newkey.size = 0; if (dbbt_lseek(db, 4 + 2 * sizeof(unsigned long) + BT_RECORD_SIZE, SEEK_SET) == (off_t) - 1) return newkey; do { if (dbbt_chunkread(&record, BT_RECORD_SIZE, 1, db) < 1) { return newkey; } } while (record.lower & 0x80000000); record.token[BT_TOKEN_MAX - 1] = 0; newkey.data = (unsigned char *) strdup((char *) (record.token)); newkey.size = strlen((char *) (record.token)); return newkey; } /* * Return the "next" key in the database, or key.data=NULL when all keys * have been returned. */ qdb_datum qdb_btree_nextkey(qdbint_t db, qdb_datum key) { struct bt_record record; unsigned long offset, parent; qdb_datum newkey; newkey.data = NULL; newkey.size = 0; if (key.data == NULL) { return newkey; } dbbt_find_token(db, key, &record, &offset, &parent); if (offset < 1) { return newkey; } if (dbbt_lseek(db, offset + BT_RECORD_SIZE, SEEK_SET) == (off_t) - 1) { return newkey; } do { if (dbbt_chunkread(&record, BT_RECORD_SIZE, 1, db) < 1) { return newkey; } } while (record.lower & 0x80000000); record.token[BT_TOKEN_MAX - 1] = 0; newkey.data = (unsigned char *) strdup((char *) (record.token)); newkey.size = strlen((char *) (record.token)); return newkey; } /* * Put the given record back into the binary tree, by storing it over again. * Returns nonzero on error. */ static int qdb_btree_delete__rewrite(qdbint_t db, bt_record_t record) { qdb_datum key, val; struct bt_record newrec; unsigned long offset, parent; int x; key.data = record->token; key.size = strlen((char *) (record->token)); val.data = (void *) (record->data); val.size = 3 * sizeof(long); if (qdb_btree_store(db, key, val)) return 1; x = dbbt_find_token(db, key, &newrec, &offset, &parent); if (offset < 4) return 1; newrec.lower = record->lower; newrec.higher = record->higher; qdb_int__sig_block(); if (dbbt_write_record(db, offset, &newrec)) { qdb_int__sig_unblock(); return 1; } qdb_int__sig_unblock(); return 0; } /* * Delete the given key from the database. Returns nonzero on error. */ int qdb_btree_delete(qdbint_t db, qdb_datum key) { struct bt_record record, recparent, reclower, rechigher; unsigned long offset, parent; int x; if (db == NULL) return 1; if (key.size < 1) return 1; x = dbbt_find_token(db, key, &record, &offset, &parent); if (offset < 5) return 1; /* * Get a copy of the lower and higher records, if any. */ if (record.lower > 0) { if (dbbt_read_record(db, record.lower, &reclower)) return 1; } if (record.higher > 0) { if (dbbt_read_record(db, record.higher, &rechigher)) return 1; } qdb_int__sig_block(); /* * Remove the link to this record from its parent. */ if (parent > 0) { if (dbbt_read_record(db, parent, &recparent)) { qdb_int__sig_unblock(); return 1; } if (x < 0) { recparent.lower = 0; } else { recparent.higher = 0; } if (dbbt_write_record(db, parent, &recparent)) { qdb_int__sig_unblock(); return 1; } } /* * Now we add this record's offset to the head of the "free records" * linked list. */ if (dbbt_markfree(db, offset)) { qdb_int__sig_unblock(); return 1; } /* * If there were any direct children, mark them as free as well. */ if (record.lower > 0) { if (dbbt_markfree(db, record.lower)) { qdb_int__sig_unblock(); return 1; } } if (record.higher > 0) { if (dbbt_markfree(db, record.higher)) { qdb_int__sig_unblock(); return 1; } } qdb_int__sig_unblock(); /* * Re-attach any children of this record to the database. */ if (record.lower > 0) { if (qdb_btree_delete__rewrite(db, &reclower)) { return 1; } } if (record.higher > 0) { if (qdb_btree_delete__rewrite(db, &rechigher)) { return 1; } } return 0; } /* * Temporarily release the lock on the database. */ void qdb_btree_unlock(qdbint_t db) { #ifdef HAVE_FCNTL dbbt_lock(db, F_UNLCK); #endif } /* * Reassert the lock on the database. */ void qdb_btree_relock(qdbint_t db) { #ifdef HAVE_FCNTL dbbt_lock(db, db->locktype); #endif db->gotheadoffs = 0; } /* * Reorganise the database for better efficiency. * * This is done by dumping all the tokens in this database into a temporary * new one, then copying this temporary database over the top of the current * database. */ void qdb_btree_optimise(qdbint_t db) { char filename[1024]; /* RATS: ignore (checked all) */ qdbint_t newdb; qdb_datum key, val, nextkey; int newdbfd, got; #ifdef P_tmpdir #ifdef HAVE_SNPRINTF snprintf(filename, sizeof(filename), #else sprintf(filename, /* RATS: ignore (checked) */ #endif "%.*s", (int) (sizeof(filename) - 1), P_tmpdir "/qsfXXXXXX"); #else #ifdef HAVE_SNPRINTF snprintf(filename, sizeof(filename), #else sprintf(filename, /* RATS: ignore (checked) */ #endif "%.*s", (int) (sizeof(filename) - 1), "/tmp/qsfXXXXXX"); #endif #ifdef HAVE_MKSTEMP newdbfd = mkstemp(filename); #else newdbfd = -1; if (tmpnam(filename) != NULL) { /* RATS: ignore (OK) */ newdbfd = open(filename, /* RATS: ignore (OK) */ O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); } #endif if (newdbfd < 0) { fprintf(stderr, "%s: %s: %s\n", filename, _("failed to create temporary file"), strerror(errno)); return; } newdb = qdb_btree_open(filename, QDB_NEW); if (newdb == NULL) { close(newdbfd); return; } key = qdb_btree_firstkey(db); while (key.data != NULL) { val = qdb_btree_fetch(db, key); if (val.data != NULL) { qdb_btree_store(newdb, key, val); free(val.data); } nextkey = qdb_btree_nextkey(db, key); free(key.data); key = nextkey; } qdb_btree_close(newdb); #ifdef HAVE_MMAP munmap(db->data, db->size); db->data = 0; #endif qdb_int__sig_block(); dbbt_lseek(db, 0, SEEK_SET); lseek(newdbfd, 0, SEEK_SET); do { unsigned char buf[4096]; /* RATS: ignore (checked) */ got = dbbt_chunkread_raw(buf, 1, sizeof(buf), newdbfd); if (got > 0) dbbt_chunkwrite_raw(buf, 1, got, db->fd); } while (got > 0); if (ftruncate(db->fd, lseek(db->fd, 0, SEEK_CUR)) != 0) { log_add(0, "%s: failed to truncate database: %s", db->filename, strerror(errno)); } close(newdbfd); remove(filename); qdb_int__sig_unblock(); db->size = dbbt_lseek(db, 0, SEEK_END); db->gotheadoffs = 0; #ifdef HAVE_MMAP db->data = mmap(NULL, db->size, PROT_READ | PROT_WRITE, MAP_SHARED, db->fd, 0); if (db->data == MAP_FAILED) db->data = 0; db->filepos = db->size; #endif } /* * Return a string describing the last database error to occur. */ char *qdb_btree_error(void) { return bt_lasterror; } #endif /* USING_BTREE */ /* EOF */ qsf-1.2.7/src/db/sqlite.c0000644000076400007640000003271010664772303012756 0ustar awaw/* * Make our db functions a wrapper for SQLite. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "database.h" #include "log.h" #ifdef USING_SQLITE #undef DEBUG_SQLITE #include #include #include #include #include #include #include #include #ifdef HAVE_FCNTL #include #endif #include struct qdbint_s { int fd; sqlite *db; /* SQLite database object */ int have_value3; /* flag, set if value3 column exists */ int locked; /* flag, set if database locked */ int compiled; /* flag, set if a zSQL VM has been compiled */ const char *ztail; /* current compiled zSQL tail */ sqlite_vm *vm; /* current VM for zSQL execution */ int readonly; /* flag, set if this database is readonly */ }; static char qdb_sqlite__errstr[4096] = { 0, }; static char *qdb_sqlite__errptr = 0; #if DEBUG_SQLITE /* * Debugging function to output every SQL statement passed to SQLite. */ static void qdb_sqlite__debug(void *ptr, const char *str) { printf("[%s]\n", str); } #endif /* * Return a file descriptor for the given database, or -1 on error. */ int qdb_sqlite_fd(qdbint_t db) { if (db == NULL) return -1; return db->fd; } /* * Temporarily release the lock on the database. */ void qdb_sqlite_unlock(qdbint_t db) { if (db == NULL) return; if (!db->locked) return; /* * We "unlock" by ending the current transaction. */ sqlite_exec(db->db, "COMMIT", NULL, NULL, &qdb_sqlite__errptr); if (qdb_sqlite__errptr) { sqlite_freemem(qdb_sqlite__errptr); qdb_sqlite__errptr = 0; } db->locked = 0; } /* * Reassert the lock on the database. */ void qdb_sqlite_relock(qdbint_t db) { int tries, ret; if (db == NULL) return; if (db->locked) return; /* * We "lock" by starting a new transaction. */ for (tries = 0; tries < 60 && !db->locked; tries++) { ret = sqlite_exec(db->db, "BEGIN", NULL, NULL, &qdb_sqlite__errptr); if (qdb_sqlite__errptr) { sqlite_freemem(qdb_sqlite__errptr); qdb_sqlite__errptr = 0; } switch (ret) { case SQLITE_OK: db->locked = 1; break; case SQLITE_BUSY: sleep(1); break; default: break; } } } /* * Return nonzero if the given file is of this database type. */ int qdb_sqlite_identify(const char *file) { FILE *fptr; unsigned char buf[64]; /* RATS: ignore (checked) */ if (file == NULL) return 0; if (strncasecmp(file, "sqlite:", 7) == 0) return 1; if (strncasecmp(file, "sqlite2:", 8) == 0) return 1; fptr = fopen(file, "rb"); if (fptr == NULL) return 0; if (fread(buf, 33, 1, fptr) < 1) { fclose(fptr); return 0; } fclose(fptr); if (strncmp((char *) buf, "** This file contains an SQLite 2", 33) == 0) return 1; return 0; } /* * Open the given database in the given way (new database, read-only, or * read-write); return a qdbint_t or NULL on error. */ qdbint_t qdb_sqlite_open(const char *file, qdb_open_t method) { qdbint_t db; char **results; int rows, cols; if (strncasecmp(file, "sqlite:", 7) == 0) file += 7; if (strncasecmp(file, "sqlite2:", 8) == 0) file += 8; db = calloc(1, sizeof(*db)); if (db == NULL) { sprintf(qdb_sqlite__errstr, "%.999s", strerror(errno)); return NULL; } db->fd = -1; db->readonly = (method == QDB_READONLY ? 1 : 0); db->have_value3 = 1; /* * If we need write access, and the file exists, check we can * physically write to the file first, since sqlite_open() seems not * to care. */ if (!db->readonly) { db->fd = open(file, O_RDWR); if (db->fd < 0) { if (errno != ENOENT) { sprintf(qdb_sqlite__errstr, "%.999s", strerror(errno)); free(db); return NULL; } } } db->db = sqlite_open(file, 0, &qdb_sqlite__errptr); if (db->db == NULL) { sprintf(qdb_sqlite__errstr, "%.999s", qdb_sqlite__errptr ? qdb_sqlite__errptr : ""); if (qdb_sqlite__errptr) { sqlite_freemem(qdb_sqlite__errptr); qdb_sqlite__errptr = 0; } free(db); return NULL; } if (method != QDB_READONLY) { /* * We deliberately ignore errors at this point, in case the * database table has already been created. */ sqlite_exec(db->db, "CREATE TABLE qsf (" " token CHAR(64) NOT NULL PRIMARY KEY," " value1 INT UNSIGNED NOT NULL," " value2 INT UNSIGNED NOT NULL," " value3 INT UNSIGNED NOT NULL" " )", NULL, NULL, &qdb_sqlite__errptr); if (qdb_sqlite__errptr) { sqlite_freemem(qdb_sqlite__errptr); qdb_sqlite__errptr = 0; } qdb_sqlite_relock(db); } #if DEBUG_SQLITE sqlite_trace(db->db, qdb_sqlite__debug, NULL); #endif if (sqlite_get_table (db->db, "SELECT value3 FROM qsf LIMIT 0,1", &results, &rows, &cols, &qdb_sqlite__errptr) != 0) { if (qdb_sqlite__errptr) { sqlite_freemem(qdb_sqlite__errptr); qdb_sqlite__errptr = 0; } db->have_value3 = 0; log_add(1, "%s", _("warning: old-style 2-value SQLite table")); } else { sqlite_free_table(results); } db->fd = open(file, O_RDONLY); return db; } /* * Close the given database. */ void qdb_sqlite_close(qdbint_t db) { if (db == NULL) return; if (db->compiled) { sqlite_finalize(db->vm, &qdb_sqlite__errptr); if (qdb_sqlite__errptr) { sqlite_freemem(qdb_sqlite__errptr); qdb_sqlite__errptr = 0; } } qdb_sqlite_unlock(db); if (db->fd >= 0) close(db->fd); sqlite_close(db->db); free(db); } /* * Construct a database query string, replacing any ? characters with an * escaped quoted (') copy of the next string in the argument list. Each * string should be given as a (long) length, not including any terminating * \0, and the char * pointer to the string. * * Returns a null-terminated string that needs free()ing after use, or NULL * on error. */ char *qdb_sqlite__query(char *format, ...) { char *buf; long len, offs; va_list ap; int i; long paramlen; char *param; va_start(ap, format); len = 0; for (i = 0; format[i] != 0; i++) { if (format[i] == '?') { paramlen = va_arg(ap, long); param = va_arg(ap, char *); len += (paramlen * 3) + 2; } else { len++; } } va_end(ap); len += 2; buf = malloc(len); if (buf == NULL) { return NULL; } offs = 0; va_start(ap, format); for (i = 0; format[i] != 0; i++) { if (format[i] == '?') { int j; buf[offs++] = '\''; paramlen = va_arg(ap, long); param = va_arg(ap, char *); for (j = 0; j < paramlen; j++) { int c; c = param[j]; if (c == '\'') { buf[offs++] = '\''; } buf[offs++] = c; } buf[offs++] = '\''; } else { buf[offs++] = format[i]; } } buf[offs++] = 0; va_end(ap); return buf; } /* * Fetch a value from the database. The datum returned needs its val.data * free()ing after use. If val.data is NULL, no value was found for the * given key. */ qdb_datum qdb_sqlite_fetch(qdbint_t db, qdb_datum key) { qdb_datum val; char *sql; char **results; int rows, cols; long val1, val2, val3; long *data; val.data = NULL; val.size = 0; if (db == NULL) return val; if (key.data == NULL) return val; if (db->have_value3) { sql = qdb_sqlite__query ("SELECT value1,value2,value3 FROM qsf " "WHERE token=?", (long) (key.size), (char *) (key.data)); } else { sql = qdb_sqlite__query("SELECT value1,value2 FROM qsf " "WHERE token=?", (long) (key.size), (char *) (key.data)); } if (sql == NULL) return val; if (sqlite_get_table (db->db, sql, &results, &rows, &cols, &qdb_sqlite__errptr) != 0) { sprintf(qdb_sqlite__errstr, "%.999s", qdb_sqlite__errptr ? qdb_sqlite__errptr : ""); if (qdb_sqlite__errptr) { sqlite_freemem(qdb_sqlite__errptr); qdb_sqlite__errptr = 0; } free(sql); return val; } free(sql); if ((cols < 2) || (rows != 1)) { sqlite_free_table(results); return val; } if (db->have_value3) { val1 = strtol(results[3], NULL, 10); val2 = strtol(results[4], NULL, 10); val3 = strtol(results[5], NULL, 10); } else { val1 = strtol(results[2], NULL, 10); val2 = strtol(results[3], NULL, 10); val3 = 0; } sqlite_free_table(results); data = malloc(3 * sizeof(long)); if (data == NULL) { sprintf(qdb_sqlite__errstr, "%.999s", strerror(errno)); return val; } data[0] = val1; data[1] = val2; data[2] = val3; val.data = (unsigned char *) data; val.size = 3 * sizeof(long); return val; } /* * Store the given key with the given value into the database, replacing any * existing value for that key. Returns nonzero on error. */ int qdb_sqlite_store(qdbint_t db, qdb_datum key, qdb_datum val) { long *data; char val1[128]; /* RATS: ignore (checked) */ char val2[128]; /* RATS: ignore (checked) */ char val3[128]; /* RATS: ignore (checked) */ char *sql; if (db == NULL) return 1; if ((key.data == NULL) || (val.data == NULL)) return 1; if (db->readonly) return 1; data = (long *) (val.data); #ifdef HAVE_SNPRINTF snprintf(val1, sizeof(val1) - 1, /* RATS: ignore (OK) */ "%ld", data[0]); snprintf(val2, sizeof(val2) - 1, /* RATS: ignore (OK) */ "%ld", data[1]); snprintf(val3, sizeof(val3) - 1, /* RATS: ignore (OK) */ "%ld", data[2]); #else sprintf(val1, "%ld", data[0]); sprintf(val2, "%ld", data[1]); sprintf(val3, "%ld", data[2]); #endif val1[sizeof(val1) - 1] = 0; val2[sizeof(val2) - 1] = 0; val3[sizeof(val3) - 1] = 0; if (db->have_value3) { sql = qdb_sqlite__query ("INSERT INTO qsf (token,value1,value2,value3) " "VALUES (?,?,?,?)", (long) (key.size), (char *) (key.data), (long) (strlen(val1)), val1, (long) (strlen(val2)), val2, (long) (strlen(val3)), val3); } else { sql = qdb_sqlite__query ("INSERT INTO qsf (token,value1,value2) " "VALUES (?,?,?)", (long) (key.size), (char *) (key.data), (long) (strlen(val1)), val1, (long) (strlen(val2)), val2); } if (sql == NULL) return 1; if (sqlite_exec(db->db, sql, NULL, NULL, &qdb_sqlite__errptr) != 0) { free(sql); if (qdb_sqlite__errptr) { sqlite_freemem(qdb_sqlite__errptr); qdb_sqlite__errptr = 0; } if (db->have_value3) { sql = qdb_sqlite__query("UPDATE qsf " "SET value1=?,value2=?,value3=? " "WHERE token=?", (long) (strlen(val1)), val1, (long) (strlen(val2)), val2, (long) (strlen(val3)), val3, (long) (key.size), (char *) (key.data)); } else { sql = qdb_sqlite__query("UPDATE qsf " "SET value1=?,value2=? " "WHERE token=?", (long) (strlen(val1)), val1, (long) (strlen(val2)), val2, (long) (key.size), (char *) (key.data)); } if (sql == NULL) return 1; if (sqlite_exec (db->db, sql, NULL, NULL, &qdb_sqlite__errptr) != 0) { free(sql); sprintf(qdb_sqlite__errstr, "%.999s", qdb_sqlite__errptr ? qdb_sqlite__errptr : ""); if (qdb_sqlite__errptr) { sqlite_freemem(qdb_sqlite__errptr); qdb_sqlite__errptr = 0; } return 1; } } free(sql); return 0; } /* * Delete the given key from the database. Returns nonzero on error. */ int qdb_sqlite_delete(qdbint_t db, qdb_datum key) { char *sql; if (db == NULL) return 1; if (key.data == NULL) return 1; if (db->readonly) return 1; sql = qdb_sqlite__query("DELETE FROM qsf WHERE token=?", (long) (key.size), (char *) (key.data)); if (sql == NULL) return 1; if (sqlite_exec(db->db, sql, NULL, NULL, &qdb_sqlite__errptr) != 0) { free(sql); sprintf(qdb_sqlite__errstr, "%.999s", qdb_sqlite__errptr ? qdb_sqlite__errptr : ""); if (qdb_sqlite__errptr) { sqlite_freemem(qdb_sqlite__errptr); qdb_sqlite__errptr = 0; } return 1; } free(sql); return 0; } /* * Return the "next" key in the database, or key.data=NULL when all keys * have been returned. */ qdb_datum qdb_sqlite_nextkey(qdbint_t db, qdb_datum key) { qdb_datum newkey; char **values; char **colnames; char *token; int ret, n; newkey.data = NULL; newkey.size = 0; if (!db->compiled) return newkey; ret = sqlite_step(db->vm, &n, (const char ***) (&values), (const char ***) (&colnames)); if (ret != SQLITE_ROW) { sqlite_finalize(db->vm, &qdb_sqlite__errptr); if (qdb_sqlite__errptr) { sqlite_freemem(qdb_sqlite__errptr); qdb_sqlite__errptr = 0; } db->compiled = 0; return newkey; } token = values[0]; newkey.data = (unsigned char *) calloc(1, 1 + strlen(token)); if (newkey.data == NULL) { sprintf(qdb_sqlite__errstr, "%.999s", strerror(errno)); return newkey; } newkey.size = strlen(token); strncpy((char *) (newkey.data), token, newkey.size); return newkey; } /* * Return the "first" key in the database, suitable for using with repeated * calls to qdb_nextkey() to walk through every key in the database. */ qdb_datum qdb_sqlite_firstkey(qdbint_t db) { qdb_datum blankkey; blankkey.data = NULL; blankkey.size = 0; if (db->compiled) { sqlite_finalize(db->vm, &qdb_sqlite__errptr); if (qdb_sqlite__errptr) { sqlite_freemem(qdb_sqlite__errptr); qdb_sqlite__errptr = 0; } } db->compiled = 0; if (sqlite_compile (db->db, "SELECT token FROM qsf ORDER BY token", &(db->ztail), &(db->vm), &qdb_sqlite__errptr) != 0) { sprintf(qdb_sqlite__errstr, "%.999s", qdb_sqlite__errptr ? qdb_sqlite__errptr : ""); if (qdb_sqlite__errptr) { sqlite_freemem(qdb_sqlite__errptr); qdb_sqlite__errptr = 0; } return blankkey; } db->compiled = 1; return qdb_sqlite_nextkey(db, blankkey); } /* * Return a string describing the last database error to occur. */ char *qdb_sqlite_error(void) { return qdb_sqlite__errstr; } #endif /* USING_SQLITE */ /* EOF */ qsf-1.2.7/src/db/mysql.c0000644000076400007640000004106110664772303012621 0ustar awaw/* * Make our db functions a wrapper for MySQL. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "database.h" #include "log.h" #ifdef USING_MYSQL #include #include #include #include #include #include #include #ifdef HAVE_FCNTL #include #endif #include #include struct qdbint_s { int fd; MYSQL *db; int readonly; int have_value3; char table[64]; /* RATS: ignore (checked all) */ char key1[256]; /* RATS: ignore (checked all) */ char key2[256]; /* RATS: ignore (checked all) */ MYSQL_RES *results; }; static char qdb_mysql__errstr[4096] = { 0, }; /* RATS: ignore (bounded OK) */ /* * Return a file descriptor for the given database, or -1 on error. */ int qdb_mysql_fd(qdbint_t db) { if (db == NULL) return -1; return db->fd; } /* * Return nonzero if the given file is of this database type. */ int qdb_mysql_identify(const char *file) { FILE *fptr; char string[4096] = { 0, }; /* RATS: ignore (checked all) */ char host[256]; /* RATS: ignore (checked all) */ char user[64]; /* RATS: ignore (checked all) */ char pass[64]; /* RATS: ignore (checked all) */ char database[64]; /* RATS: ignore (checked all) */ char table[64]; /* RATS: ignore (checked all) */ char key1[256]; /* RATS: ignore (checked all) */ char key2[256]; /* RATS: ignore (checked all) */ unsigned int port; if (file == NULL) return 0; if (strncasecmp(file, "mysql:", 6) == 0) return 1; fptr = fopen(file, "r"); if (!fptr) { sprintf(string, "%.*s", (int) (sizeof(string) - 1), file); } else { if (fread(string, 1, sizeof(string) - 1, fptr) < 1) { log_add(0, "%s: read failed: %s", file, strerror(errno)); } fclose(fptr); } string[sizeof(string) - 1] = 0; if (sscanf(string, "database=%63[^;];" "host=%255[^;];" "port=%u;" "user=%63[^;];" "pass=%63[^;];" "table=%63[^;];" "key1=%255[^;];" "key2=%255[^;]", database, host, &port, user, pass, table, key1, key2) == 8) return 1; if (sscanf(string, "database=%63[^;];" "host=%255[^;];" "port=%u;" "user=%63[^;];" "pass=;" "table=%63[^;];" "key1=%255[^;];" "key2=%255[^;]", database, host, &port, user, table, key1, key2) == 7) return 1; return 0; } /* * Initiate a database query, replacing any ? characters with an escaped * quoted (') copy of the next string in the argument list, and replacing * any ! characters with a similarly escaped string but quoted with * backquotes (`). Each string should be given as a (long) length, not * including any terminating \0, and the char * pointer to the string. * * Returns nonzero on error. */ int qdb_mysql__query(qdbint_t db, char *format, ...) { char *buf; long len, offs; va_list ap; int i, ret; long paramlen; char *param; va_start(ap, format); len = 0; for (i = 0; format[i] != 0; i++) { if (format[i] == '?') { paramlen = va_arg(ap, long); param = va_arg(ap, char *); len += (paramlen * 3) + 2; } else if (format[i] == '!') { paramlen = va_arg(ap, long); param = va_arg(ap, char *); len += (paramlen * 3) + 2; } else { len++; } } va_end(ap); len++; buf = malloc(len); if (buf == NULL) { return 1; } offs = 0; va_start(ap, format); for (i = 0; format[i] != 0; i++) { if (format[i] == '?') { buf[offs++] = '\''; paramlen = va_arg(ap, long); param = va_arg(ap, char *); offs += mysql_real_escape_string(db->db, buf + offs, param, paramlen); buf[offs++] = '\''; } else if (format[i] == '!') { buf[offs++] = '`'; paramlen = va_arg(ap, long); param = va_arg(ap, char *); offs += mysql_real_escape_string(db->db, buf + offs, param, paramlen); buf[offs++] = '`'; } else { buf[offs++] = format[i]; } } va_end(ap); ret = mysql_real_query(db->db, buf, offs); free(buf); return ret; } /* * Open the given database in the given way (new database, read-only, or * read-write); return a qdbint_t or NULL on error. */ qdbint_t qdb_mysql_open(const char *file, qdb_open_t method) { char host[256]; /* RATS: ignore (checked all) */ char user[64]; /* RATS: ignore (checked all) */ char pass[64]; /* RATS: ignore (checked all) */ char database[64]; /* RATS: ignore (checked all) */ char table[64]; /* RATS: ignore (checked all) */ char key1[256]; /* RATS: ignore (checked all) */ char key2[256]; /* RATS: ignore (checked all) */ char string[4096] = { 0, }; /* RATS: ignore (checked all) */ unsigned int port; FILE *fptr; MYSQL *mdb; qdbint_t db; if (strncasecmp(file, "mysql:", 6) == 0) file += 6; mdb = mysql_init(NULL); if (mdb == NULL) { sprintf(qdb_mysql__errstr, "%.*s", (int) (sizeof(qdb_mysql__errstr) - 1), _("mysql_init failed")); return NULL; } fptr = fopen(file, "r"); /* RATS: ignore (no race) */ if (!fptr) { sprintf(string, "%.*s", (int) (sizeof(string) - 1), file); } else { if (fread(string, 1, sizeof(string) - 1, fptr) < 1) { log_add(0, "%s: read failed: %s", file, strerror(errno)); } fclose(fptr); } string[sizeof(string) - 1] = 0; pass[0] = 0; if (sscanf(string, "database=%63[^;];" "host=%255[^;];" "port=%u;" "user=%63[^;];" "pass=;" "table=%63[^;];" "key1=%255[^;];" "key2=%255[^;]", database, host, &port, user, table, key1, key2) < 7) { if (sscanf(string, "database=%63[^;];" "host=%255[^;];" "port=%u;" "user=%63[^;];" "pass=%63[^;];" "table=%63[^;];" "key1=%255[^;];" "key2=%255[^;]", database, host, &port, user, pass, table, key1, key2) < 8) { sprintf(qdb_mysql__errstr, "%.*s: %.100s", (int) (sizeof(qdb_mysql__errstr) - 110), _("invalid DB spec"), string); mysql_close(mdb); return NULL; } } /* * Make sure all the strings we have just read are zero-terminated. */ database[sizeof(database) - 1] = 0; host[sizeof(host) - 1] = 0; user[sizeof(user) - 1] = 0; pass[sizeof(pass) - 1] = 0; table[sizeof(table) - 1] = 0; key1[sizeof(key1) - 1] = 0; key2[sizeof(key2) - 1] = 0; if (mysql_real_connect (mdb, host, user, pass, database, port, NULL, 0) == NULL) { sprintf(qdb_mysql__errstr, "%.*s: %.900s", (int) (sizeof(qdb_mysql__errstr) - 910), _("mysql connect failed"), mysql_error(mdb)); mysql_close(mdb); return NULL; } db = calloc(1, sizeof(*db)); if (db == NULL) { sprintf(qdb_mysql__errstr, "%.999s", strerror(errno)); mysql_close(mdb); return NULL; } db->fd = open(file, O_RDONLY); db->db = mdb; strncpy(db->table, table, sizeof(table) - 1); strncpy(db->key1, key1, sizeof(key1) - 1); strncpy(db->key2, key2, sizeof(key2) - 1); /* * Make sure db->{table,key1,key2} are zero-terminated. */ db->table[sizeof(db->table) - 1] = 0; db->key1[sizeof(db->key1) - 1] = 0; db->key2[sizeof(db->key2) - 1] = 0; db->readonly = (method == QDB_READONLY ? 1 : 0); /* * See whether the given table exists; if not, and we're not * supposed to be in readonly mode, try to create it. */ if (!db->readonly) { if (qdb_mysql__query(db, "SELECT value1 FROM ! LIMIT 0,1", (long) (strlen(db->table)), db->table)) { if (qdb_mysql__query(db, "CREATE TABLE ! (" "key1 BIGINT UNSIGNED NOT NULL, " "key2 BIGINT UNSIGNED NOT NULL, " "token VARCHAR(64) DEFAULT '' NOT NULL, " "value1 INT UNSIGNED NOT NULL, " "value2 INT UNSIGNED NOT NULL, " "value3 INT UNSIGNED NOT NULL, " "PRIMARY KEY (key1,key2,token), " "KEY (key1), " "KEY (key2), " "KEY (token) " ")", (long) (strlen(db->table)), db->table) == 0) { MYSQL_RES *results; results = mysql_store_result(db->db); if (results) mysql_free_result(results); log_add(1, "%s: %s", db->table, _("table autocreated")); } else { log_add(1, "%s: %s", db->table, _("invalid table specified")); } } else { MYSQL_RES *results; results = mysql_store_result(db->db); if (results) mysql_free_result(results); } } db->have_value3 = 1; if (qdb_mysql__query(db, "SELECT value3 FROM ! LIMIT 0,1", (long) (strlen(db->table)), db->table)) { db->have_value3 = 0; log_add(1, "%s", _("warning: old-style 2-value MySQL table")); } else { MYSQL_RES *results; results = mysql_store_result(db->db); if (results) mysql_free_result(results); } switch (method) { case QDB_NEW: /* fall-through */ case QDB_READWRITE: break; case QDB_READONLY: break; default: break; } #ifdef HAVE_MYSQL_AUTOCOMMIT mysql_autocommit(db->db, 0); #endif db->results = NULL; return db; } /* * Close the given database. */ void qdb_mysql_close(qdbint_t db) { if (db == NULL) return; #ifdef HAVE_MYSQL_AUTOCOMMIT mysql_commit(db->db); #endif if (db->fd >= 0) close(db->fd); mysql_close(db->db); free(db); } /* * Fetch a value from the database. The datum returned needs its val.data * free()ing after use. If val.data is NULL, no value was found for the * given key. */ qdb_datum qdb_mysql_fetch(qdbint_t db, qdb_datum key) { qdb_datum val; char *sql; MYSQL_RES *results; MYSQL_ROW row; unsigned long *lengths; long *data; char buf[256]; /* RATS: ignore (checked all) */ val.data = NULL; val.size = 0; if (db == NULL) return val; if (key.data == NULL) return val; if (db->have_value3) { sql = "SELECT value1,value2,value3 FROM ! " "WHERE key1 = ? " "AND key2 = ? " "AND token = ?"; } else { sql = "SELECT value1,value2 FROM ! " "WHERE key1 = ? " "AND key2 = ? " "AND token = ?"; } if (qdb_mysql__query(db, sql, (long) (strlen(db->table)), db->table, (long) (strlen(db->key1)), db->key1, (long) (strlen(db->key2)), db->key2, (long) (key.size), (char *) (key.data))) { sprintf(qdb_mysql__errstr, "%.*s: %.900s", (int) (sizeof(qdb_mysql__errstr) - 910), _("query failed"), mysql_error(db->db)); return val; } results = mysql_store_result(db->db); if (results == NULL) { sprintf(qdb_mysql__errstr, "%.*s: %.900s", (int) (sizeof(qdb_mysql__errstr) - 910), _("query failed on results store"), mysql_error(db->db)); return val; } row = mysql_fetch_row(results); if (row == NULL) { sprintf(qdb_mysql__errstr, "%.*s: %.900s", (int) (sizeof(qdb_mysql__errstr) - 910), _("query failed on row fetch"), mysql_error(db->db)); mysql_free_result(results); return val; } lengths = mysql_fetch_lengths(results); if (lengths == NULL) { sprintf(qdb_mysql__errstr, "%.*s: %.900s", (int) (sizeof(qdb_mysql__errstr) - 910), _("query failed on lengths fetch"), mysql_error(db->db)); mysql_free_result(results); return val; } data = malloc(3 * sizeof(long)); if (data == NULL) { sprintf(qdb_mysql__errstr, "%.999s", strerror(errno)); mysql_free_result(results); return val; } sprintf(buf, "%.*s", (int) ((lengths[0] < sizeof(buf) - 1) ? lengths[0] : sizeof(buf) - 1), row[0]); data[0] = strtol(buf, NULL, 10); sprintf(buf, "%.*s", (int) ((lengths[1] < sizeof(buf) - 1) ? lengths[1] : sizeof(buf) - 1), row[1]); data[1] = strtol(buf, NULL, 10); if (db->have_value3) { sprintf(buf, "%.*s", (int) ((lengths[2] < sizeof(buf) - 1) ? lengths[2] : sizeof(buf) - 1), row[2]); data[2] = strtol(buf, NULL, 10); } else { data[2] = 0; } mysql_free_result(results); val.data = (unsigned char *) data; val.size = 3 * sizeof(long); return val; } /* * Store the given key with the given value into the database, replacing any * existing value for that key. Returns nonzero on error. */ int qdb_mysql_store(qdbint_t db, qdb_datum key, qdb_datum val) { long *data; char val1[128]; /* RATS: ignore (checked) */ char val2[128]; /* RATS: ignore (checked) */ char val3[128]; /* RATS: ignore (checked) */ if (db == NULL) return 1; if ((key.data == NULL) || (val.data == NULL)) return 1; if (db->readonly) return 1; data = (long *) (val.data); #ifdef HAVE_SNPRINTF snprintf(val1, sizeof(val1) - 1, /* RATS: ignore (OK) */ "%ld", data[0]); snprintf(val2, sizeof(val2) - 1, /* RATS: ignore (OK) */ "%ld", data[1]); snprintf(val3, sizeof(val3) - 1, /* RATS: ignore (OK) */ "%ld", data[2]); #else sprintf(val1, "%ld", data[0]); sprintf(val2, "%ld", data[1]); sprintf(val3, "%ld", data[2]); #endif val1[sizeof(val1) - 1] = 0; val2[sizeof(val2) - 1] = 0; val3[sizeof(val3) - 1] = 0; if (db->have_value3) { if (qdb_mysql__query(db, "REPLACE INTO ! " "(key1,key2,token,value1,value2,value3) " "VALUES (?,?,?,?,?,?)", (long) (strlen(db->table)), db->table, (long) (strlen(db->key1)), db->key1, (long) (strlen(db->key2)), db->key2, (long) (key.size), (char *) (key.data), (long) (strlen(val1)), val1, (long) (strlen(val2)), val2, (long) (strlen(val3)), val3)) { sprintf(qdb_mysql__errstr, "%.*s: %.900s", (int) (sizeof(qdb_mysql__errstr) - 910), _("store failed"), mysql_error(db->db)); return 1; } } else { if (qdb_mysql__query(db, "REPLACE INTO ! " "(key1,key2,token,value1,value2) " "VALUES (?,?,?,?,?)", (long) (strlen(db->table)), db->table, (long) (strlen(db->key1)), db->key1, (long) (strlen(db->key2)), db->key2, (long) (key.size), (char *) (key.data), (long) (strlen(val1)), val1, (long) (strlen(val2)), val2)) { sprintf(qdb_mysql__errstr, "%.*s: %.900s", (int) (sizeof(qdb_mysql__errstr) - 910), _("store failed"), mysql_error(db->db)); return 1; } } return 0; } /* * Delete the given key from the database. Returns nonzero on error. */ int qdb_mysql_delete(qdbint_t db, qdb_datum key) { if (db == NULL) return 1; if (key.data == NULL) return 1; if (db->readonly) return 1; if (qdb_mysql__query(db, "DELETE FROM ! " "WHERE key1=? " "AND key2=? " "AND token=?", (long) (strlen(db->table)), db->table, (long) (strlen(db->key1)), db->key1, (long) (strlen(db->key2)), db->key2, (long) (key.size), (char *) (key.data))) { sprintf(qdb_mysql__errstr, "%.*s: %.900s", (int) (sizeof(qdb_mysql__errstr) - 910), _("delete failed"), mysql_error(db->db)); return 1; } return 0; } /* * Return the "next" key in the database, or key.data=NULL when all keys * have been returned. */ qdb_datum qdb_mysql_nextkey(qdbint_t db, qdb_datum key) { MYSQL_ROW row; unsigned long *lengths; qdb_datum newkey; newkey.data = NULL; newkey.size = 0; row = mysql_fetch_row(db->results); if (row == NULL) { sprintf(qdb_mysql__errstr, "%.*s: %.900s", (int) (sizeof(qdb_mysql__errstr) - 910), _("row fetch failed"), mysql_error(db->db)); mysql_free_result(db->results); db->results = NULL; return newkey; } lengths = mysql_fetch_lengths(db->results); if (lengths == NULL) { sprintf(qdb_mysql__errstr, "%.*s: %.900s", (int) (sizeof(qdb_mysql__errstr) - 910), _("row lengths fetch failed"), mysql_error(db->db)); mysql_free_result(db->results); db->results = NULL; return newkey; } newkey.data = (unsigned char *) calloc(1, lengths[0] + 1); if (newkey.data == NULL) { sprintf(qdb_mysql__errstr, "%.999s", strerror(errno)); return newkey; } newkey.size = lengths[0]; strncpy((char *) (newkey.data), row[0], lengths[0]); return newkey; } /* * Return the "first" key in the database, suitable for using with repeated * calls to qdb_nextkey() to walk through every key in the database. */ qdb_datum qdb_mysql_firstkey(qdbint_t db) { qdb_datum blankkey; blankkey.data = NULL; blankkey.size = 0; if (db->results) mysql_free_result(db->results); db->results = NULL; if (qdb_mysql__query(db, "SELECT token FROM ! " "WHERE key1 = ? " "AND key2 = ? " "ORDER BY token", (long) (strlen(db->table)), db->table, (long) (strlen(db->key1)), db->key1, (long) (strlen(db->key2)), db->key2)) { sprintf(qdb_mysql__errstr, "%.*s: %.900s", (int) (sizeof(qdb_mysql__errstr) - 910), _("select failed"), mysql_error(db->db)); return blankkey; } db->results = mysql_store_result(db->db); if (db->results == NULL) { sprintf(qdb_mysql__errstr, "%.*s: %.900s", (int) (sizeof(qdb_mysql__errstr) - 910), _("result store failed"), mysql_error(db->db)); return blankkey; } return qdb_mysql_nextkey(db, blankkey); } /* * Return a string describing the last database error to occur. */ char *qdb_mysql_error(void) { return qdb_mysql__errstr; } #endif /* USING_MYSQL */ /* EOF */ qsf-1.2.7/src/main/0000755000076400007640000000000010665021416011636 5ustar awawqsf-1.2.7/src/main/help.c0000644000076400007640000001136610664772303012750 0ustar awaw/* * Output command-line help to stdout. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include #include #include #include struct optdesc_s { char *optshort; char *optlong; char *param; char *description; }; /* * Display command-line help. */ void display_help(void) { struct optdesc_s optlist[] = { {"-d", "--database", _("FILE"), _("use FILE as a database")}, {"-g", "--global", _("FILE"), _("use FILE as a global (readonly) database")}, {"-P", "--plain-map", _("FILE"), _("store plaintext token map in FILE")}, {"-s", "--subject", 0, _("add \"[SPAM]\" to Subject: of spam")}, {"-S", "--subject-marker", _("MARK"), _("add \"MARK\" instead of \"[SPAM]\"")}, {"-H", "--header-marker", _("MARK"), _("set X-Spam header to \"MARK\" instead of \"YES\"")}, {"-n", "--no-header", 0, _("do not add X-Spam header to spam")}, {"-r", "--add-rating", 0, _("add an X-Spam-Rating header (0-100, 90+ = spam)")}, {"-A", "--asterisk", 0, _("add an X-Spam-Level header (0-20 *s)")}, {"-t", "--test", 0, _("do not filter, just test for spam")}, {"-a", "--allowlist", 0, _("enable the allow-list")}, {"-y", "--denylist", 0, _("enable the deny-list")}, {"-L", "--level", _("LEVEL"), _("set spam threshold level to LEVEL, not 90")}, {"-Q", "--min-tokens", _("NUM"), _("only give a score if more than NUM tokens found")}, {"-e", "--email", _("EMAIL"), _ ("update/query allow-list for given EMAIL (set to \"MSG\" to use sender address)")}, {"-v", "--verbose", 0, _("add informational headers to email")}, {"", 0, 0, 0}, {"-T", "--train", _("SPAM NON"), _("train database using SPAM and NON mbox folders")}, {"-m", "--mark-spam", 0, _("mark incoming message as spam in the database")}, {"-M", "--mark-nonspam", 0, _("mark incoming message as non-spam in the database")}, {"-w", "--weight", _("WEIGHT"), _("mark message with weight of WEIGHT instead of 1")}, /* * Deprecated options - don't list in the help. {"-N", "--no-autoprune", 0, _("do not automatically prune after every 500th entry")}, {"-p", "--prune", 0, _("remove redundant entries from the database")}, {"-X", "--prune-max", _("NUM"), _("prune at most NUM tokens, rather than 100000")}, */ {"", 0, 0, 0}, {"-D", "--dump", _("[FILE]"), _("dump database as text to FILE or stdout")}, {"-R", "--restore", _("[FILE]"), _("restore database from text FILE or stdin")}, {"-O", "--tokens", 0, _("list tokens found in a message")}, {"-E", "--merge", _("OTHERDB"), _("merge OTHERDB into current database")}, {"", 0, 0, 0}, {"-h", "--help", 0, _("show this help and exit")}, {"-V", "--version", 0, _("show version information and exit")}, {0, 0, 0, 0} }; int i, col1max = 0, tw = 77; char *optbuf; int sz; printf(_("Usage: %s [OPTION]..."), /* RATS: ignore */ PROGRAM_NAME); printf("\n%s\n\n", _ ("Read the message on standard input and output it with an X-Spam header\n" "if it is spam.")); for (i = 0; optlist[i].optshort; i++) { int width = 0; width = 2 + strlen(optlist[i].optshort); /* RATS: ignore */ #ifdef HAVE_GETOPT_LONG if (optlist[i].optlong) width += 2 + strlen(optlist[i].optlong); /* RATS: ignore */ #endif if (optlist[i].param) width += 1 + strlen(optlist[i].param); /* RATS: ignore */ if (width > col1max) col1max = width; } col1max++; sz = col1max + 16; optbuf = malloc(sz); if (optbuf == NULL) { fprintf(stderr, "%s: %s\n", PROGRAM_NAME, strerror(errno)); exit(1); } for (i = 0; optlist[i].optshort; i++) { char *start; char *end; if (optlist[i].optshort[0] == 0) { printf("\n"); continue; } #ifdef HAVE_SNPRINTF snprintf(optbuf, sz, "%s%s%s%s%s", /* RATS: ignore (checked) */ #else sprintf(optbuf, "%s%s%s%s%s", /* RATS: ignore (checked) */ #endif optlist[i].optshort, #ifdef HAVE_GETOPT_LONG optlist[i].optlong ? ", " : "", optlist[i].optlong ? optlist[i].optlong : "", #else "", "", #endif optlist[i].param ? " " : "", optlist[i].param ? optlist[i].param : ""); printf(" %-*s ", col1max - 2, optbuf); if (optlist[i].description == NULL) { printf("\n"); continue; } start = optlist[i].description; while (strlen(start) /* RATS: ignore */ >tw - col1max) { end = start + tw - col1max; while ((end > start) && (end[0] != ' ')) end--; if (end == start) { end = start + tw - col1max; } else { end++; } printf("%.*s\n%*s ", (int) (end - start), start, col1max, ""); if (end == start) end++; start = end; } printf("%s\n", start); } printf("\n"); printf(_("Please report any bugs to %s."), /* RATS: ignore */ BUG_REPORTS_TO); printf("\n"); } /* EOF */ qsf-1.2.7/src/main/options.c0000644000076400007640000001742010664772303013510 0ustar awaw/* * Parse command-line options. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "options.h" #include "spam.h" #include "log.h" #include #include #include #include #ifdef HAVE_GETOPT_H #include #endif #include #ifndef HAVE_GETOPT int minigetopt(int, char **, char *); extern char *minioptarg; extern int minioptind, miniopterr, minioptopt; #define getopt minigetopt #define optarg minioptarg #define optind minioptind #define opterr miniopterr #define optopt minioptopt #endif /* !HAVE_GETOPT */ void display_help(void); void display_version(void); /* * Free an opts_t object. */ void opts_free(opts_t opts) { if (!opts) return; if (opts->argv) free(opts->argv); if (opts->plaindata) spam_plaintext_free(opts); free(opts); } /* * Parse the given command-line arguments into an opts_t object, handling * "help" and "version" options internally. * * Returns an opts_t, or 0 on error. * * Note that the contents of *argv[] (i.e. the command line parameters) * aren't copied anywhere, just the pointers are copied, so make sure the * command line data isn't overwritten or argv[1] free()d or whatever. */ opts_t opts_parse(int argc, char **argv) { #ifdef HAVE_GETOPT_LONG struct option long_options[] = { {"help", 0, 0, 'h'}, {"version", 0, 0, 'V'}, {"subject", 0, 0, 's'}, {"subject-marker", 1, 0, 'S'}, {"header-marker", 1, 0, 'H'}, {"no-header", 0, 0, 'n'}, {"rate", 0, 0, 'r'}, {"rating", 0, 0, 'r'}, {"add-rating", 0, 0, 'r'}, {"asterisk", 0, 0, 'A'}, {"asterisks", 0, 0, 'A'}, {"stars", 0, 0, 'A'}, {"add-stars", 0, 0, 'A'}, {"add-asterisk", 0, 0, 'A'}, {"add-asterisks", 0, 0, 'A'}, {"test", 0, 0, 't'}, {"allowlist", 0, 0, 'a'}, {"allow-list", 0, 0, 'a'}, {"denylist", 0, 0, 'y'}, {"deny-list", 0, 0, 'y'}, {"plain", 1, 0, 'P'}, {"plainmap", 1, 0, 'P'}, {"plain-map", 1, 0, 'P'}, {"plaintext", 1, 0, 'P'}, {"plaintextmap", 1, 0, 'P'}, {"plaintext-map", 1, 0, 'P'}, {"level", 1, 0, 'L'}, {"threshold", 1, 0, 'L'}, {"min-tokens", 1, 0, 'Q'}, {"mintokens", 1, 0, 'Q'}, {"email", 1, 0, 'e'}, {"email-only", 1, 0, 'e'}, {"mark-spam", 0, 0, 'm'}, {"mark-nonspam", 0, 0, 'M'}, {"mark-non-spam", 0, 0, 'M'}, {"database", 1, 0, 'd'}, {"global", 1, 0, 'g'}, {"weight", 1, 0, 'w'}, {"train", 0, 0, 'T'}, {"noprune", 0, 0, 'N'}, {"no-prune", 0, 0, 'N'}, {"no-autoprune", 0, 0, 'N'}, {"noautoprune", 0, 0, 'N'}, {"prune-max", 1, 0, 'X'}, {"prunemax", 1, 0, 'X'}, {"prune", 0, 0, 'p'}, {"trim", 0, 0, 'p'}, {"dump", 0, 0, 'D'}, {"restore", 0, 0, 'R'}, {"tokens", 0, 0, 'O'}, {"benchmark", 0, 0, 'B'}, {"merge", 1, 0, 'E'}, {"verbose", 0, 0, 'v'}, {0, 0, 0, 0} }; int option_index = 0; #endif char *short_options = "hVsS:H:nrAtoayL:Q:e:mMd:g:P:w:NTX:pDROBE:v"; int c; opts_t opts; opts = calloc(1, sizeof(*opts)); if (!opts) { fprintf(stderr, /* RATS: ignore (OK) */ _("%s: option structure allocation failed (%s)"), argv[0], strerror(errno)); fprintf(stderr, "\n"); return 0; } opts->program_name = argv[0]; opts->argc = 0; opts->argv = calloc(argc + 1, sizeof(char *)); if (!opts->argv) { fprintf(stderr, /* RATS: ignore (OK) */ _ ("%s: option structure argv allocation failed (%s)"), argv[0], strerror(errno)); fprintf(stderr, "\n"); opts_free(opts); return 0; } opts->threshold = 0.9; opts->min_token_count = 0; opts->prune_max = 100000; opts->db1weight = 1; opts->db2weight = 1; opts->db3weight = 1; opts->action = ACTION_TEST; opts->showprune = 0; do { #ifdef HAVE_GETOPT_LONG c = getopt_long(argc, argv, /* RATS: ignore */ short_options, long_options, &option_index); #else c = getopt(argc, argv, short_options); /* RATS: ignore */ #endif if (c < 0) continue; switch (c) { case 'h': display_help(); opts->action = ACTION_NONE; return opts; break; case 'V': display_version(); opts->action = ACTION_NONE; return opts; break; case 's': opts->modify_subject = 1; break; case 'S': opts->modify_subject = 1; opts->subject_marker = optarg; break; case 'H': opts->header_marker = optarg; break; case 'n': opts->no_header = 1; break; case 'r': opts->add_rating = 1; break; case 'A': opts->add_stars = 1; break; case 't': opts->no_filter = 1; break; case 'a': opts->allowlist = 1; break; case 'y': opts->denylist = 1; break; case 'L': opts->threshold = (double) (atoi(optarg)) / 100; break; case 'Q': opts->min_token_count = atoi(optarg); break; case 'e': opts->emailonly = optarg; opts->allowlist = 1; break; case 'm': opts->modifydenylist = 0; if (opts->action == ACTION_MARK_SPAM) opts->modifydenylist = 1; opts->action = ACTION_MARK_SPAM; break; case 'M': opts->modifydenylist = 0; if (opts->action == ACTION_MARK_NONSPAM) opts->modifydenylist = 1; opts->action = ACTION_MARK_NONSPAM; break; case 'd': opts->database = optarg; break; case 'g': if (opts->globaldb) { opts->globaldb2 = optarg; } else { opts->globaldb = optarg; } break; case 'P': opts->plainmap = optarg; break; case 'w': opts->weight = atoi(optarg); break; case 'T': opts->action = ACTION_TRAIN; opts->showprune = 1; break; case 'N': opts->noautoprune = 1; break; case 'X': opts->prune_max = atol(optarg); break; case 'p': opts->action = ACTION_PRUNE; opts->showprune = 1; break; case 'D': opts->action = ACTION_DUMP; break; case 'R': opts->action = ACTION_RESTORE; break; case 'O': opts->action = ACTION_TOKENS; break; case 'B': opts->action = ACTION_BENCHMARK; opts->showprune = 1; break; case 'E': opts->action = ACTION_MERGE; opts->mergefrom = optarg; break; case 'v': opts->loglevel++; break; default: #ifdef HAVE_GETOPT_LONG fprintf(stderr, /* RATS: ignore (OK) */ _("Try `%s --help' for more information."), argv[0]); #else fprintf(stderr, /* RATS: ignore (OK) */ _("Try `%s -h' for more information."), argv[0]); #endif fprintf(stderr, "\n"); opts_free(opts); return 0; break; } } while (c != -1); log_level(opts->loglevel); if (opts->weight < 1) { opts->weight = 1; } else if (opts->weight > 8) { opts->weight = 8; } if (opts->threshold < 0.01) { opts->threshold = 0.01; } else if (opts->threshold > 1.00) { opts->threshold = 1.00; } if (opts->prune_max < 10) opts->prune_max = 10; while (optind < argc) { opts->argv[opts->argc++] = argv[optind++]; } if ((opts->action == ACTION_TRAIN) && ((opts->argc < 2) || (opts->argc > 3))) { fprintf(stderr, "%s: %s\n", argv[0], _("train syntax: SPAM NONSPAM [MAXROUNDS]")); opts_free(opts); return 0; } else if ((opts->action == ACTION_BENCHMARK) && ((opts->argc < 2) || (opts->argc > 3))) { fprintf(stderr, "%s: %s\n", argv[0], _("benchmark syntax: SPAM NONSPAM [MAXROUNDS]")); opts_free(opts); return 0; } else if ((opts->action == ACTION_DUMP) && (opts->argc > 1)) { fprintf(stderr, "%s: %s\n", argv[0], _ ("dump only requires one argument (file to dump to)")); opts_free(opts); return 0; } else if ((opts->action == ACTION_RESTORE) && (opts->argc > 1)) { fprintf(stderr, "%s: %s\n", argv[0], _ ("restore only requires one argument (file to restore from)")); opts_free(opts); return 0; } else if ((opts->action != ACTION_DUMP) && (opts->action != ACTION_RESTORE) && (opts->action != ACTION_TRAIN) && (opts->action != ACTION_BENCHMARK) && (opts->argc > 0) ) { fprintf(stderr, "%s: %s\n", argv[0], _ ("spurious extra arguments given on command line")); opts_free(opts); return 0; } return opts; } /* EOF */ qsf-1.2.7/src/main/version.c0000644000076400007640000000163610664772303013504 0ustar awaw/* * Output version information to stdout. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include /* * Display current package version. */ void display_version(void) { printf( /* RATS: ignore */ _("%s %s - Copyright (C) %s %s"), PROGRAM_NAME, VERSION, COPYRIGHT_YEAR, COPYRIGHT_HOLDER); printf("\n%s%s", _("Backends available:"), BACKENDS); printf("\n\n"); printf( /* RATS: ignore */ _("Web site: %s"), PROJECT_HOMEPAGE); printf("\n\n"); printf("%s", _("This program is free software, and is being distributed " "under the\nterms of the Artistic License 2.0.")); printf("\n\n"); printf("%s", _ ("This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.")); printf("\n\n"); } /* EOF */ qsf-1.2.7/src/main/main.c0000644000076400007640000004076510664772303012751 0ustar awaw/* * Main program entry point - read the command line options, then perform * the appropriate actions. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "options.h" #include "message.h" #include "spam.h" #include "database.h" #include "log.h" #include #include #include #include #include #include #include #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_MCHECK_H #include #endif /* * Process command-line arguments and set option flags, then call functions * to initialise, and finally enter the main loop. */ int main(int argc, char **argv) { char buffer[1024]; /* RATS: ignore (checked all) */ char filename[1024]; /* RATS: ignore (checked all) */ opts_t opts; int retcode = 0; int needwrite; int got, sent, totsent; double score; qdb_t dbr1, dbr2, dbr3, dbw; char *home; msg_t msg = NULL; int fd = -1; #ifdef HAVE_MCHECK_H if (getenv("MALLOC_TRACE")) /* RATS: ignore (value unused) */ mtrace(); #endif #ifdef ENABLE_NLS setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); #endif opts = opts_parse(argc, argv); if (!opts) return 1; if (opts->action == ACTION_NONE) { opts_free(opts); return 0; } atexit(log_free); log_add(2, _("version %s initialising"), VERSION); log_add(2, _("backends available:%s"), BACKENDS); /* * If we're testing, marking, or tokenising, or allow-list or * deny-list updating/querying (having not been given an email * address), we need to read a message from standard input before * proceeding. */ if (((opts->action == ACTION_TEST) || (opts->action == ACTION_MARK_SPAM) || (opts->action == ACTION_MARK_NONSPAM) ) && ((opts->emailonly == NULL) || (strcmp(opts->emailonly, "MSG") == 0) ) ) { msg = msg_parse(opts); if (msg == NULL) { log_add(2, "%s", _("failed to parse message")); log_errdump(opts->program_name); opts_free(opts); return 1; } else if (msg->content == NULL) { if (opts->emailonly) { fprintf(stderr, "%s: %s\n", opts->program_name, _ ("message is too large or has no content")); log_add(2, "%s", _("failed to parse message")); log_errdump(opts->program_name); } else if ((opts->action != ACTION_MARK_SPAM) && (opts->action != ACTION_MARK_NONSPAM) && (!opts->no_filter) ) { msg_dump(msg); } else { log_add(2, "%s", _("failed to parse message")); log_errdump(opts->program_name); } msg_free(msg); while (!feof(stdin)) { got = fread(buffer, 1, sizeof(buffer), stdin); if ((got > 0) && ((unsigned int) got > sizeof(buffer))) got = sizeof(buffer); if (opts->emailonly || opts->no_filter || (opts->action == ACTION_MARK_SPAM) || (opts->action == ACTION_MARK_NONSPAM) ) continue; totsent = 0; if (got > 0) { sent = fwrite(buffer + totsent, 1, got, stdout); if (sent <= 0) break; totsent += sent; got -= sent; } else { break; } } retcode = (opts->emailonly ? 1 : 0); opts_free(opts); return retcode; } } /* * If we're just tokenising, just do that, then exit. If the message * cannot be parsed, do not dump it on stdout. */ if (opts->action == ACTION_TOKENS) { msg = msg_parse(opts); if (msg == NULL) { opts_free(opts); return 1; } retcode = spam_dumptokens(opts, msg); msg_free(msg); opts_free(opts); return retcode; } /* * From this point on, we're going to need databases; if none was * specified on the command line, we open both /var/lib/qsfdb and * ~/.qsfdb. */ dbr1 = NULL; /* first database to read from */ dbr2 = NULL; /* second database to read from */ dbr3 = NULL; /* third database to read from */ dbw = NULL; /* database to write to (=dbr1 or dbr2 or NULL) */ /* * Work out whether we need write access. */ switch (opts->action) { case ACTION_DUMP: case ACTION_RESTORE: case ACTION_TRAIN: case ACTION_MARK_SPAM: case ACTION_MARK_NONSPAM: case ACTION_PRUNE: case ACTION_MERGE: needwrite = 1; break; default: needwrite = 0; break; } log_add(3, "%s: %s", _("need write access to a database"), needwrite ? _("yes") : _("no")); /* * Now determine database locations, and open them. */ if ((opts->action == ACTION_BENCHMARK) && (opts->database) && (strncasecmp(opts->database, "mysql:", 6) == 0) ) { /* * Benchmarking mode, with a MySQL database. Open the * database ready for use. */ filename[0] = 0; /* for remove() below */ dbr1 = qdb_open(opts->database, QDB_READWRITE); dbw = dbr1; if (dbr1 == NULL) { log_add(1, "%s: %s: %s", opts->database, _("failed to open database"), qdb_error()); fprintf(stderr, "%s: %s: %s: %s\n", opts->program_name, opts->database, _("failed to open database"), qdb_error()); retcode = 1; } else { log_add(2, "%s: [%s] %s", _("using database (rw)"), qdb_type(dbr1), opts->database); printf("%s: %s\n", _("Backend type"), qdb_type(dbr1)); } } else if (opts->action == ACTION_BENCHMARK) { /* * Benchmarking mode. Create a temporary file (which is * deleted after opening) for the database. */ #ifdef P_tmpdir #ifdef HAVE_SNPRINTF snprintf(filename, sizeof(filename), "%.*s", #else sprintf(filename, "%.*s", /* RATS: ignore (OK) */ #endif (int) (sizeof(filename) - 1), P_tmpdir "/qsfXXXXXX"); #else #ifdef HAVE_SNPRINTF snprintf(filename, sizeof(filename), "%.*s", #else sprintf(filename, "%.*s", /* RATS: ignore (OK) */ #endif (int) (sizeof(filename) - 1), "/tmp/qsfXXXXXX"); #endif #ifdef HAVE_MKSTEMP fd = mkstemp(filename); #else fd = -1; if (tmpnam(filename) != NULL) { /* RATS: ignore (OK) */ fd = open(filename, /* RATS: ignore (OK) */ O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); } #endif if (fd < 0) { fprintf(stderr, "%s: %s: %s: %s\n", opts->program_name, filename, _("failed to create temporary file"), strerror(errno)); retcode = 1; } else { char newfilename[4096]; /* RATS: ignore (checked) */ char newtype[64]; /* RATS: ignore (checked) */ newtype[0] = 0; if (opts->database) sscanf(opts->database, "%32[0-9A-Za-z]", newtype); if (newtype[0] != 0) { #ifdef HAVE_SNPRINTF snprintf(newfilename, sizeof(newfilename), "%.*s:%.*s", 32, #else sprintf(newfilename, "%.*s:%.*s", 32, /* RATS: ignore (OK) */ #endif newtype, (int) (sizeof(filename) - 1 - strlen(newtype)), filename); } chmod(filename, /* RATS: ignore (not important) */ S_IRUSR | S_IWUSR); dbr1 = qdb_open(newtype[0] == 0 ? filename : newfilename, QDB_READWRITE); dbw = dbr1; if (dbr1 == NULL) { log_add(1, "%s: %s: %s", filename, _("failed to open database"), qdb_error()); fprintf(stderr, "%s: %s: %s: %s\n", opts->program_name, filename, _("failed to open database"), qdb_error()); retcode = 1; } else { log_add(2, "%s: [%s] %s", _("using database (rw)"), qdb_type(dbr1), filename); } close(fd); remove(filename); /* RATS: ignore (no race) */ printf("%s: %s\n", _("Backend type"), qdb_type(dbr1)); } } else if (opts->database == NULL) { /* * Non-benchmarking mode, and no database specified. Work * out the best databases to use, and open them. */ if (opts->globaldb) { #ifdef HAVE_SNPRINTF snprintf(buffer, sizeof(buffer), "%.*s", #else sprintf(buffer, "%.*s", /* RATS: ignore (OK) */ #endif (int) (sizeof(buffer) - 1), opts->globaldb); } else { #ifdef HAVE_SNPRINTF snprintf(buffer, sizeof(buffer), #else sprintf(buffer, /* RATS: ignore (OK) */ #endif "%.*s", (int) (sizeof(buffer) - 1), "/var/lib/" PACKAGE "db"); } if (needwrite) { if (opts->action == ACTION_RESTORE) { dbr1 = qdb_open(buffer, QDB_NEW); } else { dbr1 = qdb_open(buffer, QDB_READWRITE); } } if (dbr1 == NULL) { dbr1 = qdb_open(buffer, QDB_READONLY); if (dbr1) log_add(2, "%s: [%s] %s", _("using database (ro)"), qdb_type(dbr1), buffer); } else { dbw = dbr1; log_add(2, "%s: [%s] %s", _("using database (rw)"), qdb_type(dbr1), buffer); } home = getenv("HOME"); /* RATS: ignore (sanitised) */ if (home == NULL) home = "/"; if (strlen(home) /* RATS: ignore */ >(sizeof(buffer) - 64)) home = "/"; #ifdef HAVE_SNPRINTF snprintf(buffer, sizeof(buffer), /* RATS: ignore (OK) */ "%s/.%sdb", home, PACKAGE); #else sprintf(buffer, /* RATS: ignore (checked above) */ "%s/.%.*sdb", home, (int) (sizeof(buffer) - 8 - strlen(home) /* RATS: ignore */ ), PACKAGE); #endif if (needwrite) { if (opts->action == ACTION_RESTORE) { dbr2 = qdb_open(buffer, QDB_NEW); } else { dbr2 = qdb_open(buffer, QDB_READWRITE); } } if (dbr2 == NULL) { dbr2 = qdb_open(buffer, QDB_READONLY); if (dbr2) log_add(2, "%s: [%s] %s", _("using database (ro)"), qdb_type(dbr2), buffer); } else if (dbw == NULL) { dbw = dbr2; log_add(2, "%s: [%s] %s", _("using database (rw)"), qdb_type(dbr2), buffer); } /* * Weight the per-user database at 10 times the * weighting of the global database. */ if (dbr2) opts->db2weight = 10; if (opts->globaldb2) { #ifdef HAVE_SNPRINTF snprintf(buffer, sizeof(buffer), #else sprintf(buffer, /* RATS: ignore (OK) */ #endif "%.*s", (int) (sizeof(buffer) - 1), opts->globaldb2); } else { #ifdef HAVE_SNPRINTF snprintf(buffer, sizeof(buffer), "%.*s", #else sprintf(buffer, "%.*s", /* RATS: ignore (OK) */ #endif (int) (sizeof(buffer) - 1), "/var/lib/" PACKAGE "db2"); } if (dbr3 == NULL) { dbr3 = qdb_open(buffer, QDB_READONLY); if (dbr3) log_add(2, "%s: [%s] %s", _("using database (ro)"), qdb_type(dbr3), buffer); } if (dbr3) { /* * Weight the first global database as twice * as "heavy" as this one. */ opts->db1weight = 2; opts->db3weight = 1; } } else { /* * Non-benchmarking mode, and a database has been specified. * Open all available databases. */ dbr1 = qdb_open(opts->database, QDB_READWRITE); if (dbr1 == NULL) { dbr1 = qdb_open(opts->database, QDB_READONLY); if (dbr1) log_add(2, "%s: [%s] %s", _("using database (ro)"), qdb_type(dbr1), opts->database); } else { dbw = dbr1; log_add(2, "%s: [%s] %s", _("using database (rw)"), qdb_type(dbr1), opts->database); } if (dbr1 == NULL) { log_add(1, "%s: %s: %s", opts->database, _("failed to open database"), qdb_error()); fprintf(stderr, "%s: %s: %s: %s\n", opts->program_name, opts->database, _("failed to open database"), qdb_error()); retcode = 1; } else { /* * Weight the per-user database at 10 times the * weighting of the global database. */ opts->db1weight = 10; } if (opts->globaldb) { dbr2 = qdb_open(opts->globaldb, QDB_READONLY); if (dbr2 == NULL) { log_add(1, "%s: %s: %s", opts->globaldb, _("failed to open database"), qdb_error()); fprintf(stderr, "%s: %s: %s: %s\n", opts->program_name, opts->globaldb, _("failed to open database"), qdb_error()); retcode = 1; } else { log_add(2, "%s: [%s] %s", _("using database (ro)"), qdb_type(dbr2), opts->globaldb); } } if (opts->globaldb2) { dbr3 = qdb_open(opts->globaldb2, QDB_READONLY); if (dbr3 == NULL) { log_add(1, "%s: %s: %s", opts->globaldb2, _("failed to open database"), qdb_error()); fprintf(stderr, "%s: %s: %s: %s\n", opts->program_name, opts->globaldb2, _("failed to open database"), qdb_error()); retcode = 1; } else { log_add(2, "%s: [%s] %s", _("using database (ro)"), qdb_type(dbr3), opts->globaldb2); /* * Weight the first global database as twice * as "heavy" as this one. */ opts->db2weight = 2; opts->db3weight = 1; } } } opts->dbr1 = dbr1; opts->dbr2 = dbr2; opts->dbr3 = dbr3; opts->dbw = dbw; if (opts->dbr1) log_add(3, "%s %d: %d", _("weight of database"), 1, opts->db1weight); if (opts->dbr2) log_add(3, "%s %d: %d", _("weight of database"), 2, opts->db2weight); if (opts->dbr3) log_add(3, "%s %d: %d", _("weight of database"), 3, opts->db3weight); if (retcode) { /* * Error condition from earlier - clean up and exit. */ if ((opts->action != ACTION_MARK_SPAM) && (opts->action != ACTION_MARK_NONSPAM) && (!opts->no_filter) ) { msg_dump(msg); } else { log_errdump(opts->program_name); } opts_free(opts); qdb_close(dbr1); qdb_close(dbr2); qdb_close(dbr3); return retcode; } if (opts->emailonly) { /* * Allow-list and deny-list manipulation / querying mode. */ if (strcmp(opts->emailonly, "MSG") == 0) { if ((msg) && (msg->sender)) opts->emailonly = msg->sender; if ((msg) && (msg->envsender)) opts->emailonly2 = msg->envsender; } if (opts->denylist) { retcode = spam_denylist_manage(opts); } else { retcode = spam_allowlist_manage(opts); } log_errdump(opts->program_name); opts_free(opts); qdb_close(dbr1); qdb_close(dbr2); qdb_close(dbr3); if (msg) msg_free(msg); return retcode; } switch (opts->action) { case ACTION_DUMP: /* * Database dump mode. */ retcode = spam_db_dump(opts); log_errdump(opts->program_name); break; case ACTION_RESTORE: /* * Database restore mode. */ retcode = spam_db_restore(opts); log_errdump(opts->program_name); break; case ACTION_PRUNE: /* * Database prune mode. */ retcode = spam_db_prune(opts); if (retcode == 0) { printf("%s", _("Optimising database...")); qdb_optimise(dbw); printf(" %s\n", _("done")); } log_errdump(opts->program_name); break; case ACTION_TRAIN: /* * Training mode. */ retcode = spam_train(opts); log_errdump(opts->program_name); break; case ACTION_BENCHMARK: /* * Benchmarking mode. */ retcode = spam_benchmark(opts); qdb_close(dbr1); remove(filename); /* RATS: ignore (no race) */ dbr1 = NULL; /* * We close the database here, instead of leaving it until * later, so that we can remove the file as well. */ log_errdump(opts->program_name); break; case ACTION_MERGE: /* * Database merge mode. */ retcode = spam_db_merge(opts); /* * Note we are closing opts->dbr1 etc instead of our dbr1 * etc because spam_db_merge() shuffles them around. */ qdb_close(opts->dbr1); qdb_close(opts->dbr2); qdb_close(opts->dbr3); dbr1 = NULL; dbr2 = NULL; dbr3 = NULL; log_errdump(opts->program_name); break; case ACTION_MARK_SPAM: retcode = spam_update(opts, msg, SPAM); msg_free(msg); log_errdump(opts->program_name); break; case ACTION_MARK_NONSPAM: retcode = spam_update(opts, msg, NONSPAM); msg_free(msg); log_errdump(opts->program_name); break; case ACTION_TEST: score = spam_check(opts, msg); if (score < -9999.00) { if (!opts->no_filter) { msg_dump(msg); } else { log_errdump(opts->program_name); } if (msg) msg_free(msg); opts_free(opts); qdb_close(dbr1); qdb_close(dbr2); qdb_close(dbr3); return 0; } log_add(2, _("raw score: %g"), score); log_add(3, _("images found: %d"), msg->num_images); if (!opts->no_header) msg_spamheader(msg, opts->header_marker, score); if (opts->add_rating) { msg_spamratingheader(msg, score, opts->threshold); if (opts->no_filter) { double spamscore, scaledscore; spamscore = score; if (spamscore < 0) spamscore += 0.01; spamscore += opts->threshold; scaledscore = spamscore * 100.0; printf("%d\n", (int) scaledscore); } } if (opts->add_stars) msg_spamlevelheader(msg, score, opts->threshold); if (score > 0) { if (opts->modify_subject) msg_spamsubject(msg, opts->subject_marker); if (!opts->no_filter) { msg_dump(msg); retcode = 0; } else { log_errdump(opts->program_name); retcode = 1; } } else { if (!opts->no_filter) { msg_dump(msg); } else { log_errdump(opts->program_name); } retcode = 0; } msg_free(msg); break; default: /* * This code should never be reached. */ log_errdump(opts->program_name); fprintf(stderr, "%s: %s\n", opts->program_name, _("unknown action, please report this as a bug!")); retcode = 1; break; } opts_free(opts); qdb_close(dbr1); qdb_close(dbr2); qdb_close(dbr3); return retcode; } /* EOF */ qsf-1.2.7/src/main/log.c0000644000076400007640000000435310664772304012600 0ustar awaw/* * Logging functions. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "log.h" #include #include #include #include static int _log_level = 0; static int _log_lines = 0; static char **_log_array = 0; /* * Set the logging level (0 is off). */ void log_level(int level) { _log_level = level; } /* * Add a log message to the queue, if logging is enabled with a level * greater than or equal to "level" (i.e. level 1 is highest priority, then * level 2, and so on). */ void log_add(int level, char *format, ...) { char buf[8192]; /* RATS: ignore (checked OK - ish) */ va_list ap; char **ptr; int sz; if (_log_level < level) return; va_start(ap, format); buf[0] = 0; #ifdef HAVE_VSNPRINTF vsnprintf(buf, sizeof(buf), format, ap); #else vsprintf(buf, format, ap); /* RATS: ignore (unavoidable) */ #endif va_end(ap); if (_log_array == 0) { ptr = (char **) malloc(sizeof(char *) * (_log_lines + 1)); } else { ptr = (char **) realloc(_log_array, /* RATS: ignore */ sizeof(char *) * (_log_lines + 1)); } if (ptr == 0) return; sz = strlen(buf) + 1; _log_array = ptr; _log_array[_log_lines] = malloc(sz); if (_log_array[_log_lines] == 0) return; memcpy(_log_array[_log_lines], buf, sz); /* RATS: ignore (checked) */ _log_lines++; } /* * Dump out all log messages, with the given prefix before each line. */ void log_dump(char *prefix) { int i; if (_log_array == 0) return; for (i = 0; i < _log_lines; i++) { if (_log_array[i] == 0) continue; printf("%s%s\n", prefix, _log_array[i]); } } /* * Dump out all log messages, with the given prefix plus ": " before each * line, to stderr. */ void log_errdump(char *prefix) { int i; if (_log_array == 0) return; for (i = 0; i < _log_lines; i++) { if (_log_array[i] == 0) continue; fprintf(stderr, "%s: %s\n", prefix, _log_array[i]); } } /* * Free all memory used by this logging system. */ void log_free(void) { int i; if (_log_array == 0) return; for (i = 0; i < _log_lines; i++) { if (_log_array[i] == 0) continue; free(_log_array[i]); _log_array[i] = 0; } free(_log_array); _log_array = 0; _log_lines = 0; } /* EOF */ qsf-1.2.7/src/main/tick.c0000644000076400007640000000074510664772304012752 0ustar awaw/* * A ticker to let the user know we've not crashed. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include #include /* * Output a ticker. */ void tick(void) { static char *ticker = "-\\|/"; static int tickpos = 0; static time_t last_tick = 0; if (time(NULL) <= last_tick) return; last_tick = time(NULL); printf("%c%c", ticker[tickpos++], 8); if (ticker[tickpos] == 0) tickpos = 0; } /* EOF */ qsf-1.2.7/src/spam/0000755000076400007640000000000010665021416011652 5ustar awawqsf-1.2.7/src/spam/update.c0000644000076400007640000000435410664772304013316 0ustar awaw/* * Functions for recognising mail as spam and updating the database. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "spami.h" #include /* * Update the database, marking the contents of the given message as either * spam or non-spam depending on whether "type" is SPAM or NONSPAM. Returns * nonzero on error. */ int spam_update(opts_t opts, msg_t msg, int type) { spam_t spam; token_t token; long i; if (opts->dbw == NULL) { fprintf(stderr, "%s: %s\n", opts->program_name, _("no database to write to")); return 1; } if (opts->denylist && opts->modifydenylist) { if (type == SPAM) { spam_denylist_add(opts, msg->sender); spam_denylist_add(opts, msg->envsender); } else { spam_denylist_remove(opts, msg->sender); spam_denylist_remove(opts, msg->envsender); } } else if (opts->allowlist) { if (type == SPAM) { spam_allowlist_remove(opts, msg->sender); spam_allowlist_remove(opts, msg->envsender); } else { spam_allowlist_add(opts, msg->sender); spam_allowlist_add(opts, msg->envsender); } } spam = spam_tokenise(opts, msg, opts->dbw, NULL, NULL, 1, 1, 1); if (type == SPAM) { spam->total_spam += opts->weight; } else { spam->total_nonspam += opts->weight; } spam->update_count++; spam_store(opts, " COUNTS", 7, spam->total_spam, spam->total_nonspam, spam->update_count); spam->since_prune++; spam_store(opts, " SINCEPRUNE", 11, spam->since_prune, 0, 0); for (i = 0; i < spam->token_count; i++) { token = spam->tarray[i]; if (type == SPAM) { token->num_spam += token->count * opts->weight; } else { token->num_nonspam += token->count * opts->weight; } token->last_updated = spam->update_count; spam_store(opts, token->token, token->length, token->num_spam, token->num_nonspam, token->last_updated); } if (spam->update_count > 1) { int oldshowprune; oldshowprune = opts->showprune; opts->showprune = 0; spam_db_prune(opts); opts->showprune = oldshowprune; } else if ((opts->action != ACTION_TRAIN) && (opts->action != ACTION_BENCHMARK) && (!opts->noautoprune) && (spam->since_prune > 500)) { spam_db_prune(opts); } spam_free(spam); return 0; } /* EOF */ qsf-1.2.7/src/spam/merge.c0000644000076400007640000000612710664772304013133 0ustar awaw/* * Functions for merging one spam database into another. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "spami.h" #include "database.h" #include #include #include #include /* * Merge the contents of another spam database into the currently writable * one. Returns nonzero on error. */ int spam_db_merge(opts_t opts) { void *dbfrom; void *dbto; spam_t spam; qdb_datum key, nextkey; char **keylist = NULL; char **newkeylist; long keylistsize = 0; long numkeys = 0; long i, a, b, c; dbto = opts->dbw; if (opts->dbr1 == opts->dbw) { if (opts->dbr2) qdb_close(opts->dbr2); if (opts->dbr3) qdb_close(opts->dbr3); opts->dbr2 = qdb_open(opts->mergefrom, QDB_READONLY); if (opts->dbr2 == NULL) { fprintf(stderr, "%s: %s: %s: %s\n", opts->program_name, opts->mergefrom, _("failed to open database"), qdb_error()); return 1; } dbfrom = opts->dbr2; } else { if (opts->dbr1) qdb_close(opts->dbr1); opts->dbr1 = qdb_open(opts->mergefrom, QDB_READONLY); if (opts->dbr1 == NULL) { fprintf(stderr, "%s: %s: %s: %s\n", opts->program_name, opts->mergefrom, _("failed to open database"), qdb_error()); return 1; } dbfrom = opts->dbr1; } spam = calloc(1, sizeof(*spam)); if (spam == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("calloc failed"), strerror(errno)); return 1; } spam->db1 = dbfrom; spam->db2 = dbto; spam->db3 = NULL; spam->db1weight = 1; spam->db2weight = 1; spam->db3weight = 1; /* * Get list of all keys in the database we're merging from. */ key = qdb_firstkey(dbfrom); while (key.data != NULL) { if (keylistsize >= numkeys) { keylistsize += 10000; if (numkeys > 0) { newkeylist = realloc(keylist, /* RATS: ignore */ sizeof(char *) * keylistsize); } else { newkeylist = malloc(sizeof(char *) * keylistsize); } if (newkeylist == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("memory allocation failed"), strerror(errno)); free(keylist); free(key.data); free(spam); return 1; } keylist = newkeylist; } keylist[numkeys] = calloc(1, key.size + 1); if (keylist[numkeys] == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("memory allocation failed"), strerror(errno)); free(keylist); free(key.data); free(spam); return 1; } strncpy(keylist[numkeys], (char *) (key.data), key.size); numkeys++; nextkey = qdb_nextkey(dbfrom, key); free(key.data); key = nextkey; } /* * For each key in the merge-from database, read the combined value * for that key in both the merge-from and, if present, the merge-to * database, then store this combined value into the merge-to * database. */ for (i = 0; i < numkeys; i++) { a = 0; b = 0; spam_fetch(spam, keylist[i], strlen(keylist[i]), &a, &b, &c); spam_store(opts, keylist[i], strlen(keylist[i]), a, b, c); free(keylist[i]); } free(keylist); free(spam); return 0; } /* EOF */ qsf-1.2.7/src/spam/alloc.c0000644000076400007640000000073410664772304013124 0ustar awaw/* * Memory allocation/deallocation functions. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "spami.h" #include /* * Free the given spam structure. */ void spam_free(spam_t spam) { long i; if (spam == NULL) return; if (spam->tarray != NULL) { for (i = 0; i < spam->token_count; i++) { free(spam->tarray[i]); } free(spam->tarray); spam->tarray = NULL; } free(spam); } /* EOF */ qsf-1.2.7/src/spam/train.c0000644000076400007640000001353610664772304013153 0ustar awaw/* * Functions for training the database to recognise spam. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "mailbox.h" #include "spami.h" #include #include #include #include #include void tick(void); /* * Train the database by repeatedly classifying the contents of two mail * folders as spam or non-spam, then updating the database for those * messages that get incorrectly classified. * * If opts->benchmark is set, only the first 75% of messages in each mailbox * will be considered, and the database will not be optimised after * training. * * Returns nonzero on error. */ int spam_train(opts_t opts) { FILE *fptr_spam; FILE *fptr_nonspam; mbox_t mbox_spam, mbox_nonspam; long numspam, numnonspam, msgnum; int round, nobetterspam, nobetternonspam; long wrongspam, wrongnonspam, prevwrongspam, prevwrongnonspam; double pctwrongspam, pctwrongnonspam; int maxrounds; time_t last_unlock; msg_t msg; setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); fptr_spam = fopen(opts->argv[0], "r"); if (fptr_spam == NULL) { fprintf(stderr, "%s: %s: %s: %s\n", opts->program_name, opts->argv[0], _("failed to open spam mailbox"), strerror(errno)); return 1; } fptr_nonspam = fopen(opts->argv[1], "r"); if (fptr_nonspam == NULL) { fprintf(stderr, "%s: %s: %s: %s\n", opts->program_name, opts->argv[1], _("failed to open non-spam mailbox"), strerror(errno)); fclose(fptr_spam); return 1; } maxrounds = 200; if ((opts->argc > 2) && (opts->argv[2])) { maxrounds = atoi(opts->argv[2]); if (maxrounds < 1) maxrounds = 1; if (maxrounds > 1000) maxrounds = 1000; } numspam = -1; numnonspam = -1; /* * Release the database lock while we're counting messages. */ spam_dbunlock(opts); printf("%s ", _("Counting messages in folders...")); mbox_spam = mbox_scan(opts, fptr_spam); if (mbox_spam == NULL) { fclose(fptr_nonspam); fclose(fptr_spam); return 1; } numspam = mbox_count(mbox_spam); printf("%ld ", numspam); mbox_nonspam = mbox_scan(opts, fptr_nonspam); if (mbox_nonspam == NULL) { fclose(fptr_nonspam); fclose(fptr_spam); mbox_free(mbox_spam); return 1; } numnonspam = mbox_count(mbox_nonspam); printf("%ld\n", numnonspam); if (opts->action == ACTION_BENCHMARK) { numspam = (numspam * 3) / 4; numnonspam = (numnonspam * 3) / 4; } nobetterspam = 0; nobetternonspam = 0; prevwrongspam = 0; prevwrongnonspam = 0; opts->weight = 1; /* * Re-lock the database. */ spam_dbrelock(opts); last_unlock = time(NULL); for (round = 1; round <= maxrounds; round++) { /* * Prune the database after every 15 rounds. */ if (round > 1 && round % 15 == 1) spam_db_prune(opts); printf("%s %d: %s", _("round"), round, _("checking spam...")); for (msgnum = 0, wrongspam = 0; msgnum < numspam; msgnum++) { tick(); /* * Briefly unlock the database every couple of * seconds, so that any other processes waiting to * read from the database can do so. */ if (time(NULL) - last_unlock > 1) { spam_dbunlock(opts); spam_dbrelock(opts); last_unlock = time(NULL); } mbox_select(opts, mbox_spam, fptr_spam, msgnum); msg = msg_parse(opts); if (msg == NULL) { mbox_select(opts, NULL, NULL, 0); mbox_free(mbox_spam); mbox_free(mbox_nonspam); fclose(fptr_spam); fclose(fptr_nonspam); return 1; } if (round == 1 && opts->allowlist) { spam_allowlist_remove(opts, msg->sender); spam_allowlist_remove(opts, msg->envsender); } if (spam_check(opts, msg) < 0.0) { wrongspam++; spam_update(opts, msg, SPAM); } msg_free(msg); } pctwrongspam = 100.0 * ((double) wrongspam) / (numspam > 0 ? (double) numspam : 1.0); printf( /* RATS: ignore */ _(" reclassified [%3.2f%%] %ld/%ld\n"), pctwrongspam, wrongspam, numspam); if (wrongspam >= prevwrongspam) { nobetterspam++; } else { nobetterspam = 0; } prevwrongspam = wrongspam; printf("%s %d: %s", _("round"), round, _("checking non-spam...")); for (msgnum = 0, wrongnonspam = 0; msgnum < numnonspam; msgnum++) { tick(); if (time(NULL) - last_unlock > 1) { spam_dbunlock(opts); spam_dbrelock(opts); last_unlock = time(NULL); } mbox_select(opts, mbox_nonspam, fptr_nonspam, msgnum); msg = msg_parse(opts); if (msg == NULL) { mbox_select(opts, NULL, NULL, 0); mbox_free(mbox_spam); mbox_free(mbox_nonspam); fclose(fptr_spam); fclose(fptr_nonspam); return 1; } if (round == 1 && opts->allowlist) { spam_allowlist_add(opts, msg->sender); spam_allowlist_add(opts, msg->envsender); } if (spam_check(opts, msg) > -0.01) { wrongnonspam++; spam_update(opts, msg, NONSPAM); } msg_free(msg); } pctwrongnonspam = 100.0 * ((double) wrongnonspam) / (numnonspam > 0 ? (double) numnonspam : 1.0); printf( /* RATS: ignore */ _(" reclassified [%3.2f%%] %ld/%ld\n"), pctwrongnonspam, wrongnonspam, numnonspam); if (wrongnonspam >= prevwrongnonspam) { nobetternonspam++; } else { nobetternonspam = 0; } prevwrongnonspam = wrongnonspam; if (wrongnonspam == 0 && pctwrongspam < 0.5 && round > 5) { printf("%s\n", _("Good results, ending training.")); round = 999999; } if (nobetterspam > 10 && nobetternonspam > 10) { printf("%s\n", _("Several rounds with no improvement, " "ending training.")); round = 999999; } } mbox_select(opts, NULL, NULL, 0); mbox_free(mbox_spam); mbox_free(mbox_nonspam); fclose(fptr_spam); fclose(fptr_nonspam); if (opts->action == ACTION_BENCHMARK) return 0; printf("%s", _("Optimising database...")); qdb_optimise(opts->dbw); printf(" %s\n", _("done")); return 0; } /* EOF */ qsf-1.2.7/src/spam/cksum.c0000644000076400007640000000176510664772304013161 0ustar awaw/* * Token checksumming functions. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "md5.h" #include #include #include /* * Generate a checksum string of the given token and return a malloc()ed * pointer to it. */ unsigned char *spam_checksum(char *key, int len) { struct MD5Context md5c; unsigned char digest[64]; /* RATS: ignore (size OK) */ char buf[16]; /* RATS: ignore (size OK) */ char resultstr[128]; /* RATS: ignore (size OK) */ unsigned char *ptr; int i; MD5Init(&md5c); MD5Update(&md5c, (unsigned char *) key, len); MD5Final(digest, &md5c); memcpy(resultstr, "!\000", 2); for (i = 0; i < 16; i++) { #ifdef HAVE_SNPRINTF snprintf(buf, sizeof(buf), "%02x", digest[i]); #else sprintf(buf, "%02x", digest[i]); #endif buf[2] = 0; memcpy(resultstr + strlen(resultstr), buf, 3); } ptr = (unsigned char *) (strdup(resultstr)); if (ptr == NULL) abort(); return ptr; } /* EOF */ qsf-1.2.7/src/spam/benchmark.c0000644000076400007640000001645110664772304013767 0ustar awaw/* * Functions for benchmarking the training process. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "mailbox.h" #include "spami.h" #include #include #include #include #include #ifdef HAVE_SYS_RESOURCE_H #include #endif #include void tick(void); #ifdef HAVE_SYS_RESOURCE_H /* * Fill in "t" with the difference in time between "t1" and "t2". */ static void diff_timeval(struct timeval *t, struct timeval *t1, struct timeval *t2) { t->tv_sec = t2->tv_sec - t1->tv_sec; t->tv_usec = t2->tv_usec - t1->tv_usec; if (t->tv_usec < 0) { t->tv_sec--; t->tv_usec += 1000000; } } /* * Fill in "t" with the sum of "t1" and "t2". */ static void add_timeval(struct timeval *t, struct timeval *t1, struct timeval *t2) { t->tv_sec = t1->tv_sec + t2->tv_sec; t->tv_usec = t1->tv_usec + t2->tv_usec; if (t->tv_usec >= 1000000) { t->tv_sec++; t->tv_usec -= 1000000; } } /* * Fill in "usage" with the difference between "usage1" and "usage2", to get * the amount of user and system time elapsed between the two, */ static void diff_usage(struct rusage *usage, struct rusage *usage1, struct rusage *usage2) { diff_timeval(&(usage->ru_utime), &(usage1->ru_utime), &(usage2->ru_utime)); diff_timeval(&(usage->ru_stime), &(usage1->ru_stime), &(usage2->ru_stime)); } #endif /* HAVE_SYS_RESOURCE_H */ /* * Benchmark the training process by training on the first 75% of messages * in each folder, and then looking at the classification of the remaining * 25% (looking for false positive/false negative results). * * Also outputs some information about how long (in CPU time) the training * process took. * * Returns nonzero on error. */ int spam_benchmark(opts_t opts) { #ifdef HAVE_SYS_RESOURCE_H struct rusage usage1, usage2, usage; struct timeval total; #endif FILE *fptr_spam; FILE *fptr_nonspam; mbox_t mbox_spam, mbox_nonspam; long numspam, numnonspam, msgnum; long false_positive, false_negative; long spam_checked, nonspam_checked; double score; msg_t msg; #ifdef HAVE_SYS_RESOURCE_H if (getrusage(RUSAGE_SELF, &usage1)) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("failed to read resource usage"), strerror(errno)); return 1; } #endif fflush(stdout); if (spam_train(opts)) return 1; #ifdef HAVE_SYS_RESOURCE_H if (getrusage(RUSAGE_SELF, &usage2)) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("failed to read resource usage"), strerror(errno)); return 1; } diff_usage(&usage, &usage1, &usage2); add_timeval(&total, &(usage.ru_utime), &(usage.ru_stime)); #endif printf("%s", _("Optimising database...")); qdb_optimise(opts->dbw); printf(" %s\n", _("done")); printf("\n"); #ifdef HAVE_SYS_RESOURCE_H printf("%s\n %s %5ld.%06ld\n %s %5ld.%06ld\n %s %5ld.%06ld\n", _("Resource usage during training and optimising:"), _(" User time (sec):"), (long) (usage.ru_utime.tv_sec), (long) (usage.ru_utime.tv_usec), _("System time (sec):"), (long) (usage.ru_stime.tv_sec), (long) (usage.ru_stime.tv_usec), _(" Total time (sec):"), (long) (total.tv_sec), (long) (total.tv_usec)); printf("\n"); #endif fptr_spam = fopen(opts->argv[0], "r"); if (fptr_spam == NULL) { fprintf(stderr, "%s: %s: %s: %s\n", opts->program_name, opts->argv[0], _("failed to open spam mailbox"), strerror(errno)); return 1; } fptr_nonspam = fopen(opts->argv[1], "r"); if (fptr_nonspam == NULL) { fprintf(stderr, "%s: %s: %s: %s\n", opts->program_name, opts->argv[1], _("failed to open non-spam mailbox"), strerror(errno)); fclose(fptr_spam); return 1; } numspam = -1; numnonspam = -1; printf("%s ", _("Counting messages in folders...")); mbox_spam = mbox_scan(opts, fptr_spam); if (mbox_spam == NULL) { fclose(fptr_nonspam); fclose(fptr_spam); return 1; } numspam = mbox_count(mbox_spam); printf("%ld ", numspam); mbox_nonspam = mbox_scan(opts, fptr_nonspam); if (mbox_nonspam == NULL) { fclose(fptr_nonspam); fclose(fptr_spam); mbox_free(mbox_spam); return 1; } numnonspam = mbox_count(mbox_nonspam); printf("%ld\n", numnonspam); #ifdef HAVE_SYS_RESOURCE_H if (getrusage(RUSAGE_SELF, &usage1)) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("failed to read resource usage"), strerror(errno)); return 1; } #endif printf("Counting incorrect classifications..."); false_positive = 0; false_negative = 0; spam_checked = 0; nonspam_checked = 0; for (msgnum = 0; msgnum < numspam; msgnum++) { tick(); mbox_select(opts, mbox_spam, fptr_spam, msgnum); msg = msg_parse(opts); if (msg == NULL) { mbox_select(opts, NULL, NULL, 0); mbox_free(mbox_spam); mbox_free(mbox_nonspam); fclose(fptr_spam); fclose(fptr_nonspam); return 1; } score = spam_check(opts, msg); if (score <= 0) { false_negative++; } msg_free(msg); spam_checked++; } for (msgnum = 0; msgnum < numnonspam; msgnum++) { tick(); mbox_select(opts, mbox_nonspam, fptr_nonspam, msgnum); msg = msg_parse(opts); if (msg == NULL) { mbox_select(opts, NULL, NULL, 0); mbox_free(mbox_spam); mbox_free(mbox_nonspam); fclose(fptr_spam); fclose(fptr_nonspam); return 1; } score = spam_check(opts, msg); if (score > 0) { false_positive++; } msg_free(msg); nonspam_checked++; } #ifdef HAVE_SYS_RESOURCE_H if (getrusage(RUSAGE_SELF, &usage2)) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("failed to read resource usage"), strerror(errno)); return 1; } diff_usage(&usage, &usage1, &usage2); add_timeval(&total, &(usage.ru_utime), &(usage.ru_stime)); #endif /* * Prevent division by zero */ if (spam_checked < 1) spam_checked = 1; if (nonspam_checked < 1) nonspam_checked = 1; printf(" \n\n"); #ifdef HAVE_SYS_RESOURCE_H printf ("%s\n %s %5ld.%06ld\n %s %5ld.%06ld\n %s %5ld.%06ld\n %s %ld\n", _("Resource usage during classification:"), _(" User time (sec):"), (long) (usage.ru_utime.tv_sec), (long) (usage.ru_utime.tv_usec), _(" System time (sec):"), (long) (usage.ru_stime.tv_sec), (long) (usage.ru_stime.tv_usec), _(" Total time (sec):"), (long) (total.tv_sec), (long) (total.tv_usec), _("Messages classified:"), spam_checked + nonspam_checked); printf("\n"); #endif printf("%s %5.2f%% [%ld/%ld] \t%s\n%s %5.2f%% [%ld/%ld] \t%s\n", _("False negatives:"), (100.0 * (double) false_negative) / (double) spam_checked, false_negative, spam_checked, _("(failing to mark spam as being spam)"), _("False positives:"), (100.0 * (double) false_positive) / (double) nonspam_checked, false_positive, nonspam_checked, _("(wrongly marking a real email as spam)")); printf("\n%s %5.4f%% [%ld/%ld]\n", _("Accuracy:"), (100.0 * (double) (spam_checked + nonspam_checked - false_negative - false_positive) / (double) (spam_checked + nonspam_checked)), (long) (spam_checked + nonspam_checked - false_negative - false_positive), (long) (spam_checked + nonspam_checked) ); mbox_select(opts, NULL, NULL, 0); mbox_free(mbox_spam); mbox_free(mbox_nonspam); fclose(fptr_spam); fclose(fptr_nonspam); return 0; } /* EOF */ qsf-1.2.7/src/spam/check.c0000644000076400007640000001303410664772304013104 0ustar awaw/* * Check whether a message is spam. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "spami.h" #include "log.h" #include #include #include #include /* * Return a probability that the message is spam, where 0.9 and above means * "definitely spam", using the Robinson method. * * Robinson's method: * * Set pN = "spam probability" of token N, where pN = f(p(w)), where p(w) * is (bad / tb) / ((bad / tb) + (good / tg)) - bad is number of times * token seen in bad messages, good is times token seen in good messages, * tb and tg are total number of bad and good messages seen; f(w) is (robs * * robx + gbtot * p(w)) / (robs + gbtot), where gbtot is is good + bad, * robs is a constant, and robx is a fudge factor calculated from the * average p(w) of all tokens that have been seen over 10 times. * * Then: * * P = 1 - ((1-p1)(1-p2)(1-p3)...(1-pN))^(1/n) * Q = 1 - (p1p2p3...pN)^(1/n) * S = (P - Q) / (P + Q) * * S is then a number from -1 to +1, so we scale it to 0-1 and then divide * by (0.54/0.9=0.6) and clip to 1, since the spam cutoff point for this * algorithm is 0.54 and we want it to be 0.9. */ double spam_check__robinson(opts_t opts, msg_t msg, spam_t spam) { token_t token; long i, n; double r, ln2, p_log, q_log, p, q, s, robs, robx; struct { double mant; int exp; } P, Q; int e; P.mant = 1.0; P.exp = 0; Q.mant = 1.0; Q.exp = 0; robx = spam->robx; robs = 1.0; n = 0; if (spam->token_count < 1) return 0.5; for (i = 0; i < spam->token_count; i++) { double pw, fw, gbtot; token = spam->tarray[i]; pw = token->prob_spam; gbtot = token->num_nonspam + token->num_spam; fw = (robs * robx + gbtot * pw) / (robs + gbtot); if (fabs(0.5 - pw) < 0.00001) continue; P.mant *= 1 - fw; if (P.mant < 1.0e-200) { P.mant = frexp(P.mant, &e); P.exp += e; } Q.mant *= fw; if (Q.mant < 1.0e-200) { Q.mant = frexp(Q.mant, &e); Q.exp += e; } n++; } if (n < 1) n = 1; r = 1.0 / (double) n; ln2 = 0.69314718055994530941; /* * Avoid floating point exceptions. */ if (P.mant <= 0) P.mant = 0.00000000001; if (Q.mant <= 0) Q.mant = 0.00000000001; p_log = log(P.mant) + P.exp * ln2; q_log = log(Q.mant) + Q.exp * ln2; p = 1.0 - exp(p_log * r); q = 1.0 - exp(q_log * r); s = (1.0 + (p - q) / (p + q)) / 2.0; s = s / 0.6; if (s > 1.0) s = 1.0; return s; } /* * Return a score above zero if the given message is probably spam, zero or * less if not. If the score is < -9999, then the message should not be * processed at all (due to the "min-tokens" option). */ double spam_check(opts_t opts, msg_t msg) { double prob; spam_t spam; spam = spam_tokenise(opts, msg, opts->dbr1, opts->dbr2, opts->dbr3, opts->db1weight, opts->db2weight, opts->db3weight); /* * If we're not in training or benchmarking mode and we know the * email address of the message sender or the envelope address, * check either against the deny-list and if a match is found, * return a "definitely spam" score. Then check against the * allow-list, and if a match is found, return a "definitely not * spam" score. Then check both again for just the "@domain" part. */ if ((opts->action != ACTION_TRAIN) && (opts->action != ACTION_BENCHMARK) ) { char *senderdomain; char *envsenderdomain; /* * First check the sender and envelope sender addresses * against the deny and allow lists. */ if ((opts->denylist) && ((spam_denylist_match(spam, msg->sender)) || (spam_denylist_match(spam, msg->envsender)) ) ) { spam_free(spam); return 0.1; } else if ((opts->allowlist) && ((spam_allowlist_match(spam, msg->sender)) || (spam_allowlist_match(spam, msg->envsender)) ) ) { spam_free(spam); return 0.00 - (opts->threshold + 0.01); } /* * Now check just the @domain part of each address. */ senderdomain = NULL; if (msg->sender) senderdomain = strchr(msg->sender, '@'); envsenderdomain = NULL; if (msg->envsender) envsenderdomain = strchr(msg->envsender, '@'); if ((opts->denylist) && ((spam_denylist_match(spam, senderdomain)) || (spam_denylist_match(spam, envsenderdomain)) ) ) { spam_free(spam); return 0.1; } else if ((opts->allowlist) && ((spam_allowlist_match(spam, senderdomain)) || (spam_allowlist_match (spam, envsenderdomain)) ) ) { spam_free(spam); return 0.00 - (opts->threshold + 0.01); } } /* * If we've been told to do nothing if there are fewer than a * particular number of tokens, then return -10000 if there aren't * enough tokens. */ if ((opts->min_token_count > spam->token_count) && (opts->action != ACTION_TRAIN) && (opts->action != ACTION_BENCHMARK) ) { spam_free(spam); return -10000.00; } if ((opts->action != ACTION_TRAIN) && (opts->action != ACTION_BENCHMARK)) log_add(2, _("token count: %d"), spam->token_count); /* * If a spam test caused an override, return the appropriate score * (definitely spam or non-spam) depending on whether the override * flag is positive or negative respectively. */ if (spam->override != 0) { prob = 0.1; if (spam->override < 0) prob = 0.00 - (opts->threshold + 0.01); spam_free(spam); return prob; } prob = spam_check__robinson(opts, msg, spam); spam_free(spam); if (prob > opts->threshold) return prob - opts->threshold; return prob - (opts->threshold + 0.01); } /* EOF */ qsf-1.2.7/src/spam/plaintext.c0000644000076400007640000001116510664772304014042 0ustar awaw/* * Plaintext database mapping functions. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "spami.h" #include "log.h" #include #include #include #include #ifdef HAVE_FCNTL #include #endif struct spam_p_item_s { char *hash; char *token; }; struct spam_p_s { FILE *fptr; #ifdef HAVE_FCNTL int lockcount; #endif struct spam_p_item_s *list; int list_size; int list_alloced; }; #ifdef HAVE_FCNTL /* * Obtain / release a read or write lock on the database. Returns nonzero on * error, and blocks until a lock can be obtained. */ static int spam_plaintext__lock(struct spam_p_s *data, int lock_type) { struct flock lock; if ((lock_type == F_UNLCK) && (data->lockcount > 1)) { data->lockcount--; return 0; } else if ((lock_type != F_UNLCK) && (data->lockcount > 0)) { data->lockcount++; return 0; } lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 0; lock.l_type = lock_type; if (fcntl(fileno(data->fptr), F_SETLKW, &lock)) { return 1; } if (lock_type == F_UNLCK) { data->lockcount--; } else { data->lockcount++; } return 0; } #endif /* HAVE_FCNTL */ /* * Add the given hash / token pair to the in-memory list. */ static void spam_plaintext__append(struct spam_p_s *data, char *hash, int hashlen, char *token, int tokenlen) { struct spam_p_item_s *ptr; if (data->list_size >= data->list_alloced) { if (data->list) { ptr = realloc(data->list, /* RATS: ignore */ (sizeof *ptr) * (data->list_alloced + 1000)); } else { ptr = malloc((sizeof *ptr) * (data->list_alloced + 1000)); } if (ptr == NULL) { log_add(1, "%s", strerror(errno)); return; } data->list = ptr; data->list_alloced += 1000; } data->list[data->list_size].hash = calloc(1, hashlen + 1); data->list[data->list_size].token = calloc(1, tokenlen + 1); if (data->list[data->list_size].hash) strncpy(data->list[data->list_size].hash, hash, hashlen); if (data->list[data->list_size].token) strncpy(data->list[data->list_size].token, token, tokenlen); data->list_size++; } /* * Update the plaintext mapping with the given hash / token pair. */ void spam_plaintext_update(opts_t opts, char *hash, int hashlen, char *token, int tokenlen) { struct spam_p_s *data; int i; if (opts->plainmap == NULL) return; if (opts->plaindata == NULL) { opts->plaindata = calloc(1, sizeof(struct spam_p_s)); if (opts->plaindata == NULL) { log_add(1, "%s: %s", opts->plainmap, strerror(errno)); return; } } data = opts->plaindata; if (data->fptr == NULL) { char hashbuf[1024]; /* RATS: ignore */ char tokenbuf[1024]; /* RATS: ignore */ data->fptr = fopen(opts->plainmap, "a+"); if (data->fptr == NULL) { log_add(1, "%s: %s", opts->plainmap, strerror(errno)); return; } #ifdef HAVE_FCNTL spam_plaintext__lock(data, F_WRLCK); #endif fseek(data->fptr, 0, SEEK_SET); while (!feof(data->fptr)) { char linebuf[4096]; /* RATS: ignore */ int n; linebuf[0] = 0; if (fgets(linebuf, sizeof(linebuf), data->fptr) == NULL) break; linebuf[sizeof(linebuf) - 1] = 0; hashbuf[0] = 0; tokenbuf[0] = 0; n = sscanf(linebuf, "%1023[^\t\n]\t%1023[^\n]", hashbuf, tokenbuf); if (n < 2) continue; spam_plaintext__append(data, hashbuf, strlen(hashbuf), tokenbuf, strlen(tokenbuf)); } } for (i = 0; i < data->list_size; i++) { if (data->list[i].hash == NULL) continue; if (strlen(data->list[i].hash) != hashlen) continue; if (strncmp(data->list[i].hash, hash, hashlen) != 0) continue; return; } spam_plaintext__append(data, hash, hashlen, token, tokenlen); if (hashlen > 1023) hashlen = 1023; if (tokenlen > 1023) tokenlen = 1023; for (i = 0; i < tokenlen; i++) { if (token[i] == '\n') { tokenlen = i; break; } } fseek(data->fptr, 0, SEEK_END); fprintf(data->fptr, "%.*s\t%.*s\n", hashlen, hash, tokenlen, token); } /* * Free the plaintext handling data area. */ void spam_plaintext_free(opts_t opts) { struct spam_p_s *data; int i; if (opts == NULL) return; if (opts->plainmap == NULL) return; if (opts->plaindata == NULL) return; data = opts->plaindata; if (data->fptr) { fflush(data->fptr); #ifdef HAVE_FCNTL spam_plaintext__lock(data, F_UNLCK); #endif fclose(data->fptr); } for (i = 0; i < data->list_size; i++) { if (data->list[i].hash) free(data->list[i].hash); if (data->list[i].token) free(data->list[i].token); } if (data->list) free(data->list); free(opts->plaindata); opts->plaindata = NULL; } /* EOF */ qsf-1.2.7/src/spam/dump.c0000644000076400007640000001716510664772304013005 0ustar awaw/* * Functions for dumping and restoring the spam database, and for dumping * tokens from a message. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "spami.h" #include #include #include #include #include #include #include #include /* * Dump the tokens from the given message on stdout, returning nonzero on * error. */ int spam_dumptokens(opts_t opts, msg_t msg) { spam_t spam; long i; spam = spam_tokenise(opts, msg, NULL, NULL, NULL, 1, 1, 1); if (spam == NULL) return 1; for (i = 0; i < spam->token_count; i++) { printf("%ld\t%.*s\n", spam->tarray[i]->count, spam->tarray[i]->length, spam->tarray[i]->token); } spam_free(spam); return 0; } /* * Dump the database on stdout in text form, returning nonzero on error. */ int spam_db_dump(opts_t opts) { FILE *fptr; qdb_t db; qdb_datum key, val, nextkey; long a, b, c; time_t t; if ((opts->argc == 1) && (opts->argv[0]) && (strcmp(opts->argv[0], "-") != 0)) { struct stat outsb, sb; /* * Before trying to write to the file, check it's not the * same file as any of the databases. We don't care if * someone moves it in the middle of us trying something. */ if (stat(opts->argv[0], &outsb)) { /* RATS: ignore */ if (errno != ENOENT) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, opts->argv[0], strerror(errno)); return 1; } } else { /* * File exists; check against databases. */ if ((opts->dbw) && (fstat(qdb_fd(opts->dbw), &sb) == 0) ) { if ((sb.st_dev == outsb.st_dev) && (sb.st_ino == outsb.st_ino) ) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, opts->argv[0], _ ("attempted to dump to an existing database")); return 1; } } if ((opts->dbr1) && (fstat(qdb_fd(opts->dbr1), &sb) == 0) ) { if ((sb.st_dev == outsb.st_dev) && (sb.st_ino == outsb.st_ino) ) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, opts->argv[0], _ ("attempted to dump to an existing database")); return 1; } } if ((opts->dbr2) && (fstat(qdb_fd(opts->dbr2), &sb) == 0) ) { if ((sb.st_dev == outsb.st_dev) && (sb.st_ino == outsb.st_ino) ) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, opts->argv[0], _ ("attempted to dump to an existing database")); return 1; } } if ((opts->dbr3) && (fstat(qdb_fd(opts->dbr3), &sb) == 0) ) { if ((sb.st_dev == outsb.st_dev) && (sb.st_ino == outsb.st_ino) ) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, opts->argv[0], _ ("attempted to dump to an existing database")); return 1; } } } /* * Now we've done the checks, so try and open the file for * writing. */ fptr = fopen(opts->argv[0], "w"); if (fptr == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, opts->argv[0], strerror(errno)); return 1; } } else { fptr = stdout; } time(&t); db = opts->dbw; if (db == NULL) db = opts->dbr1; if (db == NULL) db = opts->dbr2; if (db == NULL) db = opts->dbr3; if (db == NULL) { fprintf(stderr, "%s: %s\n", opts->program_name, _("cannot find a database to dump")); return 1; } a = 0; b = 0; c = 0; key.data = (unsigned char *) " COUNTS"; key.size = 7; val = qdb_fetch(db, key); if (val.data != NULL) { a = ((long *) (val.data))[0]; b = ((long *) (val.data))[1]; if (val.size > 2 * sizeof(long)) c = ((long *) (val.data))[2]; free(val.data); val.data = NULL; } fprintf(fptr, "# %s %s %s\n", PROGRAM_NAME, _("database dump"), VERSION); fprintf(fptr, "# %s: %s\n", _("Date of dump"), ctime(&t)); fprintf(fptr, "COUNT-SPAM %ld\n", a); fprintf(fptr, "COUNT-NONSPAM %ld\n", b); fprintf(fptr, "COUNT-UPDATES %ld\n\n", c); a = 0; key.data = (unsigned char *) " SINCEPRUNE"; key.size = 11; val = qdb_fetch(db, key); if (val.data != NULL) { a = ((long *) (val.data))[0]; b = ((long *) (val.data))[1]; free(val.data); val.data = NULL; } fprintf(fptr, "SINCEPRUNE %ld\n\n", a); fprintf(fptr, "# %s\t%s\t%s\t%s\n\n", _("Token"), _("Spam"), _("Non-Spam"), _("Last Updated")); key = qdb_firstkey(db); while (key.data != NULL) { val.data = NULL; if (((key.size == 7) && (strncmp((char *) (key.data), " COUNTS", 7) == 0) ) || ((key.size == 11) && (strncmp((char *) (key.data), " SINCEPRUNE", 11) == 0) ) ) { val.data = NULL; } else { val = qdb_fetch(db, key); } if (val.data != NULL) { a = ((long *) (val.data))[0]; b = ((long *) (val.data))[1]; c = 0; if (val.size > 2 * sizeof(long)) c = ((long *) (val.data))[2]; fprintf(fptr, "%.*s\t%ld\t%ld\t%ld\n", key.size, key.data, a, b, c); free(val.data); } nextkey = qdb_nextkey(db, key); free(key.data); key = nextkey; } if ((opts->argc == 1) && (opts->argv[0]) && (strcmp(opts->argv[0], "-") != 0)) fclose(fptr); return 0; } /* * Restore the database from stdin in text form, returning nonzero on error. */ int spam_db_restore(opts_t opts) { FILE *fptr; char linebuf[1024]; /* RATS: ignore (checked all) */ char tokenbuf[64]; /* RATS: ignore (checked all) */ qdb_t db = NULL; qdb_datum key, val; long a, b, c; long dat[3]; int got_count = 0; if ((opts->argc == 1) && (opts->argv[0]) && (strcmp(opts->argv[0], "-") != 0)) { fptr = fopen(opts->argv[0], "r"); if (fptr == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, opts->argv[0], strerror(errno)); return 1; } } else { fptr = stdin; } a = 0; b = 0; c = 0; db = opts->dbw; if (db == NULL) { fprintf(stderr, "%s: %s\n", opts->program_name, _("cannot write to a database")); if ((opts->argc == 1) && (opts->argv[0]) && (strcmp(opts->argv[0], "-") != 0)) { fclose(fptr); } return 1; } while (fgets(linebuf, sizeof(linebuf) - 1, fptr) != NULL) { linebuf[sizeof(linebuf) - 1] = 0; if (linebuf[0] == '#' || linebuf[0] == ' ' || linebuf[0] == '\t' || linebuf[0] == '\r' || linebuf[0] == '\n') continue; switch (got_count) { case 0: if (sscanf(linebuf, "COUNT-SPAM %ld", &a) == 1) got_count++; break; case 1: if (sscanf(linebuf, "COUNT-NONSPAM %ld", &b) == 1) got_count++; break; case 2: if (sscanf(linebuf, "COUNT-UPDATES %ld", &c) == 1) break; qdb_restore_start(db); key.data = (unsigned char *) " COUNTS"; key.size = 7; val.data = (unsigned char *) dat; val.size = sizeof(dat); dat[0] = a; dat[1] = b; dat[2] = c; qdb_store(db, key, val); got_count++; default: c = 0; if (sscanf(linebuf, "SINCEPRUNE %ld", &a) == 1) { key.data = (unsigned char *) " SINCEPRUNE"; key.size = 11; val.data = (unsigned char *) dat; val.size = sizeof(dat); dat[0] = a; dat[1] = 0; dat[2] = 0; qdb_store(db, key, val); } else if (sscanf(linebuf, /* RATS: ignore (const fmt) */ "%40[\\!?" TOKEN_CHARS "] " /*s" */ "%ld %ld %ld", tokenbuf, &a, &b, &c) >= 3) { tokenbuf[sizeof(tokenbuf) - 1] = 0; key.data = (unsigned char *) tokenbuf; key.size = strlen(tokenbuf); val.data = (unsigned char *) dat; val.size = sizeof(dat); dat[0] = a; dat[1] = b; dat[2] = c; qdb_store(db, key, val); } break; } } if (got_count > 2) { qdb_restore_end(db); } if ((opts->argc == 1) && (opts->argv[0]) && (strcmp(opts->argv[0], "-") != 0)) { fclose(fptr); } return 0; } /* EOF */ qsf-1.2.7/src/spam/token.c0000644000076400007640000001557410664772304013162 0ustar awaw/* * Functions for breaking a message up into tokens. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "spami.h" #include #include #include #include /* * Add a new token to the token tree. */ void spam_token_add(opts_t opts, spam_t spam, char *str, int len) { token_t *parentptr; token_t token; int c; /* * Refuse to add a token that's too small. */ if (len < 2) return; token = spam->tokens; parentptr = &(spam->tokens); while (token != NULL) { if (len > token->length) { parentptr = &(token->longer); } else { c = strncmp(str, token->token, len); if (len == token->length && c == 0) { break; } else if (c < 0) { parentptr = &(token->lower); } else { parentptr = &(token->higher); } } token = *parentptr; } if (token == NULL) { token = calloc(1, sizeof(*token)); if (token == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("calloc failed"), strerror(errno)); return; } *parentptr = token; spam->token_count++; token->token = str; token->length = len; } if (token->count < 1) spam_fetch(spam, str, len, &(token->num_spam), &(token->num_nonspam), &(token->last_updated)); token->count++; } /* * Add a token and (recursively) all its leaf nodes to the array. */ static void spam_token_arrayadd(spam_t spam, token_t token, int depth) { if (token == NULL) return; if (depth > 10000) return; if (spam->_idx >= spam->token_count) return; spam->tarray[spam->_idx++] = token; spam_token_arrayadd(spam, token->lower, depth + 1); spam_token_arrayadd(spam, token->longer, depth + 1); spam_token_arrayadd(spam, token->higher, depth + 1); } /* * Return the length of the initial segment of "buf" (length "buflen") that * consists entirely of characters in "accept". */ static int spam_tokenise__span(char *buf, int buflen, char *accept) { int len; for (len = 0; (len < buflen) && strchr(accept, buf[len]); len++) { } return len; } /* * Return the length of the initial segment of "buf" (length "buflen") that * consists entirely of characters not in "reject". */ static int spam_tokenise__cspan(char *buf, int buflen, char *reject) { int len; for (len = 0; (len < buflen) && !strchr(reject, buf[len]); len++) { } return len; } /* * Tokenise the given message and return a spam structure containing the * tokens in the message and their spam ratings. Returns NULL on error. The * following special token names are used: * * " COUNTS" - total number of spam and non-spam email messages seen, * plus the total number of updates we have ever applied * " SINCEPRUNE" - number of updates since the last prune (first val only) * * Note that these special token names all start with a space, so as to not * clash with any "real" tokens. */ spam_t spam_tokenise(opts_t opts, msg_t msg, qdb_t db1, qdb_t db2, qdb_t db3, int db1weight, int db2weight, int db3weight) { spam_t spam; long pos, start, len, i, n, dummy; char *content; long content_size; long prevstart; spam = calloc(1, sizeof(*spam)); if (spam == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("calloc failed"), strerror(errno)); return NULL; } spam->db1 = db1; spam->db2 = db2; spam->db3 = db3; spam->dbw = opts->dbw; spam->db1weight = db1weight; spam->db2weight = db2weight; spam->db3weight = db3weight; spam_fetch(spam, " COUNTS", 7, &(spam->total_spam), &(spam->total_nonspam), &(spam->update_count)); spam_fetch(spam, " SINCEPRUNE", 11, &(spam->since_prune), &pos, &dummy); if (spam->total_spam < 1) spam->total_spam = 1; if (spam->total_nonspam < 1) spam->total_nonspam = 1; content = msg->textcontent; content_size = msg->text_size; if (content == NULL) { content = msg->content; content_size = msg->content_size; } prevstart = 0; for (pos = 0; pos < content_size;) { len = spam_tokenise__span(content + pos, content_size - pos, TOKEN_CHARS); if (len <= 0) { len = spam_tokenise__cspan(content + pos, content_size - pos, TOKEN_CHARS); pos += len; if (len < 1) pos++; continue; } start = pos; pos += len; /* * Don't allow a token to start with 0-9, -, ', !, or . */ if ((content[start] >= '0' && content[start] <= '9') || content[start] == '-' || content[start] == '\'' || content[start] == '!' || content[start] == '?' || content[start] == '.') continue; /* * Skip tokens that are too short or too long */ if ((len < 3) || (len > 34)) continue; /* * Make all tokens lower case (tests indicate that case * sensitive tokens lead to a higher false positive rate, as * well as making the token database bigger) */ for (i = 0; i < len; i++) { if (content[start + i] >= 'A' && content[start + i] <= 'Z') content[start + i] += 32; } /* * Strip -, ', . from end of token */ for (i = len - 1; i > 0; i--) { if (content[start + i] == '-' || content[start + i] == '\'' || content[start + i] == '.') { len--; } else { break; } } /* * Check length again, eg in case token was "a--" */ if (len < 2) continue; spam_token_add(opts, spam, content + start, len); /* * If this isn't the first token, add a second pseudo-token * consisting of all the text from the start of the previous * token to the end of the current one. */ if ((prevstart != 0) && (prevstart < start)) { spam_token_add(opts, spam, content + prevstart, (start - prevstart) + len); } prevstart = start; } spam->override = spam_test(opts, spam, msg); if (spam->token_count < 1) return spam; spam->tarray = calloc(spam->token_count, sizeof(token_t)); if (spam->tarray == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("calloc failed"), strerror(errno)); return spam; } spam_token_arrayadd(spam, spam->tokens, 0); spam->token_count = spam->_idx; n = 0; spam->robx = 0.0; /* * Calculate the spam probabilities for each token. * * Formerly we did (bad / tb) / ((bad / tb) + (good / tg)) where * tb/tg are total bad/good messages seen. This appears to be * slightly redundant, so we now just use the token counts directly, * i.e. we do pw = bad / (bad+good) instead. This approximation * allows us to not worry about how to modify message total counts * when the database is pruned. */ for (i = 0; i < spam->token_count; i++) { double good, bad, gbtot, pw; token_t token; token = spam->tarray[i]; good = token->num_nonspam; bad = token->num_spam; gbtot = good + bad; pw = 0.0; if (gbtot > 0) { pw = bad / (bad + good); if (gbtot > 10.0) { spam->robx += pw; n++; } } token->prob_spam = pw; } if (n > 0) { spam->robx = spam->robx / (double) n; } else { spam->robx = 0.5; } return spam; } /* EOF */ qsf-1.2.7/src/spam/db.c0000644000076400007640000000706110664772304012417 0ustar awaw/* * Database fetch/store functions. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "spami.h" #include #include /* * Fetch the given key from the database, trying all databases if * applicable; if both databases have a value for that key, they are added * together - except for the SINCEPRUNE counter, which is only ever read * from the writable database and is read as 0 if all databases are * read-only. If the third value is not present, it is 0; if present in more * than one database, the highest value is returned. */ void spam_fetch(spam_t spam, char *key, int len, long *val1, long *val2, long *val3) { qdb_datum dkey, val; int needcksum = 0; dkey.data = (unsigned char *) key; dkey.size = len; if ((dkey.size == 11) && (strncmp(key, " SINCEPRUNE", 11) == 0)) { *val1 = 0; *val2 = 0; *val3 = 0; if (spam->dbw) { val = qdb_fetch(spam->dbw, dkey); if (val.data != NULL) { *val1 = ((long *) (val.data))[0]; *val2 = ((long *) (val.data))[1]; if (val.size > 2 * sizeof(long)) *val3 = ((long *) (val.data))[2]; free(val.data); } return; } else { return; } } if ((key[0] != ' ') && (key[0] != '!') && (key[0] != '?') && (key[0] != '\\') && (key[0] != '.') ) { needcksum = 1; dkey.data = spam_checksum(key, len); dkey.size = strlen((char *) (dkey.data)); } *val3 = 0; val = qdb_fetch(spam->db1, dkey); if (val.data != NULL) { *val1 += spam->db1weight * ((long *) (val.data))[0]; *val2 += spam->db1weight * ((long *) (val.data))[1]; if (val.size > 2 * sizeof(long)) { long n; n = ((long *) (val.data))[2]; if (n > *val3) *val3 = n; } free(val.data); } val = qdb_fetch(spam->db2, dkey); if (val.data != NULL) { *val1 += spam->db2weight * ((long *) (val.data))[0]; *val2 += spam->db2weight * ((long *) (val.data))[1]; if (val.size > 2 * sizeof(long)) { long n; n = ((long *) (val.data))[2]; if (n > *val3) *val3 = n; } free(val.data); } val = qdb_fetch(spam->db3, dkey); if (val.data != NULL) { *val1 += spam->db3weight * ((long *) (val.data))[0]; *val2 += spam->db3weight * ((long *) (val.data))[1]; if (val.size > 2 * sizeof(long)) { long n; n = ((long *) (val.data))[2]; if (n > *val3) *val3 = n; } free(val.data); } if (needcksum) free(dkey.data); } /* * Store the given key into the database that is opened for write access. */ void spam_store(opts_t opts, char *key, int len, long val1, long val2, long val3) { qdb_datum dkey, dval; int needcksum = 0; long dat[3]; dkey.data = (unsigned char *) key; dkey.size = len; if ((key[0] != ' ') && (key[0] != '!') && (key[0] != '?') && (key[0] != '\\') && (key[0] != '.') ) { needcksum = 1; dkey.data = spam_checksum(key, len); dkey.size = strlen((char *) (dkey.data)); } dval.data = (unsigned char *) dat; dval.size = sizeof(dat); dat[0] = val1; dat[1] = val2; dat[2] = val3; qdb_store(opts->dbw, dkey, dval); if (needcksum) { if (opts->plainmap) { spam_plaintext_update(opts, (char *) (dkey.data), dkey.size, key, len); } free(dkey.data); } } /* * Temporarily release the lock on the writable database, if any. */ void spam_dbunlock(opts_t opts) { if (opts == NULL) return; if (opts->dbw == NULL) return; qdb_unlock(opts->dbw); } /* * Reassert the lock on the writable database, if any. */ void spam_dbrelock(opts_t opts) { if (opts == NULL) return; if (opts->dbw == NULL) return; qdb_relock(opts->dbw); } /* EOF */ qsf-1.2.7/src/spam/prune.c0000644000076400007640000003572310664772304013171 0ustar awaw/* * Functions for pruning a spam database. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "spami.h" #include #include #include #include #include #include #undef DEBUG_THRESHOLD #undef DEBUG_DISCARD void tick(void); /* * Scan through the database and return the average spam (or non-spam) token * count, and fill in the maximum count found. */ static double spam_db_prune_old__maxcount(opts_t opts, long *maxcount, int spam) { long num_tokens, num_spam, num_nonspam; qdb_datum key, val, nextkey; double avg; num_tokens = 0; avg = 0; *maxcount = 0; key = qdb_firstkey(opts->dbw); while (key.data != NULL) { if (opts->showprune) { tick(); } val.data = NULL; if (((key.size == 7) && (strncmp((char *) (key.data), " COUNTS", 7) == 0) ) || ((key.size == 11) && (strncmp((char *) (key.data), " SINCEPRUNE", 11) == 0) ) || (key.data[0] == '?') ) { val.data = NULL; } else { val = qdb_fetch(opts->dbw, key); } if (val.data != NULL) { num_tokens++; free(val.data); } nextkey = qdb_nextkey(opts->dbw, key); free(key.data); key = nextkey; } key = qdb_firstkey(opts->dbw); while (key.data != NULL) { if (opts->showprune) { tick(); } val.data = NULL; if (((key.size == 7) && (strncmp((char *) (key.data), " COUNTS", 7) == 0) ) || ((key.size == 11) && (strncmp((char *) (key.data), " SINCEPRUNE", 11) == 0) ) || (key.data[0] == '?') ) { val.data = NULL; } else { val = qdb_fetch(opts->dbw, key); } if (val.data == NULL) { nextkey = qdb_nextkey(opts->dbw, key); free(key.data); key = nextkey; continue; } num_spam = ((long *) (val.data))[0]; num_nonspam = ((long *) (val.data))[1]; free(val.data); if (spam == SPAM) { avg += ((double) num_spam) / ((double) num_tokens); if (num_spam > *maxcount) *maxcount = num_spam; } else { avg += ((double) num_nonspam) / ((double) num_tokens); if (num_nonspam > *maxcount) *maxcount = num_nonspam; } nextkey = qdb_nextkey(opts->dbw, key); free(key.data); key = nextkey; } return avg; } /* * Scan through the database looking for tokens to strip, and strip them. We * also cap token counts to stop them getting too high relative to the total * message counts. Returns nonzero on error. */ static int spam_db_prune_old__strip(opts_t opts) { qdb_datum key, val, nextkey; long total_spam, total_nonspam, total_updates; long num_spam, num_nonspam, last_updated; double good, bad, prob_spam; qdb_datum *to_remove = NULL; qdb_datum *ptr; long num_to_remove = 0; long to_remove_alloced = 0; long total_tokens; long a, b, c, i; int clip; a = 0; b = 0; c = 0; key.data = (unsigned char *) " COUNTS"; key.size = 7; val = qdb_fetch(opts->dbw, key); if (val.data != NULL) { a = ((long *) (val.data))[0]; b = ((long *) (val.data))[1]; if (val.size > 2 * sizeof(long)) c = ((long *) (val.data))[2]; } total_spam = a; total_nonspam = b; total_updates = c; if (total_spam < 1) total_spam = 1; if (total_nonspam < 1) total_nonspam = 1; total_tokens = 0; key = qdb_firstkey(opts->dbw); while (key.data != NULL) { if (opts->showprune) { tick(); } val.data = NULL; if (((key.size == 7) && (strncmp((char *) (key.data), " COUNTS", 7) == 0) ) || ((key.size == 11) && (strncmp((char *) (key.data), " SINCEPRUNE", 11) == 0) ) || (key.data[0] == '?') ) { val.data = NULL; } else { val = qdb_fetch(opts->dbw, key); } if (val.data == NULL) { nextkey = qdb_nextkey(opts->dbw, key); free(key.data); key = nextkey; continue; } num_spam = ((long *) (val.data))[0]; num_nonspam = ((long *) (val.data))[1]; last_updated = 0; if (val.size > 2 * sizeof(long)) last_updated = ((long *) (val.data))[2]; free(val.data); clip = 0; if (num_spam > 3 * total_spam) { num_spam = 3 * total_spam; clip = 1; } if (num_nonspam > 3 * total_nonspam) { num_nonspam = 3 * total_nonspam; clip = 1; } if (clip) { spam_store(opts, (char *) (key.data), key.size, num_spam, num_nonspam, last_updated); } total_tokens++; good = 2 * num_nonspam; bad = num_spam; good = good / total_nonspam; if (good > 1.0) good = 1.0; bad = bad / total_spam; if (bad > 1.0) bad = 1.0; if (num_nonspam + num_spam < 4) { prob_spam = 0.5; } else if ((good < 0.00001) && (bad < 0.00001)) { prob_spam = 0.5; } else if (2 * num_nonspam + num_spam > 5) { prob_spam = bad / (good + bad); if (prob_spam > 0.9999) { prob_spam = 0.9999; } else if (prob_spam < 0.0001) { prob_spam = 0.0001; } } else { prob_spam = 1.5; } if ((prob_spam >= 0.48 && prob_spam <= 0.52) && (num_to_remove < opts->prune_max) ) { /* * Add this token to the list to delete afterwards */ num_to_remove++; if (num_to_remove > to_remove_alloced) { to_remove_alloced = num_to_remove + 10000; ptr = realloc(to_remove, /* RATS: ignore */ to_remove_alloced * sizeof(qdb_datum)); if (ptr == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _ ("memory allocation failed"), strerror(errno)); return 1; } to_remove = ptr; } to_remove[num_to_remove - 1].size = key.size; to_remove[num_to_remove - 1].data = malloc(key.size); if (to_remove[num_to_remove - 1].data == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("memory allocation failed"), strerror(errno)); return 1; } memcpy(to_remove[num_to_remove - 1].data, key.data, key.size); } nextkey = qdb_nextkey(opts->dbw, key); free(key.data); key = nextkey; } if (opts->showprune) { printf(" %ld/%ld [%3.2f%%]", num_to_remove, total_tokens, total_tokens > 0 ? 100.0 * (double) num_to_remove / (double) total_tokens : 0); } /* * Now we remove any keys in the remove list. */ if (num_to_remove > 0) { for (i = 0; i < num_to_remove; i++) { if (opts->showprune) { tick(); } qdb_delete(opts->dbw, to_remove[i]); free(to_remove[i].data); } if (to_remove != NULL) free(to_remove); } if (opts->showprune) { printf(" %s\n", _("removed")); } return 0; } /* * Prune the currently writable database, removing redundant entries and * scaling down token and message counts if they get too large. Returns * nonzero on error. * * This is the version for old-style databases that don't use token aging. */ static int spam_db_prune_old(opts_t opts) { qdb_datum key, val, nextkey; long total_spam, total_nonspam, total_updates, max_spam, max_nonspam; long num_spam, num_nonspam, last_updated; double avg_spam, avg_nonspam, top_count, scale_by; if (opts->dbw == NULL) { if (opts->showprune) { fprintf(stderr, "%s: %s\n", opts->program_name, _ ("pruning requires write access to the database")); } return 1; } setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); key.data = (unsigned char *) " SINCEPRUNE"; key.size = 11; spam_store(opts, (char *) (key.data), key.size, 0, 0, 0); total_spam = 0; total_nonspam = 0; total_updates = 0; key.data = (unsigned char *) " COUNTS"; key.size = 7; val = qdb_fetch(opts->dbw, key); if (val.data != NULL) { total_spam = ((long *) (val.data))[0]; total_nonspam = ((long *) (val.data))[1]; if (val.size > 2 * sizeof(long)) total_updates = ((long *) (val.data))[2]; free(val.data); val.data = NULL; } if (total_spam < 1) total_spam = 1; if (total_nonspam < 1) total_nonspam = 1; /* * Scan through all tokens in the database and get the highest * counts for spam and non-spam. */ if (opts->showprune) { printf("%s", _("Checking average token counts...")); } avg_spam = spam_db_prune_old__maxcount(opts, &max_spam, SPAM); avg_nonspam = spam_db_prune_old__maxcount(opts, &max_nonspam, NONSPAM); if (avg_spam < 1) avg_spam = 1; if (avg_nonspam < 1) avg_nonspam = 1; if (opts->showprune) { printf(" %f %f\n", avg_spam, avg_nonspam); } /* * Scan through all tokens in the database looking for those that * have a spam probability of somewhere around the middle or whose * counts are very tiny compared to the total spam and nonspam * counts, and remove them. */ if (opts->showprune) { printf("%s", _("Scanning for removable tokens...")); } if (spam_db_prune_old__strip(opts)) return 1; /* * Next, we scan through the database and scale down all of the * counts, and also scale down the total counts by the same amount. * This helps new additions to the database to actually make an * impact later on. */ top_count = (avg_spam < avg_nonspam ? avg_spam : avg_nonspam); scale_by = top_count / 1000.0; if (scale_by < 1.9) { /* Not worth scaling - just return */ return 0; } if (opts->showprune) { printf( /* RATS: ignore */ _ ("Scaling down token counts by a factor of %f (max: %f)..."), scale_by, top_count); } key = qdb_firstkey(opts->dbw); while (key.data != NULL) { if (opts->showprune) { tick(); } val.data = NULL; if (key.data[0] != '?') { val = qdb_fetch(opts->dbw, key); } if (val.data == NULL) { nextkey = qdb_nextkey(opts->dbw, key); free(key.data); key = nextkey; continue; } num_spam = ((long *) (val.data))[0]; num_nonspam = ((long *) (val.data))[1]; last_updated = 0; if (val.size > 2 * sizeof(long)) last_updated = ((long *) (val.data))[2]; free(val.data); spam_store(opts, (char *) (key.data), key.size, (long) (((double) num_spam) / scale_by), (long) (((double) num_nonspam) / scale_by), last_updated); nextkey = qdb_nextkey(opts->dbw, key); free(key.data); key = nextkey; } if (opts->showprune) { printf(" %s\n", _("done")); } /* * Now we go through the database again and strip out removable * tokens a final time. */ if (opts->showprune) { printf("%s", _("Secondary scan for removable tokens...")); } return spam_db_prune_old__strip(opts); } /* * Prune the currently writable database, removing redundant and old * entries. Returns nonzero on error. */ int spam_db_prune(opts_t opts) { qdb_datum key, val, nextkey; long total_updates, num_spam, num_nonspam, last_updated; qdb_datum *to_remove = NULL; qdb_datum *ptr; long num_to_remove = 0; long to_remove_alloced = 0; long total_tokens = 0; if (opts->dbw == NULL) { if (opts->showprune) { fprintf(stderr, "%s: %s\n", opts->program_name, _ ("pruning requires write access to the database")); } return 1; } total_updates = -1; key.data = (unsigned char *) " COUNTS"; key.size = 7; val = qdb_fetch(opts->dbw, key); if (val.data != NULL) { if (val.size > 2 * sizeof(long)) total_updates = ((long *) (val.data))[2]; free(val.data); val.data = NULL; } setvbuf(stdin, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0); if (total_updates < 0) return spam_db_prune_old(opts); key.data = (unsigned char *) " SINCEPRUNE"; key.size = 11; spam_store(opts, (char *) (key.data), key.size, 0, 0, 0); /* * Scan through all tokens in the database and make a list of the * ones we're going to delete. These will be ones which are too old * or insignificant to be of use; "insignificant" means that the * contribution to the overall spam score of a message will be too * small, and the threshold for "too small" moves according to how * long ago the token was last updated. */ if (opts->showprune) { printf("%s", _("Scanning for removable tokens...")); } key = qdb_firstkey(opts->dbw); while (key.data != NULL) { double good, bad, prob_spam, significance, threshold, age, agescale; if (opts->showprune) { tick(); } val.data = NULL; /* * Ignore global counters and allow-list entries - they are * never pruned. */ if ((key.data[0] != '?') && (key.data[0] != ' ')) { val = qdb_fetch(opts->dbw, key); } if (val.data == NULL) { nextkey = qdb_nextkey(opts->dbw, key); free(key.data); key = nextkey; continue; } total_tokens++; num_spam = ((long *) (val.data))[0]; num_nonspam = ((long *) (val.data))[1]; last_updated = 0; if (val.size > 2 * sizeof(long)) last_updated = ((long *) (val.data))[2]; free(val.data); good = num_nonspam; bad = num_spam; age = total_updates - last_updated; if (age < 1) age = 1; agescale = log(1.0 + (age / 10)); if (((good + bad) / agescale) < 1.0) { /* * Throw away tokens with very small counts - the * older the token, the larger the counts must be * for the token to be kept. */ prob_spam = 0.5; } else { prob_spam = bad / (good + bad); } significance = fabs(0.5 - prob_spam); /* * The threshold of significance: if the probability of * being spam is at or further than this from even (0.5), * then the token is worth keeping. */ threshold = 0.019; #ifdef DEBUG_THRESHOLD fprintf(stderr, "%s %ld %ld %ld %g %g\n", significance < threshold ? "***" : " ", num_nonspam, num_spam, (long) age, significance, (good + bad) / agescale); #endif if ((significance < threshold) && (num_to_remove < opts->prune_max)) { #ifdef DEBUG_DISCARD fprintf(stderr, "%ld %ld %ld %g %g\n", num_nonspam, num_spam, (long) age, significance, (good + bad) / agescale); #endif /* * Token is too insignificant to keep - mark it to * be discarded. */ num_to_remove++; if (num_to_remove > to_remove_alloced) { to_remove_alloced = num_to_remove + 10000; ptr = realloc(to_remove, /* RATS: ignore */ to_remove_alloced * sizeof(qdb_datum)); if (ptr == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _ ("memory allocation failed"), strerror(errno)); return 1; } to_remove = ptr; } to_remove[num_to_remove - 1].size = key.size; to_remove[num_to_remove - 1].data = malloc(key.size); if (to_remove[num_to_remove - 1].data == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("memory allocation failed"), strerror(errno)); return 1; } memcpy(to_remove[num_to_remove - 1].data, key.data, key.size); } nextkey = qdb_nextkey(opts->dbw, key); free(key.data); key = nextkey; } if (opts->showprune) { printf(" %ld/%ld [%3.2f%%]", num_to_remove, total_tokens, total_tokens > 0 ? 100.0 * (double) num_to_remove / (double) total_tokens : 0); } /* * Now we remove any keys in the remove list. */ if (num_to_remove > 0) { long i; for (i = 0; i < num_to_remove; i++) { if (opts->showprune) { tick(); } if (qdb_delete(opts->dbw, to_remove[i])) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("token deletion failed"), qdb_error()); } free(to_remove[i].data); } if (to_remove != NULL) free(to_remove); } if (opts->showprune) { printf(" %s\n", _("removed")); } return 0; } /* EOF */ qsf-1.2.7/src/spam/spami.h0000644000076400007640000000563610554714216013152 0ustar awaw/* * Internal spam handling prototypes, structures, and constants. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #ifndef _SPAMI_H #define _SPAMI_H 1 #ifndef _OPTIONS_H #include "options.h" #endif #ifndef _MESSAGE_H #include "message.h" #endif #ifndef _DATABASE_H #include "database.h" #endif #ifndef _SPAM_H #include "spam.h" #endif #ifdef __cplusplus extern "C" { #endif struct token_s; typedef struct token_s *token_t; struct spam_s; typedef struct spam_s *spam_t; struct spam_s { /* structure describing spam state */ qdb_t db1; /* first database to read from */ qdb_t db2; /* second database to read from */ qdb_t db3; /* third database to read from */ qdb_t dbw; /* writable database handle */ int db1weight; /* weighting for first database */ int db2weight; /* weighting for second database */ int db3weight; /* weighting for third database */ int override; /* if non-zero, override spam_check() */ token_t tokens; /* start of token tree */ long token_count; /* number of different tokens */ token_t *tarray; /* token tree arranged as an array */ double robx; /* Robinson "x" value */ long total_spam; /* total spam messages seen */ long total_nonspam; /* total non-spam messages seen */ long since_prune; /* number of updates since last db prune */ long update_count; /* counter, increases every update */ long _idx; /* index used when filling array */ }; struct token_s { /* structure describing an email token */ char *token; /* pointer to token start */ int length; /* length of token */ long count; /* number of times token seen */ long num_spam; /* times token seen in spam */ long num_nonspam; /* times token seen in non-spam */ long last_updated; /* update_count at last update */ double prob_spam; /* probability this token is spammy */ token_t higher; /* pointer to token nearer "Z" */ token_t lower; /* pointer to token nearer "A" */ token_t longer; /* pointer to longer token */ }; void spam_token_add(opts_t, spam_t, char *, int); spam_t spam_tokenise(opts_t, msg_t, qdb_t, qdb_t, qdb_t, int, int, int); void spam_free(spam_t); void spam_fetch(spam_t, char *, int, long *, long *, long *); void spam_store(opts_t, char *, int, long, long, long); void spam_dbunlock(opts_t); void spam_dbrelock(opts_t); unsigned char *spam_checksum(char *, int); int spam_allowlist_match(spam_t, char *); void spam_allowlist_add(opts_t, char *); void spam_allowlist_remove(opts_t, char *); int spam_denylist_match(spam_t, char *); void spam_denylist_add(opts_t, char *); void spam_denylist_remove(opts_t, char *); int spam_test(opts_t, spam_t, msg_t); #ifdef __cplusplus } #endif #endif /* _SPAMI_H */ /* EOF */ qsf-1.2.7/src/spam/allowlist.c0000644000076400007640000001545410664772304014051 0ustar awaw/* * Functions dealing with the allow-list and the deny-list. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "spami.h" #include "log.h" #include #include #include #include /* * Return a malloc()ed pointer to a null-terminated string which is the * database key for the given allow-list or deny-list email address. */ static char *spam_allowlist__token(char *address, int denylist) { unsigned char *ptr; if (address == NULL) return NULL; ptr = spam_checksum(address, strlen(address)); if (ptr != NULL) { if (denylist) { ptr[0] = '\\'; } else { ptr[0] = '?'; } } return (char *) ptr; } /* * The same as spam_allowlist__token, but converts a copy of the address to * lower case first. */ static char *spam_allowlist__lctoken(char *address, int denylist) { char *addrcopy; char *key; int i; addrcopy = strdup(address); if (addrcopy == NULL) return NULL; for (i = 0; addrcopy[i] != 0; i++) { if (addrcopy[i] >= 'A' && addrcopy[i] <= 'Z') addrcopy[i] += 32; } key = spam_allowlist__token(addrcopy, denylist); free(addrcopy); return key; } /* * Look up the given email address in the allow-list or the deny-list, * returning 1 if it is present, 0 if not. First the address is checked in * lowercase, then as-is. */ static int spam_allowlist__domatch(spam_t spam, int denylist, char *address) { char *key; long a, b, c; if (spam == NULL) return 0; if (address == NULL) return 0; key = spam_allowlist__lctoken(address, denylist); if (key != NULL) { a = 0; b = 0; c = 0; spam_fetch(spam, key, strlen(key), &a, &b, &c); free(key); if (a > 0) { log_add(2, denylist ? _("deny-list match: %s") : _("allow-list match: %s"), address); return 1; } } key = spam_allowlist__token(address, denylist); if (key != NULL) { a = 0; b = 0; c = 0; spam_fetch(spam, key, strlen(key), &a, &b, &c); free(key); if (a > 0) { log_add(2, denylist ? _("deny-list match: %s") : _("allow-list match: %s"), address); return 1; } } return 0; } /* * Add the given email address to the allow-list or the deny-list. It is * converted to lower case before being stored. */ static void spam_allowlist__doadd(opts_t opts, int denylist, char *address) { char *key; if (opts == NULL) return; if (address == NULL) return; key = spam_allowlist__lctoken(address, denylist); if (key == NULL) return; spam_store(opts, key, strlen(key), 1, 1, 0); if (opts->plainmap) { spam_plaintext_update(opts, key, strlen(key), address, strlen(address)); } free(key); } /* * Remove the given email address from the allow-list or the deny-list. Both * as-is and lower-case versions of the address will be removed. */ static void spam_allowlist__doremove(opts_t opts, int denylist, char *address) { char *key; qdb_datum qkey; if (opts == NULL) return; if (opts->dbw == NULL) return; if (address == NULL) return; key = spam_allowlist__token(address, denylist); if (key != NULL) { qkey.data = (unsigned char *) key; qkey.size = strlen(key); qdb_delete(opts->dbw, qkey); free(key); } key = spam_allowlist__lctoken(address, denylist); if (key != NULL) { qkey.data = (unsigned char *) key; qkey.size = strlen(key); qdb_delete(opts->dbw, qkey); free(key); } } /* * Look up the given email address in the allow-list, returning 1 if it is * present, 0 if not. First the address is checked in lowercase, then as-is. */ int spam_allowlist_match(spam_t spam, char *address) { return spam_allowlist__domatch(spam, 0, address); } /* * Add the given email address to the allow-list. It is converted to lower * case before being stored. */ void spam_allowlist_add(opts_t opts, char *address) { spam_allowlist__doadd(opts, 0, address); } /* * Remove the given email address from the allow-list. Both as-is and * lower-case versions of the address will be removed. */ void spam_allowlist_remove(opts_t opts, char *address) { spam_allowlist__doremove(opts, 0, address); } /* * Manage the allow-list manually (-e). */ int spam_allowlist_manage(opts_t opts) { int inlist; spam_t spam; if (opts->action == ACTION_MARK_SPAM) { spam_allowlist_remove(opts, opts->emailonly); spam_allowlist_remove(opts, opts->emailonly2); return 0; } else if (opts->action == ACTION_MARK_NONSPAM) { spam_allowlist_add(opts, opts->emailonly); spam_allowlist_add(opts, opts->emailonly2); return 0; } spam = calloc(1, sizeof(*spam)); if (spam == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("calloc failed"), strerror(errno)); return 1; } spam->db1 = opts->dbr1; spam->db2 = opts->dbr2; spam->db3 = opts->dbr3; spam->dbw = opts->dbw; spam->db1weight = 1; spam->db2weight = 1; spam->db3weight = 1; inlist = spam_allowlist_match(spam, opts->emailonly); if (!inlist) inlist = spam_allowlist_match(spam, opts->emailonly2); free(spam); if (inlist) { if (opts->no_filter) return 0; printf("YES\n"); } else { if (opts->no_filter) return 1; printf("NO\n"); } return 0; } /* * Look up the given email address in the deny-list, returning 1 if it is * present, 0 if not. First the address is checked in lowercase, then as-is. */ int spam_denylist_match(spam_t spam, char *address) { return spam_allowlist__domatch(spam, 1, address); } /* * Add the given email address to the deny-list. It is converted to lower * case before being stored. */ void spam_denylist_add(opts_t opts, char *address) { spam_allowlist__doadd(opts, 1, address); } /* * Remove the given email address from the deny-list. Both as-is and * lower-case versions of the address will be removed. */ void spam_denylist_remove(opts_t opts, char *address) { spam_allowlist__doremove(opts, 1, address); } /* * Manage the deny-list manually (-e). */ int spam_denylist_manage(opts_t opts) { int inlist; spam_t spam; if (opts->action == ACTION_MARK_NONSPAM) { spam_denylist_remove(opts, opts->emailonly); spam_denylist_remove(opts, opts->emailonly2); return 0; } else if (opts->action == ACTION_MARK_SPAM) { spam_denylist_add(opts, opts->emailonly); spam_denylist_add(opts, opts->emailonly2); return 0; } spam = calloc(1, sizeof(*spam)); if (spam == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("calloc failed"), strerror(errno)); return 1; } spam->db1 = opts->dbr1; spam->db2 = opts->dbr2; spam->db3 = opts->dbr3; spam->dbw = opts->dbw; spam->db1weight = 1; spam->db2weight = 1; spam->db3weight = 1; inlist = spam_denylist_match(spam, opts->emailonly); if (!inlist) inlist = spam_denylist_match(spam, opts->emailonly2); free(spam); if (inlist) { if (opts->no_filter) return 0; printf("YES\n"); } else { if (opts->no_filter) return 1; printf("NO\n"); } return 0; } /* EOF */ qsf-1.2.7/src/message/0000755000076400007640000000000010665021416012336 5ustar awawqsf-1.2.7/src/message/parse.c0000644000076400007640000004501010664772304013624 0ustar awaw/* * Functions for parsing and handling mail messages. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "message.h" #include "md5.h" #include #include #include #include extern char *minimemmem(char *, long, char *, long); /* * Replace the existing msg->sender, if there is one, with a malloc()ed * string containing the email address part of the given "From:" header * line. * * Note that we don't follow the RFC here, we just look for the last @ and * work backwards and forwards from there, since that will catch the vast * majority of cases and is simplest. */ static void msg_parse__fromhdr(opts_t opts, msg_t msg, char *line, long size) { long i, a, b; char *ptr; for (i = size - 1; i > 0 && line[i] != '@'; i--) { } if (line[i] != '@') return; for (a = i; a > 0 && line[a] != '<' && line[a] > 32; a--) { } if ((line[a] == '<') || (line[a] <= 32)) a++; for (b = i; b < size && line[b] != '>' && line[b] > 32; b++) { } if ((line[b] == '>') || (line[b] <= 32)) b--; if (b < (a + 2)) return; ptr = calloc(1, 2 + b - a); if (ptr == NULL) return; strncpy(ptr, line + a, 1 + b - a); if (msg->sender) free(msg->sender); msg->sender = ptr; } /* * Replace the existing msg->envsender, if there is one, with a malloc()ed * string containing the email address part of the given "Return-Path:" * header line. This works the same way as msg_parse__fromhdr() above. */ static void msg_parse__returnpathhdr(opts_t opts, msg_t msg, char *line, long size) { long i, a, b; char *ptr; for (i = size - 1; i > 0 && line[i] != '@'; i--) { } if (line[i] != '@') return; for (a = i; a > 0 && line[a] != '<' && line[a] > 32; a--) { } if ((line[a] == '<') || (line[a] <= 32)) a++; for (b = i; b < size && line[b] != '>' && line[b] > 32; b++) { } if ((line[b] == '>') || (line[b] <= 32)) b--; if (b < (a + 2)) return; ptr = calloc(1, 2 + b - a); if (ptr == NULL) return; strncpy(ptr, line + a, 1 + b - a); if (msg->envsender) free(msg->envsender); msg->envsender = ptr; } /* * Parse a single message header, updating internal state as appropriate. * Returns nonzero on error. */ static int msg_parse__header(opts_t opts, msg_t msg) { long start, end, boundstart; char *newptr; /* * Find end of this header line (even if split over * two lines) */ start = msg->_pos; end = msg->_pos; while ((end < msg->original_size) && (msg->original[end] != '\n')) { end++; if (msg->original[end] == '\n' && (msg->original[end + 1] == ' ' || msg->original[end + 1] == '\t')) { end++; } } if ((start == end) || (end == (1 + start) && msg->original[start] == '\r') ) { /* * Empty line - end of headers */ msg->_in_header--; } else if (strncasecmp(msg->original + msg->_pos, "Content-Type:", 13) == 0) { /* * Content-Type header - look for type, and * find boundary= and add a known boundary * if we find one */ msg->_pos += 13; while ((msg->original[msg->_pos] == ' ' || msg->original[msg->_pos] == '\t' || msg->original[msg->_pos] == '\r' || msg->original[msg->_pos] == '\n') && msg->_pos < end) { msg->_pos++; } msg->_nottext = 1; if (strncasecmp(msg->original + msg->_pos, "text/", 5) == 0) { msg->_nottext = 0; } else if (strncasecmp(msg->original + msg->_pos, "image/", 6) == 0) { msg->num_images++; } else if (strncasecmp (msg->original + msg->_pos, "message/", 8) == 0) { /* * Handle message/ types by allowing a blank line * and then continuing to parse header lines, so * that attached messages with inline parts can be * processed properly. */ msg->_in_header = 2; msg->_nottext = 0; } while (((msg->original[msg->_pos] & 0x60) != 'B') && (msg->_pos < end) && (strncasecmp(msg->original + msg->_pos, "boundary=", 9) != 0)) { msg->_pos++; } if ((strncasecmp(msg->original + msg->_pos, "boundary=", 9) == 0) && (msg->_bdepth < 8)) { msg->_pos += 9; if (msg->original[msg->_pos] == '"') { msg->_pos++; boundstart = msg->_pos; while ((msg->original[msg->_pos] != '"') && (msg->_pos < end)) msg->_pos++; } else { boundstart = msg->_pos; while ((msg->original[msg->_pos] != ';') && msg->original[msg->_pos] != ' ' && msg->original[msg->_pos] != '\t' && msg->original[msg->_pos] != '\r' && (msg->_pos < end)) msg->_pos++; } newptr = malloc(4 + msg->_pos - boundstart); if (newptr == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("malloc failed"), strerror(errno)); return 1; } memcpy(newptr, "\n--", 3); strncpy(newptr + 3, msg->original + boundstart, msg->_pos - boundstart); newptr[3 + msg->_pos - boundstart] = 0; if (msg->_bound[msg->_bdepth] != NULL) free(msg->_bound[msg->_bdepth]); msg->_bound[msg->_bdepth] = newptr; msg->_bdepth++; } } else if (strncasecmp(msg->original + msg->_pos, "Content-Transfer-Encoding:", 26) == 0) { /* * Content-Transfer-Encoding header - change * encoding method to expect */ msg->_pos += 26; while (msg->_pos < end && (msg->original[msg->_pos] == ' ' || msg->original[msg->_pos] == '\t' || msg->original[msg->_pos] == '\r' || msg->original[msg->_pos] == '\n')) msg->_pos++; if (strncasecmp(msg->original + msg->_pos, "Base64", 6) == 0) { msg->_encoding = 2; } else if (strncasecmp(msg->original + msg->_pos, "Quoted-Printable", 16) == 0) { msg->_encoding = 1; } else { msg->_encoding = 0; } } else if ((strncasecmp(msg->original + msg->_pos, "Subject:", 8) == 0) || (strncasecmp(msg->original + msg->_pos, "From:", 5) == 0) || (strncasecmp(msg->original + msg->_pos, "Return-Path:", 12) == 0) || (strncasecmp(msg->original + msg->_pos, "Sender:", 7) == 0) || (strncasecmp(msg->original + msg->_pos, "To:", 3) == 0) || (strncasecmp(msg->original + msg->_pos, "Reply-To:", 9) == 0)) { char *decoded; long decodedlen; /* * Add various headers to the message * content */ if (strncasecmp(msg->original + msg->_pos, "Subject: [SPAM]", 15) == 0) { msg->_pos += 15; } else if (strncasecmp(msg->original + msg->_pos, "From:", 5) == 0) { /* * If it's a From: header, look for an email address * and put it in msg->sender for later possible use */ msg_parse__fromhdr(opts, msg, msg->original + msg->_pos, end + 1 - msg->_pos); } else if (strncasecmp (msg->original + msg->_pos, "Return-Path:", 12) == 0) { /* * Also store email address of envelope sender */ msg_parse__returnpathhdr(opts, msg, msg->original + msg->_pos, end + 1 - msg->_pos); } /* * Decode RFC2047-encoded headers. */ decodedlen = end + 1 - msg->_pos; decoded = msg_decode_rfc2047(msg->original + msg->_pos, &decodedlen); if (msg_addcontent(opts, msg, decoded, decodedlen)) return 1; free(decoded); } msg->_pos = end + 1; return 0; } /* * Decode the message up to the next boundary and, if it is textual, add its * contents to msg->content. Returns nonzero on error. */ static int msg_parse__content(opts_t opts, msg_t msg) { struct MD5Context md5c; unsigned char digest[16]; /* RATS: ignore (checked all) */ char digeststr[64]; /* RATS: ignore (large enough) */ char *newptr; char *data; char *content; long boundstart; /* start of message part being decoded */ long partsize; /* size of message part being decoded */ int i, n; boundstart = msg->_pos; partsize = msg->original_size - boundstart; msg->_pos = msg->original_size; /* * Look for the next boundary */ for (i = msg->_bdepth - 1; i >= 0; i--) { if (msg->_bound[i] == NULL) continue; newptr = minimemmem(msg->original + boundstart - 1, partsize, msg->_bound[i], strlen(msg->_bound[i])); if (newptr == NULL) continue; msg->_pos = newptr - msg->original; partsize = msg->_pos - boundstart; /* * Move new position to after the boundary marker */ msg->_pos += strlen(msg->_bound[i]); while ((msg->_pos < msg->original_size) && (msg->original[msg->_pos] == '\r' || msg->original[msg->_pos] == '\n') ) msg->_pos++; /* * Set nesting depth, and we now scan headers */ msg->_bdepth = i + 1; msg->_in_header = 1; i = -1; } if (partsize < 1 || partsize > 409600) { if (msg->_in_header) { msg->_nottext = 0; msg->_encoding = 0; } return 0; } switch (msg->_encoding) { case 1: data = msg_from_qp(msg->original + boundstart, &partsize); break; case 2: data = msg_from_base64(msg->original + boundstart, &partsize); break; default: data = NULL; break; } content = data; if (content == NULL) content = msg->original + boundstart; if (msg->_nottext) { MD5Init(&md5c); MD5Update(&md5c, (unsigned char *) content, partsize); MD5Final(digest, &md5c); memcpy(digeststr, " z", 2); for (n = 0; n < 16; n++) { #ifdef HAVE_SNPRINTF snprintf(digeststr + 2 + 2 * n, sizeof(digeststr) - 2 - 2 * n, #else sprintf(digeststr + 2 + 2 * n, /* RATS: ignore */ #endif "%02X", digest[n]); } memcpy(digeststr + strlen(digeststr), "z \000", 3); if (msg_addcontent (opts, msg, digeststr, strlen(digeststr))) return 1; } else { if (msg_addcontent(opts, msg, content, partsize)) return 1; } if (data) free(data); if (msg->_in_header) { msg->_nottext = 0; msg->_encoding = 0; } return 0; } /* * Make a copy of the message content in msg->textcontent and strip all HTML * tags from it. Only HTML tags that start with an alphabetic character or / * are stripped, but only if the part within the <> is under 500 characters, * and all HTML comments are stripped from the inclusive. * * Returns nonzero on error. */ static int msg_parse__striphtml(opts_t opts, msg_t msg) { long rpos, wpos, i; int in_tag, in_comment, ch; char *ptr; static struct { char *string; int ch; } entities[] = { { "&", '&'}, { ">", '>'}, { "<", '<'}, { """, '"'}, { " ", ' '}, { "¡", '!'}, { "¢", 'c'}, { "£", '£'}, { "¤", '#'}, { "¥", 'Y'}, { "¦", '|'}, { "§", ' '}, { "¨", ':'}, { "©", 'C'}, { "ª", ' '}, { "«", '"'}, { "¬", '!'}, { "­", '-'}, { "®", 'R'}, { "¯", ' '}, { "°", ' '}, { "±", ' '}, { "²", '2'}, { "³", '3'}, { "´", '\''}, { "µ", 'u'}, { "¶", 'P'}, { "·", '.'}, { "¸", ' '}, { "¹", '1'}, { "º", ' '}, { "»", '"'}, { "¼", ' '}, { "½", ' '}, { "¾", ' '}, { "¿", '?'}, { "À", 'A'}, { "Á", 'A'}, { "Â", 'A'}, { "Ã", 'A'}, { "Ä", 'A'}, { "Å", 'A'}, { "Æ", 'A'}, { "Ç", 'C'}, { "È", 'E'}, { "É", 'E'}, { "Ê", 'E'}, { "Ë", 'E'}, { "Ì", 'I'}, { "Í", 'I'}, { "Î", 'I'}, { "Ï", 'I'}, { "Ð", 'E'}, { "Ñ", 'N'}, { "Ò", 'O'}, { "Ó", 'O'}, { "Ô", 'O'}, { "Õ", 'O'}, { "Ö", 'O'}, { "×", 'x'}, { "Ø", 'O'}, { "Ù", 'U'}, { "Ú", 'U'}, { "Û", 'U'}, { "Ü", 'U'}, { "Ý", 'Y'}, { "Þ", 'T'}, { "ß", 's'}, { "à", 'a'}, { "á", 'a'}, { "â", 'a'}, { "ã", 'a'}, { "ä", 'a'}, { "å", 'a'}, { "æ", 'a'}, { "ç", 'c'}, { "è", 'e'}, { "é", 'e'}, { "ê", 'e'}, { "ë", 'e'}, { "ì", 'i'}, { "í", 'i'}, { "î", 'i'}, { "ï", 'i'}, { "ð", 'e'}, { "ñ", 'n'}, { "ò", 'o'}, { "ó", 'o'}, { "ô", 'o'}, { "õ", 'o'}, { "ö", 'o'}, { "÷", '/'}, { "ø", 'o'}, { "ù", 'u'}, { "ú", 'u'}, { "û", 'u'}, { "ü", 'u'}, { "ý", 'y'}, { "þ", 't'}, { "ÿ", 'y'}, { 0, 0} }; if (msg->content_size < 1) return 0; msg->textcontent = malloc(msg->content_size); if (msg->textcontent == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("calloc failed"), strerror(errno)); return 1; } msg->text_size = 0; for (rpos = 0, wpos = 0, in_tag = 0, in_comment = 0; rpos < msg->content_size; rpos++) { if ((in_tag) && (msg->content[rpos] == '>') ) { in_tag = 0; continue; } if ((in_comment) && (rpos < (msg->content_size - 3)) && (strncmp(msg->content + rpos, "-->", 3) == 0) ) { in_comment = 0; rpos += 2; continue; } if (in_tag || in_comment) continue; if ((rpos < (msg->content_size - 8)) && (msg->content[rpos] == '&') && (msg->content[rpos + 1] != '#') ) { for (i = 0; entities[i].string; i++) { if (strncmp (msg->content + rpos, entities[i].string, strlen(entities[i].string)) == 0) { msg->textcontent[wpos] = entities[i].ch; rpos += strlen(entities[i].string) - 1; wpos++; msg->text_size = wpos; break; } } if (entities[i].string) continue; } if ((msg->content[rpos] == '&') && (rpos < (msg->content_size - 6)) && (msg->content[rpos + 1] == '#') ) { ch = 0; for (i = 2; (rpos + i < msg->content_size) && (msg->content[rpos + i] >= '0') && (msg->content[rpos + i] <= '9'); i++) { ch = ch * 10; ch += (msg->content[rpos + i] - '0'); } if ((rpos + i < msg->content_size) && (msg->content[rpos + i] == ';') && (ch > 0) ) { msg->textcontent[wpos] = ch; wpos++; rpos += i + 1; msg->text_size = wpos; continue; } } if ((msg->content[rpos] == '<') && (rpos < (msg->content_size - 1)) && (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "/", msg->content[rpos + 1])) && (memchr(msg->content + rpos, '>', msg->content_size - rpos)) && ((char *) memchr(msg->content + rpos, '>', msg->content_size - rpos) - (msg->content + rpos) < 500) ) { in_tag = 1; continue; } if ((msg->content[rpos] == '<') && (rpos < (msg->content_size - 5)) && (msg->content[rpos + 1] == '!') && (msg->content[rpos + 2] == '-') && (msg->content[rpos + 3] == '-') ) { in_comment = 1; continue; } msg->textcontent[wpos] = msg->content[rpos]; wpos++; msg->text_size = wpos; } ptr = realloc(msg->textcontent, /* RATS: ignore (not sensitive) */ msg->text_size); if (ptr != NULL) msg->textcontent = ptr; return 0; } /* * Trim the whitespace from msg->textcontent, such that long runs of \r, * space, tab, \n, etc get truncated to a single space. * * Also fill in the wordpos[] and wordlength[] arrays, and count the number * of words. */ static void msg_parse__trimwhitespace(opts_t opts, msg_t msg) { long rpos, wpos, words_alloced; int prevws; char *ptr; msg->num_words = 0; words_alloced = 10000; msg->wordpos = calloc(words_alloced, sizeof(long)); msg->wordlength = calloc(words_alloced, sizeof(int)); for (rpos = 0, wpos = 0, prevws = 0; rpos < msg->text_size; rpos++) { if ((msg->textcontent[rpos] == ' ') || (msg->textcontent[rpos] == '\r') || (msg->textcontent[rpos] == '\n') || (msg->textcontent[rpos] == '\t') ) { if (prevws) continue; prevws = 1; msg->textcontent[wpos++] = ' '; if (msg->num_words > 0) { msg->wordlength[msg->num_words - 1] = (wpos - 1) - msg->wordpos[msg->num_words - 1]; } continue; } /* * Non-whitespace. If it follows whitespace, or is the first * character, add it to the word list. */ if ((wpos == 0) || (prevws)) { /* * First, make sure there's room in the array; if * not, extend the array. */ if (msg->num_words >= words_alloced - 1) { long *newwordpos; int *newwordlength; words_alloced += 10000; newwordpos = realloc(msg->wordpos, /* RATS: ignore */ words_alloced * sizeof(long)); if (newwordpos != NULL) { msg->wordpos = newwordpos; newwordlength = realloc(msg->wordlength, /* RATS: ignore */ words_alloced * sizeof (int)); if (newwordlength != NULL) { msg->wordlength = newwordlength; } else { words_alloced -= 10000; } } else { words_alloced -= 10000; } } /* * Next, assuming the array can hold another entry * (the above extension could have failed), add the * word to the list. The word's default length is * set to the size of the remaining buffer. */ if (msg->num_words < words_alloced - 1) { msg->wordpos[msg->num_words] = wpos; msg->wordlength[msg->num_words] = msg->text_size - rpos; msg->num_words++; } } prevws = 0; msg->textcontent[wpos++] = msg->textcontent[rpos]; } msg->text_size = wpos; ptr = realloc(msg->textcontent, /* RATS: ignore (not sensitive) */ msg->text_size); if (ptr != NULL) msg->textcontent = ptr; return; } /* * Parse a message on standard input, and return an allocated msg_t, or NULL * on error. If the message cannot be parsed, eg if it is too big, the * "content" field will remain NULL but "original" will be allocated and * will contain the entirety of the message read so far. */ msg_t msg_parse(opts_t opts) { msg_t msg; msg = msg_alloc(opts); if (msg == NULL) return NULL; /* * Read message into memory */ if (msg_read(opts, msg)) return msg; /* * Store original message headers */ if (msg_headers_store(opts, msg)) return msg; msg->_in_header = 1; msg->_pos = 0; /* * Scan through the message, finding Content-Type and * Content-Transfer-Encoding headers to get message boundaries, and * split the body in these boundaries (and then scan each part's * headers, if any, for more boundaries and content types and so * on); selected headers are added to msg->content, as are all * textual parts of the message body (after decoding). */ while (msg->_pos < msg->original_size) { if (msg->_in_header > 0) { if (msg_parse__header(opts, msg)) return msg; } else { if (msg_parse__content(opts, msg)) return msg; } } msg_parse__striphtml(opts, msg); msg_parse__trimwhitespace(opts, msg); return msg; } /* EOF */ qsf-1.2.7/src/message/alloc.c0000644000076400007640000000371210664772304013607 0ustar awaw/* * Functions for allocating and freeing memory. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "message.h" #include #include #include #include /* * Add the content of the given length to the "content" field of the message. * * Returns nonzero on error. */ int msg_addcontent(opts_t opts, msg_t msg, char *data, long size) { char *newptr; if ((msg->content_size + size + 16) > msg->content_alloced) { newptr = realloc(msg->content, /* RATS: ignore */ msg->content_alloced + size + 8192); if (newptr == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("realloc failed"), strerror(errno)); return 1; } msg->content = newptr; msg->content_alloced += size + 8192; } memcpy(msg->content + msg->content_size, data, size); msg->content[msg->content_size + size] = 0; msg->content_size += size; return 0; } /* * Allocate a new msg_t and return it, or NULL on error. */ msg_t msg_alloc(opts_t opts) { msg_t msg; msg = calloc(1, sizeof(*msg)); if (msg == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("calloc failed"), strerror(errno)); return NULL; } return msg; } /* * Free the memory a message takes up. */ void msg_free(msg_t msg) { int i; if (msg == NULL) return; if (msg->original != NULL) free(msg->original); if (msg->content != NULL) free(msg->content); if (msg->textcontent != NULL) free(msg->textcontent); if (msg->sender != NULL) free(msg->sender); if (msg->envsender != NULL) free(msg->envsender); if (msg->wordpos != NULL) free(msg->wordpos); if (msg->wordlength != NULL) free(msg->wordlength); for (i = 0; i < msg->num_headers; i++) { if (msg->header[i] != NULL) free(msg->header[i]); } for (i = 0; i < 8; i++) { if (msg->_bound[i] != NULL) free(msg->_bound[i]); } if (msg->header != NULL) free(msg->header); free(msg); } /* EOF */ qsf-1.2.7/src/message/read.c0000644000076400007640000000344310664772304013431 0ustar awaw/* * Functions for parsing and handling mail messages. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "message.h" #include #include #include #include /* * Read a message into memory (msg->original) from either stdin or an * existing buffer (opts->inbuf), aborting if it gets too big. Returns * nonzero on abort, zero on success. */ int msg_read(opts_t opts, msg_t msg) { char buffer[1024]; /* RATS: ignore (checked all) */ char *newptr; long got; /* * Just copy inbuf if it's set */ if (opts->inbuf != NULL) { msg->original = malloc(opts->inbufsize); if (msg->original == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("malloc failed"), strerror(errno)); return 1; } memcpy(msg->original, opts->inbuf, opts->inbufsize); msg->original_size = opts->inbufsize; return 0; } /* * Read the entire message into memory from stdin, aborting if it * gets too big */ while (!feof(stdin)) { got = fread(buffer, 1, sizeof(buffer), stdin); if (got < 0) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("error reading message"), strerror(errno)); return 1; } if (got == 0) break; if (got > sizeof(buffer)) got = sizeof(buffer); newptr = realloc( /* RATS: ignore (not sensitive) */ msg->original, msg->original_size + got + 64); if (newptr == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("realloc failed"), strerror(errno)); return 1; } memcpy(newptr + msg->original_size, buffer, got); newptr[msg->original_size + got] = 0; msg->original = newptr; msg->original_size += got; if (msg->original_size >= MAX_MESSAGE_SIZE) return 1; } return 0; } /* EOF */ qsf-1.2.7/src/message/rfc2047.c0000644000076400007640000001612710664772304013610 0ustar awaw/* * Decode RFC2047-encoded strings. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "message.h" #include #include /* * Table for decoding hex digits */ static char index_hex[256] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; #define CHARHEX(c) (index_hex[(unsigned char)(c)]) /* * Take the given single RFC2047 encoded word and store it, decoded, into * the given buffer with the given maximum length. * * It it assumed that "str" contains a valid RFC2047 encoded word, as found * by the findencoded function below. */ static void decode_rfc2047_word(char *str, char *buf, long bufsize) { int seenq, encoding; char *charset; char *rpos; char *nextq; seenq = 0; charset = NULL; encoding = 0; buf[0] = 0; for (rpos = str; (nextq = strchr(rpos, '?')); rpos = nextq + 1) { char *ptr; int n; seenq++; switch (seenq) { case 2: /* CHARSET part */ n = nextq - rpos; /* * Since RFC2231 says CHARSET can be of the form * CHARSET*LANGUAGE, we need to throw away the * LANGUAGE part if an asterisk is present. */ ptr = memchr(rpos, '*', n); if (ptr) n = ptr - rpos; charset = malloc(n + 1); if (charset != NULL) { memcpy(charset, rpos, n); charset[n] = 0; } break; case 3: /* ENC part */ switch (rpos[0]) { case 'Q': case 'q': encoding = 'Q'; break; case 'B': case 'b': encoding = 'B'; break; default: if (charset) free(charset); return; } break; case 4: /* DATA part */ if (encoding == 'Q') { /* Quoted-Printable decoding */ while ((rpos < nextq) && (bufsize > 0)) { if (rpos[0] == '_') { buf[0] = ' '; buf++; bufsize--; } else if (rpos[0] == '=') { if (rpos[1] == 0) break; if (rpos[2] == 0) break; buf[0] = (CHARHEX(rpos[1]) << 4) | CHARHEX(rpos[2]); buf++; bufsize--; rpos += 2; } else { buf[0] = rpos[0]; buf++; bufsize--; } rpos++; } buf[0] = 0; } else if (encoding == 'B') { /* Base64 decoding */ char *decbuf; long size; size = nextq - rpos; decbuf = msg_from_base64(rpos, &size); if (decbuf == NULL) { if (charset) free(charset); return; } if (size > bufsize) size = bufsize; memcpy(buf, decbuf, size); free(decbuf); buf += size; bufsize -= size; buf[0] = 0; } break; } } if (charset) { /* * We don't do anything with the charset information, as * converting between character sets would make this project * a lot more complicated than it really needs to be. */ free(charset); } } /* * Find the next RFC2047 encoded word in the given string, assuming that the * encoding must be B or Q (case insensitive, as per the RFC). * * An RFC2047 encoded word looks like this: =?CHARSET?ENC?DATA?= * * CHARSET is a character set specifier, ENC is the encoding (Q for * quoted-printable, B for base64), and DATA is the encoded data. * * Returns a pointer to the start of the encoded word and fills in *endptr * with a pointer to the end of the encoded word, or returns NULL if nothing * was found. */ static char *decode_rfc2047_findencoded(char *str, char **endptr) { char *start; char *end; for (end = str; (start = strstr(end, "=?"));) { /* * Look for the next ? at the end of the CHARSET specifier; * CHARSET cannot contain "forbidden" characters. */ for (end = start + 2; (end[0] > 32) && (end[0] < 127) && (strchr("()<>@,;:\"/[].=?", end[0]) == NULL); end++) { } /* * Check we've found the ?ENC? part, where ENC is B or Q * (not case sensitive). */ if (end[0] != '?') continue; if (strchr("BQbq", end[1]) == NULL) continue; if (end[2] != '?') continue; /* * Skip the DATA part. */ for (end = end + 3; (end[0] > 32) && (end[0] < 127) && (end[0] != '?'); end++) { } /* * Check that the encoded word ends with ?= as it should. */ if ((end[0] != '?') || (end[1] != '=')) { end--; continue; } end += 2; *endptr = end; return start; } return NULL; } /* * Return a malloc()ed string containing the input string with any RFC2047 * encoded content decoded. The content of "len" is updated to contain the * size of the output string, and on entry should contain the size of the * input string. * * Returns NULL on error. */ char *msg_decode_rfc2047(char *str, long *len) { char *in; char *out; char *inptr; char *outptr; long bytesleft; int enccount; if (str == NULL) return NULL; if (len == NULL) return NULL; if (*len < 1) return NULL; if (str[0] == 0) return NULL; bytesleft = *len; in = malloc(bytesleft + 1); if (in == NULL) return NULL; out = malloc(bytesleft + 1); if (out == NULL) { free(in); return NULL; } memcpy(in, str, bytesleft); in[bytesleft] = 0; inptr = in; outptr = out; enccount = 0; while ((inptr[0] != 0) && (bytesleft > 0)) { char *start; char *end; int n; /* * Find the next RFC2047 encoded word. */ start = decode_rfc2047_findencoded(inptr, &end); /* * No encoded word found - copy the remainder of the string * to the output and exit the loop. */ if (start == NULL) { strncpy(outptr, inptr, bytesleft); outptr += bytesleft; break; } /* * Copy across parts of the string before the encoded word * to the output. However, we ignore whitespace between * encoded words if they are all that's there (i.e. we treat * "ENCWORD ENCWORD" as "ENCWORDENCWORD", but treat "ENCWORD * foo ENCWORD" as "ENCWORD foo ENCWORD". */ if (start != inptr) { n = start - inptr; if ((enccount == 0) || (strspn(inptr, " \t\r\n") != n) ) { if (n > bytesleft) n = bytesleft; memcpy(outptr, inptr, n); outptr += n; bytesleft -= n; } } decode_rfc2047_word(start, outptr, bytesleft); enccount++; bytesleft -= (1 + end - start); inptr = end; n = strlen(outptr); outptr += n; } outptr[0] = 0; *len = strlen(out); free(in); return out; } /* EOF */ qsf-1.2.7/src/message/header.c0000644000076400007640000001356410664772304013753 0ustar awaw/* * Functions for modifying mail message headers. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "message.h" #include #include #include #include /* * Store a copy of each header in the message, and store a pointer to the * start of the message body for later use by msg_dump(). Returns nonzero on * error. */ int msg_headers_store(opts_t opts, msg_t msg) { long start, end; char *newptr; start = 0; end = 1; do { end = start; while ((end < msg->original_size) && (msg->original[end] != '\n')) { end++; } if (start == end) break; newptr = realloc(msg->header, /* RATS: ignore (OK) */ sizeof(char *) * (msg->num_headers + 1)); if (newptr == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("realloc failed"), strerror(errno)); return 1; } msg->header = (char **) newptr; newptr = malloc(1 + end - start); if (newptr == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("malloc failed"), strerror(errno)); return 1; } msg->header[msg->num_headers] = newptr; memcpy(newptr, msg->original + start, end - start); newptr[end - start] = 0; msg->num_headers++; start = end + 1; } while ((start != end) && (start < msg->original_size)); msg->body = msg->original + end + 1; msg->body_size = msg->original_size - (end + 1); return 0; } /* * Modify the message's Subject line to mark it as spam, using the given * string as a marker or "[SPAM]" if NULL is supplied. */ void msg_spamsubject(msg_t msg, char *marker) { char *ptr; int gotsubject = 0; int i, sz; if (marker == NULL) marker = "[SPAM]"; for (i = 0; i < msg->num_headers; i++) { if (msg->header[i] == NULL) continue; if (strncasecmp(msg->header[i], "Subject:", 8) == 0) { gotsubject = 1; if ((msg->header[i][8] == ' ') && (strncasecmp (msg->header[i] + 9, marker, strlen(marker)) == 0)) continue; sz = strlen(msg->header[i]) + strlen(marker) + 4; ptr = malloc(sz); if (ptr == NULL) continue; #ifdef HAVE_SNPRINTF snprintf(ptr, sz, #else sprintf(ptr, /* RATS: ignore (checked) */ #endif "%.8s %s%s", msg->header[i], marker, msg->header[i] + 8); free(msg->header[i]); msg->header[i] = ptr; } } if (gotsubject == 1) return; /* * Add a Subject header if there wasn't one */ ptr = realloc(msg->header, /* RATS: ignore (OK) */ sizeof(char *) * (msg->num_headers + 1)); if (ptr == NULL) return; msg->header = (char **) ptr; sz = strlen(marker) + 12; ptr = malloc(sz); if (ptr == NULL) return; #ifdef HAVE_SNPRINTF snprintf(ptr, sz, #else sprintf(ptr, /* RATS: ignore (checked) */ #endif "Subject: %.*s", (int) (strlen(marker) + 1), marker); msg->header[msg->num_headers] = ptr; msg->num_headers++; } /* * Add an X-Spam: header to the message, YES (or header marker) if * "spamscore" >0, NO if 0. */ void msg_spamheader(msg_t msg, char *marker, double spamscore) { char *ptr; int i, sz; if (marker == NULL) marker = "YES"; for (i = 0; i < msg->num_headers; i++) { if (msg->header[i] == NULL) continue; if (strncasecmp(msg->header[i], "X-Spam:", 7) == 0) { free(msg->header[i]); msg->header[i] = NULL; } } ptr = realloc(msg->header, /* RATS: ignore (OK) */ sizeof(char *) * (msg->num_headers + 1)); if (ptr == NULL) return; msg->header = (char **) ptr; if (spamscore > 0) { sz = strlen(marker) + 9; ptr = malloc(sz); if (ptr == NULL) return; #ifdef HAVE_SNPRINTF snprintf(ptr, sz, #else sprintf(ptr, /* RATS: ignore (checked) */ #endif "X-Spam: %.*s", (int) (strlen(marker) + 1), marker); } else { ptr = strdup("X-Spam: NO"); if (ptr == NULL) return; } msg->header[msg->num_headers] = ptr; msg->num_headers++; } /* * Add an X-Spam-Rating: header to the message, giving the spam score as a * decimal percentage from 0 to 100. */ void msg_spamratingheader(msg_t msg, double spamscore, double threshold) { char buf[256]; /* RATS: ignore (OK) */ double scaledscore; char *ptr; int i; for (i = 0; i < msg->num_headers; i++) { if (msg->header[i] == NULL) continue; if (strncasecmp(msg->header[i], "X-Spam-Rating:", 14) == 0) { free(msg->header[i]); msg->header[i] = NULL; } } ptr = realloc(msg->header, /* RATS: ignore (OK) */ sizeof(char *) * (msg->num_headers + 1)); if (ptr == NULL) return; msg->header = (char **) ptr; if (spamscore < 0) spamscore += 0.01; spamscore += threshold; scaledscore = spamscore * 100.0; #ifdef HAVE_SNPRINTF snprintf(buf, sizeof(buf) - 1, "X-Spam-Rating: %d", (int) scaledscore); #else sprintf(buf, /* RATS: ignore (OK) */ "X-Spam-Rating: %d", (int) scaledscore); #endif ptr = strdup(buf); if (ptr == NULL) return; msg->header[msg->num_headers] = ptr; msg->num_headers++; } /* * Add an X-Spam-Level: header to the message, giving the spam score as a * number of stars from 0 to 20. */ void msg_spamlevelheader(msg_t msg, double spamscore, double threshold) { char buf[256]; /* RATS: ignore (OK) */ double scaledscore; char *ptr; int i, x; for (i = 0; i < msg->num_headers; i++) { if (msg->header[i] == NULL) continue; if (strncasecmp(msg->header[i], "X-Spam-Level:", 13) == 0) { free(msg->header[i]); msg->header[i] = NULL; } } ptr = realloc(msg->header, /* RATS: ignore (OK) */ sizeof(char *) * (msg->num_headers + 1)); if (ptr == NULL) return; msg->header = (char **) ptr; if (spamscore < 0) spamscore += 0.01; spamscore += threshold; scaledscore = spamscore * 100.0; memcpy(buf, "X-Spam-Level: ", 14); x = strlen(buf); for (i = 0; (i < (scaledscore * 0.2)) && (i < 20); i++) { buf[x] = '*'; x++; buf[x] = 0; } ptr = strdup(buf); if (ptr == NULL) return; msg->header[msg->num_headers] = ptr; msg->num_headers++; } /* EOF */ qsf-1.2.7/src/message/qp.c0000644000076400007640000000447010664772304013137 0ustar awaw/* * Decode a block of Quoted-Printable encoded data. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include #define XX 127 /* * Table for decoding hexadecimal in quoted-printable */ static char index_hex[256] = { /* RATS: ignore (OK) */ XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, XX, XX, XX, XX, XX, XX, XX, 10, 11, 12, 13, 14, 15, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 10, 11, 12, 13, 14, 15, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, }; #define HEXCHAR(c) (index_hex[(unsigned char)(c)]) /* * Decode a block of Quoted-Printable-encoded data and return a pointer to * the decoded data, which will have been malloc()ed, or NULL on error. The * content of "size" is updated to contain the size of the output buffer, * and on entry should contain the size of the input block. */ char *msg_from_qp(char *data, long *size) { char *out; long inpos, outpos; int byte, c, c1 = 0, c2 = 0; out = malloc(64 + *size); if (out == NULL) return NULL; for (inpos = 0, outpos = 0, byte = 0; inpos < *size; inpos++) { c = data[inpos]; switch (byte) { case 0: if (c == '=') { byte++; } else { out[outpos++] = c; } break; case 1: c1 = HEXCHAR(c); if (c1 == XX) { byte = 0; } else { byte++; } break; case 2: c2 = HEXCHAR(c); if (c2 != XX) { out[outpos++] = c1 << 4 | c2; } byte = 0; break; default: break; } } out[outpos] = 0; *size = outpos; return out; } /* EOF */ qsf-1.2.7/src/message/dump.c0000644000076400007640000000234510664772304013463 0ustar awaw/* * Dump a mail message to stdout. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "message.h" #include "log.h" #include #include /* * Dump the given message on standard output. If the "content" field is * null, the "original" field is just dumped; otherwise, the message is * reconstructed from the "header" array and the "body" field. */ void msg_dump(msg_t msg) { long pos, sent; int i; if (msg == NULL) return; if (msg->content == NULL) { pos = 0; while (pos < msg->original_size) { sent = fwrite(msg->original + pos, 1, msg->original_size - pos, stdout); if (sent <= 0) break; pos += sent; } return; } for (i = 0; i < msg->num_headers; i++) { if (msg->header[i] == NULL) continue; sent = fwrite(msg->header[i], strlen(msg->header[i]), 1, stdout); if (sent <= 0) break; sent = fwrite("\n", 1, 1, stdout); if (sent <= 0) break; } log_dump("X-QSF-Info: "); if (fwrite("\n", 1, 1, stdout) <= 0) return; pos = 0; while (pos < msg->body_size) { sent = fwrite(msg->body + pos, 1, msg->body_size - pos, stdout); if (sent <= 0) break; pos += sent; } } /* EOF */ qsf-1.2.7/src/message/base64.c0000644000076400007640000000544710664772304013610 0ustar awaw/* * Decode Base64-encoded data. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include /* * Table for decoding base64 */ static char index_64[256] = { /* RATS: ignore (OK) */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; #define CHAR64(c) (index_64[(unsigned char)(c)]) /* * Decode a block of Base64-encoded data and return a pointer to the decoded * data, which will have been malloc()ed, or NULL on error. The content of * "size" is updated to contain the size of the output buffer, and on entry * should contain the size of the input block. */ char *msg_from_base64(char *data, long *size) { char *out; long inpos, outpos; int byte, c, c1 = 0, c2 = 0, c3 = 0, c4 = 0; char buf[3]; /* RATS: ignore (checked all) */ out = malloc(64 + *size); if (out == NULL) return NULL; for (inpos = 0, outpos = 0, byte = 0; inpos < *size; inpos++) { c = data[inpos]; switch (byte) { case 0: if (c != '=' && CHAR64(c) == -1) continue; c1 = c; byte++; break; case 1: if (c != '=' && CHAR64(c) == -1) continue; c2 = c; byte++; break; case 2: if (c != '=' && CHAR64(c) == -1) continue; c3 = c; byte++; break; case 3: if (c != '=' && CHAR64(c) == -1) continue; c4 = c; byte++; break; default: break; } if (byte < 4) continue; byte = 0; if (c1 == '=' || c2 == '=') break; c1 = CHAR64(c1); c2 = CHAR64(c2); buf[0] = ((c1 << 2) | ((c2 & 0x30) >> 4)); out[outpos++] = buf[0]; if (c3 == '=') break; c3 = CHAR64(c3); buf[1] = (((c2 & 0x0F) << 4) | ((c3 & 0x3C) >> 2)); out[outpos++] = buf[1]; if (c4 == '=') break; c4 = CHAR64(c4); buf[2] = (((c3 & 0x03) << 6) | c4); out[outpos++] = buf[2]; } out[outpos] = 0; *size = outpos; return out; } /* EOF */ qsf-1.2.7/src/tests/0000755000076400007640000000000010665021416012054 5ustar awawqsf-1.2.7/src/tests/gtube.c0000644000076400007640000000126710664772304013344 0ustar awaw/* * Implement GTUBE, the Generic Test for Unsolicited Bulk Email. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "testi.h" #include #define GTUBE "XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X" extern char *minimemmem(char *, long, char *, long); /* * Override the spam filter and always mark a message as spam if it contains * the GTUBE string. This can be used to check that the spam filter is * working. */ int spam_test_gtube(opts_t opts, msg_t msg, spam_t spam) { if (minimemmem (msg->content, msg->content_size, GTUBE, strlen(GTUBE)) == 0) return 0; return 1; } /* EOF */ qsf-1.2.7/src/tests/main.c0000644000076400007640000001106410664772304013156 0ustar awaw/* * Main entry point for calling all special tests. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "testi.h" #include #include /* * Prototype all tests here, and list them in the spam_test() function * below. */ int spam_test_gtube(opts_t, msg_t, spam_t); int spam_test_attachment_scr(opts_t, msg_t, spam_t); int spam_test_attachment_pif(opts_t, msg_t, spam_t); int spam_test_attachment_exe(opts_t, msg_t, spam_t); int spam_test_attachment_vbs(opts_t, msg_t, spam_t); int spam_test_attachment_vba(opts_t, msg_t, spam_t); int spam_test_attachment_lnk(opts_t, msg_t, spam_t); int spam_test_attachment_com(opts_t, msg_t, spam_t); int spam_test_attachment_bat(opts_t, msg_t, spam_t); int spam_test_attachment_pdf(opts_t, msg_t, spam_t); int spam_test_attachment_doc(opts_t, msg_t, spam_t); int spam_test_attachment_xls(opts_t, msg_t, spam_t); int spam_test_attachment_jpg(opts_t, msg_t, spam_t); int spam_test_attachment_gif(opts_t, msg_t, spam_t); int spam_test_attachment_png(opts_t, msg_t, spam_t); int spam_test_gibberish_consonants(opts_t, msg_t, spam_t); int spam_test_gibberish_vowels(opts_t, msg_t, spam_t); int spam_test_gibberish_from_consonants(opts_t, msg_t, spam_t); int spam_test_gibberish_from_vowels(opts_t, msg_t, spam_t); int spam_test_gibberish_badstart(opts_t, msg_t, spam_t); int spam_test_gibberish_hyphens(opts_t, msg_t, spam_t); int spam_test_gibberish_longwords(opts_t, msg_t, spam_t); int spam_test_html_comments_in_words(opts_t, msg_t, spam_t); int spam_test_html_external_img(opts_t, msg_t, spam_t); int spam_test_html_font(opts_t, msg_t, spam_t); int spam_test_html_urls(opts_t, msg_t, spam_t); int spam_test_image_single(opts_t, msg_t, spam_t); int spam_test_image_multiple(opts_t, msg_t, spam_t); /* * Run each test in turn, such that if a test triggers, its special token is * added to the token list or, if the test says to override the message's * spam/nonspam value, do that. * * Returns 0 normally, nonzero if testing is to be overridden: -1 means to * always mark the message as non-spam, 1 means to always mark it as spam. * * Test functions should return 0 for no action, -1 to override all other * tests and mark as non-spam, 1 to override all tests and mark as spam, and * 1+n to continue as usual but add that test's token to the token tree "n" * times (where "n" is 1 or more). * * Tokens should start with "." to distinguish themselves from real tokens, * which can never start with ".", and should end with "." for cosmetic * reasons. Tokens should never contain any characters not in TOKEN_CHARS * (see include/spam.h), and must NEVER be longer than 32 characters. */ int spam_test(opts_t opts, spam_t spam, msg_t msg) { struct { char *token; spamtestfunc_t func; } test[] = { { ".GTUBE.", spam_test_gtube}, { ".ATTACH-SCR.", spam_test_attachment_scr}, { ".ATTACH-PIF.", spam_test_attachment_pif}, { ".ATTACH-EXE.", spam_test_attachment_exe}, { ".ATTACH-VBS.", spam_test_attachment_vbs}, { ".ATTACH-VBA.", spam_test_attachment_vba}, { ".ATTACH-LNK.", spam_test_attachment_lnk}, { ".ATTACH-COM.", spam_test_attachment_com}, { ".ATTACH-BAT.", spam_test_attachment_bat}, { ".ATTACH-PDF.", spam_test_attachment_pdf}, { ".ATTACH-DOC.", spam_test_attachment_doc}, { ".ATTACH-XLS.", spam_test_attachment_xls}, { ".ATTACH-JPG.", spam_test_attachment_jpg}, { ".ATTACH-GIF.", spam_test_attachment_gif}, { ".ATTACH-PNG.", spam_test_attachment_png}, { ".GIBBERISH-CONSONANTS.", spam_test_gibberish_consonants}, { ".GIBBERISH-VOWELS.", spam_test_gibberish_vowels}, { ".GIBBERISH-FROMCONS.", spam_test_gibberish_from_consonants}, { ".GIBBERISH-FROMVOWL.", spam_test_gibberish_from_vowels}, { ".GIBBERISH-BADSTART.", spam_test_gibberish_badstart}, { ".GIBBERISH-HYPHENS.", spam_test_gibberish_hyphens}, { ".GIBBERISH-LONGWORDS.", spam_test_gibberish_longwords}, { ".HTML-COMMENTS-IN-WORDS.", spam_test_html_comments_in_words}, { ".HTML-EXTERNAL-IMG.", spam_test_html_external_img}, { ".HTML-FONT.", spam_test_html_font}, { ".HTML-IP-IN-URLS.", spam_test_html_urls}, { ".SINGLE-IMAGE.", spam_test_image_single}, { ".MULTIPLE-IMAGES.", spam_test_image_multiple}, { NULL, NULL} }; int i, ret, n; for (i = 0; test[i].func != NULL; i++) { ret = (test[i].func) (opts, msg, spam); switch (ret) { case -1: return -1; case 0: break; case 1: return 1; default: for (n = 1; n < ret; n++) { spam_token_add(opts, spam, test[i].token, strlen(test[i].token)); } break; } } return 0; } /* EOF */ qsf-1.2.7/src/tests/imgcount.c0000644000076400007640000000112010664772304014047 0ustar awaw/* * Rules which add tokens depending on how many images are attached. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "testi.h" /* * Add a token if the message contains exactly one attached image. */ int spam_test_image_single(opts_t opts, msg_t msg, spam_t spam) { if (msg->num_images == 1) return 2; return 0; } /* * Add a token if the message contains more than one attached image. */ int spam_test_image_multiple(opts_t opts, msg_t msg, spam_t spam) { if (msg->num_images > 1) return 2; return 0; } /* EOF */ qsf-1.2.7/src/tests/urls.c0000644000076400007640000000671110664772304013222 0ustar awaw/* * Rules to look for URLs in messages. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "testi.h" #include "spam.h" #include extern char *minimemmem(char *, long, char *, long); /* * Add a token for every URL found containing an IP address, and also add * all URLs found and their hostnames as tokens in their own right. */ int spam_test_html_urls(opts_t opts, msg_t msg, spam_t spam) { int nfound, ldr, ldrl, isip, dots, isint, isurlenc; long pos, len, i, hoststart, hostend; char *leaders[] = { "http:", "Http:", "HTTP:", "ftp:", "Ftp:", "FTP:", "mailto:", "Mailto:", "MAILTO:", NULL }; char *ptr; for (nfound = 0, ldr = 0; leaders[ldr]; ldr++) { ldrl = strlen(leaders[ldr]); /* RATS: ignore (OK) */ for (pos = 0; pos < msg->content_size;) { ptr = minimemmem(msg->content + pos, msg->content_size - pos, leaders[ldr], ldrl); if (!ptr) break; pos = ptr - msg->content; if (pos < 0) break; /* * Find the length of the URL (i.e. where it ends), * counting ? as an end-of-URL character */ for (len = 0; (len < msg->content_size - pos) && !strchr("?>\"' \n\t\r", msg->content[pos + len]); len++) { } /* * Find the start of the hostname (after the // part) */ hoststart = 5; while ((hoststart < len) && (msg->content[pos + hoststart] == '/')) { hoststart++; } /* * If the URL has a @ in it, the hostname comes * after that */ for (i = 0; i < len; i++) { if (msg->content[pos + i] == '@') hoststart = i + 1; } /* * Don't go past the end of the URL */ if (hoststart >= len) hoststart = 0; /* * Find the first / after the hostname, if any */ hostend = 0; for (i = hoststart; i < len; i++) { if (msg->content[pos + i] == '/') { hostend = i; break; } } /* * Add the URL as a token */ spam_token_add(opts, spam, msg->content + pos, len); /* * Add the part of the URL that starts with the * hostname (i.e. after http://, and any @) as a * token */ if (hoststart > 0) { spam_token_add(opts, spam, msg->content + pos + hoststart, len - hoststart); /* * Add the hostname on its own as a token */ if (hostend > hoststart) { spam_token_add(opts, spam, msg->content + pos + hoststart, hostend - hoststart); } } /* * See whether the URL's hostname is an IP address, * just an integer, or might be URL-encoded */ isint = 1; isip = 1; isurlenc = 0; dots = 0; for (i = hoststart; i < len; i++) { if ((msg->content[pos + i] >= '0') && (msg->content[pos + i] <= '9')) continue; if (msg->content[pos + i] == '.') { dots++; } else if (msg->content[pos + i] == '/') { if (dots < 3) isip = 0; break; } else { isip = 0; isint = 0; if (msg->content[pos + i] == '%') isurlenc = 1; } } if (dots < 3) isip = 0; if (dots > 0) isint = 0; if (isip) { nfound++; } else if (isint) { spam_token_add(opts, spam, ".HTML-INT-IN-URL.", 18); } else if (isurlenc) { spam_token_add(opts, spam, ".HTML-URLENCODED-URL.", 21); } pos++; } } if (nfound > 0) return nfound + 1; return 0; } /* EOF */ qsf-1.2.7/src/tests/gibberish.c0000644000076400007640000001152610664772304014173 0ustar awaw/* * Rules which look for gibberish - words containing too many consonants or * vowels in a row. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "testi.h" #include #define CONSONANTS "BCDFGHJKLMNPQRSTVWXZbcdfghjklmnpqrstvwxz" \ "ÇÐÑÞßçðñþ" #define VOWELS "AEIOUYaeiouy" \ "ÀÁÂÃÄÅÆÈÉÊËÌÍÎÏÒÓÔÕÖØÙÚÛÜÝ" \ "àáâãäåæèéêëìíîïòóôõöøùúûüý\0377" /* * Return nonzero if a sequence of "count" or more characters from the * string "accept" are found in the given word, so long as the word is * shorter than 60 characters (so we don't trip up on base64 encoded stuff). */ static int spam_test_gibberish__runon(char *word, int len, char *accept, int count) { int pos = 0; int n; if (len >= 60) return 0; while (pos < len) { /* * Skip any characters not in the accept string. */ while (pos < len) { if (strchr(accept, word[pos]) != NULL) break; pos++; } if (pos >= len) return 0; /* * Count the number of allowable characters in a row. */ n = 0; while (pos < len) { if (strchr(accept, word[pos]) == NULL) break; pos++; n++; } if (n >= count) return 1; } return 0; } /* * Add a token for every word found that contains more than 5 consonants * (not including "y") in a row. */ int spam_test_gibberish_consonants(opts_t opts, msg_t msg, spam_t spam) { int nfound = 0; long n; char *word; int len; for (n = 0; n < msg->num_words; n++) { word = msg->textcontent + msg->wordpos[n]; len = msg->wordlength[n]; if (spam_test_gibberish__runon(word, len, CONSONANTS, 5)) nfound++; } if (nfound > 0) return nfound + 1; return 0; } /* * Add a token for every word found that contains more than 4 vowels * (including "y") in a row. */ int spam_test_gibberish_vowels(opts_t opts, msg_t msg, spam_t spam) { int nfound = 0; long n; char *word; int len; for (n = 0; n < msg->num_words; n++) { word = msg->textcontent + msg->wordpos[n]; len = msg->wordlength[n]; if (spam_test_gibberish__runon(word, len, VOWELS, 4)) nfound++; } if (nfound > 0) return nfound + 1; return 0; } /* * Add a token for if the "From:" or "Return-Path:" addresses contain more * than 5 consonants (not including "y") in a row. */ int spam_test_gibberish_from_consonants(opts_t opts, msg_t msg, spam_t spam) { if ((msg->sender) && (spam_test_gibberish__runon (msg->sender, strlen(msg->sender), CONSONANTS, 5))) return 2; if ((msg->envsender) && (spam_test_gibberish__runon (msg->envsender, strlen(msg->envsender), CONSONANTS, 5))) return 2; return 0; } /* * Add a token if the "From:" address contains more than 4 vowels (including * "y") in a row. */ int spam_test_gibberish_from_vowels(opts_t opts, msg_t msg, spam_t spam) { if ((msg->sender) && (spam_test_gibberish__runon (msg->sender, strlen(msg->sender), VOWELS, 4))) return 2; if ((msg->envsender) && (spam_test_gibberish__runon (msg->envsender, strlen(msg->envsender), VOWELS, 4))) return 2; return 0; } /* * Add a token for every word found that starts with non-alphanumeric * characters other than <>"'*_/. */ int spam_test_gibberish_badstart(opts_t opts, msg_t msg, spam_t spam) { int nfound = 0; long n; char *word; int len; for (n = 0; n < msg->num_words; n++) { word = msg->textcontent + msg->wordpos[n]; len = msg->wordlength[n]; if (strchr(CONSONANTS, word[0])) continue; if (strchr(VOWELS, word[0])) continue; if (strchr("<>\"'*_/", word[0])) continue; nfound++; } if (nfound > 0) return nfound + 1; return 0; } /* * Add a token for every word found that contains more than 3 hyphens or * underscores. */ int spam_test_gibberish_hyphens(opts_t opts, msg_t msg, spam_t spam) { int nfound = 0; long n; char *word; int len; for (n = 0; n < msg->num_words; n++) { int hyphens = 0; word = msg->textcontent + msg->wordpos[n]; len = msg->wordlength[n]; while (len > 0) { int c = word[0]; word++; len--; if ((c == '-') || (c == '_')) { hyphens++; if (hyphens > 3) break; } } if (hyphens > 3) nfound++; } if (nfound > 0) return nfound + 1; return 0; } /* * Add a token for every word found that is ridiculously long (over 30 * characters), not counting 60+ character words because they may be part of * a Base64-encoded chunk. */ int spam_test_gibberish_longwords(opts_t opts, msg_t msg, spam_t spam) { int nfound = 0; long n; int len; char *word; for (n = 0; n < msg->num_words; n++) { len = msg->wordlength[n]; word = msg->textcontent + msg->wordpos[n]; if (len <= 30) continue; if (len >= 60) continue; if (strchr(CONSONANTS, word[0])) continue; if (strchr(VOWELS, word[0])) continue; nfound++; } if (nfound > 0) return nfound + 1; return 0; } /* EOF */ qsf-1.2.7/src/tests/attached_files.c0000644000076400007640000001351610664772304015175 0ustar awaw/* * Rules which add tokens if a message attachment's filename matches various * patterns. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "testi.h" #include #define DISPOSITION_HEADER "\nContent-Disposition:" extern char *minimemmem(char *, long, char *, long); /* * Return the number of times an attachment with the given filename * extension (eg "scr", "pif", "exe") was found. */ static int spam_test_attachment__scan(msg_t msg, char *extension) { long pos, lastdot; int nfound = 0; pos = 0; while (pos < msg->body_size) { int quotes; char *ptr; ptr = minimemmem(msg->body + pos, msg->body_size - pos, DISPOSITION_HEADER, strlen(DISPOSITION_HEADER)); if (ptr == 0) return nfound; pos = ptr - msg->body; pos += strlen(DISPOSITION_HEADER); while ((pos < msg->body_size) && ((msg->body[pos] == ' ') || (msg->body[pos] == '\t') ) ) { pos++; } if (pos >= (msg->body_size - 12)) return nfound; if (strncasecmp(msg->body + pos, "attachment;", 11) != 0) continue; pos += 11; while ((pos < msg->body_size) && ((msg->body[pos] == ' ') || (msg->body[pos] == '\t') || (msg->body[pos] == '\r') || (msg->body[pos] == '\n') ) ) { pos++; } if (pos >= (msg->body_size - 15)) return nfound; if (strncasecmp(msg->body + pos, "filename=", 9) != 0) continue; pos += 9; quotes = 0; if (msg->body[pos] == '"') { quotes = 1; pos++; } lastdot = 0; if (quotes) { while ((pos < msg->body_size) && (msg->body[pos] != '"') && (msg->body[pos] != '\r') && (msg->body[pos] != '\n') ) { if (msg->body[pos] == '.') lastdot = pos; pos++; } } else { while ((pos < msg->body_size) && (msg->body[pos] != ';') && (msg->body[pos] != ' ') && (msg->body[pos] != '"') && (msg->body[pos] != '\t') && (msg->body[pos] != '\r') && (msg->body[pos] != '\n') ) { if (msg->body[pos] == '.') lastdot = pos; pos++; } } if (lastdot == 0) continue; if (pos >= (msg->body_size - 2)) return nfound; lastdot++; if (strlen(extension) != (pos - lastdot)) continue; if (strncasecmp (msg->body + lastdot, extension, pos - lastdot) == 0) nfound++; } return nfound; } /* * Add a token for every attachment with the filename "something.scr". */ int spam_test_attachment_scr(opts_t opts, msg_t msg, spam_t spam) { int n; n = spam_test_attachment__scan(msg, "scr"); if (n > 0) return n + 1; return 0; } /* * Add a token for every attachment with the filename "something.pif". */ int spam_test_attachment_pif(opts_t opts, msg_t msg, spam_t spam) { int n; n = spam_test_attachment__scan(msg, "pif"); if (n > 0) return n + 1; return 0; } /* * Add a token for every attachment with the filename "something.exe". */ int spam_test_attachment_exe(opts_t opts, msg_t msg, spam_t spam) { int n; n = spam_test_attachment__scan(msg, "exe"); if (n > 0) return n + 1; return 0; } /* * Add a token for every attachment with the filename "something.vbs". */ int spam_test_attachment_vbs(opts_t opts, msg_t msg, spam_t spam) { int n; n = spam_test_attachment__scan(msg, "vbs"); if (n > 0) return n + 1; return 0; } /* * Add a token for every attachment with the filename "something.vba". */ int spam_test_attachment_vba(opts_t opts, msg_t msg, spam_t spam) { int n; n = spam_test_attachment__scan(msg, "vba"); if (n > 0) return n + 1; return 0; } /* * Add a token for every attachment with the filename "something.lnk". */ int spam_test_attachment_lnk(opts_t opts, msg_t msg, spam_t spam) { int n; n = spam_test_attachment__scan(msg, "lnk"); if (n > 0) return n + 1; return 0; } /* * Add a token for every attachment with the filename "something.com". */ int spam_test_attachment_com(opts_t opts, msg_t msg, spam_t spam) { int n; n = spam_test_attachment__scan(msg, "com"); if (n > 0) return n + 1; return 0; } /* * Add a token for every attachment with the filename "something.bat". */ int spam_test_attachment_bat(opts_t opts, msg_t msg, spam_t spam) { int n; n = spam_test_attachment__scan(msg, "bat"); if (n > 0) return n + 1; return 0; } /* * Add a token for every attachment with the filename "something.pdf". */ int spam_test_attachment_pdf(opts_t opts, msg_t msg, spam_t spam) { int n; n = spam_test_attachment__scan(msg, "pdf"); if (n > 0) return n + 1; return 0; } /* * Add a token for every attachment with the filename "something.doc". */ int spam_test_attachment_doc(opts_t opts, msg_t msg, spam_t spam) { int n; n = spam_test_attachment__scan(msg, "doc"); if (n > 0) return n + 1; return 0; } /* * Add a token for every attachment with the filename "something.xls". */ int spam_test_attachment_xls(opts_t opts, msg_t msg, spam_t spam) { int n; n = spam_test_attachment__scan(msg, "xls"); if (n > 0) return n + 1; return 0; } /* * Add a token for every attachment with the filename "something.gif". */ int spam_test_attachment_gif(opts_t opts, msg_t msg, spam_t spam) { int n; n = spam_test_attachment__scan(msg, "gif"); if (n > 0) return n + 1; return 0; } /* * Add a token for every attachment with the filename "something.jpg" or * "something.jpeg". */ int spam_test_attachment_jpg(opts_t opts, msg_t msg, spam_t spam) { int n; n = spam_test_attachment__scan(msg, "jpg") + spam_test_attachment__scan(msg, "jpeg"); if (n > 0) return n + 1; return 0; } /* * Add a token for every attachment with the filename "something.png". */ int spam_test_attachment_png(opts_t opts, msg_t msg, spam_t spam) { int n; n = spam_test_attachment__scan(msg, "png"); if (n > 0) return n + 1; return 0; } /* EOF */ qsf-1.2.7/src/tests/html.c0000644000076400007640000000511610664772304013177 0ustar awaw/* * Rules to look for oddities in the HTML of messages. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "testi.h" #include "spam.h" #include extern char *minimemmem(char *, long, char *, long); /* * Add a token for every HTML comment found in the middle of a word (i.e. * with a valid token character either side of it). */ int spam_test_html_comments_in_words(opts_t opts, msg_t msg, spam_t spam) { int nfound = 0; long pos = 0; char *ptr; while (pos < msg->content_size) { ptr = minimemmem(msg->content + pos, msg->content_size - pos, "content; if ((pos < 1) || (strchr(TOKEN_CHARS, msg->content[pos - 1]) == 0) ) { pos++; continue; } pos++; ptr = minimemmem(msg->content + pos, msg->content_size - pos, ">", 1); if (!ptr) break; pos = ptr - msg->content; pos++; if (pos >= msg->content_size) break; if (strchr(TOKEN_CHARS, msg->content[pos]) != 0) nfound++; } if (nfound > 0) return nfound + 1; return 0; } /* * Add a token for every IMG tag found referring to an external URL * (containing ://). */ int spam_test_html_external_img(opts_t opts, msg_t msg, spam_t spam) { int nfound = 0; long pos = 0; char *ptr; while (pos < msg->content_size) { ptr = memchr(msg->content + pos, '<', msg->content_size - pos); if (!ptr) break; pos = ptr - msg->content; if (pos > msg->content_size - 4) break; pos++; if (strncasecmp(msg->content + pos, "img", 3) == 0) { ptr = memchr(msg->content + pos, '>', msg->content_size - pos); if (!ptr) break; if (minimemmem (msg->content + pos, (ptr - msg->content) - pos, "://", 3)) nfound++; pos = ptr - msg->content; pos++; if (pos >= msg->content_size) break; } } if (nfound > 0) return nfound + 1; return 0; } /* * Add a token for every FONT tag found. */ int spam_test_html_font(opts_t opts, msg_t msg, spam_t spam) { int nfound = 0; long pos = 0; char *ptr; while (pos < msg->content_size) { ptr = memchr(msg->content + pos, '<', msg->content_size - pos); if (!ptr) break; pos = ptr - msg->content; if (pos > msg->content_size - 5) break; pos++; if (strncasecmp(msg->content + pos, "font", 4) != 0) continue; nfound++; ptr = memchr(msg->content + pos, '>', msg->content_size - pos); if (!ptr) break; pos = ptr - msg->content; } if (nfound > 0) return nfound + 1; return 0; } /* EOF */ qsf-1.2.7/src/tests/testi.h0000644000076400007640000000102210554714241013352 0ustar awaw/* * Internal spam test prototypes, structures, and constants. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #ifndef _TESTI_H #define _TESTI_H 1 #ifndef _OPTIONS_H #include "options.h" #endif #ifndef _MESSAGE_H #include "message.h" #endif #ifdef __cplusplus extern "C" { #endif struct spam_s; typedef struct spam_s *spam_t; typedef int (*spamtestfunc_t)(opts_t, msg_t, spam_t); void spam_token_add(opts_t, spam_t, char *, int); #ifdef __cplusplus } #endif #endif /* _TESTI_H */ /* EOF */ qsf-1.2.7/src/mailbox/0000755000076400007640000000000010665021416012345 5ustar awawqsf-1.2.7/src/mailbox/mailboxi.h0000644000076400007640000000105010554714242014321 0ustar awaw/* * Internal definitions for the mailbox functions. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #ifndef _MAILBOXI_H #define _MAILBOXI_H 1 #ifdef __cplusplus extern "C" { #endif struct mbox_s { /* structure describing a mailbox */ size_t count; /* number of messages */ size_t alloced; /* size of array */ size_t *start; /* array of message start offsets */ size_t *length; /* array of message sizes */ }; #ifdef __cplusplus } #endif #endif /* _MAILBOXI_H */ /* EOF */ qsf-1.2.7/src/mailbox/alloc.c0000644000076400007640000000056310664772304013617 0ustar awaw/* * Functions for memory allocation and deallocation. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "mailbox.h" #include "mailboxi.h" #include /* * Free an mbox_t. */ void mbox_free(mbox_t mbox) { if (mbox == NULL) return; free(mbox->start); free(mbox->length); free(mbox); } /* EOF */ qsf-1.2.7/src/mailbox/count.c0000644000076400007640000000055010664772304013651 0ustar awaw/* * Count the number of messages in the given mailbox. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "mailbox.h" #include "mailboxi.h" /* * Return the number of messages in the given mailbox. */ size_t mbox_count(mbox_t mbox) { if (mbox == NULL) return 0; return mbox->count; } /* EOF */ qsf-1.2.7/src/mailbox/select.c0000644000076400007640000000256710664772304014012 0ustar awaw/* * Select a particular message from a mailbox. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "mailbox.h" #include "mailboxi.h" #include #include #include #include /* * Select the given message in the given mailbox by loading it into memory * and setting the stdin-replacement stream to be an in-memory file handle. * * Returns non-zero on error. */ int mbox_select(opts_t opts, mbox_t mbox, FILE * fptr, size_t num) { static char *buf = NULL; if (buf != NULL) { free(buf); buf = NULL; } if (fptr == NULL) return 0; if (mbox->length[num] < 1) { fprintf(stderr, "%s: %s %d: %s\n", opts->program_name, _("message"), (int) num + 1, _("invalid message size")); opts->inbuf = ""; opts->inbufsize = 1; return 1; } fseek(fptr, mbox->start[num], SEEK_SET); buf = calloc(1, mbox->length[num]); if (buf == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("calloc failed"), strerror(errno)); opts->inbuf = ""; opts->inbufsize = 1; return 1; } if (fread(buf, mbox->length[num], 1, fptr) < 1) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("failed to read mailbox"), strerror(errno)); opts->inbuf = ""; opts->inbufsize = 1; return 1; } opts->inbuf = buf; opts->inbufsize = mbox->length[num]; return 0; } /* EOF */ qsf-1.2.7/src/mailbox/scan.c0000644000076400007640000000521410664772304013447 0ustar awaw/* * Functions to scan a mailbox for messages. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include "config.h" #include "mailbox.h" #include "mailboxi.h" #include #include #include #include void tick(void); /* * Scan the mailbox on the given file handle, returning an mbox_t describing * where each message in the mailbox can be found, or NULL on error. */ mbox_t mbox_scan(opts_t opts, FILE * fptr) { char linebuf[1024]; /* RATS: ignore (size OK) */ mbox_t mbox; int prevnewline = 0; size_t pos, filepos; size_t *newptr; mbox = calloc(1, sizeof(*mbox)); if (mbox == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("calloc failed"), strerror(errno)); return NULL; } mbox->start = calloc(1, sizeof(pos)); if (mbox->start == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("calloc failed"), strerror(errno)); free(mbox); return NULL; } mbox->length = calloc(1, sizeof(pos)); if (mbox->length == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("calloc failed"), strerror(errno)); free(mbox->start); free(mbox); return NULL; } mbox->count = 0; mbox->alloced = 1; filepos = 0; while (fgets(linebuf, sizeof(linebuf) - 1, fptr) != NULL) { linebuf[sizeof(linebuf) - 1] = 0; filepos = ftell(fptr); tick(); if (strrchr(linebuf, '\n') == NULL) { prevnewline = 0; continue; } if (prevnewline && (strncmp(linebuf, "From ", 5) == 0)) { pos = filepos - strlen(linebuf); mbox->length[mbox->count] = pos - mbox->start[mbox->count]; if (mbox->count >= (mbox->alloced - 1)) { mbox->alloced += 4096; newptr = realloc( /* RATS: ignore (OK) */ mbox->start, sizeof(pos) * (mbox->alloced)); if (newptr == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("realloc failed"), strerror(errno)); free(mbox->start); free(mbox->length); free(mbox); return NULL; } mbox->start = newptr; newptr = realloc( /* RATS: ignore (OK) */ mbox->length, sizeof(pos) * (mbox->alloced)); if (newptr == NULL) { fprintf(stderr, "%s: %s: %s\n", opts->program_name, _("realloc failed"), strerror(errno)); free(mbox->start); free(mbox->length); free(mbox); return NULL; } mbox->length = newptr; } mbox->count++; mbox->start[mbox->count] = pos; mbox->length[mbox->count] = 0; } prevnewline = 1; } mbox->length[mbox->count] = filepos - mbox->start[mbox->count]; if (mbox->length[mbox->count] != 0) mbox->count++; return mbox; } /* EOF */ qsf-1.2.7/autoconf/0000755000076400007640000000000010665021416011741 5ustar awawqsf-1.2.7/autoconf/configure.in0000644000076400007640000001633510516437234014266 0ustar awawdnl Process this file with autoconf to produce a configure script. dnl AC_INIT(src/main/version.c) dnl We're using C. dnl AC_LANG_C dnl Output a header file. dnl AC_CONFIG_HEADER(src/include/config.h:autoconf/header.in) dnl Set directory to check for Configure scripts in. dnl AC_CONFIG_AUX_DIR(autoconf/scripts) dnl Read in package details. dnl PACKAGE=`cat $srcdir/doc/PACKAGE` VERSION=`cat $srcdir/doc/VERSION` UCPACKAGE=`tr a-z A-Z < $srcdir/doc/PACKAGE` AC_SUBST(PACKAGE) AC_SUBST(VERSION) AC_SUBST(UCPACKAGE) AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE") AC_DEFINE_UNQUOTED(PROGRAM_NAME, "$PACKAGE") AC_DEFINE_UNQUOTED(VERSION, "$VERSION") dnl Database backends we can use. dnl canuse_obtree="yes" canuse_btree="yes" canuse_list="yes" canuse_gdbm="yes" canuse_mysql="yes" canuse_sqlite="yes" dnl Check for compile-time options. dnl AC_ARG_ENABLE(debugging, [ --enable-debugging compile with debugging symbols], if test "$enable_debugging" = "yes"; then CFLAGS="-g -Wall" fi ) AC_ARG_ENABLE(profiling, [ --enable-profiling compile with profiling support], if test "$enable_profiling" = "yes"; then CFLAGS="-pg $CFLAGS" fi ) AC_ARG_ENABLE(static, [ --enable-static enable static linking], ) AC_ARG_WITH(obtree, [ --without-obtree omit old binary tree backend support], canuse_obtree="$with_obtree" ) AC_ARG_WITH(btree, [ --without-btree omit binary tree backend support], canuse_btree="$with_btree" ) AC_ARG_WITH(list, [ --without-list omit list backend support], canuse_list="$with_list" ) AC_ARG_WITH(gdbm, [ --without-gdbm omit GDBM backend support], canuse_gdbm="$with_gdbm" ) AC_ARG_WITH(mysql, [ --without-mysql omit MySQL backend support], canuse_mysql="$with_mysql" ) AC_ARG_WITH(sqlite, [ --without-sqlite omit SQLite v2.x backend support], canuse_sqlite="$with_sqlite" ) dnl Check for various programs. dnl CFLAGS=${CFLAGS-"-O2 -Wall -s"} AC_PROG_CC AC_PROG_CPP AC_CHECK_TOOL(LD, ld, libtool --mode=link gcc) AC_SUBST(LD) AC_PROG_INSTALL AC_PROG_MAKE_SET AC_CHECK_PROG(DO_GZIP, gzip, gzip -f9, touch) dnl Check for the maths library. dnl AC_SEARCH_LIBS(pow, m, , [AC_ERROR(maths library not found)]) dnl Check for various header files and set various other macros. dnl AC_DEFINE(HAVE_CONFIG_H) AC_HEADER_STDC AC_C_BIGENDIAN([AC_DEFINE(IS_BIG_ENDIAN)]) AC_CHECK_FUNCS(memcpy, , [AC_ERROR(the memcpy() function is required)]) AC_CHECK_FUNCS(fcntl getopt getopt_long mkstemp snprintf vsnprintf utime) AC_CHECK_HEADERS(fcntl.h getopt.h limits.h sys/resource.h mcheck.h) AC_FUNC_MMAP dnl Check for backend databases and choose one. dnl PREVCFLAGS="$CFLAGS" PREVCPPFLAGS="$CPPFLAGS" PREVLIBS="$LIBS" if test "x$canuse_mysql" = "xyes"; then dnl dnl First we try linking without the mysql_config libs, because on dnl some systems that'll give us a dynamic library - the dnl mysql_config libs often point us to static libraries. dnl dnl If static linking is enabled, we ONLY try the mysql_config libs. dnl CFLAGS=`mysql_config --cflags 2>/dev/null` CPPFLAGS=`mysql_config --include 2>/dev/null` || CPPFLAGS="$CFLAGS" LIBS="" if test "x$enable_static" != "xyes"; then AC_CHECK_HEADERS(mysql.h, [ AC_SEARCH_LIBS(mysql_real_connect, mysqlclient, [ AC_SEARCH_LIBS(mysql_real_escape_string, mysqlclient, , canuse_mysql="no") ], canuse_mysql="no") ], canuse_mysql="no") fi if test "x$canuse_mysql" = "xno"; then canuse_mysql=yes LIBS=`mysql_config --libs 2>/dev/null` AC_CHECK_HEADERS(mysql.h, [ AC_SEARCH_LIBS(mysql_real_escape_string, mysqlclient, , canuse_mysql="no") ], canuse_mysql="no") fi if test "x$enable_static" = "xyes"; then LIBS=`mysql_config --libs 2>/dev/null` AC_CHECK_HEADERS(mysql.h, [ AC_SEARCH_LIBS(mysql_real_query, mysqlclient, , canuse_mysql="no") ], canuse_mysql="no") fi if test "x$canuse_mysql" = "xyes"; then AC_CHECK_FUNCS(mysql_autocommit) fi MYSQLCFLAGS="$CFLAGS" MYSQLLIBS="$LIBS" CFLAGS="$PREVCFLAGS" CPPFLAGS="$PREVCPPFLAGS" LIBS="$PREVLIBS" fi if test "x$canuse_gdbm" = "xyes"; then PREVLIBS="$LIBS" LIBS="" AC_CHECK_HEADERS(gdbm.h, [ AC_SEARCH_LIBS(gdbm_open, gdbm, [ AC_CHECK_FUNCS(gdbm_fdesc) ], canuse_gdbm="no") ], canuse_gdbm="no") dnl dnl This is a hideous hack to try and find ".a" (static) dnl library replacements if --enable-static is given. dnl if test "x$enable_static" = "xyes"; then LIBDIR=`echo "$LIBS" | tr ' ' '\n' | sed -n 's/^-L//p'` test -z "$LIBDIR" && LIBDIR=/usr/lib LIBLIST=`echo "$LIBS" | tr ' ' '\n' | sed -n "s,^-l,$LIBDIR/lib,p" | sed -e 's,$,.a,'` NEWLIBS="" for i in $LIBLIST; do test -e "$i" && NEWLIBS="$NEWLIBS $i" done test -n "$NEWLIBS" && LIBS="$NEWLIBS" fi GDBMLIBS="$LIBS" LIBS="$PREVLIBS" fi if test "x$canuse_sqlite" = "xyes"; then LIBS="" AC_CHECK_HEADERS(sqlite.h, [ AC_SEARCH_LIBS(sqlite_open, sqlite, , canuse_sqlite="no") ], canuse_sqlite="no") dnl Hideous hack as above. if test "x$enable_static" = "xyes"; then LIBDIR=`echo "$LIBS" | tr ' ' '\n' | sed -n 's/^-L//p'` test -z "$LIBDIR" && LIBDIR=/usr/lib LIBLIST=`echo "$LIBS" | tr ' ' '\n' | sed -n "s,^-l,$LIBDIR/lib,p" | sed -e 's,$,.a,'` NEWLIBS="" for i in $LIBLIST; do test -e "$i" && NEWLIBS="$NEWLIBS $i" done test -n "$NEWLIBS" && LIBS="$NEWLIBS" fi SQLITELIBS="$LIBS" LIBS="$PREVLIBS" fi if test "x$canuse_list" = "xyes"; then AC_CHECK_HEADERS(search.h, [ AC_CHECK_FUNCS(bsearch qsort, [], canuse_list="no") ], canuse_list="no") fi AC_MSG_CHECKING(which backend databases are available) BACKENDS="" if test "x$canuse_obtree" = "xyes"; then AC_DEFINE(USING_OBTREE) BACKENDS="$BACKENDS obtree" fi if test "x$canuse_btree" = "xyes"; then AC_DEFINE(USING_BTREE) BACKENDS="$BACKENDS btree" fi if test "x$canuse_list" = "xyes"; then AC_DEFINE(USING_LIST) BACKENDS="$BACKENDS list" fi if test "x$canuse_gdbm" = "xyes"; then AC_DEFINE(USING_GDBM) EXTRALIBS="$EXTRALIBS $GDBMLIBS" BACKENDS="$BACKENDS GDBM" fi if test "x$canuse_mysql" = "xyes"; then AC_DEFINE(USING_MYSQL) EXTRALIBS="$EXTRALIBS $MYSQLLIBS" CFLAGS="$CFLAGS $MYSQLCFLAGS" BACKENDS="$BACKENDS MySQL" fi if test "x$canuse_sqlite" = "xyes"; then AC_DEFINE(USING_SQLITE) EXTRALIBS="$EXTRALIBS $SQLITELIBS" CFLAGS="$CFLAGS $SQLITECFLAGS" BACKENDS="$BACKENDS SQLite2" fi if test "x$BACKENDS" = "x"; then AC_MSG_RESULT(none) AC_MSG_ERROR(no usable database libraries found) else AC_MSG_RESULT($BACKENDS) fi LIBS="$LIBS $EXTRALIBS" AC_DEFINE_UNQUOTED(BACKENDS, "$BACKENDS") AC_SUBST(BACKENDS) test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' AC_SUBST(INSTALL_DATA) dnl Fudging for separate build directories. dnl subdirs="" for i in `find $srcdir/src -type d -print | sed s,$srcdir/,,`; do subdirs="$subdirs $i" done dnl Stitch together the Makefile fragments. dnl mk_segments="autoconf/Makefile.in" for i in vars.mk package.mk filelist.mk unreal.mk modules.mk \ rules.mk link.mk depend.mk; do mk_segments="$mk_segments:autoconf/make/$i" done dnl Output files (and create build directory structure too). dnl AC_OUTPUT(Makefile:$mk_segments doc/lsm:doc/lsm.in doc/quickref.1:doc/quickref.1.in doc/$PACKAGE.spec:doc/spec.in src/.dummy:doc/NEWS, rm -f src/.dummy for i in $subdirs; do test -d $i || mkdir $i done , subdirs="$subdirs") dnl EOF qsf-1.2.7/autoconf/header.in0000644000076400007640000000302010554714251013517 0ustar awaw/* Define if you have standard C headers. */ #undef STDC_HEADERS /* Define if you have "config.h" (yes, you have). */ #undef HAVE_CONFIG_H /* Define these to select database backends. */ #undef USING_OBTREE #undef USING_BTREE #undef USING_LIST #undef USING_GDBM #undef USING_MYSQL #undef USING_SQLITE /* Define if debugging is to be compiled in. */ #undef DEBUG /* Define these for various system header files and functions. */ #undef HAVE_GETOPT_H #undef HAVE_MCHECK_H #undef HAVE_SYS_RESOURCE_H #undef HAVE_FCNTL_H #undef HAVE_MKSTEMP #undef HAVE_GETOPT #undef HAVE_FCNTL #undef HAVE_SNPRINTF #undef HAVE_VSNPRINTF #undef HAVE_GETOPT_LONG #undef HAVE_GDBM_FDESC #undef HAVE_MMAP #undef HAVE_UTIME #undef HAVE_SEARCH_H #undef HAVE_BSEARCH #undef HAVE_QSORT #undef HAVE_MYSQL_AUTOCOMMIT #undef IS_BIG_ENDIAN #ifdef ENABLE_NLS # include # ifdef HAVE_LOCALE_H # include # endif # define _(String) gettext (String) # define N_(String) gettext_noop (String) #else # define _(String) (String) #endif /* The name of the program. */ #define PROGRAM_NAME "progname" /* The name of the package. */ #define PACKAGE "" /* The current package version. */ #define VERSION "0.0.0" /* Various identification and legal drivel. */ #define COPYRIGHT_YEAR _("2007") #define COPYRIGHT_HOLDER _("Andrew Wood ") #define PROJECT_HOMEPAGE "http://www.ivarch.com/programs/" PROGRAM_NAME "/" #define BUG_REPORTS_TO _("Andrew Wood ") /* Backends available. */ #define BACKENDS "" /* EOF */ qsf-1.2.7/autoconf/make/0000755000076400007640000000000010665021416012656 5ustar awawqsf-1.2.7/autoconf/make/filelist.mk0000644000076400007640000000565510665021314015032 0ustar awaw# Automatically generated file listings # # Creation time: Tue Aug 28 14:27:40 BST 2007 allsrc = src/library.c \ src/md5.c \ src/db/obtree.c \ src/db/list.c \ src/db/main.c \ src/db/gdbm.c \ src/db/btree.c \ src/db/sqlite.c \ src/db/mysql.c \ src/main/help.c \ src/main/options.c \ src/main/version.c \ src/main/main.c \ src/main/log.c \ src/main/tick.c \ src/spam/update.c \ src/spam/merge.c \ src/spam/alloc.c \ src/spam/train.c \ src/spam/cksum.c \ src/spam/benchmark.c \ src/spam/check.c \ src/spam/plaintext.c \ src/spam/dump.c \ src/spam/token.c \ src/spam/db.c \ src/spam/prune.c \ src/spam/allowlist.c \ src/message/parse.c \ src/message/alloc.c \ src/message/read.c \ src/message/rfc2047.c \ src/message/header.c \ src/message/qp.c \ src/message/dump.c \ src/message/base64.c \ src/tests/gtube.c \ src/tests/main.c \ src/tests/imgcount.c \ src/tests/urls.c \ src/tests/gibberish.c \ src/tests/attached_files.c \ src/tests/html.c \ src/mailbox/alloc.c \ src/mailbox/count.c \ src/mailbox/select.c \ src/mailbox/scan.c allobj = src/library.o \ src/md5.o \ src/db/obtree.o \ src/db/list.o \ src/db/main.o \ src/db/gdbm.o \ src/db/btree.o \ src/db/sqlite.o \ src/db/mysql.o \ src/main/help.o \ src/main/options.o \ src/main/version.o \ src/main/main.o \ src/main/log.o \ src/main/tick.o \ src/spam/update.o \ src/spam/merge.o \ src/spam/alloc.o \ src/spam/train.o \ src/spam/cksum.o \ src/spam/benchmark.o \ src/spam/check.o \ src/spam/plaintext.o \ src/spam/dump.o \ src/spam/token.o \ src/spam/db.o \ src/spam/prune.o \ src/spam/allowlist.o \ src/message/parse.o \ src/message/alloc.o \ src/message/read.o \ src/message/rfc2047.o \ src/message/header.o \ src/message/qp.o \ src/message/dump.o \ src/message/base64.o \ src/tests/gtube.o \ src/tests/main.o \ src/tests/imgcount.o \ src/tests/urls.o \ src/tests/gibberish.o \ src/tests/attached_files.o \ src/tests/html.o \ src/mailbox/alloc.o \ src/mailbox/count.o \ src/mailbox/select.o \ src/mailbox/scan.o \ src/db.o \ src/main.o \ src/spam.o \ src/message.o \ src/tests.o \ src/mailbox.o alldep = src/library.d \ src/md5.d \ src/db/obtree.d \ src/db/list.d \ src/db/main.d \ src/db/gdbm.d \ src/db/btree.d \ src/db/sqlite.d \ src/db/mysql.d \ src/main/help.d \ src/main/options.d \ src/main/version.d \ src/main/main.d \ src/main/log.d \ src/main/tick.d \ src/spam/update.d \ src/spam/merge.d \ src/spam/alloc.d \ src/spam/train.d \ src/spam/cksum.d \ src/spam/benchmark.d \ src/spam/check.d \ src/spam/plaintext.d \ src/spam/dump.d \ src/spam/token.d \ src/spam/db.d \ src/spam/prune.d \ src/spam/allowlist.d \ src/message/parse.d \ src/message/alloc.d \ src/message/read.d \ src/message/rfc2047.d \ src/message/header.d \ src/message/qp.d \ src/message/dump.d \ src/message/base64.d \ src/tests/gtube.d \ src/tests/main.d \ src/tests/imgcount.d \ src/tests/urls.d \ src/tests/gibberish.d \ src/tests/attached_files.d \ src/tests/html.d \ src/mailbox/alloc.d \ src/mailbox/count.d \ src/mailbox/select.d \ src/mailbox/scan.d qsf-1.2.7/autoconf/make/rules.mk0000644000076400007640000000057607701413734014356 0ustar awaw# # Compilation rules. # # .SUFFIXES: .c .d .o .c.o: $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< .c.d: sh $(srcdir)/autoconf/scripts/depend.sh \ $(CC) $< $(<:%.c=%) $(srcdir) $(CFLAGS) $(CPPFLAGS) > $@ doc/quickref.txt: doc/quickref.1 man doc/quickref.1 | col -b | cat -s > doc/quickref.txt || : chmod 644 doc/quickref.txt || : qsf-1.2.7/autoconf/make/vars.mk0000644000076400007640000000116210507164042014160 0ustar awaw# # Variables for Make. # srcdir = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ infodir = @infodir@ mandir = @mandir@ etcdir = @prefix@/etc datadir = @datadir@ sbindir = @sbindir@ VPATH = $(srcdir) @SET_MAKE@ SHELL = /bin/sh CC = @CC@ LD = @LD@ DO_GZIP = @DO_GZIP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ UNINSTALL = rm -f LDFLAGS = -r DEFS = @DEFS@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ -I$(srcdir)/src/include -Isrc/include $(DEFS) LIBS = @LDFLAGS@ @LIBS@ testdb := /tmp/@PACKAGE@test.db testfile := /tmp/@PACKAGE@test.txt testbackends := @BACKENDS@ alltarg = @PACKAGE@ # EOF qsf-1.2.7/autoconf/make/package.mk0000644000076400007640000000043610013256020014571 0ustar awaw# # Package name, version, and distribution files. # package = @PACKAGE@ version = @VERSION@ PACKAGE = @PACKAGE@ distfiles = \ $(srcdir)/README \ $(srcdir)/autoconf \ $(srcdir)/configure \ $(srcdir)/doc \ $(srcdir)/src \ $(srcdir)/test \ $(srcdir)/debian \ $(srcdir)/extra # EOF qsf-1.2.7/autoconf/make/depend.mk0000644000076400007640000001451510665021321014447 0ustar awaw# # Dependencies. # src/library.d src/library.o: src/library.c src/include/config.h src/md5.d src/md5.o: src/md5.c src/include/md5.h src/include/config.h src/db/obtree.d src/db/obtree.o: src/db/obtree.c src/include/config.h src/include/database.h src/include/log.h src/db/list.d src/db/list.o: src/db/list.c src/include/config.h src/include/database.h src/include/log.h src/db/main.d src/db/main.o: src/db/main.c src/include/config.h src/include/database.h src/db/gdbm.d src/db/gdbm.o: src/db/gdbm.c src/include/config.h src/include/database.h src/db/btree.d src/db/btree.o: src/db/btree.c src/include/config.h src/include/database.h src/include/log.h src/db/sqlite.d src/db/sqlite.o: src/db/sqlite.c src/include/config.h src/include/database.h src/include/log.h src/db/mysql.d src/db/mysql.o: src/db/mysql.c src/include/config.h src/include/database.h src/include/log.h src/main/help.d src/main/help.o: src/main/help.c src/include/config.h src/main/options.d src/main/options.o: src/main/options.c src/include/config.h src/include/options.h src/include/spam.h src/include/message.h src/include/log.h src/main/version.d src/main/version.o: src/main/version.c src/include/config.h src/main/main.d src/main/main.o: src/main/main.c src/include/config.h src/include/options.h src/include/message.h src/include/spam.h src/include/database.h src/include/log.h src/main/log.d src/main/log.o: src/main/log.c src/include/config.h src/include/log.h src/main/tick.d src/main/tick.o: src/main/tick.c src/include/config.h src/spam/update.d src/spam/update.o: src/spam/update.c src/include/config.h src/spam/spami.h src/include/options.h src/include/message.h src/include/database.h src/include/spam.h src/spam/merge.d src/spam/merge.o: src/spam/merge.c src/include/config.h src/spam/spami.h src/include/options.h src/include/message.h src/include/database.h src/include/spam.h src/spam/alloc.d src/spam/alloc.o: src/spam/alloc.c src/include/config.h src/spam/spami.h src/include/options.h src/include/message.h src/include/database.h src/include/spam.h src/spam/train.d src/spam/train.o: src/spam/train.c src/include/config.h src/include/mailbox.h src/include/options.h src/spam/spami.h src/include/message.h src/include/database.h src/include/spam.h src/spam/cksum.d src/spam/cksum.o: src/spam/cksum.c src/include/config.h src/include/md5.h src/spam/benchmark.d src/spam/benchmark.o: src/spam/benchmark.c src/include/config.h src/include/mailbox.h src/include/options.h src/spam/spami.h src/include/message.h src/include/database.h src/include/spam.h src/spam/check.d src/spam/check.o: src/spam/check.c src/include/config.h src/spam/spami.h src/include/options.h src/include/message.h src/include/database.h src/include/spam.h src/include/log.h src/spam/plaintext.d src/spam/plaintext.o: src/spam/plaintext.c src/include/config.h src/spam/spami.h src/include/options.h src/include/message.h src/include/database.h src/include/spam.h src/include/log.h src/spam/dump.d src/spam/dump.o: src/spam/dump.c src/include/config.h src/spam/spami.h src/include/options.h src/include/message.h src/include/database.h src/include/spam.h src/spam/token.d src/spam/token.o: src/spam/token.c src/include/config.h src/spam/spami.h src/include/options.h src/include/message.h src/include/database.h src/include/spam.h src/spam/db.d src/spam/db.o: src/spam/db.c src/include/config.h src/spam/spami.h src/include/options.h src/include/message.h src/include/database.h src/include/spam.h src/spam/prune.d src/spam/prune.o: src/spam/prune.c src/include/config.h src/spam/spami.h src/include/options.h src/include/message.h src/include/database.h src/include/spam.h src/spam/allowlist.d src/spam/allowlist.o: src/spam/allowlist.c src/include/config.h src/spam/spami.h src/include/options.h src/include/message.h src/include/database.h src/include/spam.h src/include/log.h src/message/parse.d src/message/parse.o: src/message/parse.c src/include/config.h src/include/message.h src/include/options.h src/include/md5.h src/message/alloc.d src/message/alloc.o: src/message/alloc.c src/include/config.h src/include/message.h src/include/options.h src/message/read.d src/message/read.o: src/message/read.c src/include/config.h src/include/message.h src/include/options.h src/message/rfc2047.d src/message/rfc2047.o: src/message/rfc2047.c src/include/config.h src/include/message.h src/include/options.h src/message/header.d src/message/header.o: src/message/header.c src/include/config.h src/include/message.h src/include/options.h src/message/qp.d src/message/qp.o: src/message/qp.c src/include/config.h src/message/dump.d src/message/dump.o: src/message/dump.c src/include/config.h src/include/message.h src/include/options.h src/include/log.h src/message/base64.d src/message/base64.o: src/message/base64.c src/include/config.h src/tests/gtube.d src/tests/gtube.o: src/tests/gtube.c src/include/config.h src/tests/testi.h src/include/options.h src/include/message.h src/tests/main.d src/tests/main.o: src/tests/main.c src/include/config.h src/tests/testi.h src/include/options.h src/include/message.h src/tests/imgcount.d src/tests/imgcount.o: src/tests/imgcount.c src/include/config.h src/tests/testi.h src/include/options.h src/include/message.h src/tests/urls.d src/tests/urls.o: src/tests/urls.c src/include/config.h src/tests/testi.h src/include/options.h src/include/message.h src/include/spam.h src/tests/gibberish.d src/tests/gibberish.o: src/tests/gibberish.c src/include/config.h src/tests/testi.h src/include/options.h src/include/message.h src/tests/attached_files.d src/tests/attached_files.o: src/tests/attached_files.c src/include/config.h src/tests/testi.h src/include/options.h src/include/message.h src/tests/html.d src/tests/html.o: src/tests/html.c src/include/config.h src/tests/testi.h src/include/options.h src/include/message.h src/include/spam.h src/mailbox/alloc.d src/mailbox/alloc.o: src/mailbox/alloc.c src/include/config.h src/include/mailbox.h src/include/options.h src/mailbox/mailboxi.h src/mailbox/count.d src/mailbox/count.o: src/mailbox/count.c src/include/config.h src/include/mailbox.h src/include/options.h src/mailbox/mailboxi.h src/mailbox/select.d src/mailbox/select.o: src/mailbox/select.c src/include/config.h src/include/mailbox.h src/include/options.h src/mailbox/mailboxi.h src/mailbox/scan.d src/mailbox/scan.o: src/mailbox/scan.c src/include/config.h src/include/mailbox.h src/include/options.h src/mailbox/mailboxi.h qsf-1.2.7/autoconf/make/unreal.mk0000644000076400007640000003520310554427314014504 0ustar awaw# # Rules for all phony targets. # .PHONY: all help dep depend depclean make \ check test memtest benchmark bigbenchmark \ clean distclean cvsclean \ index manhtml indent indentclean \ changelog doc dist release \ install uninstall \ rpmbuild srpm rpm deb all: $(alltarg) help: @echo 'This Makefile has the following utility targets:' @echo @echo ' all build all binary targets' @echo ' doc regenerate text version of man page' @echo ' install install compiled package and manual' @echo ' uninstall uninstall the package' @echo ' check / test run standardised tests on the compiled binary' @echo @echo 'Developer targets:' @echo @echo ' make rebuild the Makefile (after adding new files)' @echo ' dep / depend rebuild .d (dependency) files' @echo ' clean remove .o (object) and .c~ (backup) files' @echo ' depclean remove .d (dependency) files' @echo ' indentclean remove files left over from "make indent"' @echo ' distclean remove everything not distributed' @echo ' cvsclean remove everything not in CVS' @echo @echo ' index generate an HTML index of source code' @echo ' manhtml output HTML man page to stdout' @echo ' indent reformat all source files with "indent"' @echo ' changelog generate doc/changelog from CVS log info' @echo @echo ' memtest run "make test" using valgrind to find faults' @echo ' benchmark run benchmarking tests' @echo ' bigbenchmark run many benchmarking tests to make a graph' @echo @echo ' dist create a source tarball for distribution' @echo ' rpm build a binary RPM (passes $$RPMFLAGS to RPM)' @echo ' srpm build a source RPM (passes $$RPMFLAGS to RPM)' @echo ' deb build a binary Debian package' @echo ' release dist+rpm+srpm' @echo @echo 'Note that "test", "memtest", and "{,big}benchmark" can be passed' @echo 'additional environment variables: BACKENDS is a space separated' @echo 'list of backends to test (default is to test all) and MYSQLDB' @echo 'is a database spec for testing the MySQL backend, in the same' @echo 'format as for @PACKAGE@ -d, eg MYSQLDB=database=foo;host=...' @echo make: echo > $(srcdir)/autoconf/make/filelist.mk echo > $(srcdir)/autoconf/make/modules.mk cd $(srcdir); \ bash autoconf/scripts/makemake.sh \ autoconf/make/filelist.mk \ autoconf/make/modules.mk sh ./config.status dep depend: $(alldep) echo '#' > $(srcdir)/autoconf/make/depend.mk echo '# Dependencies.' >> $(srcdir)/autoconf/make/depend.mk echo '#' >> $(srcdir)/autoconf/make/depend.mk echo >> $(srcdir)/autoconf/make/depend.mk cat $(alldep) >> $(srcdir)/autoconf/make/depend.mk sh ./config.status clean: rm -f $(allobj) find . -type f -name "*.c~" -exec rm -f '{}' ';' rm -f memtest-out-* rm -f benchmark-report benchmark-data-* benchmark-graph-* depclean: rm -f $(alldep) indentclean: cd $(srcdir) && for FILE in $(allsrc); do rm -fv ./$${FILE}~; done distclean: clean depclean rm -f $(alltarg) src/include/config.h rm -rf $(package)-$(version).tar* $(package)-$(version) BUILD-DEB rm -f *.rpm *.deb rm -f *.html config.* rm -f test.db trace rm -f .test-spam .test-non-spam rm -f .test-benchmark-spam .test-benchmark-non-spam rm -f .testdump-a .testdump-b .testdump-c rm -f fakemail mboxsplit gmon.out rm Makefile cvsclean: distclean rm -f doc/lsm rm -f doc/$(package).spec rm -f doc/quickref.1 rm -f doc/quickref.txt rm -f configure rm -f doc/changelog ChangeLog cat /dev/null > $(srcdir)/autoconf/make/depend.mk cat /dev/null > $(srcdir)/autoconf/make/filelist.mk cat /dev/null > $(srcdir)/autoconf/make/modules.mk doc: doc/quickref.txt index: (cd $(srcdir); sh autoconf/scripts/index.sh $(srcdir)) > index.html manhtml: @man2html ./doc/quickref.1 \ | sed -e '1,/]*> ||ig' \ -e 's|]*>\([^<]*\)|\1|ig' \ -e '/

\)|\1

|ig' \ -e 's/

/
/ig' \ -e 's/<[0-9A-Za-z_.-]\+@[0-9A-Za-z_.-]\+>//g' \ -e 's|\(http://.*\)|\1|ig' \ | sed -e '1,/
Index/,/
/dev/null 2>&1 || ( \ echo '*** Please put cvs2cl in your PATH'; \ echo '*** Get it from http://www.red-bean.com/cvs2cl/'; \ exit 1; \ ) rm -f $(srcdir)/ChangeLog cd $(srcdir) && cvs2cl -S -P mv -f $(srcdir)/ChangeLog doc/changelog dist: doc test -d $(srcdir)/CVS && $(MAKE) changelog || : rm -rf $(package)-$(version) mkdir $(package)-$(version) cp -dprf Makefile $(distfiles) $(package)-$(version) cd $(package)-$(version); $(MAKE) distclean -cp -dpf doc/changelog $(package)-$(version)/doc/ cp -dpf doc/lsm $(package)-$(version)/doc/ cp -dpf doc/$(package).spec $(package)-$(version)/doc/ cp -dpf doc/quickref.txt $(package)-$(version)/doc/ chmod 644 `find $(package)-$(version) -type f -print` chmod 755 `find $(package)-$(version) -type d -print` chmod 755 `find $(package)-$(version)/autoconf/scripts` chmod 755 $(package)-$(version)/configure chmod 755 $(package)-$(version)/debian/rules rm -rf DUMMY `find $(package)-$(version) -type d -name CVS` \ `find $(package)-$(version) -type f -name .cvsignore` tar cf $(package)-$(version).tar $(package)-$(version) rm -rf $(package)-$(version) -cat $(package)-$(version).tar \ | bzip2 > $(package)-$(version).tar.bz2 \ || rm -f $(package)-$(version).tar.bz2 $(DO_GZIP) $(package)-$(version).tar .test-spam: $(CC) $(CFLAGS) $(CPPFLAGS) -o fakemail $(srcdir)/autoconf/scripts/fakemail.c ./fakemail \ $(srcdir)/test/tokenlist-non-spam 15 > .test-non-spam ./fakemail \ $(srcdir)/test/tokenlist-spam 15 > .test-spam check test: $(package) .test-spam @$(CC) -o mboxsplit $(srcdir)/autoconf/scripts/mboxsplit.c @FAIL=0; PROG=./$(package); TESTDB=$(testdb); TESTFILE=$(testfile); \ export PROG TESTDB TESTFILE; \ test "x$$BACKENDS" = x && BACKENDS="$(testbackends)"; \ CREATEDTABLE=""; \ if test x$$MYSQLDB = x; then \ CREATEDTABLE=@PACKAGE@test$$RANDOM; \ if mysql test -Be "CREATE TABLE $$CREATEDTABLE ( key1 BIGINT UNSIGNED NOT NULL, key2 BIGINT UNSIGNED NOT NULL, token VARCHAR(64) DEFAULT '' NOT NULL, value1 INT UNSIGNED NOT NULL, value2 INT UNSIGNED NOT NULL, value3 INT UNSIGNED NOT NULL, PRIMARY KEY (key1,key2,token), KEY (key1), KEY (key2), KEY (token) );" >/dev/null 2>&1; then \ MYSQLDB="database=test;host=localhost;port=3306;user=$$USER;pass=;table=$$CREATEDTABLE;key1=0;key2=0"; \ else \ CREATEDTABLE=""; \ fi; \ fi; \ for BACKEND in $$BACKENDS; do \ SKIPMYSQL=0; \ test $$BACKEND = MySQL && test x$$MYSQLDB = x && SKIPMYSQL=1; \ test $$BACKEND = mysql && test x$$MYSQLDB = x && SKIPMYSQL=1; \ test $$SKIPMYSQL = 1 && echo \*\*\* MySQL tests disabled - define \$$MYSQLDB; \ test $$SKIPMYSQL = 1 && echo \*\*\* to enable \(see man page for spec format\); \ test $$SKIPMYSQL = 1 && continue; \ TESTDB=$(testdb); \ rm -f $$TESTDB; \ export BACKEND; \ test $$BACKEND = MySQL && TESTDB=$$MYSQLDB; \ test $$BACKEND = mysql && TESTDB=$$MYSQLDB; \ for SCRIPT in $(srcdir)/test/t[0-9]*; do \ test -f $$SCRIPT || continue; \ sed -n 's/^# *TEST: */'"$$BACKEND"': /p' < $$SCRIPT | tr "\n" ' '; \ STATUS=0; \ sh -e $$SCRIPT || STATUS=1; \ test $$STATUS -eq 1 && FAIL=1; \ test $$STATUS -eq 1 && echo FAILED || echo OK; \ done; rm -f $$TESTDB $$TESTFILE; \ done; \ test x$$CREATEDTABLE = x || mysql test -Be "DROP TABLE $$CREATEDTABLE;" >/dev/null 2>&1; \ exit $$FAIL memtest: $(package) .test-spam @which valgrind >/dev/null 2>/dev/null || (\ echo These tests require valgrind to be installed.; \ echo See http://valgrind.kde.org/ for details.; \ exit 1; \ ) @$(CC) -o mboxsplit $(srcdir)/autoconf/scripts/mboxsplit.c @FAIL=0; \ PROG="valgrind --tool=memcheck --leak-check=yes --db-attach=no ./$(package)"; \ TESTDB=$(testdb); TESTFILE=$(testfile); \ export PROG TESTDB TESTFILE; \ test "x$$BACKENDS" = x && BACKENDS="$(testbackends)"; \ CREATEDTABLE=""; \ if test x$$MYSQLDB = x; then \ CREATEDTABLE=@PACKAGE@test$$RANDOM; \ if mysql test -Be "CREATE TABLE $$CREATEDTABLE ( key1 BIGINT UNSIGNED NOT NULL, key2 BIGINT UNSIGNED NOT NULL, token VARCHAR(64) DEFAULT '' NOT NULL, value1 INT UNSIGNED NOT NULL, value2 INT UNSIGNED NOT NULL, value3 INT UNSIGNED NOT NULL, PRIMARY KEY (key1,key2,token), KEY (key1), KEY (key2), KEY (token) );" >/dev/null 2>&1; then \ MYSQLDB="database=test;host=localhost;port=3306;user=$$USER;pass=;table=$$CREATEDTABLE;key1=0;key2=0"; \ else \ CREATEDTABLE=""; \ fi; \ fi; \ for BACKEND in $$BACKENDS; do \ SKIPMYSQL=0; \ test $$BACKEND = MySQL && test x$$MYSQLDB = x && SKIPMYSQL=1; \ test $$BACKEND = mysql && test x$$MYSQLDB = x && SKIPMYSQL=1; \ test $$SKIPMYSQL = 1 && echo \*\*\* MySQL tests disabled - define \$$MYSQLDB; \ test $$SKIPMYSQL = 1 && echo \*\*\* to enable \(see man page for spec format\); \ test $$SKIPMYSQL = 1 && continue; \ TESTDB=$(testdb); \ rm -f $$TESTDB; \ export BACKEND; \ test $$BACKEND = MySQL && TESTDB=$$MYSQLDB; \ test $$BACKEND = mysql && TESTDB=$$MYSQLDB; \ for SCRIPT in $(srcdir)/test/t[0-9]*; do \ test -f $$SCRIPT || continue; \ TESTOUT=memtest-out-$$BACKEND-`basename $$SCRIPT`; \ sed -n 's/^# *TEST: */'"$$BACKEND"': /p' < $$SCRIPT | tr "\n" ' '; \ STATUS=0; \ sh -e $$SCRIPT >$$TESTOUT 2>&1 || STATUS=1; \ grep '^==[0-9]\+== ERROR SUMMARY: ' $$TESTOUT \ | grep -q -v '^==[0-9]\+== ERROR SUMMARY: 0 ' && STATUS=2; \ test $$STATUS -eq 1 && FAIL=1; \ test $$STATUS -eq 2 && FAIL=1; \ test $$STATUS -eq 1 && echo FAILED, MEMTEST OK; \ test $$STATUS -eq 2 && echo FAILED MEMTEST; \ test $$STATUS -eq 0 && echo OK; \ done; rm -f $$TESTDB $$TESTFILE; \ done; \ test x$$CREATEDTABLE = x || mysql test -Be "DROP TABLE $$CREATEDTABLE;" >/dev/null 2>&1; \ exit $$FAIL .test-benchmark-spam: $(CC) $(CFLAGS) $(CPPFLAGS) -o fakemail $(srcdir)/autoconf/scripts/fakemail.c ./fakemail \ $(srcdir)/test/tokenlist-non-spam 1500 > .test-benchmark-non-spam ./fakemail \ $(srcdir)/test/tokenlist-spam 1500 > .test-benchmark-spam benchmark: $(package) .test-benchmark-spam @test "x$$BACKENDS" = x && BACKENDS="$(testbackends)"; \ CREATEDTABLE=""; \ if test x$$MYSQLDB = x; then \ CREATEDTABLE=@PACKAGE@test$$RANDOM; \ if mysql test -Be "CREATE TABLE $$CREATEDTABLE ( key1 BIGINT UNSIGNED NOT NULL, key2 BIGINT UNSIGNED NOT NULL, token VARCHAR(64) DEFAULT '' NOT NULL, value1 INT UNSIGNED NOT NULL, value2 INT UNSIGNED NOT NULL, value3 INT UNSIGNED NOT NULL, PRIMARY KEY (key1,key2,token), KEY (key1), KEY (key2), KEY (token) );" >/dev/null 2>&1; then \ MYSQLDB="database=test;host=localhost;port=3306;user=$$USER;pass=;table=$$CREATEDTABLE;key1=0;key2=0"; \ else \ CREATEDTABLE=""; \ fi; \ fi; \ for BACKEND in $$BACKENDS; do \ SKIPMYSQL=0; \ test $$BACKEND = MySQL && test x$$MYSQLDB = x && SKIPMYSQL=1; \ test $$BACKEND = mysql && test x$$MYSQLDB = x && SKIPMYSQL=1; \ test $$SKIPMYSQL = 1 && echo \*\*\* MySQL tests disabled - define \$$MYSQLDB; \ test $$SKIPMYSQL = 1 && echo \*\*\* to enable \(see man page for spec format\); \ test $$SKIPMYSQL = 1 && continue; \ TESTDB=$$BACKEND; \ test $$BACKEND = MySQL && TESTDB=mysql:$$MYSQLDB; \ test $$BACKEND = mysql && TESTDB=mysql:$$MYSQLDB; \ ./$(package) -d $$TESTDB -B .test-benchmark-spam .test-benchmark-non-spam; \ done; \ test x$$CREATEDTABLE = x || mysql test -Be "DROP TABLE $$CREATEDTABLE;" >/dev/null 2>&1 bigbenchmark: $(package) .test-benchmark-spam rm -f benchmark-report benchmark-data-* benchmark-graph-* test "x$$BACKENDS" = x && BACKENDS="$(testbackends)"; \ echo "set title 'Training times'" > benchmark-graph-train; \ echo "set title 'Classification times'" > benchmark-graph-class; \ echo "set title 'Accuracy of trained database'" > benchmark-graph-accuracy; \ for GRAPH in train class accuracy; do \ CMD=""; \ for BACKEND in $$BACKENDS; do \ CMD="$$CMD, 'benchmark-data-$$GRAPH-$$BACKEND' title '$$BACKEND' with linespoints"; \ done; \ echo "$$CMD" | sed -e 's/^,/plot/' -e 's/SQLite2/sqlite/g' >> benchmark-graph-$$GRAPH; \ done for NUM in 5 6 7 8 9 10 11 12 14 16 18 20 22 24 26 28 30 35 40 45 50 55 60 65 70 80 90 100 120 140 160 180 200 250 300 350 400 450 500 600 700 800 900 1000 1100 1200 1300 1400 1500; do \ ./fakemail $(srcdir)/test/tokenlist-non-spam $$NUM > .test-benchmark-non-spam; \ ./fakemail $(srcdir)/test/tokenlist-spam $$NUM > .test-benchmark-spam; \ $(MAKE) benchmark | tee benchmark-report; \ awk -f $(srcdir)/autoconf/scripts/benchmark.awk < benchmark-report; \ $(MAKE) benchmark | tee benchmark-report; \ awk -f $(srcdir)/autoconf/scripts/benchmark.awk < benchmark-report; \ $(MAKE) benchmark | tee benchmark-report; \ awk -f $(srcdir)/autoconf/scripts/benchmark.awk < benchmark-report; \ done @echo @echo 'You can now load the files "benchmark-graph-*" into "gnuplot".' @echo install: all doc $(srcdir)/autoconf/scripts/mkinstalldirs \ "$(DESTDIR)/$(bindir)" $(srcdir)/autoconf/scripts/mkinstalldirs \ "$(DESTDIR)/$(mandir)/man1" $(INSTALL) -m 755 $(package) \ "$(DESTDIR)/$(bindir)/$(package)" $(INSTALL) -m 644 doc/quickref.1 \ "$(DESTDIR)/$(mandir)/man1/$(package).1" $(DO_GZIP) "$(DESTDIR)/$(mandir)/man1/$(package).1" || : uninstall: $(UNINSTALL) "$(DESTDIR)/$(bindir)/$(package)" $(UNINSTALL) "$(DESTDIR)/$(mandir)/man1/$(package).1" $(UNINSTALL) "$(DESTDIR)/$(mandir)/man1/$(package).1.gz" rpmbuild: echo macrofiles: `rpm --showrc \ | grep ^macrofiles \ | cut -d : -f 2- \ | sed 's,^[^/]*/,/,'`:`pwd`/rpmmacros > rpmrc echo %_topdir `pwd`/rpm > rpmmacros rm -rf rpm mkdir rpm mkdir rpm/SPECS rpm/BUILD rpm/SOURCES rpm/RPMS rpm/SRPMS -cat /usr/lib/rpm/rpmrc /etc/rpmrc $$HOME/.rpmrc \ | grep -hsv ^macrofiles \ >> rpmrc srpm: -test -e $(package)-$(version).tar.gz || $(MAKE) dist -test -e rpmrc || $(MAKE) rpmbuild rpmbuild $(RPMFLAGS) --rcfile=rpmrc -ts $(package)-$(version).tar.bz2 mv rpm/SRPMS/*$(package)-*.rpm . rm -rf rpm rpmmacros rpmrc rpm: -test -e $(package)-$(version).tar.gz || $(MAKE) dist -test -e rpmrc || $(MAKE) rpmbuild rpmbuild $(RPMFLAGS) --rcfile=rpmrc -tb $(package)-$(version).tar.bz2 rpmbuild $(RPMFLAGS) --rcfile=rpmrc -tb --with static $(package)-$(version).tar.bz2 mv rpm/RPMS/*/$(package)-*.rpm . rm -rf rpm rpmmacros rpmrc deb: dist rm -rf BUILD-DEB mkdir BUILD-DEB cd BUILD-DEB && tar xzf ../$(package)-$(version).tar.gz cd BUILD-DEB && cd $(package)-$(version) && dpkg-buildpackage -rfakeroot mv BUILD-DEB/*.deb . rm -rf BUILD-DEB release: dist rpm srpm qsf-1.2.7/autoconf/make/modules.mk0000644000076400007640000000365210665021314014662 0ustar awaw# Automatically generated module linking rules # # Creation time: Tue Aug 28 14:27:40 BST 2007 src/db.o: src/db/btree.o src/db/gdbm.o src/db/list.o src/db/main.o src/db/mysql.o src/db/obtree.o src/db/sqlite.o $(LD) $(LDFLAGS) -o $@ src/db/btree.o src/db/gdbm.o src/db/list.o src/db/main.o src/db/mysql.o src/db/obtree.o src/db/sqlite.o src/main.o: src/main/help.o src/main/log.o src/main/main.o src/main/options.o src/main/tick.o src/main/version.o $(LD) $(LDFLAGS) -o $@ src/main/help.o src/main/log.o src/main/main.o src/main/options.o src/main/tick.o src/main/version.o src/spam.o: src/spam/alloc.o src/spam/allowlist.o src/spam/benchmark.o src/spam/check.o src/spam/cksum.o src/spam/db.o src/spam/dump.o src/spam/merge.o src/spam/plaintext.o src/spam/prune.o src/spam/token.o src/spam/train.o src/spam/update.o $(LD) $(LDFLAGS) -o $@ src/spam/alloc.o src/spam/allowlist.o src/spam/benchmark.o src/spam/check.o src/spam/cksum.o src/spam/db.o src/spam/dump.o src/spam/merge.o src/spam/plaintext.o src/spam/prune.o src/spam/token.o src/spam/train.o src/spam/update.o src/message.o: src/message/alloc.o src/message/base64.o src/message/dump.o src/message/header.o src/message/parse.o src/message/qp.o src/message/read.o src/message/rfc2047.o $(LD) $(LDFLAGS) -o $@ src/message/alloc.o src/message/base64.o src/message/dump.o src/message/header.o src/message/parse.o src/message/qp.o src/message/read.o src/message/rfc2047.o src/tests.o: src/tests/attached_files.o src/tests/gibberish.o src/tests/gtube.o src/tests/html.o src/tests/imgcount.o src/tests/main.o src/tests/urls.o $(LD) $(LDFLAGS) -o $@ src/tests/attached_files.o src/tests/gibberish.o src/tests/gtube.o src/tests/html.o src/tests/imgcount.o src/tests/main.o src/tests/urls.o src/mailbox.o: src/mailbox/alloc.o src/mailbox/count.o src/mailbox/scan.o src/mailbox/select.o $(LD) $(LDFLAGS) -o $@ src/mailbox/alloc.o src/mailbox/count.o src/mailbox/scan.o src/mailbox/select.o qsf-1.2.7/autoconf/make/link.mk0000644000076400007640000000043307721207662014154 0ustar awaw# # Targets. # # mainobjs := src/main.o src/md5.o src/library.o src/db.o src/message.o src/mailbox.o src/spam.o src/tests.o $(package): $(mainobjs) $(CC) $(CFLAGS) -o $@ $(mainobjs) $(LIBS) $(package)-static: $(mainobjs) $(CC) $(CFLAGS) -static -o $@ $(mainobjs) $(LIBS) # EOF qsf-1.2.7/autoconf/Makefile.in0000644000076400007640000000101110240610410013762 0ustar awaw# # Files from which this is generated (inside directory `autoconf/make'): # # package.mk # package name and distribution details # vars.mk # compilation, shell and linking variables # filelist.mk # lists of files (autogenerated) # unreal.mk # phony targets # modules.mk # module linking rules (autogenerated) # rules.mk # compilation rules # link.mk # real top-level targets # depend.mk # dependencies (autogenerated) # # qsf-1.2.7/autoconf/scripts/0000755000076400007640000000000010665021416013430 5ustar awawqsf-1.2.7/autoconf/scripts/benchmark.awk0000755000076400007640000000076110516505176016102 0ustar awaw#!/bin/awk -f /Backend type:/ { backend=$NF; } /Counting messages/ { msgcount=$NF; } /during training/ { tnext=1; } /during classification/ { tnext=2; } /Total time/ { if (tnext == 1) { time_train=$NF; } else { time_class=$NF; } } /Accuracy:/ { accuracy=$2; printf "%d %f\n", msgcount, time_train >>"benchmark-data-train-"backend; printf "%d %f\n", msgcount, time_class >>"benchmark-data-class-"backend; printf "%d %f\n", msgcount, accuracy >>"benchmark-data-accuracy-"backend; } # EOF qsf-1.2.7/autoconf/scripts/install.sh0000755000076400007640000001272107611763233015447 0ustar awaw#! /bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 qsf-1.2.7/autoconf/scripts/makemake.sh0000755000076400007640000000634010466173113015546 0ustar awaw#!/bin/sh # # Generate Makefile dependencies inclusion and module target file "depend.mk" # by scanning the directory "src" for files ending in ".c" and ".d", and for # subdirectories not starting with "_". # # Modules live inside subdirectories called [^_]* - i.e. a directory "foo" will # have a rule created which links all code inside it to "foo.o". # # The directory "src/include" is never scanned; neither are CVS directories. # outlist=$1 outlink=$2 FIND=find GREP=grep which gfind 2>/dev/null | grep /gfind >/dev/null && FIND=gfind which ggrep 2>/dev/null | grep /ggrep >/dev/null && GREP=ggrep echo '# Automatically generated file listings' > $outlist echo '#' >> $outlist echo "# Creation time: `date`" >> $outlist echo >> $outlist echo '# Automatically generated module linking rules' > $outlink echo '#' >> $outlink echo "# Creation time: `date`" >> $outlink echo >> $outlink case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac echo $ECHO_N "Scanning for source files: $ECHO_C" allsrc=`$FIND src -type f -name "*.c" -print` allobj=`echo $allsrc | tr ' ' '\n' | sed 's/\.c$/.o/'` alldep=`echo $allsrc | tr ' ' '\n' | sed 's/\.c$/.d/'` echo `echo $allsrc | wc -w | tr -d ' '` found echo $ECHO_N "Scanning for modules: $ECHO_C" modules=`$FIND src -type d -print \ | $GREP -v '^src$' \ | $GREP -v '/_' \ | $GREP -v '^src/include' \ | $GREP -v 'CVS' \ | while read DIR; do \ CONTENT=\$(/bin/ls -d \$DIR/* \ | $GREP -v '.po$' \ | $GREP -v '.gmo$' \ | $GREP -v '.mo$' \ | $GREP -v '.h$' \ | sed -n '$p'); \ [ -n "\$CONTENT" ] || continue; \ echo \$DIR; \ done ` echo up to `echo $modules | wc -w | tr -d ' '` found echo "Writing module linking rules" echo $ECHO_N "[$ECHO_C" for i in $modules; do echo $ECHO_N " $ECHO_C"; done echo $ECHO_N -e "]\r[$ECHO_C" for i in $modules; do echo $ECHO_N ".$ECHO_C" allobj="$allobj $i.o" deps="" for j in $i/*.c; do [ -f $j ] || continue newobj=`echo $j | sed -e 's@\.c$@.o@'` deps="$deps $newobj" done for j in $i/*; do [ -d "$j" ] || continue [ `basename $j` = "CVS" ] && continue CONTENT=`/bin/ls -d $j/* \ | $GREP -v '.po$' \ | $GREP -v '.gmo$' \ | $GREP -v '.mo$' \ | $GREP -v '.h$' \ | sed -n '$p'` [ -n "$CONTENT" ] || continue deps="$deps $j.o" done [ -n "$deps" ] || continue echo "$i.o: $deps" >> $outlink echo ' $(LD) $(LDFLAGS) -o $@' "$deps" >> $outlink echo >> $outlink done echo ']' echo "Listing source, object and dependency files" echo $ECHO_N "allsrc = $ECHO_C" >> $outlist echo $allsrc | sed 's,src/nls/cat-id-tbl.c,,' | sed -e 's/ / \\!/g'\ | tr '!' '\n' >> $outlist echo >> $outlist echo $ECHO_N "allobj = $ECHO_C" >> $outlist echo $allobj | sed -e 's/ / \\!/g' | tr '!' '\n' >> $outlist echo >> $outlist echo $ECHO_N "alldep = $ECHO_C" >> $outlist echo $alldep | sed -e 's/ / \\!/g' | tr '!' '\n' >> $outlist echo >> $outlist echo >> $outlink # EOF qsf-1.2.7/autoconf/scripts/mkinstalldirs0000755000076400007640000000126107611763233016245 0ustar awaw#!/bin/sh # mkinstalldirs --- make directory hierarchy # Author: Noah Friedman # Created: 1993-05-16 # Last modified: 1994-03-25 # Public domain errstatus=0 for file in ${1+"$@"} ; do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d in ${1+"$@"} ; do pathcomp="$pathcomp$d" case "$pathcomp" in -* ) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" 1>&2 mkdir "$pathcomp" || errstatus=$? chmod 755 $pathcomp 2>/dev/null fi pathcomp="$pathcomp/" done done exit $errstatus # mkinstalldirs ends here qsf-1.2.7/autoconf/scripts/depend.sh0000755000076400007640000000072607667346351015253 0ustar awaw#!/bin/sh # # Generate dependencies for a C source file. CC=$1 shift file=$1 shift stem=$1 shift srcdir=$1 abssrc=`echo $srcdir | sed ':1 s,^\./,,g t1'` shift abssrc=`echo "$abssrc" | sed 's,\\.,\\\\.,g'` srcdir=`echo "$srcdir" | sed 's,\\.,\\\\.,g'` $CC -M -MG $* $file \ | sed -e 's, /[^ ]*,,g' -e "s,^.*\.o:,${stem}.d ${stem}.o:," \ -e '/^ \\$/d' -e 's/ \\$//' \ -e 's,'"$srcdir"'/,,g' -e 's,'"$abssrc"'/,,g' \ | tr '\n' ' ' \ | tr -s ' ' echo # EOF qsf-1.2.7/autoconf/scripts/fakemail.c0000755000076400007640000000470010554714253015356 0ustar awaw/* * Small program to generate a fake email given a wordlist to choose words * from. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include #include #include #include #include #include "config.h" /* * Return a random word from the given word list. */ char *random_word(char **wordlist, int wordcount) { return wordlist[rand() % wordcount]; } /* * Output between "min" and "max" (inclusive) random words to stdout. */ void random_words(char **wordlist, int wordcount, int wmin, int wmax) { int numtodo, i; numtodo = wmin + (rand() % (wmax - wmin)); for (i = 0; i < numtodo; i++) { if (i > 0) printf(" "); printf("%s", random_word(wordlist, wordcount)); } } /* * Main program. */ int main(int argc, char **argv) { char **wordlist = NULL; char **newptr; char *strptr; int wordcount = 0; char buf[1024]; /* RATS: ignore (checked) */ char *suffix[] = { ".co.uk", ".com", ".net", ".org", ".org.uk" }; int mailnum; time_t t; FILE *fptr; if (argc != 3) { fprintf(stderr, "Usage: fakemail WORDFILE NUMMESSAGES\n"); return(1); } fptr = fopen(argv[1], "r"); if (!fptr) { fprintf(stderr, "fakemail: %s: %s\n", argv[1], strerror(errno)); return(1); } while (fgets(buf, sizeof(buf) - 1, fptr)) { wordcount++; if (wordlist) { newptr = realloc(wordlist, wordcount * sizeof(char *)); /* RATS: ignore */ } else { newptr = malloc(wordcount * sizeof(char *)); } if (!newptr) { fprintf(stderr, "fakemail: %s\n", strerror(errno)); fclose(fptr); return (1); } strptr = strchr(buf, '\n'); if (strptr) *strptr = 0; wordlist = newptr; wordlist[wordcount-1] = strdup(buf); } fclose(fptr); srand(time(NULL)); /* RATS: ignore (randomness not important) */ for (mailnum = 0; mailnum < atoi(argv[2]); mailnum++) { #ifdef HAVE_SNPRINTF snprintf(buf, sizeof(buf), #else sprintf(buf, /* RATS: ignore */ #endif "%s.%s@%s%s", random_word(wordlist, wordcount), random_word(wordlist, wordcount), random_word(wordlist, wordcount), suffix[rand()%5]); t = time(NULL); printf("From %s %s", buf, ctime(&t)); printf("Return-Path: <%s>\n", buf); printf("From: <%s>\n", buf); printf("To: you@your.com\n"); printf("Date: %s", ctime(&t)); printf("Subject: "); random_words(wordlist, wordcount, 2, 10); printf("\n\n"); random_words(wordlist, wordcount, 20, 400); printf("\n\n"); } return(0); } /* EOF */ qsf-1.2.7/autoconf/scripts/mboxsplit.c0000755000076400007640000000150510554714254015627 0ustar awaw/* * Small program to output the Nth message from an mbox file on stdin. * * Copyright 2007 Andrew Wood, distributed under the Artistic License. */ #include #include #include /* * Main program. */ int main(int argc, char **argv) { int dispmsg, prevnl, msgnum; char buf[1024]; /* RATS: ignore (checked) */ if (argc != 2) { fprintf(stderr, "Usage: mboxsplit MESSAGENUM\n"); return(1); } dispmsg = atoi(argv[1]); prevnl = 1; msgnum = 0; while (fgets(buf, sizeof(buf) - 1, stdin)) { if (prevnl && (strncmp(buf, "From ", 5) == 0)) { msgnum++; prevnl = 0; } else if (buf[0] == '\n') { prevnl = 1; } else if ((buf[0] == '\r') && (buf[1] == '\n')) { prevnl = 1; } else { prevnl = 0; } if (msgnum == dispmsg) printf("%s", buf); } return(0); } /* EOF */ qsf-1.2.7/autoconf/scripts/index.sh0000755000076400007640000001236310466173207015110 0ustar awaw#!/bin/ash # # Script to generate an HTML index of all C code from the current directory # downwards (skipping directories ending in ~). The header comment in each # file is listed, and each function's prototype and comment are given. A # list of "TODO:" comments is also generated. # # Outputs the HTML on standard output. # # If a parameter is given, it is the prefix to put before any "view file" # links, eg ".." to link to "../dir/file.c" instead of "dir/file.c". # # Skips any files containing the string !NOINDEX. # # Requires ctags and cproto. OFFS=$1 case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac # Convert the given string to HTML-escaped values (<, >, & escaped) on # stdout. # html_safe () { echo "$*" \ | sed -e 's|&|\&|g;s|<|\<|g;s|>|\>|g' } # Convert the given string to HTML-escaped values (<, >, & escaped) on # stdout, also adding a
to the end of each line. # html_safebr () { echo "$*" \ | sed -e 's|&|\&|g;s|<|\<|g;s|>|\>|g;s/$/
/' } ALLFILES=`find . -name '*~' -prune -o -type f -name '*.c' \ -exec grep -FL '!NOINDEX' /dev/null '{}' ';'` CTAGDATA=`echo "$ALLFILES" \ | ctags -nRf- -L- --c-types=f \ | sed 's/ .\// /;s/;" .*$//'` FILELIST=`echo "$CTAGDATA" | cut -d ' ' -f 2 | sort | uniq` echo '' echo 'Source Code Index' echo '' echo '

Source Code Index

' echo '

' echo '

File Listing

' echo '

    ' echo "$FILELIST" \ | sed -e \ 's|^.*$|
  • \0
  • |' echo '

' for FILE in $FILELIST; do DIR=`dirname $FILE` FUNCDEFS=`cproto -f1 -I. -Isrc/include -I$DIR $FILE 2>/dev/null \ | sed -n 's/^.*[ *]\([^ *(]*\)(.*$/\1/p'` FILEHEAD="`sed -n -e \ '1,/\*\//{/\/\*/,/\*\//{s/^[\/ *]//;s/^\*[\/]*//;p;};}' \ < $FILE`" FILESHORTDESC=`echo "$FILEHEAD" | sed -n '1,/^ *$/{/^ *[^ ]*/p;}'` FILELONGDESC=`echo "$FILEHEAD" | sed '1,/^ *$/d'` echo '


' echo '

' echo '' echo '' echo '' echo '
' echo ''"$FILE"' - '`html_safe "$FILESHORTDESC"`'

' echo '

[View File]

' echo '

' echo "`html_safebr "$FILELONGDESC"`" echo '

' if [ -n "$FUNCDEFS" ]; then echo '

Functions defined:

' echo '

    ' echo "$FUNCDEFS" \ | sed 's|^.*$|\0|' \ | sed 's/^/
  • /;s|$|
  • |' echo '

' fi echo '

[' echo 'Top |' echo 'To Do |' echo 'Functions ]

' done echo '

Function Listing

' echo '

    ' echo "$CTAGDATA" | while read FUNC FILE LINENUM REST; do echo $ECHO_N '
  • '"$ECHO_C" echo $ECHO_N ''"$FUNC"' '"$ECHO_C" echo '['"$FILE"']
  • ' done echo '

' echo "$CTAGDATA" | while read FUNC FILE LINENUM REST; do FUNCDEF=`sed -n "$LINENUM,/{/p" < $FILE \ | tr '\n' ' ' \ | tr -d '{'` LASTCOMLINE=`sed -n '1,'"$LINENUM"'{/\/\*/=;}' < $FILE | sed -n '$p'` [ -z "$LASTCOMLINE" ] && LASTCOMLINE=1 LASTENDFUNCLINE=`sed -n '1,'"$LINENUM"'{/}/=;}' < $FILE | sed -n '$p'` [ -z "$LASTENDFUNCLINE" ] && LASTENDFUNCLINE=1 FUNCHEAD="`sed -n -e \ "$LASTCOMLINE,"'/\*\//{h;s/^[\/ *]//;s/^\*[\/]*//;p;x;/\*\//q;}' \ < $FILE`" [ "$LASTCOMLINE" -le "$LASTENDFUNCLINE" ] && FUNCHEAD="" echo '


' echo '

' echo $ECHO_N ''"$ECHO_C" echo $ECHO_N "$FUNC"' '"$ECHO_C" echo $ECHO_N '['"$ECHO_C" echo "$FILE"']' echo '

' echo '

'"`html_safe "$FUNCDEF"`"'

' echo '

' echo "`html_safebr "$FUNCHEAD"`" echo '

' echo '

[' echo 'Top |' echo 'To Do |' echo 'Files ]

' done echo '

To Do Listing

' echo '

    ' for FILE in $FILELIST; do TODOLINES=`sed -n \ -e '/\/\*.*\*\//!{/\/\*/,/\*\//{/TODO:/{=;};};}' \ -e '/\/\*.*\*\//{/TODO:/{=;};}' \ < $FILE` [ -z "$TODOLINES" ] && continue echo $ECHO_N '
  • '"$ECHO_C" echo ''"$FILE"'' echo '
      ' for NUM in $TODOLINES; do TODO=`sed -n "$NUM"'{s/^.*TODO://;s/\*\/.*$//;p;}' < $FILE` echo "
    • [$NUM] `html_safe "$TODO"`
    • " done echo '
  • ' done echo '' # EOF qsf-1.2.7/autoconf/configure.in.orig0000644000076400007640000001544210470054104015211 0ustar awawdnl Process this file with autoconf to produce a configure script. dnl AC_INIT(src/main/version.c) dnl We're using C. dnl AC_LANG_C dnl Output a header file. dnl AC_CONFIG_HEADER(src/include/config.h:autoconf/header.in) dnl Set directory to check for Configure scripts in. dnl AC_CONFIG_AUX_DIR(autoconf/scripts) dnl Read in package details. dnl PACKAGE=`cat $srcdir/doc/PACKAGE` VERSION=`cat $srcdir/doc/VERSION` UCPACKAGE=`tr a-z A-Z < $srcdir/doc/PACKAGE` AC_SUBST(PACKAGE) AC_SUBST(VERSION) AC_SUBST(UCPACKAGE) AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE") AC_DEFINE_UNQUOTED(PROGRAM_NAME, "$PACKAGE") AC_DEFINE_UNQUOTED(VERSION, "$VERSION") dnl Database backends we can use. dnl canuse_obtree="yes" canuse_btree="yes" canuse_gdbm="yes" canuse_mysql="yes" canuse_sqlite="yes" dnl Check for compile-time options. dnl AC_ARG_ENABLE(debugging, [ --enable-debugging compile with debugging symbols], if test "$enable_debugging" = "yes"; then CFLAGS="-g -Wall" fi ) AC_ARG_ENABLE(profiling, [ --enable-profiling compile with profiling support], if test "$enable_profiling" = "yes"; then CFLAGS="-pg $CFLAGS" fi ) AC_ARG_ENABLE(static, [ --enable-static enable static linking], ) AC_ARG_WITH(obtree, [ --without-obtree omit old binary tree backend support], canuse_obtree="$with_obtree" ) AC_ARG_WITH(btree, [ --without-btree omit binary tree backend support], canuse_btree="$with_btree" ) AC_ARG_WITH(gdbm, [ --without-gdbm omit GDBM backend support], canuse_gdbm="$with_gdbm" ) AC_ARG_WITH(mysql, [ --without-mysql omit MySQL backend support], canuse_mysql="$with_mysql" ) AC_ARG_WITH(sqlite, [ --without-sqlite omit SQLite v2.x backend support], canuse_sqlite="$with_sqlite" ) dnl Check for various programs. dnl CFLAGS=${CFLAGS-"-O2 -Wall -s"} AC_PROG_CC AC_PROG_CPP AC_CHECK_TOOL(LD, ld, libtool --mode=link gcc) AC_SUBST(LD) AC_PROG_INSTALL AC_PROG_MAKE_SET AC_CHECK_PROG(DO_GZIP, gzip, gzip -f9, touch) dnl Check for the maths library. dnl AC_SEARCH_LIBS(pow, m, , [AC_ERROR(maths library not found)]) dnl Check for various header files and set various other macros. dnl AC_DEFINE(HAVE_CONFIG_H) AC_HEADER_STDC AC_C_BIGENDIAN([AC_DEFINE(IS_BIG_ENDIAN)]) AC_CHECK_FUNCS(memcpy, , [AC_ERROR(the memcpy() function is required)]) AC_CHECK_FUNCS(fcntl getopt getopt_long mkstemp snprintf vsnprintf utime) AC_CHECK_HEADERS(fcntl.h getopt.h limits.h sys/resource.h mcheck.h) AC_FUNC_MMAP dnl Check for backend databases and choose one. dnl PREVCFLAGS="$CFLAGS" PREVCPPFLAGS="$CPPFLAGS" PREVLIBS="$LIBS" if test "x$canuse_mysql" = "xyes"; then dnl dnl First we try linking without the mysql_config libs, because on dnl some systems that'll give us a dynamic library - the dnl mysql_config libs often point us to static libraries. dnl dnl If static linking is enabled, we ONLY try the mysql_config libs. dnl CFLAGS=`mysql_config --cflags 2>/dev/null` CPPFLAGS=`mysql_config --include 2>/dev/null` || CPPFLAGS="$CFLAGS" LIBS="" if test "x$enable_static" != "xyes"; then AC_CHECK_HEADERS(mysql.h, [ AC_SEARCH_LIBS(mysql_real_connect, mysqlclient, [ AC_SEARCH_LIBS(mysql_real_escape_string, mysqlclient, , canuse_mysql="no") ], canuse_mysql="no") ], canuse_mysql="no") fi if test "x$canuse_mysql" = "xno"; then canuse_mysql=yes LIBS=`mysql_config --libs 2>/dev/null` AC_CHECK_HEADERS(mysql.h, [ AC_SEARCH_LIBS(mysql_real_escape_string, mysqlclient, , canuse_mysql="no") ], canuse_mysql="no") fi if test "x$enable_static" = "xyes"; then LIBS=`mysql_config --libs 2>/dev/null` AC_CHECK_HEADERS(mysql.h, [ AC_SEARCH_LIBS(mysql_real_query, mysqlclient, , canuse_mysql="no") ], canuse_mysql="no") fi MYSQLCFLAGS="$CFLAGS" MYSQLLIBS="$LIBS" CFLAGS="$PREVCFLAGS" CPPFLAGS="$PREVCPPFLAGS" LIBS="$PREVLIBS" fi if test "x$canuse_gdbm" = "xyes"; then PREVLIBS="$LIBS" LIBS="" AC_CHECK_HEADERS(gdbm.h, [ AC_SEARCH_LIBS(gdbm_open, gdbm, [ AC_CHECK_FUNCS(gdbm_fdesc) ], canuse_gdbm="no") ], canuse_gdbm="no") dnl dnl This is a hideous hack to try and find ".a" (static) dnl library replacements if --enable-static is given. dnl if test "x$enable_static" = "xyes"; then LIBDIR=`echo "$LIBS" | tr ' ' '\n' | sed -n 's/^-L//p'` test -z "$LIBDIR" && LIBDIR=/usr/lib LIBLIST=`echo "$LIBS" | tr ' ' '\n' | sed -n "s,^-l,$LIBDIR/lib,p" | sed -e 's,$,.a,'` NEWLIBS="" for i in $LIBLIST; do test -e "$i" && NEWLIBS="$NEWLIBS $i" done test -n "$NEWLIBS" && LIBS="$NEWLIBS" fi GDBMLIBS="$LIBS" LIBS="$PREVLIBS" fi if test "x$canuse_sqlite" = "xyes"; then LIBS="" AC_CHECK_HEADERS(sqlite.h, [ AC_SEARCH_LIBS(sqlite_open, sqlite, , canuse_sqlite="no") ], canuse_sqlite="no") dnl Hideous hack as above. if test "x$enable_static" = "xyes"; then LIBDIR=`echo "$LIBS" | tr ' ' '\n' | sed -n 's/^-L//p'` test -z "$LIBDIR" && LIBDIR=/usr/lib LIBLIST=`echo "$LIBS" | tr ' ' '\n' | sed -n "s,^-l,$LIBDIR/lib,p" | sed -e 's,$,.a,'` NEWLIBS="" for i in $LIBLIST; do test -e "$i" && NEWLIBS="$NEWLIBS $i" done test -n "$NEWLIBS" && LIBS="$NEWLIBS" fi SQLITELIBS="$LIBS" LIBS="$PREVLIBS" fi AC_MSG_CHECKING(which backend databases are available) BACKENDS="" if test "x$canuse_obtree" = "xyes"; then AC_DEFINE(USING_OBTREE) BACKENDS="$BACKENDS obtree" fi if test "x$canuse_btree" = "xyes"; then AC_DEFINE(USING_BTREE) BACKENDS="$BACKENDS btree" fi if test "x$canuse_gdbm" = "xyes"; then AC_DEFINE(USING_GDBM) EXTRALIBS="$EXTRALIBS $GDBMLIBS" BACKENDS="$BACKENDS GDBM" fi if test "x$canuse_mysql" = "xyes"; then AC_DEFINE(USING_MYSQL) EXTRALIBS="$EXTRALIBS $MYSQLLIBS" CFLAGS="$CFLAGS $MYSQLCFLAGS" BACKENDS="$BACKENDS MySQL" fi if test "x$canuse_sqlite" = "xyes"; then AC_DEFINE(USING_SQLITE) EXTRALIBS="$EXTRALIBS $SQLITELIBS" CFLAGS="$CFLAGS $SQLITECFLAGS" BACKENDS="$BACKENDS SQLite2" fi if test "x$BACKENDS" = "x"; then AC_MSG_RESULT(none) AC_MSG_ERROR(no usable database libraries found) else AC_MSG_RESULT($BACKENDS) fi LIBS="$LIBS $EXTRALIBS" AC_DEFINE_UNQUOTED(BACKENDS, "$BACKENDS") AC_SUBST(BACKENDS) test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' AC_SUBST(INSTALL_DATA) dnl Fudging for separate build directories. dnl subdirs="" for i in `find $srcdir/src -type d -print | sed s,$srcdir/,,`; do subdirs="$subdirs $i" done dnl Stitch together the Makefile fragments. dnl mk_segments="autoconf/Makefile.in" for i in vars.mk package.mk filelist.mk unreal.mk modules.mk \ rules.mk link.mk depend.mk; do mk_segments="$mk_segments:autoconf/make/$i" done dnl Output files (and create build directory structure too). dnl AC_OUTPUT(Makefile:$mk_segments doc/lsm:doc/lsm.in doc/quickref.1:doc/quickref.1.in doc/$PACKAGE.spec:doc/spec.in src/.dummy:doc/NEWS, rm -f src/.dummy for i in $subdirs; do test -d $i || mkdir $i done , subdirs="$subdirs") dnl EOF qsf-1.2.7/debian/0000755000076400007640000000000010665021416011345 5ustar awawqsf-1.2.7/debian/copyright0000644000076400007640000002172710665021215013306 0ustar awawThis package was debianized by Tom Parker on Wed, 22 Jan 2003 15:36:15 +0000. It was downloaded from http://www.ivarch.com/programs/qsf/ Upstream Author: Andrew Wood Copyright Holder: (C) 2003-2007 Andrew Wood License: This package is free software, and is being distributed under the terms of the Artistic License 2.0. ---------------------------------------------------------- Artistic License 2.0 Copyright (c) 2000-2006, The Perl Foundation. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble This license establishes the terms under which a given free software Package may be copied, modified, distributed, and/or redistributed. The intent is that the Copyright Holder maintains some artistic control over the development of that Package while still keeping the Package available as open source and free software. You are always permitted to make arrangements wholly outside of this license directly with the Copyright Holder of a given Package. If the terms of this license do not permit the full use that you propose to make of the Package, you should contact the Copyright Holder and seek a different licensing arrangement. Definitions "Copyright Holder" means the individual(s) or organization(s) named in the copyright notice for the entire Package. "Contributor" means any party that has contributed code or other material to the Package, in accordance with the Copyright Holder's procedures. "You" and "your" means any person who would like to copy, distribute, or modify the Package. "Package" means the collection of files distributed by the Copyright Holder, and derivatives of that collection and/or of those files. A given Package may consist of either the Standard Version, or a Modified Version. "Distribute" means providing a copy of the Package or making it accessible to anyone else, or in the case of a company or organization, to others outside of your company or organization. "Distributor Fee" means any fee that you charge for Distributing this Package or providing support for this Package to another party. It does not mean licensing fees. "Standard Version" refers to the Package if it has not been modified, or has been modified only in ways explicitly requested by the Copyright Holder. "Modified Version" means the Package, if it has been changed, and such changes were not explicitly requested by the Copyright Holder. "Original License" means this Artistic License as Distributed with the Standard Version of the Package, in its current version or as it may be modified by The Perl Foundation in the future. "Source" form means the source code, documentation source, and configuration files for the Package. "Compiled" form means the compiled bytecode, object code, binary, or any other form resulting from mechanical transformation or translation of the Source form. Permission for Use and Modification Without Distribution (1) You are permitted to use the Standard Version and create and use Modified Versions for any purpose without restriction, provided that you do not Distribute the Modified Version. Permissions for Redistribution of the Standard Version (2) You may Distribute verbatim copies of the Source form of the Standard Version of this Package in any medium without restriction, either gratis or for a Distributor Fee, provided that you duplicate all of the original copyright notices and associated disclaimers. At your discretion, such verbatim copies may or may not include a Compiled form of the Package. (3) You may apply any bug fixes, portability changes, and other modifications made available from the Copyright Holder. The resulting Package will still be considered the Standard Version, and as such will be subject to the Original License. Distribution of Modified Versions of the Package as Source (4) You may Distribute your Modified Version as Source (either gratis or for a Distributor Fee, and with or without a Compiled form of the Modified Version) provided that you clearly document how it differs from the Standard Version, including, but not limited to, documenting any non-standard features, executables, or modules, and provided that you do at least ONE of the following: (a) make the Modified Version available to the Copyright Holder of the Standard Version, under the Original License, so that the Copyright Holder may include your modifications in the Standard Version. (b) ensure that installation of your Modified Version does not prevent the user installing or running the Standard Version. In addition, the Modified Version must bear a name that is different from the name of the Standard Version. (c) allow anyone who receives a copy of the Modified Version to make the Source form of the Modified Version available to others under (i) the Original License or (ii) a license that permits the licensee to freely copy, modify and redistribute the Modified Version using the same licensing terms that apply to the copy that the licensee received, and requires that the Source form of the Modified Version, and of any works derived from it, be made freely available in that license fees are prohibited but Distributor Fees are allowed. Distribution of Compiled Forms of the Standard Version or Modified Versions without the Source (5) You may Distribute Compiled forms of the Standard Version without the Source, provided that you include complete instructions on how to get the Source of the Standard Version. Such instructions must be valid at the time of your distribution. If these instructions, at any time while you are carrying out such distribution, become invalid, you must provide new instructions on demand or cease further distribution. If you provide valid instructions or cease distribution within thirty days after you become aware that the instructions are invalid, then you do not forfeit any of your rights under this license. (6) You may Distribute a Modified Version in Compiled form without the Source, provided that you comply with Section 4 with respect to the Source of the Modified Version. Aggregating or Linking the Package (7) You may aggregate the Package (either the Standard Version or Modified Version) with other packages and Distribute the resulting aggregation provided that you do not charge a licensing fee for the Package. Distributor Fees are permitted, and licensing fees for other components in the aggregation are permitted. The terms of this license apply to the use and Distribution of the Standard or Modified Versions as included in the aggregation. (8) You are permitted to link Modified and Standard Versions with other works, to embed the Package in a larger work of your own, or to build stand-alone binary or bytecode versions of applications that include the Package, and Distribute the result without restriction, provided the result does not expose a direct interface to the Package. Items That are Not Considered Part of a Modified Version (9) Works (including, but not limited to, modules and scripts) that merely extend or make use of the Package, do not, by themselves, cause the Package to be a Modified Version. In addition, such works are not considered parts of the Package itself, and are not subject to the terms of this license. General Provisions (10) Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license. (11) If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license. (12) This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder. (13) This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed. (14) Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------- qsf-1.2.7/debian/patches/0000755000076400007640000000000010665021416012774 5ustar awawqsf-1.2.7/debian/patches/index.html.diff0000644000076400007640000000123310665021216015675 0ustar awawdiff -urN old/doc/index.html new/doc/index.html --- old/doc/index.html 2005-05-11 19:14:22.000000000 -0300 +++ new/doc/index.html 2005-05-11 19:17:46.000000000 -0300 @@ -7,13 +7,11 @@

    qsf-1.2.7/debian/control0000644000076400007640000000346710561647362012773 0ustar awawSource: qsf Section: mail Priority: optional Maintainer: Nelson A. de Oliveira Uploaders: Bartosz Fenski Build-Depends: cdbs, patchutils, debhelper (>= 5), libgdbm-dev, libmysqlclient15-dev, libsqlite0-dev, bsdmainutils, man-db Standards-Version: 3.7.2 Package: qsf Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Recommends: procmail | maildrop Suggests: mail-transport-agent, mysql-server | sqlite, mutt, fetchmail Description: small and fast Bayesian spam filter Quick Spam Filter (QSF) is an Open Source email classification filter, designed to be small, fast, and accurate, which works to classify incoming email as either spam or non-spam. . QSF's targets are speed, accuracy and simplicity: * It is small and is written in C so it starts up quickly, unlike filters written in Perl. * It understands MIME and HTML, so it can intelligently deal with modern spam, unlike older Bayesian filters such as ifile. * It runs as an inline filter rather than as a daemon, so it is simple to install. * It is written to do only one job - decide whether an email is spam or not using the content of the message alone - so it is less complex than filters such as SpamAssassin. Less complexity means bugs and security problems are less likely. * As well as words and word pairs, QSF also spots special patterns in email such as runs of gibberish, HTML comments embedded in text, and other common spam giveaways, and its flexible tokeniser allows more patterns to be added as spammers change their tactics. . Homepage: http://www.ivarch.com/programs/qsf/ XB-Tag: implemented-in::c, interface::commandline, mail::filters, role::plugin, role::program, scope::application, use::checking, works-with-format::plaintext, works-with::db, works-with::mail, works-with::text qsf-1.2.7/debian/rules0000755000076400007640000000047510370214750012431 0ustar awaw#!/usr/bin/make -f include /usr/share/cdbs/1/rules/simple-patchsys.mk include /usr/share/cdbs/1/rules/debhelper.mk include /usr/share/cdbs/1/class/autotools.mk DEB_INSTALL_DIRS_ALL := usr/share/lintian/overrides binary-install/qsf:: cp debian/lintian-override $(CURDIR)/debian/qsf/usr/share/lintian/overrides/qsf qsf-1.2.7/debian/doc-base0000644000076400007640000000066310665021216012750 0ustar awawDocument: qsf Title: Quick Spam Filter Documentation Index Author: Andrew Wood Abstract: Quick Spam Filter (QSF) is an Open Source email classification filter, designed to be small, fast, and accurate, which works to classify incoming email as either spam or non-spam. Section: Applications/Net Format: text Files: /usr/share/doc/qsf/quickref.txt.gz Format: HTML Index: /usr/share/doc/qsf/index.html Files: /usr/share/doc/qsf/*.html qsf-1.2.7/debian/changelog0000644000076400007640000001505010665021215013215 0ustar awawqsf (1.2.7-1) unstable; urgency=low * New upstream version: - Updated license from Artistic License to Artistic License 2.0 -- Nelson A. de Oliveira Tue, 28 Aug 2007 09:35:41 -0300 qsf (1.2.6-1) unstable; urgency=medium * New upstream version; * Medium urgency since it fix a bug that might cause undelivered mail. -- Nelson A. de Oliveira Mon, 5 Feb 2007 09:20:24 -0200 qsf (1.2.5-2) unstable; urgency=low * Adding a Build-Depends on bsdmainutils and man-db, so quickref.txt gets correctly generated. -- Nelson A. de Oliveira Sun, 21 Jan 2007 22:02:57 -0200 qsf (1.2.5-1) unstable; urgency=medium * New upstream version; * New maintainer address. -- Nelson A. de Oliveira Sun, 21 Jan 2007 15:14:49 -0200 qsf (1.2.1-1) unstable; urgency=low * New upstream version. -- Nelson A. de Oliveira Wed, 25 Oct 2006 12:21:30 -0300 qsf (1.2.0-1) unstable; urgency=low * New upstream version; * Added tags on debian/control. -- Nelson A. de Oliveira Sun, 1 Oct 2006 20:22:09 -0300 qsf (1.1.13-1) unstable; urgency=low * New upstream version; * Bumped Standards-Version to 3.7.2 (no changes needed). -- Nelson A. de Oliveira Mon, 14 Aug 2006 20:51:00 -0300 qsf (1.1.7-1) unstable; urgency=low * New upstream version. -- Nelson A. de Oliveira Sat, 8 Apr 2006 15:02:59 -0300 qsf (1.1.6-1) unstable; urgency=low * New upstream version. -- Nelson A. de Oliveira Thu, 2 Feb 2006 16:20:29 -0200 qsf (1.1.2-3) unstable; urgency=low * Updated to debhelper compatibility level 5: - debian/compat updated; - debian/control: build-depends debhelper (>= 5). * libmysqlclient transition: - debian/control: changed from libmysqlclient14-dev to libmysqlclient15-dev on build-depends. (Closes: #343801) * Updated watch file; * Added a Lintian override to fix a warning about a line too long on qsf's manual: - added debian/lintian-override; - updated debian/rules to install the override. -- Nelson A. de Oliveira Sat, 17 Dec 2005 21:30:19 -0200 qsf (1.1.2-2) unstable; urgency=low * Fixed section of QSF - mail, instead of net. (Closes: #317267). Thank to Laurent Fousse. -- Nelson A. de Oliveira Fri, 08 Jul 2005 01:04:39 -0300 qsf (1.1.2-1) unstable; urgency=low * New upstream version. -- Nelson A. de Oliveira Wed, 06 Jul 2005 13:49:14 -0300 qsf (1.1.0-2) unstable; urgency=low * Fix small typo in description (Closes: #317042). Thanks to Laurent Fousse for pointing this. -- Nelson A. de Oliveira Wed, 06 Jul 2005 02:22:08 -0300 qsf (1.1.0-1) unstable; urgency=low * New maintainer; * First official Debian release (Closes: #273937); * Using CDBS now. -- Nelson A. de Oliveira Wed, 11 May 2005 16:05:48 -0300 qsf (1.0.35-1) unstable; urgency=low * New version (not released). -- Andrew Wood Thu, 21 Apr 2005 12:32:16 +0100 qsf (1.0.31-1) unstable; urgency=low * Updated to newest release. -- Andrew Wood Fri, 04 Mar 2005 19:09:01 +0000 qsf (1.0.22-1) unstable; urgency=low * Updated to newest release. -- Andrew Wood Mon, 28 Feb 2005 19:50:04 +0000 qsf (1.0.18-1) unstable; urgency=low * Updated to newest release. -- Andrew Wood Sat, 19 Feb 2005 12:04:22 +0000 qsf (1.0.15-1) unstable; urgency=low * Updated to newest release. -- Andrew Wood Sat, 5 Feb 2005 18:29:08 +0000 qsf (1.0.14-1) unstable; urgency=low * Updated to newest release. -- Andrew Wood Sun, 26 Sep 2004 15:01:30 +0100 qsf (1.0.2-1) unstable; urgency=low * Updated to newest release. -- Andrew Wood Wed, 28 Apr 2004 22:08:38 +0100 qsf (1.0.1-1) unstable; urgency=low * Updated to newest release. -- Andrew Wood Sun, 14 Mar 2004 23:45:50 +0000 qsf (0.9.25-1) unstable; urgency=low * Updated to newest release. -- Andrew Wood Fri, 16 Jan 2004 00:03:06 +0000 qsf (0.9.18-1) unstable; urgency=low * Updated to newest release. -- Andrew Wood Mon, 5 Jan 2004 20:08:58 +0000 qsf (0.9.12-1) unstable; urgency=low * Updated to newest release. -- Andrew Wood Thu, 1 Jan 2004 13:35:55 +0000 qsf (0.9.9-1) unstable; urgency=low * Updated to newest release. -- Andrew Wood Sat, 29 Nov 2003 22:41:14 +0000 qsf (0.9.6-1) unstable; urgency=low * Updated to newest release. -- Andrew Wood Sat, 15 Nov 2003 01:00:58 +0000 qsf (0.9.4-1) unstable; urgency=low * Updated to newest release. -- Andrew Wood Tue, 21 Oct 2003 21:43:37 +0100 qsf (0.9.0-1) unstable; urgency=low * Updated to newest release. -- Andrew Wood Fri, 29 Aug 2003 01:36:23 +0100 qsf (0.8.1-1) unstable; urgency=low * Updated to newest release. -- Andrew Wood Thu, 21 Aug 2003 08:37:45 +0100 qsf (0.7.8-1) unstable; urgency=low * Updated to newest release. -- Andrew Wood Mon, 18 Aug 2003 21:26:22 +0100 qsf (0.7.7-1) unstable; urgency=low * Updated to newest release. -- Andrew Wood Thu, 31 Jul 2003 00:16:43 +0100 qsf (0.7.6-1) unstable; urgency=low * Updated to newest release. -- Andrew Wood Wed, 23 Jul 2003 09:58:44 +0100 qsf (0.7.4-1) unstable; urgency=low * Updated to newest release. -- Andrew Wood Tue, 8 Jul 2003 19:57:59 +0100 qsf (0.7.0-1) unstable; urgency=low * Updated to newest release. -- Andrew Wood Sat, 28 Jun 2003 16:48:39 +0100 qsf (0.5.4-1) unstable; urgency=low * Updated to newest release. -- Andrew Wood Wed, 4 Jun 2003 12:44:25 +0100 qsf (0.5.0-1) unstable; urgency=low * Updated to newest release. -- Andrew Wood Sat, 10 May 2003 04:22:15 +0100 qsf (0.3.4-1) unstable; urgency=low * Reformatted, minor changes to get "make deb" working under Debian 2.2. -- Andrew Wood Wed, 29 Jan 2003 23:12:23 +0000 qsf (0.3.1-1) unstable; urgency=low * Initial Release. * My first debian package. -- Tom Parker Wed, 22 Jan 2003 15:36:15 +0000 qsf-1.2.7/debian/lintian-override0000644000076400007640000000004110351131333014526 0ustar awawqsf: manpage-has-errors-from-man qsf-1.2.7/debian/compat0000644000076400007640000000000210370214750012541 0ustar awaw5 qsf-1.2.7/debian/watch0000644000076400007640000000005610370214750012375 0ustar awawversion=3 http://sf.net/qsf/qsf-(.*)\.tar\.gz qsf-1.2.7/debian/install0000644000076400007640000000003310240742410012723 0ustar awawextra/ /usr/share/doc/qsf/ qsf-1.2.7/debian/docs0000644000076400007640000000013110415776642012226 0ustar awawREADME doc/TODO doc/NEWS doc/quickref.txt doc/index.html doc/postfix-howto doc/changelog qsf-1.2.7/doc/0000755000076400007640000000000010665021416010670 5ustar awawqsf-1.2.7/doc/INSTALL0000644000076400007640000001723007611763234011734 0ustar awawBasic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, a file `config.cache' that saves the results of its tests to speed up reconfiguring, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.in' is used to create `configure' by a program called `autoconf'. You only need `configure.in' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not supports the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `--host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields: CPU-COMPANY-SYSTEM See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the host type. If you are building compiler tools for cross-compiling, you can also use the `--target=TYPE' option to select the type of system they will produce code for and the `--build=TYPE' option to select the type of system on which you are compiling the package. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Operation Controls ================== `configure' recognizes the following options to control how it operates. `--cache-file=FILE' Use and save the results of the tests in FILE instead of `./config.cache'. Set FILE to `/dev/null' to disable caching, for debugging `configure'. `--help' Print a summary of the options to `configure', and exit. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--version' Print the version of Autoconf used to generate the `configure' script, and exit. `configure' also accepts some other, not widely useful, options. qsf-1.2.7/doc/COPYING0000644000076400007640000002125310664536761011743 0ustar awawThis package is free software, and is being distributed under the terms of the Artistic License 2.0. ---------------------------------------------------------- Artistic License 2.0 Copyright (c) 2000-2006, The Perl Foundation. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble This license establishes the terms under which a given free software Package may be copied, modified, distributed, and/or redistributed. The intent is that the Copyright Holder maintains some artistic control over the development of that Package while still keeping the Package available as open source and free software. You are always permitted to make arrangements wholly outside of this license directly with the Copyright Holder of a given Package. If the terms of this license do not permit the full use that you propose to make of the Package, you should contact the Copyright Holder and seek a different licensing arrangement. Definitions "Copyright Holder" means the individual(s) or organization(s) named in the copyright notice for the entire Package. "Contributor" means any party that has contributed code or other material to the Package, in accordance with the Copyright Holder's procedures. "You" and "your" means any person who would like to copy, distribute, or modify the Package. "Package" means the collection of files distributed by the Copyright Holder, and derivatives of that collection and/or of those files. A given Package may consist of either the Standard Version, or a Modified Version. "Distribute" means providing a copy of the Package or making it accessible to anyone else, or in the case of a company or organization, to others outside of your company or organization. "Distributor Fee" means any fee that you charge for Distributing this Package or providing support for this Package to another party. It does not mean licensing fees. "Standard Version" refers to the Package if it has not been modified, or has been modified only in ways explicitly requested by the Copyright Holder. "Modified Version" means the Package, if it has been changed, and such changes were not explicitly requested by the Copyright Holder. "Original License" means this Artistic License as Distributed with the Standard Version of the Package, in its current version or as it may be modified by The Perl Foundation in the future. "Source" form means the source code, documentation source, and configuration files for the Package. "Compiled" form means the compiled bytecode, object code, binary, or any other form resulting from mechanical transformation or translation of the Source form. Permission for Use and Modification Without Distribution (1) You are permitted to use the Standard Version and create and use Modified Versions for any purpose without restriction, provided that you do not Distribute the Modified Version. Permissions for Redistribution of the Standard Version (2) You may Distribute verbatim copies of the Source form of the Standard Version of this Package in any medium without restriction, either gratis or for a Distributor Fee, provided that you duplicate all of the original copyright notices and associated disclaimers. At your discretion, such verbatim copies may or may not include a Compiled form of the Package. (3) You may apply any bug fixes, portability changes, and other modifications made available from the Copyright Holder. The resulting Package will still be considered the Standard Version, and as such will be subject to the Original License. Distribution of Modified Versions of the Package as Source (4) You may Distribute your Modified Version as Source (either gratis or for a Distributor Fee, and with or without a Compiled form of the Modified Version) provided that you clearly document how it differs from the Standard Version, including, but not limited to, documenting any non-standard features, executables, or modules, and provided that you do at least ONE of the following: (a) make the Modified Version available to the Copyright Holder of the Standard Version, under the Original License, so that the Copyright Holder may include your modifications in the Standard Version. (b) ensure that installation of your Modified Version does not prevent the user installing or running the Standard Version. In addition, the Modified Version must bear a name that is different from the name of the Standard Version. (c) allow anyone who receives a copy of the Modified Version to make the Source form of the Modified Version available to others under (i) the Original License or (ii) a license that permits the licensee to freely copy, modify and redistribute the Modified Version using the same licensing terms that apply to the copy that the licensee received, and requires that the Source form of the Modified Version, and of any works derived from it, be made freely available in that license fees are prohibited but Distributor Fees are allowed. Distribution of Compiled Forms of the Standard Version or Modified Versions without the Source (5) You may Distribute Compiled forms of the Standard Version without the Source, provided that you include complete instructions on how to get the Source of the Standard Version. Such instructions must be valid at the time of your distribution. If these instructions, at any time while you are carrying out such distribution, become invalid, you must provide new instructions on demand or cease further distribution. If you provide valid instructions or cease distribution within thirty days after you become aware that the instructions are invalid, then you do not forfeit any of your rights under this license. (6) You may Distribute a Modified Version in Compiled form without the Source, provided that you comply with Section 4 with respect to the Source of the Modified Version. Aggregating or Linking the Package (7) You may aggregate the Package (either the Standard Version or Modified Version) with other packages and Distribute the resulting aggregation provided that you do not charge a licensing fee for the Package. Distributor Fees are permitted, and licensing fees for other components in the aggregation are permitted. The terms of this license apply to the use and Distribution of the Standard or Modified Versions as included in the aggregation. (8) You are permitted to link Modified and Standard Versions with other works, to embed the Package in a larger work of your own, or to build stand-alone binary or bytecode versions of applications that include the Package, and Distribute the result without restriction, provided the result does not expose a direct interface to the Package. Items That are Not Considered Part of a Modified Version (9) Works (including, but not limited to, modules and scripts) that merely extend or make use of the Package, do not, by themselves, cause the Package to be a Modified Version. In addition, such works are not considered parts of the Package itself, and are not subject to the terms of this license. General Provisions (10) Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license. (11) If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license. (12) This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder. (13) This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed. (14) Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------- qsf-1.2.7/doc/index.html0000644000076400007640000000077307611763233012703 0ustar awaw Documentation Index

    Documentation Index

    qsf-1.2.7/doc/VERSION0000644000076400007640000000000610664771531011745 0ustar awaw1.2.7 qsf-1.2.7/doc/spec.in0000644000076400007640000001400310664771512012160 0ustar awawSummary: Quick Spam Filter %if %{?_with_static:1}0 Name: @PACKAGE@-static %else Name: @PACKAGE@ %endif Version: @VERSION@ Release: 1%{?dist} License: Artistic 2.0 Group: Development/Tools Source: http://www.ivarch.com/programs/sources/@PACKAGE@-@VERSION@.tar.bz2 URL: http://www.ivarch.com/programs/@PACKAGE@.shtml BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) %if %{?_with_static:1}0 Obsoletes: @PACKAGE@ %else Obsoletes: @PACKAGE@-static %endif Provides: @PACKAGE@ = @VERSION@-1 %description Quick Spam Filter (@PACKAGE@) is a small, fast spam filter that works by learning to recognise the words that are more likely to appear in spam than non-spam. It is intended to be used in a procmail recipe to mark email as being possible spam. Available rpmbuild rebuild options: --without: gdbm mysql sqlite --with: static %prep %setup -q -n @PACKAGE@-@VERSION@ %build CFLAGS="$RPM_OPT_FLAGS" sh ./configure \ %if %{?_without_gdbm:1}0 --without-gdbm \ %endif %if %{?_without_mysql:1}0 --without-mysql \ %endif %if %{?_without_sqlite:1}0 --without-sqlite \ %endif %if %{?_with_static:1}0 --enable-static \ %endif --prefix=/usr \ --infodir=/usr/share/info \ --mandir=/usr/share/man \ --sysconfdir=/etc make %{?_smp_mflags} %install [ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT" [ -e "$RPM_BUILD_ROOT" ] || mkdir -m 755 "$RPM_BUILD_ROOT" make install DESTDIR="$RPM_BUILD_ROOT" chmod 755 "$RPM_BUILD_ROOT"/usr/bin/@PACKAGE@* %clean [ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT" %files %defattr(-, root, root) /usr/bin/@PACKAGE@ %docdir /usr/share/man/man1 /usr/share/man/man1/* %doc README doc/NEWS doc/TODO doc/COPYING doc/postfix-howto extra/*.sh %changelog * Tue Aug 28 2007 Andrew Wood 1.2.7-1 - Changed to Artistic License 2.0. - Removed "-l" option. * Sun Feb 4 2007 Andrew Wood 1.2.6-1 - Removed locking from MySQL as it makes it too slow. * Sun Jan 21 2007 Andrew Wood 1.2.5-1 - Major bugfix in the "list" backend to fix the random deletion of tokens. - Improved MySQL support. * Wed Oct 25 2006 Andrew Wood 1.2.1-1 - Concurrent updates now work correctly on all database backends. * Mon Oct 2 2006 Andrew Wood - A new database backend called "list". New options to set value of X-Spam - header, keep a plaintext mapping of hashes to tokens, and maintain a - deny-list. Allow and deny lists can now list domains as well as individual - email addresses. * Mon Aug 14 2006 Andrew Wood - Code cleanup and fixes for various non-i386-Linux problems. * Sat Apr 8 2006 Andrew Wood - Addresses from the Return-Path: header are now also checked against the - allow-list in addition to those from the From: header. * Thu Feb 2 2006 Andrew Wood - Tokenisation fixes for URLs at the start of messages and for nested - attachments. * Thu Jul 7 2005 Andrew Wood - Allow list matching is now case insensitive; - a btree database's last-modification is updated after any modification; - the spec file was fixed to work with Fedora Core 4. * Thu May 12 2005 Andrew Wood - Tokens now have an age marker; - additional token types were added; - the database pruning algorithm was improved; - the binary tree backend has had some speed enhancements. * Fri Mar 4 2005 Andrew Wood - Moved all internal db functions to one file; - all backends can now be compiled into the same binary; - some cleanup of code; - benchmarking has been improved; - the RPM can now be built with statically linked backends. * Mon Feb 28 2005 Andrew Wood - Fixed the documentation of the "--dump" option; - checked where "--dump" is dumping data to; - no longer dump large messages in non-filtering mode; - reporting of database backend in verbose mode. * Sat Feb 19 2005 Andrew Wood - A new option to skip short messages was added; - an option to tune the extent of database pruning was added; - and the tokeniser was improved. * Sat Feb 5 2005 Andrew Wood - Bug fixes when building RPMs, and added support for "rpmbuild --with". * Sun Sep 26 2004 Andrew Wood - Code cleanup, and new routines to decode character-encoded headers. * Wed Sep 22 2004 Andrew Wood - A new database backend based on SQLite was added. * Tue Jun 22 2004 Andrew Wood - A new verbosity option to add errors and information as message headers; - an option to output stars like SpamAssassin was added; - the allow-list can be queried using an address read from an email; and - a system-wide filtering HOWTO was added. * Tue Apr 27 2004 Andrew Wood - More explanation of tokenisation, and a new troubleshooting section added to the manual. * Fri Mar 12 2004 Andrew Wood - Code cleanup, many new filters, and some command line syntax improvements. * Fri Jan 16 2004 Andrew Wood - A new option to query and update the allow-list directly was added; - the spam threshold level can be now altered; - a second "global" database can now be used; and - some minor bug fixes were made. * Mon Jan 5 2004 Andrew Wood - The tokeniser was improved further to recognise distinct URLs and compress whitespace. - Additional filters for IP-based URLs and virus attachments were added. * Sat Dec 27 2003 Andrew Wood - Minor cosmetic fixes were made for non-Linux systems. - Speed improvements have been made in the binary tree backend database. * Fri Nov 14 2003 Andrew Wood - Added "-mysql" subpackage for optional MySQL backend * Thu Aug 21 2003 Andrew Wood - Added package description * Sat Jan 11 2003 Andrew Wood - First draft of spec file created qsf-1.2.7/doc/qsf.spec0000644000076400007640000001366110665021365012347 0ustar awawSummary: Quick Spam Filter %if %{?_with_static:1}0 Name: qsf-static %else Name: qsf %endif Version: 1.2.7 Release: 1%{?dist} License: Artistic 2.0 Group: Development/Tools Source: http://www.ivarch.com/programs/sources/qsf-1.2.7.tar.bz2 URL: http://www.ivarch.com/programs/qsf.shtml BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) %if %{?_with_static:1}0 Obsoletes: qsf %else Obsoletes: qsf-static %endif Provides: qsf = 1.2.7-1 %description Quick Spam Filter (qsf) is a small, fast spam filter that works by learning to recognise the words that are more likely to appear in spam than non-spam. It is intended to be used in a procmail recipe to mark email as being possible spam. Available rpmbuild rebuild options: --without: gdbm mysql sqlite --with: static %prep %setup -q -n qsf-1.2.7 %build CFLAGS="$RPM_OPT_FLAGS" sh ./configure \ %if %{?_without_gdbm:1}0 --without-gdbm \ %endif %if %{?_without_mysql:1}0 --without-mysql \ %endif %if %{?_without_sqlite:1}0 --without-sqlite \ %endif %if %{?_with_static:1}0 --enable-static \ %endif --prefix=/usr \ --infodir=/usr/share/info \ --mandir=/usr/share/man \ --sysconfdir=/etc make %{?_smp_mflags} %install [ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT" [ -e "$RPM_BUILD_ROOT" ] || mkdir -m 755 "$RPM_BUILD_ROOT" make install DESTDIR="$RPM_BUILD_ROOT" chmod 755 "$RPM_BUILD_ROOT"/usr/bin/qsf* %clean [ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf "$RPM_BUILD_ROOT" %files %defattr(-, root, root) /usr/bin/qsf %docdir /usr/share/man/man1 /usr/share/man/man1/* %doc README doc/NEWS doc/TODO doc/COPYING doc/postfix-howto extra/*.sh %changelog * Tue Aug 28 2007 Andrew Wood 1.2.7-1 - Changed to Artistic License 2.0. - Removed "-l" option. * Sun Feb 4 2007 Andrew Wood 1.2.6-1 - Removed locking from MySQL as it makes it too slow. * Sun Jan 21 2007 Andrew Wood 1.2.5-1 - Major bugfix in the "list" backend to fix the random deletion of tokens. - Improved MySQL support. * Wed Oct 25 2006 Andrew Wood 1.2.1-1 - Concurrent updates now work correctly on all database backends. * Mon Oct 2 2006 Andrew Wood - A new database backend called "list". New options to set value of X-Spam - header, keep a plaintext mapping of hashes to tokens, and maintain a - deny-list. Allow and deny lists can now list domains as well as individual - email addresses. * Mon Aug 14 2006 Andrew Wood - Code cleanup and fixes for various non-i386-Linux problems. * Sat Apr 8 2006 Andrew Wood - Addresses from the Return-Path: header are now also checked against the - allow-list in addition to those from the From: header. * Thu Feb 2 2006 Andrew Wood - Tokenisation fixes for URLs at the start of messages and for nested - attachments. * Thu Jul 7 2005 Andrew Wood - Allow list matching is now case insensitive; - a btree database's last-modification is updated after any modification; - the spec file was fixed to work with Fedora Core 4. * Thu May 12 2005 Andrew Wood - Tokens now have an age marker; - additional token types were added; - the database pruning algorithm was improved; - the binary tree backend has had some speed enhancements. * Fri Mar 4 2005 Andrew Wood - Moved all internal db functions to one file; - all backends can now be compiled into the same binary; - some cleanup of code; - benchmarking has been improved; - the RPM can now be built with statically linked backends. * Mon Feb 28 2005 Andrew Wood - Fixed the documentation of the "--dump" option; - checked where "--dump" is dumping data to; - no longer dump large messages in non-filtering mode; - reporting of database backend in verbose mode. * Sat Feb 19 2005 Andrew Wood - A new option to skip short messages was added; - an option to tune the extent of database pruning was added; - and the tokeniser was improved. * Sat Feb 5 2005 Andrew Wood - Bug fixes when building RPMs, and added support for "rpmbuild --with". * Sun Sep 26 2004 Andrew Wood - Code cleanup, and new routines to decode character-encoded headers. * Wed Sep 22 2004 Andrew Wood - A new database backend based on SQLite was added. * Tue Jun 22 2004 Andrew Wood - A new verbosity option to add errors and information as message headers; - an option to output stars like SpamAssassin was added; - the allow-list can be queried using an address read from an email; and - a system-wide filtering HOWTO was added. * Tue Apr 27 2004 Andrew Wood - More explanation of tokenisation, and a new troubleshooting section added to the manual. * Fri Mar 12 2004 Andrew Wood - Code cleanup, many new filters, and some command line syntax improvements. * Fri Jan 16 2004 Andrew Wood - A new option to query and update the allow-list directly was added; - the spam threshold level can be now altered; - a second "global" database can now be used; and - some minor bug fixes were made. * Mon Jan 5 2004 Andrew Wood - The tokeniser was improved further to recognise distinct URLs and compress whitespace. - Additional filters for IP-based URLs and virus attachments were added. * Sat Dec 27 2003 Andrew Wood - Minor cosmetic fixes were made for non-Linux systems. - Speed improvements have been made in the binary tree backend database. * Fri Nov 14 2003 Andrew Wood - Added "-mysql" subpackage for optional MySQL backend * Thu Aug 21 2003 Andrew Wood - Added package description * Sat Jan 11 2003 Andrew Wood - First draft of spec file created qsf-1.2.7/doc/postfix-howto0000644000076400007640000000473610066123031013446 0ustar awawThis document was mainly written by M. Kölbl, and details the steps that can be taken to implement QSF as a system-wide mail filter. 1. Create a user "filter" with password "*" and usergroup "nogroup". 2. Make the dir "/var/spool/filter" 3. Do "> /var/spool/filter/.qsfdb" (i.e. create an empty file). 4. Do "chown -R filter:nogroup /var/spool/filter" 5. Do "chmod -R 700 /var/spool/filter" 6. Create a file "/usr/bin/qsf-postfix" with the following content: #### BEGIN #### #!/bin/sh # Simple shell-based filter. It is meant to be invoked as follows: # /path/to/script -f sender recipients... # Localize these. INSPECT_DIR=/var/spool/filter SENDMAIL="/usr/sbin/sendmail -i" QSF="/usr/bin/qsf -r" # Exit codes from EX_TEMPFAIL=75 EX_UNAVAILABLE=69 # Clean up when done or when aborting. trap "rm -f in.$$; rm -f out.$$" 0 1 2 3 15 # Start processing. cd $INSPECT_DIR || { echo $INSPECT_DIR does not exist; exit $EX_TEMPFAIL; } cat >in.$$ || { echo Cannot save mail to file; exit $EX_TEMPFAIL; } # Specify your content filter here. $QSF out.$$|| { echo Message content rejected; exit $EX_UNAVAILABLE; } $SENDMAIL "$@" /d' -e '/<\/body>/,$d' - update HTML for todo and news - copy and sign tar.gz to HTML directory - upload package to SourceForge - create a new release on SourceForge - submit new release to Freshmeat - upload HTML - check validator results for project page and manual - send notice to mailing list - cvs tag vVERSION (eg cvs tag v1_0_0) qsf-1.2.7/doc/PACKAGE0000644000076400007640000000000407611763234011650 0ustar awawqsf qsf-1.2.7/doc/quickref.txt0000644000076400007640000011342310665021373013250 0ustar awawQSF(1) User Manuals QSF(1) NAME qsf - quick spam filter SYNOPSIS Filtering: qsf [-snrAtav] [-d DB] [-g DB] [-L LVL] [-S SUBJ] [-H MARK] [-Q NUM] [-X NUM] Training: qsf -T SPAM NONSPAM [MAXROUNDS] [-d DB] Retraining: qsf -[m|M] [-d DB] [-w WEIGHT] [-ayN] Database: qsf -[p|D|R|O] [-d DB] Database merge: qsf -E OTHERDB [-d DB] Allowlist query: qsf -e EMAIL [-m|-M|-t] [-d DB] [-g DB] Denylist query: qsf -y -e EMAIL [-m -m|-M -M|-t] [-d DB] [-g DB] Help: qsf -[h|V] DESCRIPTION qsf reads a single email on standard input, and by default outputs it on standard output. If the email is determined to be spam, an addi- tional header ("X-Spam: YES") will be added, and optionally the subject line can have "[SPAM]" prepended to it. qsf is intended to be used in a procmail(1) recipe, in a ruleset such as this: :0 wf | qsf -ra :0 H: * X-Spam: YES $HOME/mail/spam For more examples, including sample procmail(1) recipes, see the EXAM- PLES section below. TRAINING Before qsf can be used properly, it needs to be trained. A good way to train qsf is to collect a copy of all your email into two folders - one for spam, and one for non-spam. Once you have done this, you can use the training function, like this: qsf -aT spam-folder non-spam-folder This will generate a database that can be used by qsf to guess whether email received in the future is spam or not. Note that this initial training run may take a long time, but you should only need to do it once. To mark a single message as spam, pipe it to qsf with the --mark-spam or -m ("mark as spam") option. This will update the database accord- ingly and discard the email. To mark a single message as non-spam, pipe it to qsf with the --mark- nonspam or -M ("mark as non-spam") option. Again, this will discard the email. If a message has been mis-tagged, simply send it to qsf as the opposite type, i.e. if it has been mistakenly tagged as spam, pipe it into qsf --mark-nonspam --weight=2 to add it to the non-spam side of the database with double the usual weighting. OPTIONS The qsf options are listed below. -d, --database [TYPE:]FILE Use FILE as the spam/non-spam database. The default is to use /var/lib/qsfdb and, if that is not available or is read-only, $HOME/.qsfdb. This option can also be useful if there is a sys- tem-wide database but you do not want to use it - specifying your own here will override the default. If you prefix the filename with a TYPE, of the form btree:$HOME/.qsfdb, then this will specify what kind of database FILE is, such as list, btree, gdbm, sqlite and so on. Check the output of qsf -V to see which database backends are available. The default is to auto-detect the type, or, if the file does not already exist, use list. Note that TYPE is not case-sensitive. -g, --global [TYPE:]FILE Use FILE as the default global database, instead of /var/lib/qsfdb. If you also specify a database with -d, then this "global" database will be used in read-only mode in con- junction with the read-write database specified with -d. The -g option can be used a second time to specify a third database, which will also be used in read-only mode. Again, the filename can optionally be prefixed with a TYPE which specifies the database type. -P, --plain-map FILE Maintain a mapping of all database tokens to their non-hashed counterparts in FILE, one token per line. This can be useful if you want to be able to list the contents of your database at a later date, for instance to get a list of email addresses in your allow-list. Note that using this option may slow qsf down, and only entries written to the database while this option is active will be stored in FILE. -s, --subject Rewrite the Subject line of any email that turns out to be spam, adding "[SPAM]" to the start of the line. -S, --subject-marker SUBJECT Instead of adding "[SPAM]", add SUBJECT to the Subject line of any email that turns out to be spam. Implies -s. -H, --header-marker MARK Instead of setting the X-Spam header to "YES", set it to MARK if email turns out to be spam. This can be useful if your email client can only search all headers for a string, rather than one particular header (so searching for "YES" might match more than just the output of qsf). -n, --no-header Do not add an X-Spam header to messages. -r, --add-rating Insert an additional header X-Spam-Rating which is a rating of the "spamminess" of a message from 0 to 100; 90 and above are counted as spam, anything under 90 is not considered spam. If combined with -t, then the rating (0-100) will be output, on its own, on standard output. -A, --asterisk Insert an additional header X-Spam-Level which will contain between 0 and 20 asterisks (*), depending on the spam rating. -t, --test Instead of passing the message out on standard output, output nothing, and exit 0 if the message is not spam, or exit 1 if the message is spam. If combined with -r, then the spam rating will be output on standard output. -a, --allowlist Enable the allow-list. This causes the email addresses given in the message's "From:" and "Return-Path:" headers to be checked against a list; if either one matches, then the message is always treated as non-spam, regardless of what the token database says. When specified with a retraining flag, -a -m (mark as spam) will remove that address from the allow-list as well as marking the message as spam, and -a -M (mark as non- spam) will add that address to the allow-list as well as marking the message as non-spam. The idea is that you add all of your friends to the allow-list, and then none of their messages ever get marked as spam. -y, --denylist Enable the deny-list. This causes the email addresses given in the message's "From:" and "Return-Path:" headers to be checked against a second list; if either one matches, then theh message is always treated as spam. Training works in the same way as with -a, except that you must specify -m or -M twice to modify the deny-list instead of the allow-list, and with the reverse syntax: -y -m -m (mark as spam) will add that address to the deny-list, whereas -y -M -M (mark as non-spam) will remove that address from the deny-list. This double specification is so that the usual retraining process never touches the deny-list; the deny-list should be carefully maintained rather than auto- matically generated. Normally you would not need to use the deny-list. -L, --level, --threshold LEVEL Change the spam scoring threshold level which must be reached before an email is classified as spam. The default is 90. -Q, --min-tokens NUM Only give a score if more than NUM tokens are found in the mes- sage - otherwise the message is assumed to be non-spam, and it is not modified in any way. The default is 0. This option might be useful if you find that very short messages are being frequently miscategorised. -e, --email, --email-only EMAIL Query or update the allow-list entry for the email address EMAIL. With no other options, this will simply output "YES" if EMAIL is in the allow-list, or "NO" if it is not. With -t, it will not output anything, but will exit 0 (success) if EMAIL is in the allow-list, or 1 (failure) if it is not. With the -m (mark-spam) option, any previous allow-list entry for EMAIL will be removed. Finally, with the -M (mark-nonspam) option, EMAIL will be added to the allow-list if it is not already on it. If EMAIL is just the word MSG on its own, then an email will be read from standard input, and the email addresses given in the "From:" and "Return-Path:" headers will be used. Using -e automatically switches on -a. If you also specify -y, then the deny-list will be operated on. Remember that -m and -M are reversed with the deny-list. If you specify an email address of the form @domain (nothing before the @), then the whole domain will be allow or deny listed. -v, --verbose Add extra X-QSF-Info headers to any filtered email, containing error messages and so on if applicable. Specify -v more than once to increase verbosity. -T, --train SPAM NONSPAM [MAXROUNDS] Train the database using the two mbox folders SPAM and NONSPAM, by testing each message in each folder and updating the database each time a message is miscategorised. This is done several times, and may take a while to run. Specify the -a (allow-list) flag to add every sender in the NONSPAM folder to your allow- list as a side-effect of the training process. If MAXROUNDS is specified, training will end after this number of rounds if the results are still not good enough. The default is a maximum of 200 rounds. -m, --mark-spam Instead of passing the message out on standard output, mark its contents as spam and update the database accordingly. If the allow-list (-a) is enabled, the message's "From:" and "Return- Path:" addresses are removed from the allow-list. If the deny- list (-y) is enabled and you specify -m twice, the message's addresses are added to the deny-list instead. -M, --mark-nonspam Instead of passing the message out on standard output, mark its contents as non-spam and update the database accordingly. If the allow-list (-a) is enabled, the message's "From:" and "Return-Path:" addresses are added to the allow-list (see the -a option above). If the deny-list (-y) is enabled and you specify -M twice, the message's addresses are removed from the deny-list instead. -w, --weight WEIGHT When marking as spam or non-spam, update the database with a weighting of WEIGHT per token instead of the default of 1. Use- ful when correcting mistakes, eg a message that has been mistak- enly detected as spam should be marked as non-spam using a weighting of 2, i.e. double the usual weighting, to counteract the error. -D, --dump [FILE] Dump the contents of the database as a platform-independent text file, suitable for archival, transfer to another machine, and so on. The data is output on stdout or into the given FILE. -R, --restore [FILE] Rebuild the database from scratch from the text file on stdin. If a FILE is given, data is read from there instead of from stdin. -O, --tokens Instead of filtering, output a list of the tokens found in the message read from standard input, along with the number of times each token was found. This is only useful if you want to use qsf as a general tokeniser for use with another filtering pack- age. -E, --merge OTHERDB Merge the OTHERDB database into the current database. This can be useful if you want to take one user's mailbox and merge it into the system-wide one, for instance (this would be done by, as root, doing qsf -d /var/lib/qsfdb -E /home/user/.qsfdb and then removing /home/user/.qsfdb). -B, --benchmark SPAM NONSPAM [MAXROUNDS] Benchmark the training process using the two mbox folders SPAM and NONSPAM. A temporary database is created and trained using the first 75% of the messages in each folder, and then the entire contents of each folder is tested to see how many false positives and false negatives occur. Some timing information is also displayed. This can be used to decide which backend is best on your system. Use -d to select a backend, eg qsf -B spam nonspam -d GDBM - this will create a temporary database which is removed after- wards. The exception to this is the MySQL backend, where a full database specification must be given (-d MySQL:database=db;host=localhost;...) and the database table given will not be wiped beforehand or dropped afterwards. As with -T, if MAXROUNDS is specified, training will never be done for more than this number of rounds; the default is 200. -h, --help Print a usage message on standard output and exit successfully. -V, --version Print version information, including a list of available database backends, on standard output and exit successfully. DEPRECATED OPTIONS The following options are only for use with the old binary tree database backend or old databases that haven't been upgraded to the new format that came in with version 1.1.0. -N, --no-autoprune When marking as spam or nonspam, never automatically prune the database. Usually the database is pruned after every 500 marks; if you would rather --prune manually, use -N to disable auto- matic pruning. -p, --prune Remove redundant entries from the database and clean it up a little. This is automatically done after several calls to --mark-spam or --mark-nonspam, and during training with --train if the training takes a large number of rounds, so it should rarely be necessary to use --prune manually unless you are using -N / --no-autoprune. -X, --prune-max NUM When the database is being pruned, no more than NUM entries will be considered for removal. This is to prevent CPU and memory resources being taken over. The default is 100,000 but in some circumstances (if you find that pruning takes too long) this option may be used to reduce it to a more manageable number. FILES /var/lib/qsfdb The default (system-wide) spam database. If you wish to install qsf system-wide, this should be read-only to everyone; there should be one user with write access who can update the spam database with qsf --mark-spam and qsf --mark-non-spam when necessary. /var/lib/qsfdb2 A second, read-only, system-wide database. This can be useful when installing qsf system-wide and using third-party spam databases; the first global database can be updated with system- specific changes, and this second database can be periodically updated when the third-party spam database is updated. $HOME/.qsfdb The default spam database for per-user data. Users without write access to the system-wide database will have their data written here, and the two databases will be read together. The per-user database will be given a weighting equivalent to 10 times the weighting of the global database. NOTES Currently, you cannot use qsf to check for spam while the database is being updated. This means that while an update is in progress, all email is passed through as non-spam. There is an upper size limit of 512Kb on incoming email; anything larger than this is just passed through as non-spam, to avoid tying up machine resources. The plaintext token mapping maintained by --plain-map will never shrink, only grow. It is intended for use by housekeeping and user interface scripts that, for instance, the user can use to list all email addresses on their allow-list. These scripts should take care of weeding out entries for tokens that are no longer in the database. If you have no such scripts, there is probably no point in using --plain- map anyway. Avoid using the deny-list (-y) in any automated retraining, as it can be cause the filter to reject mail unnecessarily. In general the deny- list is probably best left unused unless explicitly required by your particular setup. If both the allow-list and the deny-list are enabled, then email addresses will first be checked against the deny-list, then the allow- list, then the domain of the email address will be checked for matching "@domain" entries in the deny-list and then in the allow-list. EXAMPLES To filter all of your mail through qsf, with the allow-list enabled and the "spam rating" header being added, add this to your .procmailrc file: :0 wf | qsf -ra If you want qsf to add "[SPAM]" to the subject line of any messages it thinks are spam, do this instead: :0 wf | qsf -sra To automatically mark any email sent to spambox@yourdomain.com as spam (this is the "naive" version): :0 H * ^To:.*spambox@yourdomain.com | qsf -am To do the same, but cleverly, so that only email to spambox@yourdo- main.com which qsf does NOT already classify as spam gets marked as spam in the database (this stops the database getting too heavily weighted): # If sent to spambox@yourdomain.com: :0 * ^To:.*spambox@yourdomain.com { :0 wf | qsf -a # The above two lines can be skipped if you've # already piped the message through qsf. # If the qsf database says it's not spam, # mark it as spam! :0 H * ^X-Spam: NO | qsf -am } Remove the -a option in the above examples if you don't want to use the allow-list. A more complicated filtering example - this will only run qsf on mes- sages which don't have a subject line saying "your is on fire" and which don't have a sender address ending in "@foobar.com", meaning that messages with that subject line OR that sender address will NEVER be marked as spam, no matter what: :0 wf * ! ^Subject: Your .* is on fire * ! ^From: .*@foobar.com | qsf -ra For more on procmail(1) recipes, see the procmailrc(5) and proc- mailex(5) manual pages. A couple of macros to add to your .muttrc file, if you use mutt(1) as a mail user agent: # Press F5 to mark a message as spam and delete it macro index "qsf -am\n" macro pager "qsf -am\n" # Press F9 to mark a message as non-spam macro index "qsf -aM\n" macro pager "qsf -aM\n" Again, remove the -a option in the above examples if you don't want to use the allow-list. Note, however, that the above macros won't work when operating on mul- tiple tagged messages. For that, you'd need something like this: macro index ":set pipe_split\nqsf -am\n\n:unset pipe_split\n" If you use qmail(7), then to get procmail working with it you will need to put a line containing just DEFAULT=./Maildir/ at the top of your ~/.procmailrc file, so that procmail delivers to your Maildir folder instead of trying to deliver to /var/spool/mail/$USER, and you will need to put this in your ~/.qmail file: | preline procmail This will cause all your mail to be delivered via procmail instead of being delivered directly into your mail directory. See the qmail(7) documentation for more about mail delivery with qmail. If you use postfix(1), you can set up a system-wide mail filter by cre- ating a user account for the purpose of filtering mail, populating that account's .qsfdb, and then creating a shell script, to run as that user, which runs qsf on stdin and passes stdout to sendmail(8). Doing this requires some knowledge of postfix configuration and care needs to be taken to avoid mail loops. One qsf user's full HOWTO is included in the doc/ directory with this package. THE ALLOW-LIST A feature called the "allow-list" can be switched on by specifying the --allowlist or -a option. This causes messages' "From:" and "Return- Path:" addresses to be checked against a list of people you have said to allow all messages from, and if a message's "From:" or "Return- Path:" address is in the list, it is never marked as spam. This means you can add all your friends to an "allow-list" and qsf will then never mis-file their messages - a quick way to do this is to use -a with -T (train); everyone in your non-spam folder who has sent you an email will be added to the allow-list automatically during training. You can manually add and remove addresses to and from the allow-list using the -e (email) option. For instance, to add foo@bar.com to the allow-list, do this: qsf -e foo@bar.com -M To remove bad@nasty.com from the allow-list, do this: qsf -e bad@nasty.com -m And to see whether someone@somewhere.com is in the allow-list or not, just do this: qsf -e someone@somewhere.com In general, you probably always want to enable the allow-list, so always specify the -a option when using qsf. This will automatically maintain the allow-list based on what you classify as spam or non-spam. The only times you might want to turn it off are when people on your allow-list are prone to getting viruses or if a virus is causing email to be sent to you that is pretending to be from someone on your allow- list. BACKUP AND RESTORE Because the database format is platform-specific, it is a good idea to periodically dump the database to a text file using qsf -D so that, if necessary, it can be transferred to another machine and restored with qsf -R later on. Also note that since the actual contents of email messages are never stored in the database (see TECHNICAL DETAILS), you can safely share your qsf database with friends - simply dump your database to a file, like this: qsf -D > your-database-dump.txt Once you have sent your-database-dump.txt to another person, they can do this: qsf -R < your-database-dump.txt They will then have an identical database to yours. TECHNICAL DETAILS When a message is passed to qsf, any attachments are decoded, all HTML elements are removed, and the message text is then broken up into "tokens", where a "token" is a single word or URL. Each token is hashed using the MD5 algorithm (see below for why), and that hash is then used to look up each token in the qsf database. For full details of which parts of an email (headers, body, attach- ments, etc) are used to calculate the spam rating, see the TOKENISATION section below. Within the database, each token has two numbers associated with it: the number of times that token has been seen in spam, and the number of times it has been seen in non-spam. These two numbers, along with the total number of spam and non-spam messages seen, are then used to give a "spamminess" value for that particular token. This "spamminess" value ranges from "definitely not spammy" at one end of the scale, through "neutral" in the middle, up to "definitely spammy" at the other end. Once a "spamminess" value has been calculated for all of the tokens in the message, a summary calculation is made to give an overall "is this spam?" probability rating for the message. If the overall probability is 0.9 or above, the message is flagged as spam. In addition to the probability test is the "allow-list". If enabled (with the -a option), the whole probability check is skipped if the sender of the message is listed in the allow-list, and the message is not marked as spam. When training the database, a message is split up into tokens as described above, and then the numbers in the database for each token are simply added to: if you tell qsf that a message is spam, it adds one to the "number of times seen in spam" counter for each token, and if you tell it a message is not spam, it adds one to the "number of times seen in non-spam" counter for each token. If you specify a weight, with -w, then the number you specify is added instead of one. To stop the database growing uncontrollably, the database keeps track of when a token was last used. Underused tokens are automatically removed from the database. (The old method was to "prune" every 500 updates). Finally, the reason MD5 hashes were used is privacy. If the actual tokens from the messages, and the actual email addresses in the allow- list, were stored, you could not share a single qsf database between multiple users because bits of everyone's messages would be in the database - things like emailed passwords, keywords relating to personal gossip, and so on. So a hash is stored instead. A hash is a "one-way" function; it is easy to turn a token into a hash but very hard (some might say impossible) to turn a hash back into the token that created it. This means that you end up with a database with no personal infor- mation in it. TOKENISATION When a message is broken up into tokens, various parts of the message are treated in different ways. First, all header fields are discarded, except for the important ones: From, Return-Path, Sender, To, Reply-To, and Subject. Next, any MIME-encoded attachments are decoded. Any attachments whose MIME type starts with "text/" (i.e. HTML and text) are tokenised, after having any HTML tags stripped. Any non-textual attachments are replaced with their MD5 hash (such that two identical attachments will have the same hash), and that hash is then used as a token. In addition to single-word tokens from textual message parts, qsf adds doubled-up tokens so that word pairs get added to the database. This makes the database a bit bigger (although the automatic pruning tends to take care of that) but makes matching more exact. SPECIAL FILTERS As well as using the textual content of email to detect spam, qsf also uses special filters which create "pseudo-tokens" based on various rules. This means that specific patterns, not just individual words, can be used to determine whether a message is spam or not. For example, if a message contains lots of words with multiple conso- nants, like "ashjkbnxcsdjh", then each time a word like that is seen the special token ".GIBBERISH-CONSONANTS." is added to the list of tokens found in the message. If it turns out that most messages with words that trigger this filter rule are spam, then other messages with gibberish consonant strings will be more likely to be flagged as spam. Currently the special filters are: GTUBE Flags any message containing the string XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST- EMAIL*C.34X as spam - useful for testing that your qsf installa- tion is working. ATTACH-SCR ATTACH-PIF ATTACH-EXE ATTACH-VBS ATTACH-VBA ATTACH-LNK ATTACH-COM ATTACH-BAT Adds a token for every attachment whose filename ends in ".scr", ".pif", ".exe", ".vbs", ".vba", ".lnk", ".com", and ".bat" respectively (these are often viruses). ATTACH-GIF ATTACH-JPG ATTACH-PNG Adds a token for every attachment whose filename ends in ".gif", ".jpg" or ".jpeg", and ".png" respectively. ATTACH-DOC ATTACH-XLS ATTACH-PDF Adds a token for every attachment whose filename ends in ".doc", ".xls", or ".pdf" respectively (these tend to indicate a non- spam email). SINGLE-IMAGE Adds a token if the message contains exactly one attached image. MULTIPLE-IMAGES Adds a token if the message contains more than one attached image. GIBBERISH-CONSONANTS Adds a token for every word found that has multiple consonants in a row, as described above. Spam often contains strings of gibberish. GIBBERISH-VOWELS Adds a token for every word found that has multiple vowels in a row, eg "aeaiaiaeeio". GIBBERISH-FROMCONS Like GIBBERISH-CONSONANTS, but only for the "From:" and "Return- Path:" addresses on their own. GIBBERISH-FROMVOWL Like GIBBERISH-VOWELS, but only for the "From:" and "Return- Path:" addresses on their own. GIBBERISH-BADSTART Adds a token for every word that starts with a bad character such as %. GIBBERISH-HYPHENS Adds a token for every word with more than three hyphens or underscores in it. GIBBERISH-LONGWORDS Adds a token for every word with over 30 characters in it (but less than 60). HTML-COMMENTS-IN-WORDS Adds a token for every HTML comment found in the middle of a word. Spam often contains HTML inside words, like this: word HTML-EXTERNAL-IMG Adds a token for every HTML (image) tag found that con- tains :// (i.e. it refers to an external image). HTML-FONT Adds a token for every HTML tag found. HTML-IP-IN-URLS Adds a token for every URL found containing an IP address. HTML-INT-IN-URL Adds a token for every URL found containing an integer in its hostname. HTML-URLENCODED-URL Adds a token for every URL found containing a % sign in its hostname. Normally, filters will just cause a token to be added, and these tokens are processed by the normal weighting algorithm. However the GTUBE filter will immediately flag any matching message as spam, bypassing the token matching. DATABASE BACKENDS The inbuilt "list" database backend will not necessarily provide the best performance, but is provided because using it requires no external libraries. If, when qsf was compiled, the correct libraries were available, then it will be possible to use qsf with alternative database backends. To find out which backends you have available, run qsf -V (capital V) and read the second line of output. To see how well a backend performs, collect some spam and non-spam and use qsf -d BACKEND -B SPAM NONSPAM (see the entry for -B above). Some people find that they get the best performance out of the gdbm backend; this is a library that is widely available on many systems. To efficiently share a qsf database across multiple machines, you may find the MySQL backend useful. However, using it is a little more com- plicated. To use the MySQL backend you will need to create a table with the fields key1, key2, token, value1, value2 and value3. The token, value1, value2, and value3 fields must be VARCHAR(64), BIGINT or INT, and BIGINT or INT respectively, and indexing on the token field is a good idea. The key1 and key2 fields can be anything, but they must be present. For example: USE mydatabase; CREATE TABLE qsfdb ( key1 BIGINT UNSIGNED NOT NULL, key2 BIGINT UNSIGNED NOT NULL, token VARCHAR(64) DEFAULT '' NOT NULL, value1 INT UNSIGNED NOT NULL, value2 INT UNSIGNED NOT NULL, value3 INT UNSIGNED NOT NULL, PRIMARY KEY (key1,key2,token), KEY (key1), KEY (key2), KEY (token) ); The key1 and key2 fields allow you to have multiple qsf databases in one table, by specifying different key1 and key2 values on invocation. Instead of specifying a database file with the --database / -d option, you must specify either a specification string as described below, or the name of a file containing such a string on its first line. The specification string is as follows: database=DATABASE;host=HOST;port=PORT; user=USER;pass=PASS;table=TABLE; key1=KEY1;key2=KEY2 This string must be all on one line, with no spaces. DATABASE is the name of the MySQL database. HOST is the hostname of the database server (eg "localhost"). PORT is the TCP port to connect on (eg 3306). USER is the username to connect with. PASS is the password to connect with. TABLE is the database table to use. If a table with this name does not exist when qsf is called in update or training mode, then it will be created if permissions allow this to be done. KEY1 is the value to use for the key1 field. KEY2 is the value to use for the key2 field. Since command lines can be seen in the process list, it is probably best to specify a filename (eg qsf -d mysql:qsfdb.spec) and put the specification string inside that file. TROUBLESHOOTING If you have problems with qsf, please check the list below; if this does not help, go to the qsf home page and investigate the mailing lists, or email the author. Nothing is being marked as spam. First, use the -r option to switch on the X-Spam-Rating header, and check that this header appears in email passed through qsf. If it does not, then it is likely that qsf is not being run at all - check your configuration of procmail(1) or its equivalent. If you are seeing X-Spam-Rating headers, and different emails have different scores, then you may simply need to retrain your database a little more. Take more spam email and pass it to qsf -m. If you are seeing X-Spam-Rating headers but they all give the same spam rating, then the most likely reason is that qsf is not reading any database. Make sure that whatever is processing the email has read permissions on /var/lib/qsfdb and/or ~/.qsfdb - and make sure that, if you are using ~/.qsfdb, what your database creator thought was ~ ($HOME) is the same as it is for whatever is processing the email. Retraining sometimes takes a very long time. With the obtree backend or 2-column MySQL or SQLite tables, every 500th retrain (-m or -M), the database is pruned. On some systems this may take some time, and during this time the database is locked (except when using the MySQL or SQLite back- ends). If you constantly do a lot of retraining and want to avoid this, then use the -N option to suppress auto-pruning, and then have a cron(8) job or something run a manual prune (qsf -p) every now and again. Running qsf from procmail fails with an error. If you can run qsf from the command line, but in your procmail log file you get errors about "qsf: cannot execute binary file", then contact your system administrator for help. It may be that incoming email is handled by a different server to the one you normally shell into, and either they are of a different archi- tecture or operating system, or the mail server is not permitted to execute user-owned binaries. ACKNOWLEDGEMENTS The following people have contributed suggestions, comments, patches, and testing: Tom Parker Dr Kelly A. Parker Vesselin Mladenov Glyn Faulkner Mark Reynolds Sam Roberts Scott Allen Karsten Kankowski M. Kolbl Micha Holzmann Jef Poskanzer Clemens Fischer Nelson A. de Oliveira Michal Vitecek Tommy Pettersson AUTHOR The author: Andrew Wood http://www.ivarch.com/ Project home page: http://www.ivarch.com/programs/qsf/ BUGS If you find any bugs, please contact the author, either by email or by using the contact form on the web site. SEE ALSO procmail(1), procmailrc(5), procmailex(5) Someone has written a guide to using qsf with KMail that can be found at: http://www.softwaredesign.co.uk/Information.SpamFilters.html LICENSE This is free software, distributed under the ARTISTIC 2.0 license. Linux August 2007 QSF(1) qsf-1.2.7/doc/lsm.in0000644000076400007640000000071210664771335012026 0ustar awawBegin3 Title: @PACKAGE@ Version: @VERSION@ Entered-date: 28AUG07 Description: Quick spam filter - marks email as spam depending on its content using a database built up through training. Keywords: spam filter, antispam, UCE Author: Andrew Wood Maintained-by: Andrew Wood Primary-site: http://www.ivarch.com/programs/@PACKAGE@/ Alternate-site: Original-site: Platforms: Copying-policy: Artistic 2.0 End qsf-1.2.7/doc/NEWS0000644000076400007640000002752410664771421011410 0ustar awaw1.2.7 - 28 August 2007 - license change to Artistic 2.0 - pointless option "-l" removed 1.2.6 - 4 February 2007 - bugfix (reversion): removed locking from MySQL as it makes it too slow 1.2.5 - 21 January 2007 - bugfix: fixed random token deletion in list backend - bugfix: added table locking to MySQL backend to maintain integrity - bugfix: fixed MySQL database type autodetection for files - cleanup: rpmlint fixes to spec file 1.2.1 - 25 October 2006 - bugfix: concurrent updates now work properly on all backends - developers: "make bigbenchmark" generates graph data for gnuplot 1.2.0 - 2 October 2006 - new default backend database "list" (better than btree) - new option "-H" to set value of X-Spam header (Michal Vitecek) - new option "-P" to keep a plaintext mapping of hashes to tokens - new option "-y" to use a deny-list as well as an allow-list - new allow/deny-list syntax "@domain" to list whole domains 1.1.13 - 15 August 2006 - bugfix: patch from Michal Vitecek to fix segfault in btree backend - bugfix: fixed MD5 problem on 64-bit systems (eg AMD64) - bugfix: fixed mmap problem with btree on OpenBSD - cleanup: better compilation on Solaris - cleanup: use snprintf more and strcpy/strcat less - cleanup: fixed problems spotted by Tommy Pettersson 1.1.7 - 8 April 2006 - check Return-Path: header against allow-list as well as From: 1.1.6 - 2 February 2006 - cosmetic fixes to prevent compilation warnings with GCC 4.x - bugfix: improved MySQL detection when running configure script - bugfix: if a URL is the first thing in the body it is now still found - bugfix: handle message/* nested attachments 1.1.2 - 7 July 2005 - allow list matching is now case insensitive - new btree database mtime is updated after any modification - spec file fix for FC4 1.1.0 - 12 May 2005 - per-user databases are now given 10x the weighting of global databases - improved the pruning algorithm to take token "age" into account - new number-of-updates counter; each token now has a "last updated" time - the internal binary tree database is much faster on systems with mmap() - "make test", "make benchmark", and "qsf -B" now support the MySQL backend - token for words beginning with non-alphanumeric characters - token for words with more than 3 hyphens or underscores - token for words between 31 and 59 characters long - token for FONT tags - replaced image token with "external image" token - bugfix: fixed hard-to-trigger SQLite crash after multiple db prunes 1.0.31 - 4 March 2005 - put all internal binary tree db code into a single file - allow more than one backend to be compiled in at once - check for gdbm_fdesc, some systems don't have it - check for mysql_real_escape_string (if absent, MySQL is too old) - code cleanup - configure option "--enable-static" to allow static linking against libs - developers: new "make benchmark" benchmarks available backends - developers: benchmarking ("-B") now reports more information - packagers: RPM options are now just plain and "static" 1.0.22 - 28 February 2005 - optional argument to "-D" documented in man page - bugfix: if "-D" is given a filename, check it won't overwrite a database - bugfix: don't output >512kb messages in mark/non-filter mode - developers: in "-vv" (very verbose) mode, report which backend is in use 1.0.18 - 19 February 2005 - new option "-Q" to pass through messages containing insufficient tokens - new option "-X" to set a limit on how many tokens can be pruned at once - filter now adds tokens for more attachment types (DOC, XLS, PDF, images) as well as for single and multiple images 1.0.15 - 5 February 2005 - fixed bug in RPM spec file when looking for MySQL libraries - fixed bug in "make rpm" and "make srpm" build targets - updated spec file to use "--with" options (gdbm, mysql, sqlite) 1.0.14 - 26 September 2004 - decode email headers that are expressed in alternate encodings - minor cleanup of option parsing code - added "memtest" Makefile target for testing with valgrind - option "-e" now automatically enables "-a" - more tests for "make test"; tests no longer depend on "formail" 1.0.9 - 22 September 2004 - added new SQLite backend - added "-sqlite" package to RPM spec file for "qsf-sqlite" package - added "--with-sqlite" option to configure script 1.0.6 - 22 June 2004 - added "-v" option to add logging headers to email - added "-A" option to add "X-Spam-Level" header, like SpamAssassin - use "-e MSG" to update/query allow list using address read from an email - included Postfix filtering HOWTO from M. Kölbl 1.0.2 - 28 April 2004 - added tokenisation details and a troubleshooting section to the manual - added "srpm" and "release" Makefile targets 1.0.1 - 15 March 2004 - corrected default per-user database name back to ~/.qsfdb 1.0.0 - 12 March 2004 - added mailstats.sh to the new "extra/" source directory - added statstable.sh to the new "extra/" source directory - scripts from extra/ are installed as documentation in the RPM - code cleanup using RATS to check for potential problems - portability fixes in the build process - word-wrapping in "--help" output - abort with an error if superfluous command line arguments are given - abort with an error if an invalid database is supplied - keyboard interrupt signals blocked during critical db writing parts - new option "-N" to prevent automatic pruning - both "-R" and "-D" can take a filename instead of stdin/stdout - filter to check for gibberish in the sender address - filter now adds extra tokens for the hostname part of URLs - filter now checks URL-encoded hostnames (http://%6d%6e%3f/) - filter now checks for integer hostnames (http://1234567890/) - filter to look for tags 0.9.25 - 16 January 2004 - new option "-e" to query and update the allow-list directly - new option "-L" to change the spam threshold level - option to allow "-g" to be used twice, for two global databases - removed locks from procmail examples - added information on using qsf with qmail - MySQL option allows dynamic linking - bugfix: prevent memory hogging by limiting number of tokens in one prune 0.9.18 - 6 January 2004 - allow a combination of "-r" "-t" to just output the spam score - tokeniser improvement: strip multiple spaces/newlines - tokeniser improvement: add URLs to tokeniser - filter to add URLs as tokens, with and without "@" parts - filter for numeric IP addresses in URLs - filter for .vbs, .vba, .lnk, .com, .bat file extensions 0.9.12 - 1 January 2004 - minor cosmetic fixes for non-Linux systems - speedup: replaced stdio with low-level read/write in btree db backend - bugfix in "make index" (only of interest to developers) 0.9.9 - 29 November 2003 - fixed outdated information in the README - fixed memory management bug in MySQL backend - minor fixes to "make test" and "make leaktest" - some speedups in the binary tree database backend 0.9.6 - 15 November 2003 - added MySQL database backend - added "--global" to change default global database - added qsf-mysql RPM package using optional MySQL backend 0.9.4 - 21 October 2003 - switched from RPM_BUILD_ROOT to DESTDIR in "make install" - added locking to binary tree database backend - data corruption bugfix in binary tree database backend - dropped support for Berkeley DB - made the internal binary tree database the default (not GDBM) - documented the new filters 0.9.0 - 29 August 2003 - switched spam rating calculation to Robinson method - removed shifting weighting from training (--train) - removed the "-o" (--add-tokens) option, as it is now redundant - added support for multiple extra tests/token adding rules - new rule: GTUBE (see http://www.spamassassin.org/gtube/) - new rules: detect if an attachment ends in .scr, .pif, .exe - new rules: detect runs of multiple consonants / vowels - new rule: detect HTML comments in the middle of words - changed automatic pruning to only prune after every 500 updates - added "--enable-profiling" to configure script - added new --subject-marker option to set subject line - added token pairing to match pairs of words 0.8.1 - 21 August 2003 - added more documentation, with examples, to the manual - changed "-a -T" to behave exactly as manual specifies - some minor (cosmetic) cleanups in the build process 0.7.8 - 18 August 2003 - added "--allowlist" for email address whitelisting 0.7.7 - 31 July 2003 - added automatic database pruning after every 100 updates 0.7.6 - 23 July 2003 - added "--merge" option to merge two databases together - added C fakemail replacement to speed up "make test" 0.7.4 - 8 July 2003 - increased max HTML tag length from 100 to 500 characters - decode HTML entities like   and " - increased minimum token size to 3 characters from 2 - bugfix in header addition 0.7.0 - 5 July 2003 - added logarithmic probability scaling - changed X-Spam-Rating: values to range from 0 to 100 (>90=spam) - fixed bug in --prune that forced you to specify your database - new option to add X-Spam-Token: headers (mainly for debugging) - added new --benchmark option for developers - stopped looking at the Received: header (causes too much skew) - added "Sender:" to the list of headers we look at - prune function now throws away tokens with <4 counts - added new database-independent storage backend - exclamation marks now allowed in tokens - moved upper/lower probability cap back to 3 decimal places, not 4 - new developer option "make indent" to reformat source code - extra code to allow compilation under MinGW (Windows) 0.5.9 - 27 June 2003 - replaced MD5 code with a public domain version - binary attachments now have their MD5 checksum used as a token - maximum token length increased to 34 - bug fixes in mailbox parser (extra null message, missing last message) - bug fix in shifting weighting code 0.5.4 - 4 June 2003 - improved training method of --train using shifting weightings - removed GNU getopt code from source tree - replaced test spam/nonspam mail folders with test token lists 0.5.1 - 11 May 2003 - minor bugfix in --restore 0.5.0 - 10 May 2003 - tokens now stored as MD5 hashes for privacy - added new "--add-rating" (-r) option to add X-Spam-Rating header - added new "--prune" (-p) option to prune redundant database entries - tokeniser now strips HTML where appropriate - tokeniser now only allows . ' and - when not at start or end (i.e. URLs) - added support for Berkeley DB 1.85 and 4 - now seems to build and test OK on Mac OS X - added "debian" directory from Tom Parker - added "make rpm" and "make deb" targets to build RPM and Debian packages - fixed buffer handling mistake in message parser - build fixes and cleanups, added tests 0.3.1 - 22 January 2003 - allow the use of per-user databases and a system-wide database together - added variable weighting to the training algorithm - improved parsing of multipart messages / attachments - removed use of tolower(), which was causing glibc version problems (!) - added X-Spam: NO header to non-spam email - moved all database calls to a wrapper for future portability - split up message parser for better readability - split up spam checking functions for better readability - split up mailbox parsing functions for better readability 0.2.2 - 19 January 2003 - worked around procmail bug: now always exit 0 when filtering 0.2.1 - 17 January 2003 - removed dependency on fmemopen(), which isn't standard - found and documented bug in handling with procmail 0.2.0 - 15 January 2003 - non-textual attachments are now skipped - added --train option - checked for memory leaks - tested --train on big mailboxes (around 28000 messages in total) 0.1.0 - 14 January 2003 - first working version 0.0.1 - 11 January 2003 - package created - first draft of man page written qsf-1.2.7/doc/quickref.1.in0000644000076400007640000010672010664771435013212 0ustar awaw.TH @UCPACKAGE@ 1 "August 2007" Linux "User Manuals" .SH NAME @PACKAGE@ \- quick spam filter .SH SYNOPSIS Filtering: \fB@PACKAGE@\fR [\fI\-snrAtav\fR] [\fI-d DB\fR] [\fI-g DB\fR] .br [\fI-L LVL\fR] [\fI-S SUBJ\fR] [\fI-H MARK\fR] [\fI-Q NUM\fR] .br [\fI-X NUM\fR] .br Training: \fB@PACKAGE@\fR \fI\-T SPAM NONSPAM\fR [\fIMAXROUNDS\fR] [\fI-d DB\fR] .br Retraining: \fB@PACKAGE@\fR \fI\-\fR[\fIm|M\fR] [\fI-d DB\fR] [\fI-w WEIGHT\fR] [\fI-ayN\fR] .br Database: \fB@PACKAGE@\fR \fI\-\fR[\fIp|D|R|O\fR] [\fI-d DB\fR] .br Database merge: \fB@PACKAGE@\fR \fI\-E OTHERDB\fR [\fI-d DB\fR] .br Allowlist query: \fB@PACKAGE@\fR \fI\-e EMAIL\fR [\fI-m|-M|-t\fR] [\fI-d DB\fR] [\fI-g DB\fR] .br Denylist query: \fB@PACKAGE@\fR \fI\-y\fR \fI\-e EMAIL\fR [\fI-m -m|-M -M|-t\fR] [\fI-d DB\fR] [\fI-g DB\fR] .br Help: \fB@PACKAGE@\fR \fI-\fR[\fIh|V\fR] .SH DESCRIPTION .B @PACKAGE@ reads a single email on standard input, and by default outputs it on standard output. If the email is determined to be spam, an additional header ("X-Spam: YES") will be added, and optionally the subject line can have "[SPAM]" prepended to it. .B @PACKAGE@ is intended to be used in a .BR procmail (1) recipe, in a ruleset such as this: .RS :0 wf | @PACKAGE@ -ra :0 H: * X-Spam: YES $HOME/mail/spam .RE For more examples, including sample .BR procmail (1) recipes, see the .B EXAMPLES section below. .SH TRAINING Before .B @PACKAGE@ can be used properly, it needs to be trained. A good way to train .B @PACKAGE@ is to collect a copy of all your email into two folders - one for spam, and one for non-spam. Once you have done this, you can use the training function, like this: .RS @PACKAGE@ -aT spam-folder non-spam-folder .RE This will generate a database that can be used by .B @PACKAGE@ to guess whether email received in the future is spam or not. Note that this initial training run may take a long time, but you should only need to do it once. To mark a .B single message as .BR spam , pipe it to .B @PACKAGE@ with the .BR \-\-mark-spam " or " \-m ("mark as spam") option. This will update the database accordingly and discard the email. To mark a .B single message as .BR non-spam , pipe it to .B @PACKAGE@ with the .BR \-\-mark-nonspam " or " \-M ("mark as non-spam") option. Again, this will discard the email. If a message has been mis-tagged, simply send it to .B @PACKAGE@ as the opposite type, i.e. if it has been mistakenly tagged as spam, pipe it into .B @PACKAGE@ --mark-nonspam --weight=2 to add it to the non-spam side of the database with double the usual weighting. .SH OPTIONS The .B @PACKAGE@ options are listed below. .TP .BI "\-d, \-\-database " [TYPE:]FILE Use .I FILE as the spam/non-spam database. The default is to use .B /var/lib/@PACKAGE@db and, if that is not available or is read-only, .BR $HOME/.@PACKAGE@db . This option can also be useful if there is a system-wide database but you do not want to use it - specifying your own here will override the default. If you prefix the filename with a .BR TYPE , of the form .BR btree:$HOME/.@PACKAGE@db , then this will specify what kind of database .B FILE is, such as .BR list ", " btree ", " gdbm ", " sqlite and so on. Check the output of .B @PACKAGE@ -V to see which database backends are available. The default is to auto-detect the type, or, if the file does not already exist, use .BR list . Note that .B TYPE is not case-sensitive. .TP .BI "\-g, \-\-global " [TYPE:]FILE Use .I FILE as the default global database, instead of .BR /var/lib/@PACKAGE@db . If you also specify a database with .BR \-d , then this "global" database will be used in read-only mode in conjunction with the read-write database specified with .BR \-d . The .B \-g option can be used a second time to specify a third database, which will also be used in read-only mode. Again, the filename can optionally be prefixed with a .B TYPE which specifies the database type. .TP .BR "\-P, \-\-plain-map " "FILE" Maintain a mapping of all database tokens to their non-hashed counterparts in .IR FILE , one token per line. This can be useful if you want to be able to list the contents of your database at a later date, for instance to get a list of email addresses in your allow-list. Note that using this option may slow .B @PACKAGE@ down, and only entries written to the database while this option is active will be stored in .IR FILE . .TP .B \-s, \-\-subject Rewrite the Subject line of any email that turns out to be spam, adding "[SPAM]" to the start of the line. .TP .BI "\-S, \-\-subject-marker " "SUBJECT" Instead of adding "[SPAM]", add .B SUBJECT to the Subject line of any email that turns out to be spam. Implies .BR \-s . .TP .BI "\-H, \-\-header-marker " "MARK" Instead of setting the X-Spam header to "YES", set it to .B MARK if email turns out to be spam. This can be useful if your email client can only search all headers for a string, rather than one particular header (so searching for "YES" might match more than just the output of .BR @PACKAGE@ ). .TP .B \-n, \-\-no-header Do not add an X-Spam header to messages. .TP .B \-r, \-\-add-rating Insert an additional header X-Spam-Rating which is a rating of the "spamminess" of a message from 0 to 100; 90 and above are counted as spam, anything under 90 is not considered spam. If combined with .BR \-t , then the rating (0-100) will be output, on its own, on standard output. .TP .B \-A, \-\-asterisk Insert an additional header X-Spam-Level which will contain between 0 and 20 asterisks (*), depending on the spam rating. .TP .B \-t, \-\-test Instead of passing the message out on standard output, output nothing, and exit 0 if the message is not spam, or exit 1 if the message is spam. If combined with .BR \-r , then the spam rating will be output on standard output. .TP .B \-a, \-\-allowlist Enable the allow-list. This causes the email addresses given in the message's "From:" and "Return-Path:" headers to be checked against a list; if either one matches, then the message is always treated as non-spam, regardless of what the token database says. When specified with a retraining flag, .B -a -m (mark as spam) will remove that address from the allow-list as well as marking the message as spam, and .B -a -M (mark as non-spam) will add that address to the allow-list as well as marking the message as non-spam. The idea is that you add all of your friends to the allow-list, and then none of their messages ever get marked as spam. .TP .B \-y, \-\-denylist Enable the deny-list. This causes the email addresses given in the message's "From:" and "Return-Path:" headers to be checked against a second list; if either one matches, then theh message is always treated as spam. Training works in the same way as with .BR \-a , except that you must specify .B -m or .B -M twice to modify the deny-list instead of the allow-list, and with the reverse syntax: .B -y -m -m (mark as spam) will add that address to the deny-list, whereas .B -y -M -M (mark as non-spam) will remove that address from the deny-list. This double specification is so that the usual retraining process never touches the deny-list; the deny-list should be carefully maintained rather than automatically generated. Normally you would not need to use the deny-list. .TP .BI "\-L, \-\-level, \-\-threshold " "LEVEL" Change the spam scoring threshold level which must be reached before an email is classified as spam. The default is 90. .TP .BI "\-Q, \-\-min-tokens " "NUM" Only give a score if more than .B NUM tokens are found in the message - otherwise the message is assumed to be non-spam, and it is not modified in any way. The default is 0. This option might be useful if you find that very short messages are being frequently miscategorised. .TP .BI "\-e, \-\-email, \-\-email\-only " "EMAIL" Query or update the allow-list entry for the email address .BR EMAIL . With no other options, this will simply output "YES" if .B EMAIL is in the allow-list, or "NO" if it is not. With .BR \-t , it will not output anything, but will exit 0 (success) if .B EMAIL is in the allow-list, or 1 (failure) if it is not. With the .B \-m (mark-spam) option, any previous allow-list entry for .B EMAIL will be removed. Finally, with the .B \-M (mark-nonspam) option, .B EMAIL will be added to the allow-list if it is not already on it. If .B EMAIL is just the word .B MSG on its own, then an email will be read from standard input, and the email addresses given in the "From:" and "Return-Path:" headers will be used. Using .B \-e automatically switches on .BR \-a . If you also specify .BR \-y , then the deny-list will be operated on. Remember that .B \-m and .B \-M are reversed with the deny-list. If you specify an email address of the form .B @domain (nothing before the @), then the whole .I domain will be allow or deny listed. .TP .B \-v, \-\-verbose Add extra .B X-@UCPACKAGE@-Info headers to any filtered email, containing error messages and so on if applicable. Specify .B \-v more than once to increase verbosity. .TP .BI "\-T, \-\-train " "SPAM NONSPAM [MAXROUNDS]" Train the database using the two mbox folders .B SPAM and .BR NONSPAM , by testing each message in each folder and updating the database each time a message is miscategorised. This is done several times, and may take a while to run. Specify the .B -a (allow-list) flag to add every sender in the .B NONSPAM folder to your allow-list as a side-effect of the training process. If .B MAXROUNDS is specified, training will end after this number of rounds if the results are still not good enough. The default is a maximum of 200 rounds. .TP .B \-m, \-\-mark-spam Instead of passing the message out on standard output, mark its contents as spam and update the database accordingly. If the allow-list .BR "" ( -a ) is enabled, the message's "From:" and "Return-Path:" addresses are removed from the allow-list. If the deny-list .BR "" ( -y ) is enabled and you specify .B -m twice, the message's addresses are added to the deny-list instead. .TP .B \-M, \-\-mark-nonspam Instead of passing the message out on standard output, mark its contents as non-spam and update the database accordingly. If the allow-list .BR "" ( -a ) is enabled, the message's "From:" and "Return-Path:" addresses are added to the allow-list (see the .B -a option above). If the deny-list .BR "" ( -y ) is enabled and you specify .B -M twice, the message's addresses are removed from the deny-list instead. .TP .BI "\-w, \-\-weight " WEIGHT When marking as spam or non-spam, update the database with a weighting of .B WEIGHT per token instead of the default of 1. Useful when correcting mistakes, eg a message that has been mistakenly detected as spam should be marked as non-spam using a weighting of 2, i.e. double the usual weighting, to counteract the error. .TP .BI "\-D, \-\-dump " "[FILE]" Dump the contents of the database as a platform-independent text file, suitable for archival, transfer to another machine, and so on. The data is output on stdout or into the given .BR FILE . .TP .BI "\-R, \-\-restore " "[FILE]" Rebuild the database from scratch from the text file on stdin. If a .B FILE is given, data is read from there instead of from stdin. .TP .B \-O, \-\-tokens Instead of filtering, output a list of the tokens found in the message read from standard input, along with the number of times each token was found. This is only useful if you want to use .B @PACKAGE@ as a general tokeniser for use with another filtering package. .TP .BI "\-E, \-\-merge " "OTHERDB" Merge the .B OTHERDB database into the current database. This can be useful if you want to take one user's mailbox and merge it into the system-wide one, for instance (this would be done by, as root, doing .B @PACKAGE@ -d /var/lib/@PACKAGE@db -E /home/user/.@PACKAGE@db and then removing .BR /home/user/.@PACKAGE@db ). .TP .BI "\-B, \-\-benchmark " "SPAM NONSPAM [MAXROUNDS]" Benchmark the training process using the two mbox folders .B SPAM and .BR NONSPAM . A temporary database is created and trained using the first 75% of the messages in each folder, and then the entire contents of each folder is tested to see how many false positives and false negatives occur. Some timing information is also displayed. This can be used to decide which backend is best on your system. Use .B -d to select a backend, eg .B @PACKAGE@ -B spam nonspam -d GDBM - this will create a temporary database which is removed afterwards. The exception to this is the MySQL backend, where a full database specification must be given .BR "" "(" "-d MySQL:database=db;host=localhost;..." ")" and the database table given will not be wiped beforehand or dropped afterwards. As with .BR -T , if .B MAXROUNDS is specified, training will never be done for more than this number of rounds; the default is 200. .TP .B \-h, \-\-help Print a usage message on standard output and exit successfully. .TP .B \-V, \-\-version Print version information, including a list of available database backends, on standard output and exit successfully. .SH DEPRECATED OPTIONS The following options are only for use with the old binary tree database backend or old databases that haven't been upgraded to the new format that came in with version 1.1.0. .TP .B \-N, \-\-no-autoprune When marking as spam or nonspam, never automatically prune the database. Usually the database is pruned after every 500 marks; if you would rather .B \-\-prune manually, use .B \-N to disable automatic pruning. .TP .B \-p, \-\-prune Remove redundant entries from the database and clean it up a little. This is automatically done after several calls to .B --mark-spam or .BR --mark-nonspam , and during training with .B \-\-train if the training takes a large number of rounds, so it should rarely be necessary to use .B \-\-prune manually unless you are using .BR \-N " / " \-\-no\-autoprune . .TP .BI "\-X, \-\-prune\-max " NUM When the database is being pruned, no more than .B NUM entries will be considered for removal. This is to prevent CPU and memory resources being taken over. The default is 100,000 but in some circumstances (if you find that pruning takes too long) this option may be used to reduce it to a more manageable number. .SH FILES .TP .B /var/lib/@PACKAGE@db The default (system-wide) spam database. If you wish to install .B @PACKAGE@ system-wide, this should be read-only to everyone; there should be one user with write access who can update the spam database with .B @PACKAGE@ --mark-spam and .B @PACKAGE@ --mark-non-spam when necessary. .TP .B /var/lib/@PACKAGE@db2 A second, read-only, system-wide database. This can be useful when installing .B @PACKAGE@ system-wide and using third-party spam databases; the first global database can be updated with system-specific changes, and this second database can be periodically updated when the third-party spam database is updated. .TP .B $HOME/.@PACKAGE@db The default spam database for per-user data. Users without write access to the system-wide database will have their data written here, and the two databases will be read together. The per-user database will be given a weighting equivalent to 10 times the weighting of the global database. .SH NOTES Currently, you cannot use .B @PACKAGE@ to check for spam while the database is being updated. This means that while an update is in progress, all email is passed through as non-spam. There is an upper size limit of 512Kb on incoming email; anything larger than this is just passed through as non-spam, to avoid tying up machine resources. The plaintext token mapping maintained by .B --plain-map will never shrink, only grow. It is intended for use by housekeeping and user interface scripts that, for instance, the user can use to list all email addresses on their allow-list. These scripts should take care of weeding out entries for tokens that are no longer in the database. If you have no such scripts, there is probably no point in using .B --plain-map anyway. Avoid using the deny-list .BR "" ( -y ) in any automated retraining, as it can be cause the filter to reject mail unnecessarily. In general the deny-list is probably best left unused unless explicitly required by your particular setup. If both the allow-list and the deny-list are enabled, then email addresses will first be checked against the deny-list, then the allow-list, then the domain of the email address will be checked for matching "@domain" entries in the deny-list and then in the allow-list. .SH EXAMPLES To filter all of your mail through .BR @PACKAGE@ , with the allow-list enabled and the "spam rating" header being added, add this to your .B .procmailrc file: .RS :0 wf | @PACKAGE@ -ra .RE If you want .B @PACKAGE@ to add "[SPAM]" to the subject line of any messages it thinks are spam, do this instead: .RS :0 wf | @PACKAGE@ -sra .RE To automatically mark any email sent to .B spambox@yourdomain.com as spam (this is the "naive" version): .RS :0 H * ^To:.*spambox@yourdomain.com | @PACKAGE@ -am .RE To do the same, but cleverly, so that only email to .B spambox@yourdomain.com which .B @PACKAGE@ does NOT already classify as spam gets marked as spam in the database (this stops the database getting too heavily weighted): .RS # If sent to spambox@yourdomain.com: :0 * ^To:.*spambox@yourdomain.com { :0 wf | @PACKAGE@ -a # The above two lines can be skipped if you've # already piped the message through @PACKAGE@. # If the @PACKAGE@ database says it's not spam, # mark it as spam! :0 H * ^X-Spam: NO | @PACKAGE@ -am } .RE Remove the .B -a option in the above examples if you don't want to use the allow-list. A more complicated filtering example - this will only run .B @PACKAGE@ on messages which don't have a subject line saying "your is on fire" and which don't have a sender address ending in "@foobar.com", meaning that messages with that subject line OR that sender address will NEVER be marked as spam, no matter what: .RS :0 wf * ! ^Subject: Your .* is on fire * ! ^From: .*@foobar.com | @PACKAGE@ -ra .RE For more on .BR procmail (1) recipes, see the .BR procmailrc (5) and .BR procmailex (5) manual pages. A couple of macros to add to your .B .muttrc file, if you use .BR mutt (1) as a mail user agent: .RS # Press F5 to mark a message as spam and delete it macro index "@PACKAGE@ -am\\n" macro pager "@PACKAGE@ -am\\n" # Press F9 to mark a message as non-spam macro index "@PACKAGE@ -aM\\n" macro pager "@PACKAGE@ -aM\\n" .RE Again, remove the .B -a option in the above examples if you don't want to use the allow-list. Note, however, that the above macros won't work when operating on multiple tagged messages. For that, you'd need something like this: .RS macro index ":set pipe_split\\n@PACKAGE@ -am\\n\\n:unset pipe_split\\n" .RE If you use .BR qmail (7), then to get .B procmail working with it you will need to put a line containing just .B DEFAULT=./Maildir/ at the top of your .B ~/.procmailrc file, so that .B procmail delivers to your Maildir folder instead of trying to deliver to /var/spool/mail/$USER, and you will need to put this in your .B ~/.qmail file: .RS | preline procmail .RE This will cause all your mail to be delivered via .B procmail instead of being delivered directly into your mail directory. See the .BR qmail (7) documentation for more about mail delivery with qmail. If you use .BR postfix (1), you can set up a system-wide mail filter by creating a user account for the purpose of filtering mail, populating that account's .BR .@PACKAGE@db , and then creating a shell script, to run as that user, which runs .B @PACKAGE@ on stdin and passes stdout to .BR sendmail (8). Doing this requires some knowledge of .B postfix configuration and care needs to be taken to avoid mail loops. One .B @PACKAGE@ user's full HOWTO is included in the .B doc/ directory with this package. .SH "THE ALLOW-LIST" A feature called the "allow-list" can be switched on by specifying the .BR \-\-allowlist " or " \-a option. This causes messages' "From:" and "Return-Path:" addresses to be checked against a list of people you have said to allow all messages from, and if a message's "From:" or "Return-Path:" address is in the list, it is never marked as spam. This means you can add all your friends to an "allow-list" and .B @PACKAGE@ will then never mis-file their messages - a quick way to do this is to use .B -a with .B -T (train); everyone in your non-spam folder who has sent you an email will be added to the allow-list automatically during training. You can manually add and remove addresses to and from the allow-list using the .B \-e (email) option. For instance, to add .B foo@bar.com to the allow-list, do this: .RS @PACKAGE@ -e foo@bar.com -M .RE To remove .B bad@nasty.com from the allow-list, do this: .RS @PACKAGE@ -e bad@nasty.com -m .RE And to see whether .B someone@somewhere.com is in the allow-list or not, just do this: .RS @PACKAGE@ -e someone@somewhere.com .RE In general, you probably always want to enable the allow-list, so always specify the .B -a option when using .BR @PACKAGE@ . This will automatically maintain the allow-list based on what you classify as spam or non-spam. The only times you might want to turn it off are when people on your allow-list are prone to getting viruses or if a virus is causing email to be sent to you that is pretending to be from someone on your allow-list. .SH "BACKUP AND RESTORE" Because the database format is platform-specific, it is a good idea to periodically dump the database to a text file using .B @PACKAGE@ -D so that, if necessary, it can be transferred to another machine and restored with .B @PACKAGE@ -R later on. Also note that since the actual contents of email messages are never stored in the database (see .BR "TECHNICAL DETAILS" ), you can safely share your .B @PACKAGE@ database with friends - simply dump your database to a file, like this: .RS @PACKAGE@ -D > your-database-dump.txt .RE Once you have sent .B your-database-dump.txt to another person, they can do this: .RS @PACKAGE@ -R < your-database-dump.txt .RE They will then have an identical database to yours. .SH "TECHNICAL DETAILS" When a message is passed to .BR @PACKAGE@ , any attachments are decoded, all HTML elements are removed, and the message text is then broken up into "tokens", where a "token" is a single word or URL. Each token is hashed using the MD5 algorithm (see below for why), and that hash is then used to look up each token in the .B @PACKAGE@ database. For full details of which parts of an email (headers, body, attachments, etc) are used to calculate the spam rating, see the .B TOKENISATION section below. Within the database, each token has two numbers associated with it: the number of times that token has been seen in spam, and the number of times it has been seen in non-spam. These two numbers, along with the total number of spam and non-spam messages seen, are then used to give a "spamminess" value for that particular token. This "spamminess" value ranges from "definitely not spammy" at one end of the scale, through "neutral" in the middle, up to "definitely spammy" at the other end. Once a "spamminess" value has been calculated for all of the tokens in the message, a summary calculation is made to give an overall "is this spam?" probability rating for the message. If the overall probability is 0.9 or above, the message is flagged as spam. In addition to the probability test is the "allow-list". If enabled (with the .B -a option), the whole probability check is skipped if the sender of the message is listed in the allow-list, and the message is not marked as spam. When training the database, a message is split up into tokens as described above, and then the numbers in the database for each token are simply added to: if you tell .B @PACKAGE@ that a message is spam, it adds one to the "number of times seen in spam" counter for each token, and if you tell it a message is not spam, it adds one to the "number of times seen in non-spam" counter for each token. If you specify a weight, with .BR -w , then the number you specify is added instead of one. To stop the database growing uncontrollably, the database keeps track of when a token was last used. Underused tokens are automatically removed from the database. (The old method was to "prune" every 500 updates). Finally, the reason MD5 hashes were used is privacy. If the actual tokens from the messages, and the actual email addresses in the allow-list, were stored, you could not share a single .B @PACKAGE@ database between multiple users because bits of everyone's messages would be in the database - things like emailed passwords, keywords relating to personal gossip, and so on. So a hash is stored instead. A hash is a "one-way" function; it is easy to turn a token into a hash but very hard (some might say impossible) to turn a hash back into the token that created it. This means that you end up with a database with no personal information in it. .SH "TOKENISATION" When a message is broken up into tokens, various parts of the message are treated in different ways. First, all header fields are discarded, except for the important ones: .BR From , .BR Return-Path , .BR Sender , .BR To , .BR Reply-To , and .BR Subject . Next, any MIME-encoded attachments are decoded. Any attachments whose MIME type starts with "text/" (i.e. HTML and text) are tokenised, after having any HTML tags stripped. Any non-textual attachments are replaced with their MD5 hash (such that two identical attachments will have the same hash), and that hash is then used as a token. In addition to single-word tokens from textual message parts, .B @PACKAGE@ adds doubled-up tokens so that word pairs get added to the database. This makes the database a bit bigger (although the automatic pruning tends to take care of that) but makes matching more exact. .SH "SPECIAL FILTERS" As well as using the textual content of email to detect spam, .B @PACKAGE@ also uses special filters which create "pseudo-tokens" based on various rules. This means that specific patterns, not just individual words, can be used to determine whether a message is spam or not. For example, if a message contains lots of words with multiple consonants, like "ashjkbnxcsdjh", then each time a word like that is seen the special token ".GIBBERISH-CONSONANTS." is added to the list of tokens found in the message. If it turns out that most messages with words that trigger this filter rule are spam, then other messages with gibberish consonant strings will be more likely to be flagged as spam. Currently the special filters are: .TP .B GTUBE Flags any message containing the string .B XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X as spam - useful for testing that your .B @PACKAGE@ installation is working. .TP .B ATTACH-SCR .TP .B ATTACH-PIF .TP .B ATTACH-EXE .TP .B ATTACH-VBS .TP .B ATTACH-VBA .TP .B ATTACH-LNK .TP .B ATTACH-COM .TP .B ATTACH-BAT Adds a token for every attachment whose filename ends in ".scr", ".pif", ".exe", ".vbs", ".vba", ".lnk", ".com", and ".bat" respectively (these are often viruses). .TP .B ATTACH-GIF .TP .B ATTACH-JPG .TP .B ATTACH-PNG Adds a token for every attachment whose filename ends in ".gif", ".jpg" or ".jpeg", and ".png" respectively. .TP .B ATTACH-DOC .TP .B ATTACH-XLS .TP .B ATTACH-PDF Adds a token for every attachment whose filename ends in ".doc", ".xls", or ".pdf" respectively (these tend to indicate a non-spam email). .TP .B SINGLE-IMAGE Adds a token if the message contains exactly one attached image. .TP .B MULTIPLE-IMAGES Adds a token if the message contains more than one attached image. .TP .B GIBBERISH-CONSONANTS Adds a token for every word found that has multiple consonants in a row, as described above. Spam often contains strings of gibberish. .TP .B GIBBERISH-VOWELS Adds a token for every word found that has multiple vowels in a row, eg "aeaiaiaeeio". .TP .B GIBBERISH-FROMCONS Like .BR GIBBERISH-CONSONANTS , but only for the "From:" and "Return-Path:" addresses on their own. .TP .B GIBBERISH-FROMVOWL Like .BR GIBBERISH-VOWELS , but only for the "From:" and "Return-Path:" addresses on their own. .TP .B GIBBERISH-BADSTART Adds a token for every word that starts with a bad character such as %. .TP .B GIBBERISH-HYPHENS Adds a token for every word with more than three hyphens or underscores in it. .TP .B GIBBERISH-LONGWORDS Adds a token for every word with over 30 characters in it (but less than 60). .TP .B HTML-COMMENTS-IN-WORDS Adds a token for every HTML comment found in the middle of a word. Spam often contains HTML inside words, like this: word .TP .B HTML-EXTERNAL-IMG Adds a token for every HTML (image) tag found that contains :// (i.e. it refers to an external image). .TP .B HTML-FONT Adds a token for every HTML tag found. .TP .B HTML-IP-IN-URLS Adds a token for every URL found containing an IP address. .TP .B HTML-INT-IN-URL Adds a token for every URL found containing an integer in its hostname. .TP .B HTML-URLENCODED-URL Adds a token for every URL found containing a % sign in its hostname. .P Normally, filters will just cause a token to be added, and these tokens are processed by the normal weighting algorithm. However the .B GTUBE filter will immediately flag any matching message as spam, bypassing the token matching. .SH DATABASE BACKENDS The inbuilt "list" database backend will not necessarily provide the best performance, but is provided because using it requires no external libraries. If, when .B @PACKAGE@ was compiled, the correct libraries were available, then it will be possible to use .B @PACKAGE@ with alternative database backends. To find out which backends you have available, run .B @PACKAGE@ -V (capital V) and read the second line of output. To see how well a backend performs, collect some spam and non-spam and use .B @PACKAGE@ -d BACKEND -B SPAM NONSPAM (see the entry for .B -B above). Some people find that they get the best performance out of the .B gdbm backend; this is a library that is widely available on many systems. To efficiently share a .B @PACKAGE@ database across multiple machines, you may find the MySQL backend useful. However, using it is a little more complicated. To use the MySQL backend you will need to create a table with the fields .IR key1 ", " key2 ", " token ", " value1 ", " value2 " and " value3 . The .IR token ", " value1 ", " value2 ", and " value3 fields must be .BR VARCHAR(64) ", " BIGINT " or " INT ", and " BIGINT " or " INT respectively, and indexing on the .I token field is a good idea. The .IR key1 " and " key2 fields can be anything, but they must be present. For example: .RS USE mydatabase; CREATE TABLE @PACKAGE@db ( key1 BIGINT UNSIGNED NOT NULL, key2 BIGINT UNSIGNED NOT NULL, token VARCHAR(64) DEFAULT '' NOT NULL, value1 INT UNSIGNED NOT NULL, value2 INT UNSIGNED NOT NULL, value3 INT UNSIGNED NOT NULL, PRIMARY KEY (key1,key2,token), KEY (key1), KEY (key2), KEY (token) ); .RE The .IR key1 " and " key2 fields allow you to have multiple .B @PACKAGE@ databases in one table, by specifying different .IR key1 " and " key2 values on invocation. Instead of specifying a database file with the .BR --database " / " -d option, you must specify either a specification string as described below, or the name of a file containing such a string on its first line. The specification string is as follows: .RS database=DATABASE;host=HOST;port=PORT; user=USER;pass=PASS;table=TABLE; key1=KEY1;key2=KEY2 .RE This string must be all on one line, with no spaces. .TP .B DATABASE is the name of the MySQL database. .TP .B HOST is the hostname of the database server (eg "localhost"). .TP .B PORT is the TCP port to connect on (eg 3306). .TP .B USER is the username to connect with. .TP .B PASS is the password to connect with. .TP .B TABLE is the database table to use. If a table with this name does not exist when .B @PACKAGE@ is called in update or training mode, then it will be created if permissions allow this to be done. .TP .B KEY1 is the value to use for the .I key1 field. .TP .B KEY2 is the value to use for the .I key2 field. .P Since command lines can be seen in the process list, it is probably best to specify a filename (eg .BR "@PACKAGE@ -d mysql:@PACKAGE@db.spec" ) and put the specification string inside that file. .SH TROUBLESHOOTING If you have problems with .BR @PACKAGE@ , please check the list below; if this does not help, go to the .B @PACKAGE@ home page and investigate the mailing lists, or email the author. .TP .B Nothing is being marked as spam. .br First, use the .B -r option to switch on the .B X-Spam-Rating header, and check that this header appears in email passed through .BR @PACKAGE@ . If it does not, then it is likely that .B @PACKAGE@ is not being run at all - check your configuration of .BR procmail (1) or its equivalent. .TP .B " " .br If you are seeing .B X-Spam-Rating headers, and different emails have different scores, then you may simply need to retrain your database a little more. Take more spam email and pass it to .BR "@PACKAGE@ -m" . .TP .B " " .br If you are seeing .B X-Spam-Rating headers but they all give the same spam rating, then the most likely reason is that .B @PACKAGE@ is not reading any database. Make sure that whatever is processing the email has read permissions on .B /var/lib/@PACKAGE@db and/or .B ~/.@PACKAGE@db - and make sure that, if you are using .BR ~/.@PACKAGE@db , what your database creator thought was .BR ~ " (" $HOME ")" is the same as it is for whatever is processing the email. .TP .B Retraining sometimes takes a very long time. With the .B obtree backend or 2-column MySQL or SQLite tables, every 500th retrain .BR "" "(" -m " or " -M ")," the database is pruned. On some systems this may take some time, and during this time the database is locked (except when using the MySQL or SQLite backends). If you constantly do a lot of retraining and want to avoid this, then use the .B -N option to suppress auto-pruning, and then have a .BR cron (8) job or something run a manual prune .BR "" "(" "@PACKAGE@ -p" ")" every now and again. .TP .B Running @PACKAGE@ from procmail fails with an error. If you can run .B @PACKAGE@ from the command line, but in your .B procmail log file you get errors about "@PACKAGE@: cannot execute binary file", then contact your system administrator for help. It may be that incoming email is handled by a different server to the one you normally shell into, and either they are of a different architecture or operating system, or the mail server is not permitted to execute user-owned binaries. .SH ACKNOWLEDGEMENTS The following people have contributed suggestions, comments, patches, and testing: .RS Tom Parker .IR "" < http://www.bits.bris.ac.uk/palfrey/ > .br Dr Kelly A. Parker .br Vesselin Mladenov .IR "" < http://www.antipodes.bg/ > .br Glyn Faulkner .br Mark Reynolds .br Sam Roberts .br Scott Allen .br Karsten Kankowski .br M. Kolbl .br Micha Holzmann .br Jef Poskanzer .IR "" < http://www.acme.com/jef/ > .br Clemens Fischer .IR "" < http://ino-waiting.gmxhome.de/ > .br Nelson A. de Oliveira .br Michal Vitecek .br Tommy Pettersson .IR "" < http://www.lysator.liu.se/~ptp/ > .RE .SH AUTHOR The author: .RS Andrew Wood .br .I http://www.ivarch.com/ .RE Project home page: .RS .I http://www.ivarch.com/programs/@PACKAGE@/ .RE .SH BUGS If you find any bugs, please contact the author, either by email or by using the contact form on the web site. .SH "SEE ALSO" .BR procmail (1), .BR procmailrc (5), .BR procmailex (5) Someone has written a guide to using .B @PACKAGE@ with KMail that can be found at: .br http://www.softwaredesign.co.uk/Information.SpamFilters.html .SH LICENSE This is free software, distributed under the ARTISTIC 2.0 license. qsf-1.2.7/doc/changelog0000644000076400007640000006522310665021415012551 0ustar awaw2007-08-28 14:02 naoliv * debian/: changelog, copyright, doc-base, patches/index.html.diff: Updated debian/ dir for new QSF release 2007-08-28 11:17 ivarch * README, doc/COPYING, doc/NEWS, doc/VERSION, doc/lsm.in, doc/quickref.1.in, doc/spec.in, src/main/help.c, src/main/license.c, src/main/options.c, src/main/version.c: Removal of "-l" and change of license to Artistic 2.0 2007-02-05 11:21 naoliv * debian/changelog: New upstream release 2007-02-04 23:50 ivarch * doc/NEWS, doc/TODO, doc/VERSION, doc/lsm.in, doc/quickref.1.in, doc/spec.in, src/db/mysql.c, test/t02-markspam, test/t03-marknonspam, test/t20-locking: Removed locking from MySQL again because it causes major delays due to whole-table locking, and prepared for release of 1.2.6. 2007-01-22 00:16 naoliv * debian/control: Forgot this file 2007-01-22 00:15 naoliv * debian/changelog: Now quickref.txt is included on the package 2007-01-21 22:20 naoliv * debian/changelog: Uploaded with medium urgency, since it's a bug fix release and also it will be good to have this fixed release on Etch 2007-01-21 17:16 naoliv * debian/changelog: New QSF release 2007-01-21 16:48 ivarch * README, autoconf/header.in, autoconf/scripts/fakemail.c, autoconf/scripts/mboxsplit.c, debian/copyright, doc/TODO, extra/mailstats.sh, extra/statstable.sh, src/library.c, src/db/btree.c, src/db/gdbm.c, src/db/list.c, src/db/main.c, src/db/mysql.c, src/db/obtree.c, src/db/sqlite.c, src/include/database.h, src/include/log.h, src/include/mailbox.h, src/include/message.h, src/include/options.h, src/include/spam.h, src/mailbox/alloc.c, src/mailbox/count.c, src/mailbox/mailboxi.h, src/mailbox/scan.c, src/mailbox/select.c, src/main/help.c, src/main/license.c, src/main/log.c, src/main/main.c, src/main/options.c, src/main/tick.c, src/main/version.c, src/message/alloc.c, src/message/base64.c, src/message/dump.c, src/message/header.c, src/message/parse.c, src/message/qp.c, src/message/read.c, src/message/rfc2047.c, src/spam/alloc.c, src/spam/allowlist.c, src/spam/benchmark.c, src/spam/check.c, src/spam/cksum.c, src/spam/db.c, src/spam/dump.c, src/spam/merge.c, src/spam/plaintext.c, src/spam/prune.c, src/spam/spami.h, src/spam/token.c, src/spam/train.c, src/spam/update.c, src/tests/attached_files.c, src/tests/gibberish.c, src/tests/gtube.c, src/tests/html.c, src/tests/imgcount.c, src/tests/main.c, src/tests/testi.h, src/tests/urls.c: Copyright date and TODO updates 2007-01-21 13:25 ivarch * autoconf/make/unreal.mk, doc/NEWS, doc/VERSION, doc/lsm.in, doc/quickref.1.in, doc/spec.in: Cleanup for release 1.2.5 2007-01-20 12:35 ivarch * src/db/list.c, src/db/mysql.c, test/t02-markspam, test/t03-marknonspam, test/t20-locking: Fixed token deletion bug in list backend which would cause extra tokens - including COUNTS and SINCEPRUNE - to be deleted when other tokens are deleted. 2007-01-20 11:08 ivarch * src/spam/token.c: Correction to comment about the COUNT token 2007-01-20 00:36 ivarch * src/db/mysql.c: Fix for autodetection of MySQL spec files - previously "-d database=...." worked, but "-d FILE" where FILE contained the spec, did not. 2007-01-20 00:32 ivarch * doc/spec.in: rpmlint fixes 2006-12-07 02:25 naoliv * debian/: changelog, control: Updated to my debian address 2006-10-25 16:22 naoliv * debian/changelog: New release. 2006-10-25 12:24 ivarch * src/: db/btree.c, db/list.c, db/mysql.c, message/dump.c, spam/plaintext.c: Fixes for warnings with GCC 4.1.1, Fedora Core 5 2006-10-25 12:23 ivarch * doc/: NEWS, VERSION, lsm.in, spec.in: Version bump 2006-10-21 23:48 ivarch * autoconf/: make/unreal.mk, scripts/benchmark.awk: Added new "bigbenchmark" Makefile rule, to generate benchmark data for graphs. 2006-10-21 20:38 ivarch * src/db/btree.c: Fix for concurrent access under OpenBSD. 2006-10-21 20:07 ivarch * autoconf/configure.in, autoconf/header.in, autoconf/make/unreal.mk, doc/NEWS, src/db/btree.c, src/db/gdbm.c, src/db/list.c, src/db/main.c, src/db/mysql.c, src/db/obtree.c, src/db/sqlite.c, src/include/database.h, test/t20-locking: Added a test, and fixes for, concurrent updates. Also added mysql_commit() usage for MySQL client versions that support it. 2006-10-03 22:41 ivarch * autoconf/make/unreal.mk, src/db/mysql.c, test/t01-dbcreate: Updates to allow MySQL database to be specified with a blank password, and to automatically enable MySQL tests if there is a localhost "test" database with no password in which a temporary test table can be created. 2006-10-03 20:17 ivarch * src/: db/list.c, spam/db.c: Added some casting and minor type changes to avoid warnings with gcc 4.x. 2006-10-02 09:38 ivarch * doc/: NEWS, lsm.in, quickref.1.in, spec.in: Pre-release cleanups. 2006-10-02 00:32 naoliv * debian/changelog: Fixing the version that I typed wrongly. 2006-10-02 00:31 naoliv * debian/: changelog, control: New QSF release 2006-10-01 23:28 ivarch * src/db/list.c: Optimisation to buffer up additions and sort them individually instead of re-sorting the whole array every time. 2006-09-30 22:41 ivarch * src/: db/gdbm.c, db/list.c, db/main.c, db/mysql.c, db/obtree.c, db/sqlite.c, include/database.h, spam/dump.c: Code cleanup and new database hook - restore_start and restore_end - to speed up -R. 2006-09-30 17:55 ivarch * doc/: NEWS, lsm.in, spec.in: Pre-release cleanups. 2006-09-30 17:26 ivarch * doc/NEWS, doc/TODO, doc/quickref.1.in, src/spam/allowlist.c, src/spam/check.c, test/t19-listdomain: Allow domain-level allow/deny listing with "@domain". 2006-09-29 15:10 ivarch * doc/NEWS, doc/TODO, doc/quickref.1.in, src/include/options.h, src/include/spam.h, src/main/help.c, src/main/main.c, src/main/options.c, src/spam/allowlist.c, src/spam/check.c, src/spam/db.c, src/spam/dump.c, src/spam/plaintext.c, src/spam/spami.h, test/t17-denylistadd, test/t18-denylistdel: New option "-y" to use a deny-list, listing email addresses that cause messages to be rejected as spam unconditionally. 2006-09-29 11:18 ivarch * autoconf/make/unreal.mk, autoconf/make/vars.mk, doc/NEWS, doc/TODO, doc/quickref.1.in, src/include/options.h, src/include/spam.h, src/main/help.c, src/main/options.c, src/spam/allowlist.c, src/spam/db.c, src/spam/plaintext.c, test/t16-plainmap: New option "-P" to store mappings between hashed and non-hashed values in a plaintext file. 2006-08-28 17:48 naoliv * debian/control: Made the long description shorter, while trying to maintain all the features of QSF 2006-08-15 20:54 ivarch * test/t15-headermarker: Fix for test 15 for systems (Solaris) whose grep does not support -q 2006-08-15 20:25 ivarch * doc/NEWS, doc/quickref.1.in, src/include/message.h, src/include/options.h, src/main/help.c, src/main/main.c, src/main/options.c, src/message/header.c, test/t15-headermarker: New "-H" / "--header-marker" option to change X-Spam: YES to X-Spam: WHATEVER (based on patch from Michal Vitecek) 2006-08-15 17:02 ivarch * build-and-test-sf.sh, autoconf/make/unreal.mk, src/spam/benchmark.c: More "make benchmark" fixes for Solaris 2006-08-15 14:21 ivarch * autoconf/make/unreal.mk: Fix for compilation of fakemail for "make benchmark" 2006-08-15 11:17 ivarch * autoconf/configure.in, autoconf/header.in, doc/NEWS, doc/VERSION, doc/quickref.1.in, src/db/list.c, src/db/main.c: Re-added new "list" backend. 2006-08-15 00:53 naoliv * debian/changelog: Updated debian/ dir for the new QSF release 2006-08-14 14:25 ivarch * doc/: NEWS, lsm.in, spec.in: Pre-release cleanup. 2006-08-14 12:09 ivarch * autoconf/configure.in, autoconf/header.in, doc/NEWS, doc/VERSION, doc/quickref.1.in, src/db/list.c, src/db/main.c: Removed "list" backend so that the next release can be bugfixes only - will add it later to make a new release. 2006-08-14 11:53 ivarch * README, doc/quickref.1.in: Acknowledgements update 2006-08-14 11:40 ivarch * src/db/: btree.c, list.c, obtree.c: Revert a couple of changes which would have no effect due to limited data ranges 2006-08-14 10:31 ivarch * src/: db/btree.c, db/list.c, db/main.c, db/mysql.c, db/obtree.c, mailbox/select.c, main/main.c: Fixes for potential problems highlighted by Tommy Pettersson 2006-08-10 20:29 ivarch * autoconf/configure.in, autoconf/header.in, src/md5.c, src/include/md5.h: Portability fix for MD5 on 64-bit systems, eg AMD64 2006-08-10 00:37 ivarch * src/: db/mysql.c, db/sqlite.c, main/log.c, main/main.c, message/header.c: Use #ifdef instead of #if for HAVE_* for consistency 2006-08-10 00:33 ivarch * autoconf/make/unreal.mk, autoconf/scripts/fakemail.c, doc/NEWS, src/db/btree.c, src/db/list.c, src/main/help.c, src/main/log.c, src/main/main.c, src/message/header.c, src/message/parse.c, src/spam/cksum.c: Code cleanup to placate the pickier compiler on OpenBSD - use snprintf more, strcat and strcpy less 2006-08-09 23:02 ivarch * autoconf/: configure.in, make/vars.mk: Get configure script to check for LD so that we can compile on the SourceForge compile farm x86-solaris1 host 2006-08-08 21:43 ivarch * autoconf/make/unreal.mk, autoconf/scripts/index.sh, autoconf/scripts/makemake.sh, test/t08-dbprune2: Replace "echo -n" with more portable code 2006-08-08 19:33 ivarch * src/db/btree.c: Patch from Michal Vitecek to fix segfault in btree backend 2006-05-14 19:26 ivarch * autoconf/configure.in, autoconf/header.in, doc/NEWS, doc/VERSION, doc/quickref.1.in, src/db/list.c, src/db/main.c: Added new "list" backend - an in-memory flat list, which is the new default backend. 2006-05-07 17:30 naoliv * debian/: changelog, control, copyright: Some small updates 2006-05-03 04:33 naoliv * debian/: changelog, control: Updated Debian standards version. 2006-05-03 02:33 naoliv * autoconf/make/unreal.mk: Forgot $(package)-$(version) :-( 2006-05-03 02:32 naoliv * autoconf/make/unreal.mk: There is no need to include .cvsignore files when distributing the final tarball 2006-04-08 19:03 naoliv * debian/changelog: New version released. 2006-04-08 17:11 ivarch * doc/NEWS, doc/VERSION, doc/lsm.in, doc/quickref.1.in, doc/spec.in, src/include/message.h, src/include/options.h, src/main/main.c, src/message/alloc.c, src/message/parse.c, src/spam/allowlist.c, src/spam/check.c, src/spam/train.c, src/spam/update.c, src/tests/gibberish.c: Check Return-Path: header against allow-list as well as From: header 2006-03-29 00:50 naoliv * debian/control: Just adding a space before Homepage:, as Debian Policy says. 2006-02-03 17:01 naoliv * debian/docs: docs/changelog is included again. My fault in not asking Andrew. 2006-02-02 18:28 naoliv * debian/: changelog, docs: New QSF version. Also, it seems that changelog isn't being shipped, so remove it from being installed. If it appears again, we just need to add one line on debian/docs. 2006-02-01 20:41 ivarch * doc/: NEWS, lsm.in, quickref.1.in, spec.in: Documentation update prior to release 2005-12-18 00:52 naoliv * debian/: changelog, compat, control, lintian-override, rules: Some minor fixes, including transition of libmysql 2005-11-19 03:44 naoliv * debian/watch: Updated watch file, to get latest version 2005-08-22 04:00 naoliv * debian/changelog: New upstream version. 2005-08-21 00:32 ivarch * doc/: NEWS, lsm.in, spec.in: Docs update prior to release 2005-08-20 23:12 ivarch * autoconf/configure.in: Second attempt at --include fallback. 2005-08-20 23:07 ivarch * autoconf/configure.in: Work around mysql_config --include not being available in MySQL 3.23.58 by falling back to --cflags. 2005-08-20 23:03 ivarch * autoconf/configure.in, doc/NEWS, doc/TODO, doc/VERSION, src/db/mysql.c: Improve MySQL detection by using as the include file instead of , since we are using the output of mysql_config --cflags. 2005-08-20 21:31 ivarch * test/t08-dbprune2: Rephrased test comparison for better portability - Solaris did not like "! test = " so used "test !=". 2005-08-20 21:09 ivarch * doc/NEWS, doc/TODO, doc/VERSION, src/message/parse.c, test/t13-attach, test/t14-rfc822: Fixed handling of nested attachments in message/rfc822 content-types, which had been preventing any tokens from being seen at all. 2005-08-14 10:44 ivarch * src/db/main.c: Workaround for weird error on OpenBSD: take copies of key and val data before passing them on to the backend. 2005-08-14 01:10 ivarch * src/main/main.c: Cast field width to int to silence compiler warning and for clarity. 2005-08-05 23:20 ivarch * doc/NEWS, doc/VERSION, src/tests/urls.c: Fix for bug where if a URL (http://foo) was the first thing in the message body, it would not be picked up as a token in its own right by the URL tokeniser. 2005-07-15 08:18 naoliv * debian/control: We don't need to suggest mysql-server and sqlite. The user will need just one database. So, changing to mysql-server OR sqlite. 2005-07-10 22:07 ivarch * src/: db/btree.c, db/obtree.c, spam/allowlist.c, spam/check.c: Further warnings fixes 2005-07-10 11:16 ivarch * doc/NEWS, doc/VERSION, src/db/btree.c, src/db/gdbm.c, src/db/mysql.c, src/db/obtree.c, src/db/sqlite.c, src/spam/allowlist.c, src/spam/cksum.c, src/spam/db.c, src/spam/merge.c, src/spam/prune.c: Put casts into various places to avoid triggering spurious pointer signedness warnings with GCC 4.x 2005-07-08 05:41 naoliv * debian/: changelog, control: Fixing the section of QSF - mail instead of net 2005-07-08 05:40 naoliv * debian/docs: Including upstream changelog on the Debian package 2005-07-06 17:50 naoliv * debian/changelog: New upstream release 2005-07-06 06:26 naoliv * debian/changelog: Syncing with Debian's changelog 2005-07-06 06:18 naoliv * debian/control: Updated Standards-version and added Uploaders field 2005-07-06 06:16 naoliv * debian/control: Corrected span -> spam 2005-06-15 21:03 ivarch * autoconf/configure.in, autoconf/header.in, src/db/btree.c: We now run utime() on the database, if available, if it has been modified because mmap()ed files do not always get their mtime updated. 2005-06-15 20:30 ivarch * src/main/main.c: Comments fixed to match what is actually happening. 2005-06-05 10:51 naoliv * debian/dirs: Not needed. CDBS takes care of it automatically. 2005-06-05 10:45 naoliv * debian/changelog: Preparing to next upstream release. 2005-06-05 10:43 naoliv * debian/rules: Don't update debian/control automatically anymore. 2005-06-05 10:42 naoliv * debian/control: Including some more recommends and suggests. Also, version of patchutils. 2005-06-05 10:35 naoliv * debian/control.in: This file should not exist anymore. That is because Debian policy (control files should not be regenarated on package building) 2005-05-16 21:48 ivarch * doc/NEWS, src/spam/allowlist.c, test/t10-allowlistadd, test/t11-allowlistdel: Allow-list matching is now case insensitive; this addition sponsored by SpamDefy, http://www.spamdefy.com/ 2005-05-14 06:58 naoliv * debian/: control, control.in: Small update on suggests 2005-05-12 23:54 ivarch * test/: t04-training, t12-benchmark: Cut training/benchmark tests short to 10 rounds, to speed up "make test" and "make memtest". 2005-05-12 22:41 ivarch * doc/: NEWS, lsm.in, spec.in: Commit ready for release of 1.1.0, just waiting for final Debian packaging updates. 2005-05-12 22:12 ivarch * autoconf/make/unreal.mk: Make changelog copy in "make dist" optional, i.e. softfail 2005-05-12 22:09 naoliv * debian/patches/index.html.diff: Patch necessary for index.html 2005-05-12 22:06 naoliv * debian/doc-base: Documentation base for Debian 2005-05-12 22:05 naoliv * debian/: compat, control.in, install, watch: New files needed by the Debian Package 2005-05-12 21:59 naoliv * debian/: changelog, control, copyright, docs, rules: Updated Debian package 2005-05-12 09:32 ivarch * autoconf/make/unreal.mk: Only run "make changelog" during "make dist" if the source directory contains CVS entries. 2005-05-12 09:21 ivarch * generate.sh, autoconf/Makefile.in, autoconf/configure.in, autoconf/make/.cvsignore, autoconf/make/unreal.mk, autoconf/scripts/makemake.sh: Changed build process to use .mk instead of .mk~ extension for autogenerated Makefile components, and added .cvsignore to keep the autogenerated files out of CVS. This allows the Debian build process to work, as it was removing those files. 2005-05-10 23:52 ivarch * src/db/btree.c: Updated mmap code to call lseek() as little as possible. 2005-05-10 23:40 ivarch * src/spam/: check.c, dump.c, spami.h, token.c, update.c: Fixed bug in --mark-{non,}spam caused by the new database weighting code. 2005-05-10 23:39 ivarch * src/db/btree.c: RATS check 2005-05-10 23:36 ivarch * autoconf/configure.in, autoconf/header.in, doc/NEWS, src/db/btree.c: Added mmap() support to btree backend, resulting in much faster operation. Needs testing on other systems, though. Falls back to normal read()/write() when mmap cannot be used. 2005-05-10 22:28 ivarch * src/db/btree.c: Added optimisation function for the btree backend. 2005-05-10 21:01 ivarch * doc/quickref.1.in, src/main/options.c, src/spam/prune.c, src/spam/train.c: Tweaked the pruning algorithm so it chooses the tokens to be discarded more sensibly (and fixed the new pruning algorithm to obey the "max tokens to prune" setting), and added a MAXROUNDS parameter to -B and -T. 2005-05-09 09:39 ivarch * doc/quickref.1.in, src/main/main.c: Changed per-user database weighting to 10x instead of 100x, as 100x seems to be causing problems. 2005-05-08 22:42 ivarch * src/message/parse.c: RATS lint 2005-05-08 19:30 ivarch * doc/: NEWS, VERSION, lsm.in, spec.in: Version bump ready for 1.1.0 2005-05-08 19:13 ivarch * doc/NEWS, doc/TODO, doc/quickref.1.in, src/include/options.h, src/main/main.c, src/main/options.c, src/spam/allowlist.c, src/spam/db.c, src/spam/merge.c, src/spam/spami.h, src/spam/token.c: Added weighting to databases, set to 100 for per-user / -d databases, 1 for global, 2 for first global if two globals are defined. 2005-05-08 14:48 ivarch * doc/NEWS, doc/TODO, doc/quickref.1.in, src/tests/html.c, src/tests/main.c: Added new test for FONT tags in HTML; originally was going to look for tiny text (FONT SIZE=1) but that gives worse performance in the benchmarking than just looking for FONT. 2005-05-06 15:00 ivarch * doc/NEWS, doc/TODO, doc/quickref.1.in, src/tests/html.c, src/tests/main.c: Replaced the IMG test with the EXTERNAL-IMG test, since this gives better benchmark results - presumably tags in normal HTML mail are quite common, but tags referring to external (non-embedded) images are more likely to appear in spam. For some reason leaving both IMG and EXTERNAL-IMG in drops the benchmark performance. 2005-05-06 14:07 ivarch * doc/NEWS, src/tests/html.c: Made test for IMG tags case-insensitive. 2005-05-06 13:31 ivarch * doc/NEWS, doc/TODO, doc/quickref.1.in, src/tests/gibberish.c, src/tests/main.c: Added GIBBERISH-LONGWORDS filter - add tokens for any words 30-60 characters in length that start with a letter. 2005-05-06 12:45 ivarch * doc/TODO: Removed "optimise attachment scanning" TODO since profiler says it takes up 0.06% of run-time; not a priority. 2005-05-06 11:29 ivarch * src/: include/message.h, message/alloc.c, message/parse.c, tests/gibberish.c: Optimised the gibberish checks by building up a list of word positions when the message is parsed, instead of repeatedly scanning through for each gibberish check. 2005-05-04 14:43 ivarch * README: Added note about MySQL 4.1.x performance improvement 2005-05-04 14:42 ivarch * doc/quickref.1.in: Reworded pruning note to take account of new pruning rules 2005-05-03 00:05 ivarch * doc/TODO, src/db/btree.c, src/spam/prune.c: Fixed bug in btree backend causing -B to give a different training pattern to GDBM etc: pruning was causing corruption due to a mistake in the "mark block as free" code. 2005-05-01 15:35 ivarch * doc/TODO: There is a bug in the btree backend, it seems, since running -B with GDBM/SQLite/MySQL gives a slightly different training pattern to running with the btree backend; the end result is that the btree backend gives a less accurate filter. This needs fixing; adding to TODO. 2005-05-01 13:08 ivarch * src/db/sqlite.c: Fixed bug triggered in sqlite due to not finalising a query run (during pruning). 2005-04-30 21:17 ivarch * doc/TODO: Removed "independent databases" TODO, since this is not required - the code seems to suggest that pruning will be fine with token aging and multiple databases, as the update count is read from the writable database (the one being pruned), and that is the only time it is used. 2005-04-30 19:14 ivarch * test/t08-dbprune2: Further fix to obsolete test, so it works in "make memtest". 2005-04-30 18:55 ivarch * test/t08-dbprune2: Fixed obsolete pruning test so it skips on anything but the old binary tree backend. 2005-04-30 18:46 ivarch * src/spam/: prune.c, update.c: Fix so we just display pruning information when we are supposed to, not every update. 2005-04-30 18:12 ivarch * doc/NEWS, doc/TODO, doc/VERSION, doc/lsm.in, doc/spec.in, src/spam/prune.c, src/spam/token.c, src/spam/update.c: Added new pruning algorithm which takes token age into account; should fall back to the old pruning method if the last update counter is not available. Also changed the token probability calculation to just use the raw spam/nonspam counts for each token instead of scaling with the global message counts; this means that database pruning will not need to modify the message counts, and in fact for new style databases the global message counts are no longer necessary. 2005-04-29 14:40 ivarch * autoconf/make/unreal.mk: Added new Makefile target for doc/changelog, for release manager use 2005-04-29 14:38 ivarch * doc/release-checklist: Release checklist updated to reflect existence of Debian package maintainer 2005-04-21 12:57 ivarch * debian/changelog, doc/NEWS, doc/TODO, doc/VERSION, doc/lsm.in, doc/quickref.1.in, doc/spec.in, src/tests/gibberish.c, src/tests/main.c: Added gibberish "badstart" and "hyphens" tests (sponsored by SpamDefy, http://www.spamdefy.com/). 2005-03-08 15:13 ivarch * debian/rules: Removed problematic "make distclean" from debian/rules 2005-03-06 12:21 ivarch * autoconf/configure.in: Fix for MySQL detection on systems that wrongly cache lib lookups 2005-03-05 17:27 ivarch * autoconf/make/unreal.mk, debian/changelog, doc/NEWS, doc/TODO, doc/VERSION, src/db/mysql.c, src/main/main.c, test/t01-dbcreate, test/t12-benchmark: Allow MySQL testing if MYSQLDB env var passed to "make test" et al; also, attempt to autocreate MySQL database if it does not exist, warn otherwise. 2005-03-05 15:25 ivarch * src/db/obtree.c: Only complain to user about obtree if they did not specify it explicitly 2005-03-05 14:51 ivarch * autoconf/configure.in, autoconf/header.in, debian/changelog, doc/NEWS, doc/TODO, doc/VERSION, doc/lsm.in, doc/quickref.1.in, doc/spec.in, src/db/btree.c, src/db/main.c, src/db/mysql.c, src/db/obtree.c, src/db/sqlite.c, src/spam/allowlist.c, src/spam/check.c, src/spam/db.c, src/spam/dump.c, src/spam/merge.c, src/spam/prune.c, src/spam/spami.h, src/spam/token.c, src/spam/update.c: Added third parameter for each token, a "last updated" counter; added "obtree" backend for old-format backend that does not have this third parameter, and we now warn verbosely if that obtree backend is used. 2005-03-04 19:08 ivarch * src/: db/sqlite.c, main/main.c: Fixed SQLite write access bug that claimed open succeeded when write access was not actually possible 2005-03-04 18:53 ivarch * src/: include/log.h, main/log.c, main/main.c: More logging information; output logs even if not adding message headers, but output them to stderr in that case 2005-03-04 18:36 ivarch * autoconf/make/unreal.mk, doc/NEWS, doc/VERSION, doc/spec.in: RPM build update to allow "--with static" for a new "qsf-static" RPM 2005-03-04 12:09 ivarch * src/spam/benchmark.c: Further benchmark output improvements 2005-03-04 11:57 ivarch * autoconf/make/unreal.mk, debian/changelog, doc/NEWS, doc/TODO, doc/VERSION, doc/quickref.1.in, doc/spec.in, src/main/main.c, src/spam/benchmark.c: Benchmarking improvements 2005-03-03 22:47 ivarch * autoconf/configure.in, debian/changelog, doc/NEWS, doc/TODO, doc/VERSION: Added --enable-static to configure script 2005-03-03 21:59 ivarch * autoconf/make/unreal.mk, src/db/gdbm.c, src/include/options.h, src/main/main.c, src/main/options.c, src/spam/allowlist.c, src/spam/check.c, src/spam/prune.c, src/spam/train.c, src/spam/update.c: Code cleanup 2005-03-03 00:05 ivarch * autoconf/configure.in: Look for MySQL libraries both without and with mysql_config --libs, to try and get dynamic libraries first 2004-06-22 22:54 ivarch * doc/NEWS, doc/VERSION, doc/quickref.1.in, doc/spec.in, src/include/message.h, src/include/options.h, src/main/help.c, src/main/main.c, src/main/options.c, src/message/header.c: Added "-A" (asterisks) option. 2004-06-22 22:41 ivarch * README, doc/quickref.1.in: Acknowledgements update 2004-06-22 22:41 ivarch * doc/: NEWS, lsm.in, spec.in: Spec file and changelog update 2004-06-22 22:38 ivarch * doc/: NEWS, TODO, VERSION, postfix-howto, quickref.1.in, spec.in: Added Postfix server-wide filtering HOWTO from M Kolbl 2004-06-22 22:11 ivarch * doc/quickref.1.in: Typo fix in manual 2004-06-22 22:10 ivarch * doc/quickref.1.in: Added "-v" documentation to the manual. 2004-06-22 22:03 ivarch * doc/NEWS, doc/TODO, doc/VERSION, doc/quickref.1.in, src/main/help.c, src/main/main.c: Added "-e MSG" syntax, to read the email address to update/query from a message on standard input 2003-01-17 11:18 ivarch * README, configure, generate.sh, autoconf/Makefile.in, autoconf/configure.in, autoconf/header.in, autoconf/make/link.mk, autoconf/make/package.mk, autoconf/make/rules.mk, autoconf/make/unreal.mk, autoconf/make/vars.mk, autoconf/scripts/depend.sh, autoconf/scripts/htmlmunge.pl, autoconf/scripts/index.sh, autoconf/scripts/install.sh, autoconf/scripts/linux-msg.sed, autoconf/scripts/makemake.sh, autoconf/scripts/mkinstalldirs, autoconf/scripts/po2tbl.sed, autoconf/scripts/xopen-msg.sed, doc/COPYING, doc/index.html, doc/INSTALL, doc/NEWS, doc/PACKAGE, doc/TODO, doc/VERSION, doc/lsm.in, doc/quickref.1.in, doc/spec.in, src/include/getopt.h, src/include/message.h, src/include/options.h, src/include/spam.h, src/main/dump.c, src/main/help.c, src/main/license.c, src/main/main.c, src/main/message.c, src/main/options.c, src/main/spam.c, src/main/train.c, src/main/version.c: Initial revision qsf-1.2.7/doc/lsm0000644000076400007640000000067210665021365011416 0ustar awawBegin3 Title: qsf Version: 1.2.7 Entered-date: 28AUG07 Description: Quick spam filter - marks email as spam depending on its content using a database built up through training. Keywords: spam filter, antispam, UCE Author: Andrew Wood Maintained-by: Andrew Wood Primary-site: http://www.ivarch.com/programs/qsf/ Alternate-site: Original-site: Platforms: Copying-policy: Artistic 2.0 End qsf-1.2.7/doc/TODO0000644000076400007640000000210110574007032011347 0ustar awawThings still to do, in order of priority: 20070222: weight as personal if 1 database, use -d/-g for weight if more than 1 (Pavel Kolar) 20070129: strip \r, re-add afterwards, if first line is \r\n (Nora Etukudo) 20050227: autotrain option "-u", retrains based on classification 20050624: try stripping double/triple letters, eg "fffinancce" -> "finance" 20050308: token for nonsense META tags (META NAME="blah blah blah") 20050226: support MH/Maildir training folders 20050227: environment variable for -d and -g 20050228: more verbosity, with profiling data 20040320: comma-separated training folders (-T spam1,spam2,spam3 nonspam1,2,3) 20050322: generate a "%age new tokens" score (eg 90% new tokens) 20050201: support for SQLite v3 20050527: look at http://plg.uwaterloo.ca/~trlynam/spamjig/ 20060217: allow MySQL Unix socket connections (socket location configurable) 20060217: remove pruning step from training if using 3-column database 20070121: improve efficiency of token deletion from list backend Any assistance would be appreciated. qsf-1.2.7/extra/0000755000076400007640000000000010665021416011246 5ustar awawqsf-1.2.7/extra/statstable.sh0000644000076400007640000001052710554714303013756 0ustar awaw#!/bin/sh # # Script to generate an HTML table of stats on standard output, generated # from the MySQL table maintained by mailstats.sh. # # This script requires the MySQL command-line client, `mysql'. It may need # to run under bash, rather than Bourne shell; this has not been tested. # # Fill in the MYSQL* variables to make this script work, and alter DAYS # (number of days in the past to start from), HOURDIV (number of hours # between rows), and BARLEN (pixel width of bar graph) as appropriate. # # Copyright 2007 Andrew Wood, distributed under the Artistic License. # MYSQLUSER= MYSQLPASS= MYSQLDB= MYSQLTABLE=spamlog DAYS=14 HOURDIV=24 BARLEN=300 # Remove this next line to enable this script! echo "Please read this script first, copy it, THEN run it."; exit 1 TOTALS=\ ' COUNT(IF(type="SPAM",1,NULL)) AS spam, COUNT(IF(type="SPAM-BOUNCE",1,NULL)) AS spambounce, COUNT(IF(type="SPAM-REPLY",1,NULL)) AS spamreply, COUNT(IF(type="DELIVERED",1,NULL)) AS delivered, COUNT(IF(type="RETRAIN-SPAM",1,NULL)) AS retrainspam, COUNT(IF(type="RETRAIN-NONSPAM",1,NULL)) AS retrainnonspam' function graph_row () { local VAL COL NAME MAX BARLEN WIDTH VAL="$1" COL="$2" NAME="$3" MAX="$4" BARLEN="$5" WIDTH=$[$[$VAL * $BARLEN] / $MAX] [ $WIDTH -lt 0 ] && WIDTH=0 echo '' if [ $WIDTH -lt 1 ]; then echo '" if [ $[$ROWNUM % 10] -eq 1 ]; then echo "" fi echo '' echo '
     $NAME
    ' } export BARLEN export HOURDIV MAX=`mysql -u $MYSQLUSER -p$MYSQLPASS $MYSQLDB -B -N -e \ 'SELECT '"$TOTALS"' FROM '"$MYSQLTABLE"' WHERE stamp >= DATE_SUB(FROM_DAYS(TO_DAYS(NOW())), INTERVAL '"$DAYS"' DAY) GROUP BY DATE_FORMAT(stamp,"%Y-%m-%d"), '"$HOURDIV"'*FLOOR(EXTRACT(HOUR FROM stamp)/'"$HOURDIV"')' \ | ( while read ROWS ROWSB ROWSR ROWD ROWRS ROWRN; do SPAM=$[$[$ROWS-$ROWSR]+$ROWRS] FALSENEG=$ROWRS NONSPAM=$[$[$ROWD+$ROWRN]-$ROWRS] FALSEPOS=$ROWSR echo $SPAM echo $FALSENEG echo $NONSPAM echo $FALSEPOS done ) \ | sort -n \ | tail -n 1` [ $MAX -lt 1 ] && MAX=1 export MAX mysql -u $MYSQLUSER -p$MYSQLPASS $MYSQLDB -B -N -e \ 'SELECT DATE_FORMAT(stamp,"%Y-%m-%d") AS date, '"$HOURDIV"'*FLOOR(EXTRACT(HOUR FROM stamp)/'"$HOURDIV"') AS hour, '"$TOTALS"' FROM '"$MYSQLTABLE"' WHERE stamp >= DATE_SUB(FROM_DAYS(TO_DAYS(NOW())), INTERVAL '"$DAYS"' DAY) GROUP BY date,hour' \ | ( echo '' echo '' echo '' [ $HOURDIV -lt 24 ] && echo '' echo '' echo '' echo '' echo '' echo '' echo '' echo '' echo '' PREVDATE="" ROWNUM=0 while read DATE TIME ROWS ROWSB ROWSR ROWD ROWRS ROWRN; do SPAM=$[$[$ROWS-$ROWSR]+$ROWRS] FALSENEG=$ROWRS NONSPAM=$[$[$ROWD+$ROWRN]-$ROWRS] FALSEPOS=$ROWSR ROWNUM=$[1+$ROWNUM] if [ "$DATE" = "$PREVDATE" ]; then echo '' echo '' else echo '' echo "" fi PREVDATE=$DATE [ $HOURDIV -lt 24 ] \ && echo "" FIRSTVAL=1 for VAL in $ROWS $ROWSB $ROWSR $ROWD $ROWRS $ROWRN; do C=val [ $FIRSTVAL = 1 ] && C=firstval FIRSTVAL=0 echo "" done echo '' echo '' done echo '
    DateTimeSSBSRDRSRN 
     
    $DATE$TIME:00$VAL' graph_row $NONSPAM '080' 'Non-spam' $MAX $BARLEN graph_row $FALSEPOS '800' 'Non-spam falsely marked as spam' $MAX $BARLEN graph_row $SPAM '088' 'Spam' $MAX $BARLEN graph_row $FALSENEG '008' 'Spam that slipped through' $MAX $BARLEN echo '
    ' ) # EOF qsf-1.2.7/extra/mailstats.sh0000644000076400007640000000704610554714304013614 0ustar awaw#!/bin/sh # # Script to rotate procmail.log (appends it, gzip-compressed, to # procmail.log.old.gz). New data is converted to SQL INSERT statements and # inserted into a MySQL table. # # Note that this script requires GNU `date', `awk', and `sed'. It also needs # the MySQL command-line client, `mysql'. It may need to run under bash, # rather than Bourne shell, too; this has not been tested. # # The spam log table has two fields, "stamp" and "type". "stamp" is the date # and time of the email, and "type" is the type of email: # # SPAM Message was flagged as spam and a bounce sent by JMBA. # SPAM-BOUNCE A bounce sent by JMBA was returned as undeliverable. # SPAM-REPLY A bounce sent by JMBA was replied to. # DELIVERED The email was delivered normally. # RETRAIN-SPAM User retraining QSF - message was really spam. # RETRAIN-NONSPAM User retraining QSF - message was really non-spam. # # The procmail.log file is expected in $LOGDIR (defined below), and it # should be generated by adding this to the top of your .procmailrc file: # # LOGFILE=$HOME/procmail.log # LOGABSTRACT=yes # # (replace $HOME/ with whatever you set $LOGDIR to below). # # For this script to be able to tell what options you called JMBA and QSF # with, be sure to put the action options first (i.e. "jmba -b ..." instead # of "jmba ... -b", "jmba -s ..." not "jmba ... -s", and "qsf -M ..." rather # than "qsf -d foo -g bar -g baz -a -M"). # # You will need a table in database $MYSQLDB called $MYSQLTABLE (default is # "spamlog"). The following schema will do: # # CREATE TABLE `spamlog` ( # `stamp` TIMESTAMP(14) NOT NULL, # `type` ENUM('SPAM','SPAM-BOUNCE','SPAM-REPLY','DELIVERED', # 'RETRAIN-SPAM','RETRAIN-NONSPAM') # NOT NULL DEFAULT 'DELIVERED', # KEY (`stamp`), # KEY (`type`) # ); # # If you run this script regularly (say, once a day) from cron, you can then # do SQL queries on that table to get a picture of your spam blocking. # # Fill in the MYSQL* and LOGDIR variables below to make this script work. # # Copyright 2007 Andrew Wood, distributed under the Artistic License. # MYSQLUSER= MYSQLPASS= MYSQLDB= MYSQLTABLE=spamlog LOGDIR=$HOME # Remove this next line to enable this script! echo "Please read this script first, copy it, THEN run it."; exit 1 cd $LOGDIR || exit 1 [ -s procmail.log ] || exit 0 rm -f procmail.log.old procmail.log.new touch procmail.log.new || exit 1 chmod 600 procmail.log.new || exit 1 ln procmail.log procmail.log.old || exit 1 mv -f procmail.log.new procmail.log || exit 1 gzip -9 < procmail.log.old >> procmail.log.old.gz cat procmail.log.old \ | sed -n \ -e 's/^From [^ ]\+ \([0-9A-Za-z_ :-]*\).*$/ \1/p'\ -e 's/^ Folder: \(.*\)[ ][ ]\+.*$/\1/p' \ | sed 's/[ ]*$//' \ | awk '/^ /{cmd="date -d \"" $0 "\" +%Y-%m-%d_%H:%M:%S";cmd | getline d; close(cmd);} /^[^ ]/{print d " " $0}' \ | awk '/jmba -b/{print $1 " SPAM-BOUNCE";next} /jmba -v -b/{print $1 " SPAM-BOUNCE";next} /jmba -s/{print $1 " SPAM-REPLY";next} /jmba -v -s/{print $1 " SPAM-REPLY";next} /sendmail/{print $1 " SPAM";next} /\/dev\/null/{next} /qsf(-mysql)? .* *(-[^ -]*m|--mark-spam)/{print $1 " RETRAIN-SPAM";next} /qsf(-mysql)? .* *(-[^ -]*M|--mark-nonspam)/{print $1 " RETRAIN-NONSPAM";next} {print $1 " DELIVERED"}' \ | sed -e 's/ /","/' \ -e 's/_/ /' \ -e 's/^/INSERT INTO '"$MYSQLTABLE"' (`stamp`,`type`) VALUES ("/' \ -e 's/$/");/' \ | mysql -s -u $MYSQLUSER -p$MYSQLPASS $MYSQLDB rm -f procmail.log.old # EOF qsf-1.2.7/configure0000755000076400007640000067655310665021272012060 0ustar awaw#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.59. # # Copyright (C) 2003 Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH # Name of the host. # hostname on some systems (SVR3.2, Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` exec 6>&1 # # Initializations. # ac_default_prefix=/usr/local ac_config_libobj_dir=. cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Maximum number of lines to put in a shell here document. # This variable seems obsolete. It should probably be removed, and # only ac_max_sed_lines should be used. : ${ac_max_here_lines=38} # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= ac_unique_file="src/main/version.c" # Factoring default headers for most tests. ac_includes_default="\ #include #if HAVE_SYS_TYPES_H # include #endif #if HAVE_SYS_STAT_H # include #endif #if STDC_HEADERS # include # include #else # if HAVE_STDLIB_H # include # endif #endif #if HAVE_STRING_H # if !STDC_HEADERS && HAVE_MEMORY_H # include # endif # include #endif #if HAVE_STRINGS_H # include #endif #if HAVE_INTTYPES_H # include #else # if HAVE_STDINT_H # include # endif #endif #if HAVE_UNISTD_H # include #endif" ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS PACKAGE VERSION UCPACKAGE CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP LD ac_ct_LD INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA SET_MAKE DO_GZIP EGREP BACKENDS LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. ac_init_help= ac_init_version=false # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datadir='${prefix}/share' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' libdir='${exec_prefix}/lib' includedir='${prefix}/include' oldincludedir='/usr/include' infodir='${prefix}/info' mandir='${prefix}/man' ac_prev= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval "$ac_prev=\$ac_option" ac_prev= continue fi ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_option in -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad | --data | --dat | --da) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ | --da=*) datadir=$ac_optarg ;; -disable-* | --disable-*) ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` eval "enable_$ac_feature=no" ;; -enable-* | --enable-*) ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid feature name: $ac_feature" >&2 { (exit 1); exit 1; }; } ac_feature=`echo $ac_feature | sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "enable_$ac_feature='$ac_optarg'" ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst \ | --locals | --local | --loca | --loc | --lo) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* \ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package| sed 's/-/_/g'` case $ac_option in *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; *) ac_optarg=yes ;; esac eval "with_$ac_package='$ac_optarg'" ;; -without-* | --without-*) ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid package name: $ac_package" >&2 { (exit 1); exit 1; }; } ac_package=`echo $ac_package | sed 's/-/_/g'` eval "with_$ac_package=no" ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) { echo "$as_me: error: unrecognized option: $ac_option Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 { (exit 1); exit 1; }; } ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` eval "$ac_envvar='$ac_optarg'" export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` { echo "$as_me: error: missing argument to $ac_option" >&2 { (exit 1); exit 1; }; } fi # Be sure to have absolute paths. for ac_var in exec_prefix prefix do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* | NONE | '' ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac done # Be sure to have absolute paths. for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ localstatedir libdir includedir oldincludedir infodir mandir do eval ac_val=$`echo $ac_var` case $ac_val in [\\/$]* | ?:[\\/]* ) ;; *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; };; esac done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then its parent. ac_confdir=`(dirname "$0") 2>/dev/null || $as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$0" : 'X\(//\)[^/]' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$0" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` srcdir=$ac_confdir if test ! -r $srcdir/$ac_unique_file; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r $srcdir/$ac_unique_file; then if test "$ac_srcdir_defaulted" = yes; then { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 { (exit 1); exit 1; }; } else { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 { (exit 1); exit 1; }; } fi fi (cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 { (exit 1); exit 1; }; } srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` ac_env_build_alias_set=${build_alias+set} ac_env_build_alias_value=$build_alias ac_cv_env_build_alias_set=${build_alias+set} ac_cv_env_build_alias_value=$build_alias ac_env_host_alias_set=${host_alias+set} ac_env_host_alias_value=$host_alias ac_cv_env_host_alias_set=${host_alias+set} ac_cv_env_host_alias_value=$host_alias ac_env_target_alias_set=${target_alias+set} ac_env_target_alias_value=$target_alias ac_cv_env_target_alias_set=${target_alias+set} ac_cv_env_target_alias_value=$target_alias ac_env_CC_set=${CC+set} ac_env_CC_value=$CC ac_cv_env_CC_set=${CC+set} ac_cv_env_CC_value=$CC ac_env_CFLAGS_set=${CFLAGS+set} ac_env_CFLAGS_value=$CFLAGS ac_cv_env_CFLAGS_set=${CFLAGS+set} ac_cv_env_CFLAGS_value=$CFLAGS ac_env_LDFLAGS_set=${LDFLAGS+set} ac_env_LDFLAGS_value=$LDFLAGS ac_cv_env_LDFLAGS_set=${LDFLAGS+set} ac_cv_env_LDFLAGS_value=$LDFLAGS ac_env_CPPFLAGS_set=${CPPFLAGS+set} ac_env_CPPFLAGS_value=$CPPFLAGS ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} ac_cv_env_CPPFLAGS_value=$CPPFLAGS ac_env_CPP_set=${CPP+set} ac_env_CPP_value=$CPP ac_cv_env_CPP_set=${CPP+set} ac_cv_env_CPP_value=$CPP # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] _ACEOF cat <<_ACEOF Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --datadir=DIR read-only architecture-independent data [PREFIX/share] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --infodir=DIR info documentation [PREFIX/info] --mandir=DIR man documentation [PREFIX/man] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-debugging compile with debugging symbols --enable-profiling compile with profiling support --enable-static enable static linking Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --without-obtree omit old binary tree backend support --without-btree omit binary tree backend support --without-list omit list backend support --without-gdbm omit GDBM backend support --without-mysql omit MySQL backend support --without-sqlite omit SQLite v2.x backend support Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. _ACEOF fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. ac_popdir=`pwd` for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d $ac_dir || continue ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac cd $ac_dir # Check for guested configure; otherwise get Cygnus style configure. if test -f $ac_srcdir/configure.gnu; then echo $SHELL $ac_srcdir/configure.gnu --help=recursive elif test -f $ac_srcdir/configure; then echo $SHELL $ac_srcdir/configure --help=recursive elif test -f $ac_srcdir/configure.ac || test -f $ac_srcdir/configure.in; then echo $ac_configure --help else echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi cd $ac_popdir done fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF Copyright (C) 2003 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit 0 fi exec 5>config.log cat >&5 <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.59. Invocation command line was $ $0 $@ _ACEOF { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` hostinfo = `(hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. echo "PATH: $as_dir" done } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_sep= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; 2) ac_configure_args1="$ac_configure_args1 '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" # Get rid of the leading space. ac_sep=" " ;; esac done done $as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } $as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Be sure not to use single quotes in there, as some shells, # such as our DU 5.0 friend, will then `close' the trap. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo cat <<\_ASBOX ## ---------------- ## ## Cache variables. ## ## ---------------- ## _ASBOX echo # The following way of writing the cache mishandles newlines in values, { (set) 2>&1 | case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in *ac_space=\ *) sed -n \ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" ;; *) sed -n \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } echo cat <<\_ASBOX ## ----------------- ## ## Output variables. ## ## ----------------- ## _ASBOX echo for ac_var in $ac_subst_vars do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo if test -n "$ac_subst_files"; then cat <<\_ASBOX ## ------------- ## ## Output files. ## ## ------------- ## _ASBOX echo for ac_var in $ac_subst_files do eval ac_val=$`echo $ac_var` echo "$ac_var='"'"'$ac_val'"'"'" done | sort echo fi if test -s confdefs.h; then cat <<\_ASBOX ## ----------- ## ## confdefs.h. ## ## ----------- ## _ASBOX echo sed "/^$/d" confdefs.h | sort echo fi test "$ac_signal" != 0 && echo "$as_me: caught signal $ac_signal" echo "$as_me: exit $exit_status" } >&5 rm -f core *.core && rm -rf conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo >confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special # files actually), so we avoid doing that. if test -f "$cache_file"; then { echo "$as_me:$LINENO: loading cache $cache_file" >&5 echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . $cache_file;; *) . ./$cache_file;; esac fi else { echo "$as_me:$LINENO: creating cache $cache_file" >&5 echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in `(set) 2>&1 | sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val="\$ac_cv_env_${ac_var}_value" eval ac_new_val="\$ac_env_${ac_var}_value" case $ac_old_set,$ac_new_set in set,) { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 echo "$as_me: former value: $ac_old_val" >&2;} { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 echo "$as_me: current value: $ac_new_val" >&2;} ac_cache_corrupted=: fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 echo "$as_me: error: changes in the environment can compromise the build" >&2;} { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} { (exit 1); exit 1; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers src/include/config.h:autoconf/header.in" ac_aux_dir= for ac_dir in autoconf/scripts $srcdir/autoconf/scripts; do if test -f $ac_dir/install-sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f $ac_dir/install.sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f $ac_dir/shtool; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in autoconf/scripts $srcdir/autoconf/scripts" >&5 echo "$as_me: error: cannot find install-sh or install.sh in autoconf/scripts $srcdir/autoconf/scripts" >&2;} { (exit 1); exit 1; }; } fi ac_config_guess="$SHELL $ac_aux_dir/config.guess" ac_config_sub="$SHELL $ac_aux_dir/config.sub" ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. PACKAGE=`cat $srcdir/doc/PACKAGE` VERSION=`cat $srcdir/doc/VERSION` UCPACKAGE=`tr a-z A-Z < $srcdir/doc/PACKAGE` cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define PROGRAM_NAME "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF canuse_obtree="yes" canuse_btree="yes" canuse_list="yes" canuse_gdbm="yes" canuse_mysql="yes" canuse_sqlite="yes" # Check whether --enable-debugging or --disable-debugging was given. if test "${enable_debugging+set}" = set; then enableval="$enable_debugging" if test "$enable_debugging" = "yes"; then CFLAGS="-g -Wall" fi fi; # Check whether --enable-profiling or --disable-profiling was given. if test "${enable_profiling+set}" = set; then enableval="$enable_profiling" if test "$enable_profiling" = "yes"; then CFLAGS="-pg $CFLAGS" fi fi; # Check whether --enable-static or --disable-static was given. if test "${enable_static+set}" = set; then enableval="$enable_static" fi; # Check whether --with-obtree or --without-obtree was given. if test "${with_obtree+set}" = set; then withval="$with_obtree" canuse_obtree="$with_obtree" fi; # Check whether --with-btree or --without-btree was given. if test "${with_btree+set}" = set; then withval="$with_btree" canuse_btree="$with_btree" fi; # Check whether --with-list or --without-list was given. if test "${with_list+set}" = set; then withval="$with_list" canuse_list="$with_list" fi; # Check whether --with-gdbm or --without-gdbm was given. if test "${with_gdbm+set}" = set; then withval="$with_gdbm" canuse_gdbm="$with_gdbm" fi; # Check whether --with-mysql or --without-mysql was given. if test "${with_mysql+set}" = set; then withval="$with_mysql" canuse_mysql="$with_mysql" fi; # Check whether --with-sqlite or --without-sqlite was given. if test "${with_sqlite+set}" = set; then withval="$with_sqlite" canuse_sqlite="$with_sqlite" fi; CFLAGS=${CFLAGS-"-O2 -Wall -s"} ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi CC=$ac_ct_CC else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi CC=$ac_ct_CC else CC="$ac_cv_prog_CC" fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then echo "$as_me:$LINENO: result: $CC" >&5 echo "${ECHO_T}$CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_CC+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 echo "${ECHO_T}$ac_ct_CC" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi test -n "$ac_ct_CC" && break done CC=$ac_ct_CC fi fi test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&5 echo "$as_me: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } # Provide some information about the compiler. echo "$as_me:$LINENO:" \ "checking for C compiler version" >&5 ac_compiler=`set X $ac_compile; echo $2` { (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 (eval $ac_compiler --version &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 (eval $ac_compiler -v &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 (eval $ac_compiler -V &5) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 (eval $ac_link_default) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # Find the output, starting from the most likely. This scheme is # not robust to junk in `.', hence go to wildcards (a.*) only as a last # resort. # Be careful to initialize this variable, since it used to be cached. # Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. ac_cv_exeext= # b.out is created by i960 compilers. for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; conftest.$ac_ext ) # This is the source file. ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` # FIXME: I believe we export ac_cv_exeext for Libtool, # but it would be cool to find out if it's true. Does anybody # maintain Libtool? --akim. export ac_cv_exeext break;; * ) break;; esac done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { echo "$as_me:$LINENO: error: C compiler cannot create executables See \`config.log' for more details." >&5 echo "$as_me: error: C compiler cannot create executables See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; } fi ac_exeext=$ac_cv_exeext echo "$as_me:$LINENO: result: $ac_file" >&5 echo "${ECHO_T}$ac_file" >&6 # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. echo "$as_me:$LINENO: checking whether the C compiler works" >&5 echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 # FIXME: These cross compiler hacks should be removed for Autoconf 3.0 # If not cross compiling, check that we can run a simple program. if test "$cross_compiling" != yes; then if { ac_try='./$ac_file' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { echo "$as_me:$LINENO: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&5 echo "$as_me: error: cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi fi fi echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 rm -f a.out a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save # Check the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 echo "$as_me:$LINENO: result: $cross_compiling" >&5 echo "${ECHO_T}$cross_compiling" >&6 echo "$as_me:$LINENO: checking for suffix of executables" >&5 echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` export ac_cv_exeext break;; * ) break;; esac done else { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f conftest$ac_cv_exeext echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 echo "${ECHO_T}$ac_cv_exeext" >&6 rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT echo "$as_me:$LINENO: checking for suffix of object files" >&5 echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 if test "${ac_cv_objext+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&5 echo "$as_me: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 echo "${ECHO_T}$ac_cv_objext" >&6 OBJEXT=$ac_cv_objext ac_objext=$OBJEXT echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 if test "${ac_cv_c_compiler_gnu+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_compiler_gnu=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_compiler_gnu=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 GCC=`test $ac_compiler_gnu = yes && echo yes` ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS CFLAGS="-g" echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 if test "${ac_cv_prog_cc_g+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_cc_g=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_prog_cc_g=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 if test "${ac_cv_prog_cc_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_cv_prog_cc_stdc=no ac_save_CC=$CC cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std1 is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std1. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF # Don't try gcc -ansi; that turns off useful extensions and # breaks some systems' header files. # AIX -qlanglvl=ansi # Ultrix and OSF/1 -std1 # HP-UX 10.20 and later -Ae # HP-UX older versions -Aa -D_HPUX_SOURCE # SVR4 -Xc -D__EXTENSIONS__ for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_prog_cc_stdc=$ac_arg break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext done rm -f conftest.$ac_ext conftest.$ac_objext CC=$ac_save_CC fi case "x$ac_cv_prog_cc_stdc" in x|xno) echo "$as_me:$LINENO: result: none needed" >&5 echo "${ECHO_T}none needed" >&6 ;; *) echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 CC="$CC $ac_cv_prog_cc_stdc" ;; esac # Some people use a C++ compiler to compile C. Since we use `exit', # in C++ we need to declare it. In case someone uses the same compiler # for both compiling C and C++ we need to have the C++ compiler decide # the declaration of exit, since it's the most demanding environment. cat >conftest.$ac_ext <<_ACEOF #ifndef __cplusplus choke me #endif _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then for ac_declaration in \ '' \ 'extern "C" void std::exit (int) throw (); using std::exit;' \ 'extern "C" void std::exit (int); using std::exit;' \ 'extern "C" void exit (int) throw ();' \ 'extern "C" void exit (int);' \ 'void exit (int);' do cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_declaration #include int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 continue fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_declaration int main () { exit (42); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext done rm -f conftest* if test -n "$ac_declaration"; then echo '#ifdef __cplusplus' >>confdefs.h echo $ac_declaration >>confdefs.h echo '#endif' >>confdefs.h fi else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test "${ac_cv_prog_CPP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether non-existent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then # Broken: success on invalid input. continue else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi echo "$as_me:$LINENO: result: $CPP" >&5 echo "${ECHO_T}$CPP" >&6 ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then : else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether non-existent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then # Broken: success on invalid input. continue else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details." >&5 echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ld", so it can be a program name with args. set dummy ${ac_tool_prefix}ld; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_LD+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$LD"; then ac_cv_prog_LD="$LD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LD="${ac_tool_prefix}ld" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done fi fi LD=$ac_cv_prog_LD if test -n "$LD"; then echo "$as_me:$LINENO: result: $LD" >&5 echo "${ECHO_T}$LD" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi fi if test -z "$ac_cv_prog_LD"; then ac_ct_LD=$LD # Extract the first word of "ld", so it can be a program name with args. set dummy ld; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_ac_ct_LD+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$ac_ct_LD"; then ac_cv_prog_ac_ct_LD="$ac_ct_LD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_LD="ld" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_prog_ac_ct_LD" && ac_cv_prog_ac_ct_LD="libtool --mode=link gcc" fi fi ac_ct_LD=$ac_cv_prog_ac_ct_LD if test -n "$ac_ct_LD"; then echo "$as_me:$LINENO: result: $ac_ct_LD" >&5 echo "${ECHO_T}$ac_ct_LD" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi LD=$ac_ct_LD else LD="$ac_cv_prog_LD" fi # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6 if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in ./ | .// | /cC/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi done done ;; esac done fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. We don't cache a # path for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the path is relative. INSTALL=$ac_install_sh fi fi echo "$as_me:$LINENO: result: $INSTALL" >&5 echo "${ECHO_T}$INSTALL" >&6 # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,:./+-,___p_,'` if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.make <<\_ACEOF all: @echo 'ac_maketemp="$(MAKE)"' _ACEOF # GNU make sometimes prints "make[1]: Entering...", which would confuse us. eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=` if test -n "$ac_maketemp"; then eval ac_cv_prog_make_${ac_make}_set=yes else eval ac_cv_prog_make_${ac_make}_set=no fi rm -f conftest.make fi if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then echo "$as_me:$LINENO: result: yes" >&5 echo "${ECHO_T}yes" >&6 SET_MAKE= else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 SET_MAKE="MAKE=${MAKE-make}" fi # Extract the first word of "gzip", so it can be a program name with args. set dummy gzip; ac_word=$2 echo "$as_me:$LINENO: checking for $ac_word" >&5 echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 if test "${ac_cv_prog_DO_GZIP+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test -n "$DO_GZIP"; then ac_cv_prog_DO_GZIP="$DO_GZIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DO_GZIP="gzip -f9" echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done test -z "$ac_cv_prog_DO_GZIP" && ac_cv_prog_DO_GZIP="touch" fi fi DO_GZIP=$ac_cv_prog_DO_GZIP if test -n "$DO_GZIP"; then echo "$as_me:$LINENO: result: $DO_GZIP" >&5 echo "${ECHO_T}$DO_GZIP" >&6 else echo "$as_me:$LINENO: result: no" >&5 echo "${ECHO_T}no" >&6 fi echo "$as_me:$LINENO: checking for library containing pow" >&5 echo $ECHO_N "checking for library containing pow... $ECHO_C" >&6 if test "${ac_cv_search_pow+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_func_search_save_LIBS=$LIBS ac_cv_search_pow=no cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char pow (); int main () { pow (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_search_pow="none required" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$ac_cv_search_pow" = no; then for ac_lib in m; do LIBS="-l$ac_lib $ac_func_search_save_LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char pow (); int main () { pow (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_search_pow="-l$ac_lib" break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext done fi LIBS=$ac_func_search_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_search_pow" >&5 echo "${ECHO_T}$ac_cv_search_pow" >&6 if test "$ac_cv_search_pow" != no; then test "$ac_cv_search_pow" = "none required" || LIBS="$ac_cv_search_pow $LIBS" else { { echo "$as_me:$LINENO: error: maths library not found" >&5 echo "$as_me: error: maths library not found" >&2;} { (exit 1); exit 1; }; } fi cat >>confdefs.h <<\_ACEOF #define HAVE_CONFIG_H 1 _ACEOF echo "$as_me:$LINENO: checking for egrep" >&5 echo $ECHO_N "checking for egrep... $ECHO_C" >&6 if test "${ac_cv_prog_egrep+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if echo a | (grep -E '(a|b)') >/dev/null 2>&1 then ac_cv_prog_egrep='grep -E' else ac_cv_prog_egrep='egrep' fi fi echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 echo "${ECHO_T}$ac_cv_prog_egrep" >&6 EGREP=$ac_cv_prog_egrep echo "$as_me:$LINENO: checking for ANSI C header files" >&5 echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 if test "${ac_cv_header_stdc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_header_stdc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_header_stdc=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } _ACEOF rm -f conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) ac_cv_header_stdc=no fi rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi fi echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 echo "${ECHO_T}$ac_cv_header_stdc" >&6 if test $ac_cv_header_stdc = yes; then cat >>confdefs.h <<\_ACEOF #define STDC_HEADERS 1 _ACEOF fi echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5 echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6 if test "${ac_cv_c_bigendian+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else # See if sys/param.h defines the BYTE_ORDER macro. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { #if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN bogus endian macros #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then # It does; now see whether it defined to BIG_ENDIAN or not. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_c_bigendian=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_c_bigendian=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # It does not; compile a test program. if test "$cross_compiling" = yes; then # try to guess the endianness by grepping values into an object file ac_cv_c_bigendian=unknown cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ short ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; short ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; } short ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; short ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; } int main () { _ascii (); _ebcdic (); ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then ac_cv_c_bigendian=yes fi if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else # finding both strings is unlikely to happen, but who knows? ac_cv_c_bigendian=unknown fi fi else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { /* Are we little or big endian? From Harbison&Steele. */ union { long l; char c[sizeof (long)]; } u; u.l = 1; exit (u.c[sizeof (long) - 1] == 1); } _ACEOF rm -f conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_c_bigendian=no else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) ac_cv_c_bigendian=yes fi rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5 echo "${ECHO_T}$ac_cv_c_bigendian" >&6 case $ac_cv_c_bigendian in yes) cat >>confdefs.h <<\_ACEOF #define IS_BIG_ENDIAN 1 _ACEOF ;; no) ;; *) { { echo "$as_me:$LINENO: error: unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" >&5 echo "$as_me: error: unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" >&2;} { (exit 1); exit 1; }; } ;; esac for ac_func in memcpy do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$as_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define $ac_func to an innocuous variant, in case declares $ac_func. For example, HP-UX 11i declares gettimeofday. */ #define $ac_func innocuous_$ac_func /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $ac_func /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else char (*f) () = $ac_func; #endif #ifdef __cplusplus } #endif int main () { return f != $ac_func; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF else { { echo "$as_me:$LINENO: error: the memcpy() function is required" >&5 echo "$as_me: error: the memcpy() function is required" >&2;} { (exit 1); exit 1; }; } fi done for ac_func in fcntl getopt getopt_long mkstemp snprintf vsnprintf utime do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$as_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define $ac_func to an innocuous variant, in case declares $ac_func. For example, HP-UX 11i declares gettimeofday. */ #define $ac_func innocuous_$ac_func /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $ac_func /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else char (*f) () = $ac_func; #endif #ifdef __cplusplus } #endif int main () { return f != $ac_func; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_Header=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_Header=no" fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in fcntl.h getopt.h limits.h sys/resource.h mcheck.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## ------------------------------------------ ## ## Report this to the AC_PACKAGE_NAME lists. ## ## ------------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in stdlib.h unistd.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## ------------------------------------------ ## ## Report this to the AC_PACKAGE_NAME lists. ## ## ------------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_func in getpagesize do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$as_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define $ac_func to an innocuous variant, in case declares $ac_func. For example, HP-UX 11i declares gettimeofday. */ #define $ac_func innocuous_$ac_func /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $ac_func /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else char (*f) () = $ac_func; #endif #ifdef __cplusplus } #endif int main () { return f != $ac_func; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done echo "$as_me:$LINENO: checking for working mmap" >&5 echo $ECHO_N "checking for working mmap... $ECHO_C" >&6 if test "${ac_cv_func_mmap_fixed_mapped+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else if test "$cross_compiling" = yes; then ac_cv_func_mmap_fixed_mapped=no else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default /* malloc might have been renamed as rpl_malloc. */ #undef malloc /* Thanks to Mike Haertel and Jim Avera for this test. Here is a matrix of mmap possibilities: mmap private not fixed mmap private fixed at somewhere currently unmapped mmap private fixed at somewhere already mapped mmap shared not fixed mmap shared fixed at somewhere currently unmapped mmap shared fixed at somewhere already mapped For private mappings, we should verify that changes cannot be read() back from the file, nor mmap's back from the file at a different address. (There have been systems where private was not correctly implemented like the infamous i386 svr4.0, and systems where the VM page cache was not coherent with the file system buffer cache like early versions of FreeBSD and possibly contemporary NetBSD.) For shared mappings, we should conversely verify that changes get propagated back to all the places they're supposed to be. Grep wants private fixed already mapped. The main things grep needs to know about mmap are: * does it exist and is it safe to write into the mmap'd area * how to use it (BSD variants) */ #include #include #if !STDC_HEADERS && !HAVE_STDLIB_H char *malloc (); #endif /* This mess was copied from the GNU getpagesize.h. */ #if !HAVE_GETPAGESIZE /* Assume that all systems that can run configure have sys/param.h. */ # if !HAVE_SYS_PARAM_H # define HAVE_SYS_PARAM_H 1 # endif # ifdef _SC_PAGESIZE # define getpagesize() sysconf(_SC_PAGESIZE) # else /* no _SC_PAGESIZE */ # if HAVE_SYS_PARAM_H # include # ifdef EXEC_PAGESIZE # define getpagesize() EXEC_PAGESIZE # else /* no EXEC_PAGESIZE */ # ifdef NBPG # define getpagesize() NBPG * CLSIZE # ifndef CLSIZE # define CLSIZE 1 # endif /* no CLSIZE */ # else /* no NBPG */ # ifdef NBPC # define getpagesize() NBPC # else /* no NBPC */ # ifdef PAGESIZE # define getpagesize() PAGESIZE # endif /* PAGESIZE */ # endif /* no NBPC */ # endif /* no NBPG */ # endif /* no EXEC_PAGESIZE */ # else /* no HAVE_SYS_PARAM_H */ # define getpagesize() 8192 /* punt totally */ # endif /* no HAVE_SYS_PARAM_H */ # endif /* no _SC_PAGESIZE */ #endif /* no HAVE_GETPAGESIZE */ int main () { char *data, *data2, *data3; int i, pagesize; int fd; pagesize = getpagesize (); /* First, make a file with some known garbage in it. */ data = (char *) malloc (pagesize); if (!data) exit (1); for (i = 0; i < pagesize; ++i) *(data + i) = rand (); umask (0); fd = creat ("conftest.mmap", 0600); if (fd < 0) exit (1); if (write (fd, data, pagesize) != pagesize) exit (1); close (fd); /* Next, try to mmap the file at a fixed address which already has something else allocated at it. If we can, also make sure that we see the same garbage. */ fd = open ("conftest.mmap", O_RDWR); if (fd < 0) exit (1); data2 = (char *) malloc (2 * pagesize); if (!data2) exit (1); data2 += (pagesize - ((long) data2 & (pagesize - 1))) & (pagesize - 1); if (data2 != mmap (data2, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, fd, 0L)) exit (1); for (i = 0; i < pagesize; ++i) if (*(data + i) != *(data2 + i)) exit (1); /* Finally, make sure that changes to the mapped area do not percolate back to the file as seen by read(). (This is a bug on some variants of i386 svr4.0.) */ for (i = 0; i < pagesize; ++i) *(data2 + i) = *(data2 + i) + 1; data3 = (char *) malloc (pagesize); if (!data3) exit (1); if (read (fd, data3, pagesize) != pagesize) exit (1); for (i = 0; i < pagesize; ++i) if (*(data + i) != *(data3 + i)) exit (1); close (fd); exit (0); } _ACEOF rm -f conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_func_mmap_fixed_mapped=yes else echo "$as_me: program exited with status $ac_status" >&5 echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) ac_cv_func_mmap_fixed_mapped=no fi rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi echo "$as_me:$LINENO: result: $ac_cv_func_mmap_fixed_mapped" >&5 echo "${ECHO_T}$ac_cv_func_mmap_fixed_mapped" >&6 if test $ac_cv_func_mmap_fixed_mapped = yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_MMAP 1 _ACEOF fi rm -f conftest.mmap PREVCFLAGS="$CFLAGS" PREVCPPFLAGS="$CPPFLAGS" PREVLIBS="$LIBS" if test "x$canuse_mysql" = "xyes"; then CFLAGS=`mysql_config --cflags 2>/dev/null` CPPFLAGS=`mysql_config --include 2>/dev/null` || CPPFLAGS="$CFLAGS" LIBS="" if test "x$enable_static" != "xyes"; then for ac_header in mysql.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## ------------------------------------------ ## ## Report this to the AC_PACKAGE_NAME lists. ## ## ------------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF echo "$as_me:$LINENO: checking for library containing mysql_real_connect" >&5 echo $ECHO_N "checking for library containing mysql_real_connect... $ECHO_C" >&6 if test "${ac_cv_search_mysql_real_connect+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_func_search_save_LIBS=$LIBS ac_cv_search_mysql_real_connect=no cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char mysql_real_connect (); int main () { mysql_real_connect (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_search_mysql_real_connect="none required" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$ac_cv_search_mysql_real_connect" = no; then for ac_lib in mysqlclient; do LIBS="-l$ac_lib $ac_func_search_save_LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char mysql_real_connect (); int main () { mysql_real_connect (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_search_mysql_real_connect="-l$ac_lib" break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext done fi LIBS=$ac_func_search_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_search_mysql_real_connect" >&5 echo "${ECHO_T}$ac_cv_search_mysql_real_connect" >&6 if test "$ac_cv_search_mysql_real_connect" != no; then test "$ac_cv_search_mysql_real_connect" = "none required" || LIBS="$ac_cv_search_mysql_real_connect $LIBS" echo "$as_me:$LINENO: checking for library containing mysql_real_escape_string" >&5 echo $ECHO_N "checking for library containing mysql_real_escape_string... $ECHO_C" >&6 if test "${ac_cv_search_mysql_real_escape_string+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_func_search_save_LIBS=$LIBS ac_cv_search_mysql_real_escape_string=no cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char mysql_real_escape_string (); int main () { mysql_real_escape_string (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_search_mysql_real_escape_string="none required" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$ac_cv_search_mysql_real_escape_string" = no; then for ac_lib in mysqlclient; do LIBS="-l$ac_lib $ac_func_search_save_LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char mysql_real_escape_string (); int main () { mysql_real_escape_string (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_search_mysql_real_escape_string="-l$ac_lib" break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext done fi LIBS=$ac_func_search_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_search_mysql_real_escape_string" >&5 echo "${ECHO_T}$ac_cv_search_mysql_real_escape_string" >&6 if test "$ac_cv_search_mysql_real_escape_string" != no; then test "$ac_cv_search_mysql_real_escape_string" = "none required" || LIBS="$ac_cv_search_mysql_real_escape_string $LIBS" else canuse_mysql="no" fi else canuse_mysql="no" fi else canuse_mysql="no" fi done fi if test "x$canuse_mysql" = "xno"; then canuse_mysql=yes LIBS=`mysql_config --libs 2>/dev/null` for ac_header in mysql.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## ------------------------------------------ ## ## Report this to the AC_PACKAGE_NAME lists. ## ## ------------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF echo "$as_me:$LINENO: checking for library containing mysql_real_escape_string" >&5 echo $ECHO_N "checking for library containing mysql_real_escape_string... $ECHO_C" >&6 if test "${ac_cv_search_mysql_real_escape_string+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_func_search_save_LIBS=$LIBS ac_cv_search_mysql_real_escape_string=no cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char mysql_real_escape_string (); int main () { mysql_real_escape_string (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_search_mysql_real_escape_string="none required" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$ac_cv_search_mysql_real_escape_string" = no; then for ac_lib in mysqlclient; do LIBS="-l$ac_lib $ac_func_search_save_LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char mysql_real_escape_string (); int main () { mysql_real_escape_string (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_search_mysql_real_escape_string="-l$ac_lib" break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext done fi LIBS=$ac_func_search_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_search_mysql_real_escape_string" >&5 echo "${ECHO_T}$ac_cv_search_mysql_real_escape_string" >&6 if test "$ac_cv_search_mysql_real_escape_string" != no; then test "$ac_cv_search_mysql_real_escape_string" = "none required" || LIBS="$ac_cv_search_mysql_real_escape_string $LIBS" else canuse_mysql="no" fi else canuse_mysql="no" fi done fi if test "x$enable_static" = "xyes"; then LIBS=`mysql_config --libs 2>/dev/null` for ac_header in mysql.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## ------------------------------------------ ## ## Report this to the AC_PACKAGE_NAME lists. ## ## ------------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF echo "$as_me:$LINENO: checking for library containing mysql_real_query" >&5 echo $ECHO_N "checking for library containing mysql_real_query... $ECHO_C" >&6 if test "${ac_cv_search_mysql_real_query+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_func_search_save_LIBS=$LIBS ac_cv_search_mysql_real_query=no cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char mysql_real_query (); int main () { mysql_real_query (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_search_mysql_real_query="none required" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$ac_cv_search_mysql_real_query" = no; then for ac_lib in mysqlclient; do LIBS="-l$ac_lib $ac_func_search_save_LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char mysql_real_query (); int main () { mysql_real_query (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_search_mysql_real_query="-l$ac_lib" break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext done fi LIBS=$ac_func_search_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_search_mysql_real_query" >&5 echo "${ECHO_T}$ac_cv_search_mysql_real_query" >&6 if test "$ac_cv_search_mysql_real_query" != no; then test "$ac_cv_search_mysql_real_query" = "none required" || LIBS="$ac_cv_search_mysql_real_query $LIBS" else canuse_mysql="no" fi else canuse_mysql="no" fi done fi if test "x$canuse_mysql" = "xyes"; then for ac_func in mysql_autocommit do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$as_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define $ac_func to an innocuous variant, in case declares $ac_func. For example, HP-UX 11i declares gettimeofday. */ #define $ac_func innocuous_$ac_func /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $ac_func /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else char (*f) () = $ac_func; #endif #ifdef __cplusplus } #endif int main () { return f != $ac_func; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done fi MYSQLCFLAGS="$CFLAGS" MYSQLLIBS="$LIBS" CFLAGS="$PREVCFLAGS" CPPFLAGS="$PREVCPPFLAGS" LIBS="$PREVLIBS" fi if test "x$canuse_gdbm" = "xyes"; then PREVLIBS="$LIBS" LIBS="" for ac_header in gdbm.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## ------------------------------------------ ## ## Report this to the AC_PACKAGE_NAME lists. ## ## ------------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF echo "$as_me:$LINENO: checking for library containing gdbm_open" >&5 echo $ECHO_N "checking for library containing gdbm_open... $ECHO_C" >&6 if test "${ac_cv_search_gdbm_open+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_func_search_save_LIBS=$LIBS ac_cv_search_gdbm_open=no cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char gdbm_open (); int main () { gdbm_open (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_search_gdbm_open="none required" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$ac_cv_search_gdbm_open" = no; then for ac_lib in gdbm; do LIBS="-l$ac_lib $ac_func_search_save_LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char gdbm_open (); int main () { gdbm_open (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_search_gdbm_open="-l$ac_lib" break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext done fi LIBS=$ac_func_search_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_search_gdbm_open" >&5 echo "${ECHO_T}$ac_cv_search_gdbm_open" >&6 if test "$ac_cv_search_gdbm_open" != no; then test "$ac_cv_search_gdbm_open" = "none required" || LIBS="$ac_cv_search_gdbm_open $LIBS" for ac_func in gdbm_fdesc do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$as_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define $ac_func to an innocuous variant, in case declares $ac_func. For example, HP-UX 11i declares gettimeofday. */ #define $ac_func innocuous_$ac_func /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $ac_func /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else char (*f) () = $ac_func; #endif #ifdef __cplusplus } #endif int main () { return f != $ac_func; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done else canuse_gdbm="no" fi else canuse_gdbm="no" fi done if test "x$enable_static" = "xyes"; then LIBDIR=`echo "$LIBS" | tr ' ' '\n' | sed -n 's/^-L//p'` test -z "$LIBDIR" && LIBDIR=/usr/lib LIBLIST=`echo "$LIBS" | tr ' ' '\n' | sed -n "s,^-l,$LIBDIR/lib,p" | sed -e 's,$,.a,'` NEWLIBS="" for i in $LIBLIST; do test -e "$i" && NEWLIBS="$NEWLIBS $i" done test -n "$NEWLIBS" && LIBS="$NEWLIBS" fi GDBMLIBS="$LIBS" LIBS="$PREVLIBS" fi if test "x$canuse_sqlite" = "xyes"; then LIBS="" for ac_header in sqlite.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## ------------------------------------------ ## ## Report this to the AC_PACKAGE_NAME lists. ## ## ------------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF echo "$as_me:$LINENO: checking for library containing sqlite_open" >&5 echo $ECHO_N "checking for library containing sqlite_open... $ECHO_C" >&6 if test "${ac_cv_search_sqlite_open+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_func_search_save_LIBS=$LIBS ac_cv_search_sqlite_open=no cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char sqlite_open (); int main () { sqlite_open (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_search_sqlite_open="none required" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test "$ac_cv_search_sqlite_open" = no; then for ac_lib in sqlite; do LIBS="-l$ac_lib $ac_func_search_save_LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char sqlite_open (); int main () { sqlite_open (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_search_sqlite_open="-l$ac_lib" break else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext done fi LIBS=$ac_func_search_save_LIBS fi echo "$as_me:$LINENO: result: $ac_cv_search_sqlite_open" >&5 echo "${ECHO_T}$ac_cv_search_sqlite_open" >&6 if test "$ac_cv_search_sqlite_open" != no; then test "$ac_cv_search_sqlite_open" = "none required" || LIBS="$ac_cv_search_sqlite_open $LIBS" else canuse_sqlite="no" fi else canuse_sqlite="no" fi done if test "x$enable_static" = "xyes"; then LIBDIR=`echo "$LIBS" | tr ' ' '\n' | sed -n 's/^-L//p'` test -z "$LIBDIR" && LIBDIR=/usr/lib LIBLIST=`echo "$LIBS" | tr ' ' '\n' | sed -n "s,^-l,$LIBDIR/lib,p" | sed -e 's,$,.a,'` NEWLIBS="" for i in $LIBLIST; do test -e "$i" && NEWLIBS="$NEWLIBS $i" done test -n "$NEWLIBS" && LIBS="$NEWLIBS" fi SQLITELIBS="$LIBS" LIBS="$PREVLIBS" fi if test "x$canuse_list" = "xyes"; then for ac_header in search.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 else # Is the header compilable? echo "$as_me:$LINENO: checking $ac_header usability" >&5 echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest.$ac_objext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_header_compiler=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 echo "${ECHO_T}$ac_header_compiler" >&6 # Is the header present? echo "$as_me:$LINENO: checking $ac_header presence" >&5 echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null; then if test -s conftest.err; then ac_cpp_err=$ac_c_preproc_warn_flag ac_cpp_err=$ac_cpp_err$ac_c_werror_flag else ac_cpp_err= fi else ac_cpp_err=yes fi if test -z "$ac_cpp_err"; then ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 echo "${ECHO_T}$ac_header_preproc" >&6 # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ( cat <<\_ASBOX ## ------------------------------------------ ## ## Report this to the AC_PACKAGE_NAME lists. ## ## ------------------------------------------ ## _ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac echo "$as_me:$LINENO: checking for $ac_header" >&5 echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 if eval "test \"\${$as_ac_Header+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 fi if test `eval echo '${'$as_ac_Header'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF for ac_func in bsearch qsort do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 if eval "test \"\${$as_ac_var+set}\" = set"; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define $ac_func to an innocuous variant, in case declares $ac_func. For example, HP-UX 11i declares gettimeofday. */ #define $ac_func innocuous_$ac_func /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $ac_func /* Override any gcc2 internal prototype to avoid an error. */ #ifdef __cplusplus extern "C" { #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else char (*f) () = $ac_func; #endif #ifdef __cplusplus } #endif int main () { return f != $ac_func; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 (eval $ac_link) 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; } && { ac_try='test -s conftest$ac_exeext' { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 (eval $ac_try) 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then eval "$as_ac_var=yes" else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 if test `eval echo '${'$as_ac_var'}'` = yes; then cat >>confdefs.h <<_ACEOF #define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF else canuse_list="no" fi done else canuse_list="no" fi done fi echo "$as_me:$LINENO: checking which backend databases are available" >&5 echo $ECHO_N "checking which backend databases are available... $ECHO_C" >&6 BACKENDS="" if test "x$canuse_obtree" = "xyes"; then cat >>confdefs.h <<\_ACEOF #define USING_OBTREE 1 _ACEOF BACKENDS="$BACKENDS obtree" fi if test "x$canuse_btree" = "xyes"; then cat >>confdefs.h <<\_ACEOF #define USING_BTREE 1 _ACEOF BACKENDS="$BACKENDS btree" fi if test "x$canuse_list" = "xyes"; then cat >>confdefs.h <<\_ACEOF #define USING_LIST 1 _ACEOF BACKENDS="$BACKENDS list" fi if test "x$canuse_gdbm" = "xyes"; then cat >>confdefs.h <<\_ACEOF #define USING_GDBM 1 _ACEOF EXTRALIBS="$EXTRALIBS $GDBMLIBS" BACKENDS="$BACKENDS GDBM" fi if test "x$canuse_mysql" = "xyes"; then cat >>confdefs.h <<\_ACEOF #define USING_MYSQL 1 _ACEOF EXTRALIBS="$EXTRALIBS $MYSQLLIBS" CFLAGS="$CFLAGS $MYSQLCFLAGS" BACKENDS="$BACKENDS MySQL" fi if test "x$canuse_sqlite" = "xyes"; then cat >>confdefs.h <<\_ACEOF #define USING_SQLITE 1 _ACEOF EXTRALIBS="$EXTRALIBS $SQLITELIBS" CFLAGS="$CFLAGS $SQLITECFLAGS" BACKENDS="$BACKENDS SQLite2" fi if test "x$BACKENDS" = "x"; then echo "$as_me:$LINENO: result: none" >&5 echo "${ECHO_T}none" >&6 { { echo "$as_me:$LINENO: error: no usable database libraries found" >&5 echo "$as_me: error: no usable database libraries found" >&2;} { (exit 1); exit 1; }; } else echo "$as_me:$LINENO: result: $BACKENDS" >&5 echo "${ECHO_T}$BACKENDS" >&6 fi LIBS="$LIBS $EXTRALIBS" cat >>confdefs.h <<_ACEOF #define BACKENDS "$BACKENDS" _ACEOF test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' subdirs="" for i in `find $srcdir/src -type d -print | sed s,$srcdir/,,`; do subdirs="$subdirs $i" done mk_segments="autoconf/Makefile.in" for i in vars.mk package.mk filelist.mk unreal.mk modules.mk \ rules.mk link.mk depend.mk; do mk_segments="$mk_segments:autoconf/make/$i" done ac_config_files="$ac_config_files Makefile:$mk_segments doc/lsm:doc/lsm.in doc/quickref.1:doc/quickref.1.in doc/$PACKAGE.spec:doc/spec.in src/.dummy:doc/NEWS" ac_config_commands="$ac_config_commands default" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, don't put newlines in cache variables' values. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. { (set) 2>&1 | case `(ac_space=' '; set | grep ac_space) 2>&1` in *ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote # substitution turns \\\\ into \\, and sed turns \\ into \). sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n \ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" ;; esac; } | sed ' t clear : clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ : end' >>confcache if diff $cache_file confcache >/dev/null 2>&1; then :; else if test -w $cache_file; then test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" cat confcache >$cache_file else echo "not updating unwritable cache $cache_file" fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # VPATH may cause trouble with some makes, so we remove $(srcdir), # ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=/{ s/:*\$(srcdir):*/:/; s/:*\${srcdir}:*/:/; s/:*@srcdir@:*/:/; s/^\([^=]*=[ ]*\):*/\1/; s/:*$//; s/^[^=]*=[ ]*$//; }' fi DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_i=`echo "$ac_i" | sed 's/\$U\././;s/\.o$//;s/\.obj$//'` # 2. Add them. ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : ${CONFIG_STATUS=./config.status} ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 echo "$as_me: creating $CONFIG_STATUS" >&6;} cat >$CONFIG_STATUS <<_ACEOF #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then set -o posix fi DUALCASE=1; export DUALCASE # for MKS sh # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # Work around bugs in pre-3.0 UWIN ksh. $as_unset ENV MAIL MAILPATH PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. for as_var in \ LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ LC_TELEPHONE LC_TIME do if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then eval $as_var=C; export $as_var else $as_unset $as_var fi done # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)$' \| \ . : '\(.\)' 2>/dev/null || echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } /^X\/\(\/\/\)$/{ s//\1/; q; } /^X\/\(\/\).*/{ s//\1/; q; } s/.*/./; q'` # PATH needs CR, and LINENO needs CR and PATH. # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then echo "#! /bin/sh" >conf$$.sh echo "exit 0" >>conf$$.sh chmod +x conf$$.sh if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then PATH_SEPARATOR=';' else PATH_SEPARATOR=: fi rm -f conf$$.sh fi as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" || { # Find who we are. Look in the path if we contain no path at all # relative or not. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} { (exit 1); exit 1; }; } fi case $CONFIG_SHELL in '') as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for as_base in sh bash ksh sh5; do case $as_dir in /*) if ("$as_dir/$as_base" -c ' as_lineno_1=$LINENO as_lineno_2=$LINENO as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` test "x$as_lineno_1" != "x$as_lineno_2" && test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } CONFIG_SHELL=$as_dir/$as_base export CONFIG_SHELL exec "$CONFIG_SHELL" "$0" ${1+"$@"} fi;; esac done done ;; esac # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line before each line; the second 'sed' does the real # work. The second script uses 'N' to pair each line-number line # with the numbered line, and appends trailing '-' during # substitution so that $LINENO is not a special case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) sed '=' <$as_myself | sed ' N s,$,-, : loop s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, t loop s,-$,, s,^['$as_cr_digits']*\n,, ' >$as_me.lineno && chmod +x $as_me.lineno || { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensible to this). . ./$as_me.lineno # Exit status is that of the last command. exit } case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac if expr a : '\(a\)' >/dev/null 2>&1; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file echo >conf$$.file if ln -s conf$$.file conf$$ 2>/dev/null; then # We could just check for DJGPP; but this test a) works b) is more generic # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). if test -f conf$$.exe; then # Don't use ln at all; we don't have any links as_ln_s='cp -p' else as_ln_s='ln -s' fi elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.file if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_executable_p="test -f" # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" # IFS # We need space, tab and new line, in precisely that order. as_nl=' ' IFS=" $as_nl" # CDPATH. $as_unset CDPATH exec 6>&1 # Open the log real soon, to keep \$[0] and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. Logging --version etc. is OK. exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX } >&5 cat >&5 <<_CSEOF This file was extended by $as_me, which was generated by GNU Autoconf 2.59. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ _CSEOF echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 echo >&5 _ACEOF # Files that config.status was made for. if test -n "$ac_config_files"; then echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS fi if test -n "$ac_config_headers"; then echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS fi if test -n "$ac_config_links"; then echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS fi if test -n "$ac_config_commands"; then echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS fi cat >>$CONFIG_STATUS <<\_ACEOF ac_cs_usage="\ \`$as_me' instantiates files from templates according to the current configuration. Usage: $0 [OPTIONS] [FILE]... -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.59, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" Copyright (C) 2003 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." srcdir=$srcdir INSTALL="$INSTALL" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # If no file are specified by the user, then we need to provide default # value. By we need to know if files were specified by the user. ac_need_defaults=: while test $# != 0 do case $1 in --*=*) ac_option=`expr "x$1" : 'x\([^=]*\)='` ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` ac_shift=: ;; -*) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; *) # This is not an option, so the user has probably given explicit # arguments. ac_option=$1 ac_need_defaults=false;; esac case $ac_option in # Handling of the options. _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --vers* | -V ) echo "$ac_cs_version"; exit 0 ;; --he | --h) # Conflict between --help and --header { { echo "$as_me:$LINENO: error: ambiguous option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: ambiguous option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; };; --help | --hel | -h ) echo "$ac_cs_usage"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift CONFIG_FILES="$CONFIG_FILES $ac_optarg" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" ac_need_defaults=false;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 Try \`$0 --help' for more information." >&5 echo "$as_me: error: unrecognized option: $1 Try \`$0 --help' for more information." >&2;} { (exit 1); exit 1; }; } ;; *) ac_config_targets="$ac_config_targets $1" ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF if \$ac_cs_recheck; then echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF # # INIT-COMMANDS section. # subdirs="$subdirs" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_config_target in $ac_config_targets do case "$ac_config_target" in # Handling of arguments. "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile:$mk_segments" ;; "doc/lsm" ) CONFIG_FILES="$CONFIG_FILES doc/lsm:doc/lsm.in" ;; "doc/quickref.1" ) CONFIG_FILES="$CONFIG_FILES doc/quickref.1:doc/quickref.1.in" ;; "doc/$PACKAGE.spec" ) CONFIG_FILES="$CONFIG_FILES doc/$PACKAGE.spec:doc/spec.in" ;; "src/.dummy" ) CONFIG_FILES="$CONFIG_FILES src/.dummy:doc/NEWS" ;; "default" ) CONFIG_COMMANDS="$CONFIG_COMMANDS default" ;; "src/include/config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS src/include/config.h:autoconf/header.in" ;; *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 echo "$as_me: error: invalid argument: $ac_config_target" >&2;} { (exit 1); exit 1; }; };; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason to put it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Create a temporary directory, and hook for its removal unless debugging. $debug || { trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 trap '{ (exit 1); exit 1; }' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./confstat$$-$RANDOM (umask 077 && mkdir $tmp) } || { echo "$me: cannot create a temporary directory in ." >&2 { (exit 1); exit 1; } } _ACEOF cat >>$CONFIG_STATUS <<_ACEOF # # CONFIG_FILES section. # # No need to generate the scripts if there are no CONFIG_FILES. # This happens for instance when ./config.status config.h if test -n "\$CONFIG_FILES"; then # Protect against being on the right side of a sed subst in config.status. sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF s,@SHELL@,$SHELL,;t t s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t s,@exec_prefix@,$exec_prefix,;t t s,@prefix@,$prefix,;t t s,@program_transform_name@,$program_transform_name,;t t s,@bindir@,$bindir,;t t s,@sbindir@,$sbindir,;t t s,@libexecdir@,$libexecdir,;t t s,@datadir@,$datadir,;t t s,@sysconfdir@,$sysconfdir,;t t s,@sharedstatedir@,$sharedstatedir,;t t s,@localstatedir@,$localstatedir,;t t s,@libdir@,$libdir,;t t s,@includedir@,$includedir,;t t s,@oldincludedir@,$oldincludedir,;t t s,@infodir@,$infodir,;t t s,@mandir@,$mandir,;t t s,@build_alias@,$build_alias,;t t s,@host_alias@,$host_alias,;t t s,@target_alias@,$target_alias,;t t s,@DEFS@,$DEFS,;t t s,@ECHO_C@,$ECHO_C,;t t s,@ECHO_N@,$ECHO_N,;t t s,@ECHO_T@,$ECHO_T,;t t s,@LIBS@,$LIBS,;t t s,@PACKAGE@,$PACKAGE,;t t s,@VERSION@,$VERSION,;t t s,@UCPACKAGE@,$UCPACKAGE,;t t s,@CC@,$CC,;t t s,@CFLAGS@,$CFLAGS,;t t s,@LDFLAGS@,$LDFLAGS,;t t s,@CPPFLAGS@,$CPPFLAGS,;t t s,@ac_ct_CC@,$ac_ct_CC,;t t s,@EXEEXT@,$EXEEXT,;t t s,@OBJEXT@,$OBJEXT,;t t s,@CPP@,$CPP,;t t s,@LD@,$LD,;t t s,@ac_ct_LD@,$ac_ct_LD,;t t s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t s,@INSTALL_DATA@,$INSTALL_DATA,;t t s,@SET_MAKE@,$SET_MAKE,;t t s,@DO_GZIP@,$DO_GZIP,;t t s,@EGREP@,$EGREP,;t t s,@BACKENDS@,$BACKENDS,;t t s,@LIBOBJS@,$LIBOBJS,;t t s,@LTLIBOBJS@,$LTLIBOBJS,;t t CEOF _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # Split the substitutions into bite-sized pieces for seds with # small command number limits, like on Digital OSF/1 and HP-UX. ac_max_sed_lines=48 ac_sed_frag=1 # Number of current file. ac_beg=1 # First line for current file. ac_end=$ac_max_sed_lines # Line after last line for current file. ac_more_lines=: ac_sed_cmds= while $ac_more_lines; do if test $ac_beg -gt 1; then sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag else sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag fi if test ! -s $tmp/subs.frag; then ac_more_lines=false else # The purpose of the label and of the branching condition is to # speed up the sed processing (if there are no `@' at all, there # is no need to browse any of the substitutions). # These are the two extra sed commands mentioned above. (echo ':t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed if test -z "$ac_sed_cmds"; then ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" else ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" fi ac_sed_frag=`expr $ac_sed_frag + 1` ac_beg=$ac_end ac_end=`expr $ac_end + $ac_max_sed_lines` fi done if test -z "$ac_sed_cmds"; then ac_sed_cmds=cat fi fi # test -n "$CONFIG_FILES" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case $ac_file in - | *:- | *:-:* ) # input from stdin cat >$tmp/stdin ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; * ) ac_file_in=$ac_file.in ;; esac # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. ac_dir=`(dirname "$ac_file") 2>/dev/null || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` { if $as_mkdir_p; then mkdir -p "$ac_dir" else as_dir="$ac_dir" as_dirs= while test ! -d "$as_dir"; do as_dirs="$as_dir $as_dirs" as_dir=`(dirname "$as_dir") 2>/dev/null || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` done test ! -n "$as_dirs" || mkdir $as_dirs fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} { (exit 1); exit 1; }; }; } ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_builddir$INSTALL ;; esac if test x"$ac_file" != x-; then { echo "$as_me:$LINENO: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} rm -f "$ac_file" fi # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ if test x"$ac_file" = x-; then configure_input= else configure_input="$ac_file. " fi configure_input=$configure_input"Generated from `echo $ac_file_in | sed 's,.*/,,'` by configure." # First look for the input files in the build tree, otherwise in the # src tree. ac_file_inputs=`IFS=: for f in $ac_file_in; do case $f in -) echo $tmp/stdin ;; [\\/$]*) # Absolute (can't be DOS-style, as IFS=:) test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } echo "$f";; *) # Relative if test -f "$f"; then # Build tree echo "$f" elif test -f "$srcdir/$f"; then # Source tree echo "$srcdir/$f" else # /dev/null tree { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } fi;; esac done` || { (exit 1); exit 1; } _ACEOF cat >>$CONFIG_STATUS <<_ACEOF sed "$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s,@configure_input@,$configure_input,;t t s,@srcdir@,$ac_srcdir,;t t s,@abs_srcdir@,$ac_abs_srcdir,;t t s,@top_srcdir@,$ac_top_srcdir,;t t s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t s,@builddir@,$ac_builddir,;t t s,@abs_builddir@,$ac_abs_builddir,;t t s,@top_builddir@,$ac_top_builddir,;t t s,@abs_top_builddir@,$ac_abs_top_builddir,;t t s,@INSTALL@,$ac_INSTALL,;t t " $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out rm -f $tmp/stdin if test x"$ac_file" != x-; then mv $tmp/out $ac_file else cat $tmp/out rm -f $tmp/out fi done _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # # CONFIG_HEADER section. # # These sed commands are passed to sed as "A NAME B NAME C VALUE D", where # NAME is the cpp macro being defined and VALUE is the value it is being given. # # ac_d sets the value in "#define NAME VALUE" lines. ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' ac_dB='[ ].*$,\1#\2' ac_dC=' ' ac_dD=',;t' # ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' ac_uB='$,\1#\2define\3' ac_uC=' ' ac_uD=',;t' for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". case $ac_file in - | *:- | *:-:* ) # input from stdin cat >$tmp/stdin ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; * ) ac_file_in=$ac_file.in ;; esac test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 echo "$as_me: creating $ac_file" >&6;} # First look for the input files in the build tree, otherwise in the # src tree. ac_file_inputs=`IFS=: for f in $ac_file_in; do case $f in -) echo $tmp/stdin ;; [\\/$]*) # Absolute (can't be DOS-style, as IFS=:) test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } # Do quote $f, to prevent DOS paths from being IFS'd. echo "$f";; *) # Relative if test -f "$f"; then # Build tree echo "$f" elif test -f "$srcdir/$f"; then # Source tree echo "$srcdir/$f" else # /dev/null tree { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 echo "$as_me: error: cannot find input file: $f" >&2;} { (exit 1); exit 1; }; } fi;; esac done` || { (exit 1); exit 1; } # Remove the trailing spaces. sed 's/[ ]*$//' $ac_file_inputs >$tmp/in _ACEOF # Transform confdefs.h into two sed scripts, `conftest.defines' and # `conftest.undefs', that substitutes the proper values into # config.h.in to produce config.h. The first handles `#define' # templates, and the second `#undef' templates. # And first: Protect against being on the right side of a sed subst in # config.status. Protect against being in an unquoted here document # in config.status. rm -f conftest.defines conftest.undefs # Using a here document instead of a string reduces the quoting nightmare. # Putting comments in sed scripts is not portable. # # `end' is used to avoid that the second main sed command (meant for # 0-ary CPP macros) applies to n-ary macro definitions. # See the Autoconf documentation for `clear'. cat >confdef2sed.sed <<\_ACEOF s/[\\&,]/\\&/g s,[\\$`],\\&,g t clear : clear s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp t end s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp : end _ACEOF # If some macros were called several times there might be several times # the same #defines, which is useless. Nevertheless, we may not want to # sort them, since we want the *last* AC-DEFINE to be honored. uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs rm -f confdef2sed.sed # This sed command replaces #undef with comments. This is necessary, for # example, in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. cat >>conftest.undefs <<\_ACEOF s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, _ACEOF # Break up conftest.defines because some shells have a limit on the size # of here documents, and old seds have small limits too (100 cmds). echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS echo ' :' >>$CONFIG_STATUS rm -f conftest.tail while grep . conftest.defines >/dev/null do # Write a limited-size here document to $tmp/defines.sed. echo ' cat >$tmp/defines.sed <>$CONFIG_STATUS # Speed up: don't consider the non `#define' lines. echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS # Work around the forget-to-reset-the-flag bug. echo 't clr' >>$CONFIG_STATUS echo ': clr' >>$CONFIG_STATUS sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS echo 'CEOF sed -f $tmp/defines.sed $tmp/in >$tmp/out rm -f $tmp/in mv $tmp/out $tmp/in ' >>$CONFIG_STATUS sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail rm -f conftest.defines mv conftest.tail conftest.defines done rm -f conftest.defines echo ' fi # grep' >>$CONFIG_STATUS echo >>$CONFIG_STATUS # Break up conftest.undefs because some shells have a limit on the size # of here documents, and old seds have small limits too (100 cmds). echo ' # Handle all the #undef templates' >>$CONFIG_STATUS rm -f conftest.tail while grep . conftest.undefs >/dev/null do # Write a limited-size here document to $tmp/undefs.sed. echo ' cat >$tmp/undefs.sed <>$CONFIG_STATUS # Speed up: don't consider the non `#undef' echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS # Work around the forget-to-reset-the-flag bug. echo 't clr' >>$CONFIG_STATUS echo ': clr' >>$CONFIG_STATUS sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS echo 'CEOF sed -f $tmp/undefs.sed $tmp/in >$tmp/out rm -f $tmp/in mv $tmp/out $tmp/in ' >>$CONFIG_STATUS sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail rm -f conftest.undefs mv conftest.tail conftest.undefs done rm -f conftest.undefs cat >>$CONFIG_STATUS <<\_ACEOF # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ if test x"$ac_file" = x-; then echo "/* Generated by configure. */" >$tmp/config.h else echo "/* $ac_file. Generated by configure. */" >$tmp/config.h fi cat $tmp/in >>$tmp/config.h rm -f $tmp/in if test x"$ac_file" != x-; then if diff $ac_file $tmp/config.h >/dev/null 2>&1; then { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 echo "$as_me: $ac_file is unchanged" >&6;} else ac_dir=`(dirname "$ac_file") 2>/dev/null || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` { if $as_mkdir_p; then mkdir -p "$ac_dir" else as_dir="$ac_dir" as_dirs= while test ! -d "$as_dir"; do as_dirs="$as_dir $as_dirs" as_dir=`(dirname "$as_dir") 2>/dev/null || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` done test ! -n "$as_dirs" || mkdir $as_dirs fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} { (exit 1); exit 1; }; }; } rm -f $ac_file mv $tmp/config.h $ac_file fi else cat $tmp/config.h rm -f $tmp/config.h fi done _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF # # CONFIG_COMMANDS section. # for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue ac_dest=`echo "$ac_file" | sed 's,:.*,,'` ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'` ac_dir=`(dirname "$ac_dest") 2>/dev/null || $as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_dest" : 'X\(//\)[^/]' \| \ X"$ac_dest" : 'X\(//\)$' \| \ X"$ac_dest" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$ac_dest" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` { if $as_mkdir_p; then mkdir -p "$ac_dir" else as_dir="$ac_dir" as_dirs= while test ! -d "$as_dir"; do as_dirs="$as_dir $as_dirs" as_dir=`(dirname "$as_dir") 2>/dev/null || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| \ . : '\(.\)' 2>/dev/null || echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } /^X\(\/\/\)[^/].*/{ s//\1/; q; } /^X\(\/\/\)$/{ s//\1/; q; } /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` done test ! -n "$as_dirs" || mkdir $as_dirs fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} { (exit 1); exit 1; }; }; } ac_builddir=. if test "$ac_dir" != .; then ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` # A "../" for each directory in $ac_dir_suffix. ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` else ac_dir_suffix= ac_top_builddir= fi case $srcdir in .) # No --srcdir option. We are building in place. ac_srcdir=. if test -z "$ac_top_builddir"; then ac_top_srcdir=. else ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` fi ;; [\\/]* | ?:[\\/]* ) # Absolute path. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ;; *) # Relative path. ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_builddir$srcdir ;; esac # Do not use `cd foo && pwd` to compute absolute paths, because # the directories may not exist. case `pwd` in .) ac_abs_builddir="$ac_dir";; *) case "$ac_dir" in .) ac_abs_builddir=`pwd`;; [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; *) ac_abs_builddir=`pwd`/"$ac_dir";; esac;; esac case $ac_abs_builddir in .) ac_abs_top_builddir=${ac_top_builddir}.;; *) case ${ac_top_builddir}. in .) ac_abs_top_builddir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; esac;; esac case $ac_abs_builddir in .) ac_abs_srcdir=$ac_srcdir;; *) case $ac_srcdir in .) ac_abs_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; esac;; esac case $ac_abs_builddir in .) ac_abs_top_srcdir=$ac_top_srcdir;; *) case $ac_top_srcdir in .) ac_abs_top_srcdir=$ac_abs_builddir;; [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; esac;; esac { echo "$as_me:$LINENO: executing $ac_dest commands" >&5 echo "$as_me: executing $ac_dest commands" >&6;} case $ac_dest in default ) rm -f src/.dummy for i in $subdirs; do test -d $i || mkdir $i done ;; esac done _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF { (exit 0); exit 0; } _ACEOF chmod +x $CONFIG_STATUS ac_clean_files=$ac_clean_files_save # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || { (exit 1); exit 1; } fi qsf-1.2.7/test/0000755000076400007640000000000010665021416011102 5ustar awawqsf-1.2.7/test/t03-marknonspam0000644000076400007640000000122710561467751013774 0ustar awaw#!/bin/sh # # TEST: Non-spam mark readback: ./mboxsplit 1 < .test-non-spam | $PROG -d $BACKEND:$TESTDB -M -w 2 ISSPAM=0 ./mboxsplit 1 < .test-non-spam | $PROG -d $BACKEND:$TESTDB -t || ISSPAM=1 test $ISSPAM -eq 0 test $BACKEND = MySQL && exit 0 test $BACKEND = mysql && exit 0 if test "$BACKEND" != "obtree"; then UPDATECOUNT1=`$PROG -d $BACKEND:$TESTDB -D | sed -n 's/^COUNT-UPDATES //p'` for NUM in 1 2 3 4 5 6 7 8 9 10; do ./mboxsplit $NUM < .test-spam | $PROG -d $BACKEND:$TESTDB -M done UPDATECOUNT2=`$PROG -d $BACKEND:$TESTDB -D | sed -n 's/^COUNT-UPDATES //p'` DIFFERENCE=`expr $UPDATECOUNT2 - $UPDATECOUNT1` test $DIFFERENCE -eq 10 fi qsf-1.2.7/test/t13-attach0000644000076400007640000000335110301706473012700 0ustar awaw#!/bin/sh # # TEST: Tokenising HTML attachments: rm -f $TESTDB MALLOC_CHECK_=2 export MALLOC_CHECK_ cat > $TESTDB </dev/null (echo From: blah@test3.com; echo; echo test) | $PROG -d $BACKEND:$TESTDB -yM >/dev/null $PROG -d $BACKEND:$TESTDB -ymme @Test3.com (echo From: test@test3.com; echo; echo test) | $PROG -d $BACKEND:$TESTDB -ayt >/dev/null || exit 0 exit 1 qsf-1.2.7/test/t07-dbprune10000644000076400007640000000070110211420133013135 0ustar awaw#!/bin/sh # # TEST: Automatic database pruning (1): $PROG -d $BACKEND:$TESTDB -D > .testdump-a $PROG -d $BACKEND:$TESTDB -D | grep SINCEPRUNE > .testdump-b ./mboxsplit 1 < .test-non-spam \ | $PROG -d $BACKEND:$TESTDB -m >/dev/null $PROG -d $BACKEND:$TESTDB -D | grep SINCEPRUNE > .testdump-c bash -c "if cmp -s .testdump-a .testdump-b; then exit 1; fi; exit 0" $PROG -d $BACKEND:$TESTDB -R < .testdump-a rm -f .testdump-a .testdump-b .testdump-c qsf-1.2.7/test/t16-plainmap0000644000076400007640000000060610507170163013237 0ustar awaw#!/bin/sh # # TEST: Plaintext map: rm -f $TESTDB ./mboxsplit 1 < .test-spam | $PROG -d $BACKEND:$TESTDB -P $TESTFILE -m -w 2 ISSPAM=0 ./mboxsplit 1 < .test-spam | $PROG -d $BACKEND:$TESTDB -t || ISSPAM=1 test $ISSPAM -eq 1 ./mboxsplit 2 < .test-spam | $PROG -d $BACKEND:$TESTDB -P $TESTFILE -m COUNT=`wc -l < $TESTFILE | tr -d ' '` test "$COUNT" -gt 2 && exit 0 exit 1 qsf-1.2.7/test/t20-locking0000644000076400007640000000322010561467716013067 0ustar awaw#!/bin/sh # # TEST: Concurrency / locking: rm -f $TESTDB ./mboxsplit 1 < .test-spam | $PROG -d $BACKEND:$TESTDB -m UPDATECOUNT1=`$PROG -d $BACKEND:$TESTDB -D | sed -n 's/^COUNT-UPDATES //p'` ((echo From: test1@test.com; echo Subject: test; echo; cat .test-spam ) | $PROG -d $BACKEND:$TESTDB -aM) & ((echo From: test2@test.com; echo Subject: test; echo; cat .test-spam ) | $PROG -d $BACKEND:$TESTDB -aM) & ((echo From: test3@test.com; echo Subject: test; echo; cat .test-spam ) | $PROG -d $BACKEND:$TESTDB -aM) & ((echo From: test4@test.com; echo Subject: test; echo; cat .test-spam ) | $PROG -d $BACKEND:$TESTDB -aM) & ((echo From: test5@test.com; echo Subject: test; echo; cat .test-spam ) | $PROG -d $BACKEND:$TESTDB -aM) & ((echo From: test6@test.com; echo Subject: test; echo; cat .test-spam ) | $PROG -d $BACKEND:$TESTDB -aM) & ((echo From: test7@test.com; echo Subject: test; echo; cat .test-spam ) | $PROG -d $BACKEND:$TESTDB -aM) & ((echo From: test8@test.com; echo Subject: test; echo; cat .test-spam ) | $PROG -d $BACKEND:$TESTDB -aM) & wait $PROG -d $BACKEND:$TESTDB -te test1@test.com $PROG -d $BACKEND:$TESTDB -te test2@test.com $PROG -d $BACKEND:$TESTDB -te test3@test.com $PROG -d $BACKEND:$TESTDB -te test4@test.com $PROG -d $BACKEND:$TESTDB -te test5@test.com $PROG -d $BACKEND:$TESTDB -te test6@test.com $PROG -d $BACKEND:$TESTDB -te test7@test.com $PROG -d $BACKEND:$TESTDB -te test8@test.com test $BACKEND = MySQL && exit 0 test $BACKEND = mysql && exit 0 if test $UPDATECOUNT1 -gt 0; then UPDATECOUNT2=`$PROG -d $BACKEND:$TESTDB -D | sed -n 's/^COUNT-UPDATES //p'` DIFFERENCE=`expr $UPDATECOUNT2 - $UPDATECOUNT1` test $DIFFERENCE -eq 8 fi qsf-1.2.7/test/t05-trainvalid0000644000076400007640000000055610211420137013564 0ustar awaw#!/bin/sh # # TEST: Validity of trained database: for SPAM in 1 12 3 7 9; do ISSPAM=0 ./mboxsplit $SPAM < .test-spam \ | $PROG -d $BACKEND:$TESTDB -t || ISSPAM=1 test $ISSPAM -eq 1 || exit 1 done for NONSPAM in 5 13 2 8 14; do ISSPAM=0 ./mboxsplit $NONSPAM < .test-non-spam \ | $PROG -d $BACKEND:$TESTDB -t || ISSPAM=1 test $ISSPAM -eq 0 || exit 1 done qsf-1.2.7/test/tokenlist-non-spam0000644000076400007640000056714510125255411014604 0ustar awaw$.02 $id $id $ipc _base64_ _getbytes aaa aaa01585 aaa01744 aaa05442 aaa05468 aaa20267 aaa20289 aaa29487 aaa30846 aaa30864 abc abc.bat abc123 abcd ability ability ability ability able able able able able able able able able able able able able able able able able about about about about about about about about about about about about about about about about about about about about about about about about about about about about about about about about about about about about about about about about about above above above above above above above above above above above abstract abstract abstract abstract abstract abstract academic accept accept accepts access access access access access access access access access access access access access access access access access access access access access access access access access access access access access access accessed accessed accessing accessing accessing according according account account account account acknowledge acknowledges acknowledges across across action action action action action action action actions actions actions actions actions activex activex activex activex activities activity activity activity activity activity activity activity activity activity activity activity activity activity activity activity activity activity activity activity activity activity activity activity actually actually actually ad20030318.html ad20030318.html add addendum adding addition addition addition addition addition addition additional additional additional additional additional additional additionally additionally additionally additions additions address address address address address address address address address address address address address address address address address address address address address address address address address address address address address address address addresses addresses addresses addresses addresses addresses addressing addressing addressing adds adequately adhere admin admin admin123 administrative administrative administrative administrative administrative administrative administrative administrative administrative administrative administrative administrative administrator administrator administrator administrator administrator administrator administrator administrator administrators administrators administrators administrators administrators administrators administrators admins advanced advanced advanced advanced advanced advanced advanced advantages advantages advantages advantages advantages advantages advantages advantages advantages advantages advice advice advice advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisories advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory advisory affect affect affect affect affect affect affected affected affected affected affected affected affected affected affected affected affected affected affected affected affected affected affected affected affected affected affected affected affected affected affected affected affected affected affected affected affected affected affected affected affected affected affected affecting affecting affects affects affects aforementioned africa after after after again again against against against against against agent agent agent agent agent agents agents agents agents agents agents agents agreement agreement agrees ai aiding aix aix aix aix aix aix aix aix aix aix aix ala alcatel alcatel alcatel alcatel alcatel alcatel alcatel alcatel alcatel alcatel alcatel alcatel alcatel's alert alert alert alert alertdetail.jsp alertdetail.jsp alerts alive alive alive alive alive all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all all allen allman allman allocate allocate allocation allocation allow allow allow allow allow allow allow allow allow allow allow allow allow allow allow allow allow allow allow allow allow allow allow allowed allowed allowed allowed allowed allowed allowed allowed allowed allows allows almost alone alone along along along along along along alpha already already already also also also also also also also also also also also also also also also also also also also also also also also also also also also also also also also also also also also also also also also also also also also also also also also also alter alter alternatively alternatively alternatively although although although although although altogether am am am am am am am am am am am ambiguity america america among amount amounts an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an an analysis analysis and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and and anderson andrew andrew andrew andrew andrew andrew andrew andrew andrew andrew andrew andrew's andrew's anf announcement announcement announcements announcements announcements annual annual_rpts another another another another another another another another another another another ans ansi answer answer answer answer answer answer answer answer answer answer answer anti-virus anti-virus anti-virus anti-virus anti-virus anti-virus any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any any anyone anyone anyone anyone anyone anyone anyone anyone anyone anything anything anything anyway anyway anyway anyway aos aos aos aos aos aos aos aos aos aos aos apar apar apar apar apar apar api api api api api api api api api api api api api api api api api apis apologize app app app app app app app app app app1 app1 app1's app1's app2 apparent appear appear appear appeared appears appended appendix appendix appendix appendix appendix appendix appendix appendix appendix appendix appendix appendix appendix appendix appendix appendix appendix appendix appendix appendix appendix appendix appendix appendix appendix apple apple apple apple appliance appliance appliance appliances application application application application application application application application application application applications applications applications applications applications applications applications applications applications applications applications applications applications applications applications applications applications applications applications applications applications applied applied applied applied apply apply apply apply apply apply apply apply apply apply apply apply apply apply apply apply apply apply apply apply applying applying appointment approach appropriate appropriate appropriate appropriate approval approval approx approx approx apps apps apps arbitrary arbitrary arbitrary arbitrary arbitrary arbitrary arbitrary arbitrary arbitrary arbitrary arbitrary arbitrary arbitrary arbitrary arbitrary arbitrary arbitrary arbitrary arbitrary arbitrary arbitrary architect architect architect architect architect architecture architecture architecture archive archive archive archive archiving are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are are area arg arg argument around around around arpa arpa arpa arpanet array art article article article articles as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as as asdf ask ask ask ask asked asked asked asking asp assertion assertion assertion assertion assertion assessing assetrade.com assetrade.com assigned assistance assistance assistance assisting assmann assmann associated associated associated associated associated assume assume assumed assuming assuming assuming assumtion assumtion assumtion at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at at attached attached attack attack attack attack attack attack attack attack attacker attacker attacker attacker attacker attacker attacker attacker attacker attacker attacker attacker attacker attacker attacker attacker attacker attacker attacker attacker attacker attacker attacker attacker attacker attacker attacker attacker attacker attackers attackers attackers attackers attackers attackers attackers attackers attackers attackers attackers attackers attacking attacks attacks attacks attacks attacks attacks attacks attacks attacks attacks attacks attacks attacks attacks attacks attempt attempt attempting attempting attempts attempts attempts attempts attention attention attest attributes attributes attributes attributes attributes attributes attributes attributes attributes attributes attributes attributes audit auth-module authenticate authentication authentication authentication authentication authentication authentication authentication author author author author authored authoritative authorized authors authors authors authors authors autoconf autodesk autodesk autodesk autodesk autodesk autodesk.autodesk.com autodesk.autodesk.com autodesk.autodesk.com autodesk.autodesk.com autodesk.autodesk.com autodesk.autodesk.com autodesk.autodesk.com autodesk.autodesk.com autodesk.autodesk.com autodesk.autodesk.com autodesk.autodesk.com autodesk.autodesk.com autodesk.autodesk.com autodesk.autodesk.com autodesk.autodesk.com autodesk.autodesk.com autodesk.autodesk.com autodesk.autodesk.com autodesk.autodesk.com autodesk.autodesk.com autodesk.autodesk.com autodesk.com autodesk.com autodesk.com autodesk.com autodesk.com autodesk.com autodesk.com autodesk.com autodesk.com autodesk.com autodesk.com autodesk.com autodesk.com autodesk.com autodesk.com autodesk.com autodesk.com autodesk.com autodesk.com autodesk.com autodesk.com autodesk.com automated automated automatic automatic automatic automatically automatically availabe availabe availability availability availability availability available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available available avaya avaya aw aw aw aw aw aw aw aw aw aw aw aw aw aw aw aw aw aw aw aw aw aw aw aw aw aw aw aw await aware aware aware away baa16263 back back back back backdoor backdoor backdoor backdoors backdoors backdoors background bad bag bag ball ball bang base base base base base based based based based based based basic basic basically basically basilisk basis basis basis basis basis basis basis basis basis basis basis be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be be beat because because because because because because because because because becomes becomes becomes becomes becomes been been been been been been been been been been been been been been been been been been been been been been been been been been been been before before before before before before before before before before before begin beginning beginning beginning beginnings beginnings beginnings begins begins behalf behalf behalf behavior behavior behavior behavior being being being being being being being being being being being being being being being believe believe believe believe believe believed believed below below below below below below below below below below below below below below berkeley best best best beta better better better better better better better better better better betting betting betting betting betting between between between between between between between between between between bgjyskeeagbnaglkvazui48totc bi-directional bibliographic big binaries bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind bind-8.2.6-1u60_2cl.i386.rpm bind-security.html bind4 bind4910.diff bind8 bind826.diff bind833.diff bind9.html binhex bit bit bit bit bit bloated block block block block block block block block block block blocking blocking blocking blocking bodies bodies body body body body body body body body body body book book book book book books books books books border border border border border borderware borderware borderware borenstein bot bot bot bot both both both both both both both both both both both both both bots bots bouncing box box box boxes boxes boxes brand bring brisbane brisbane brisbane brisbane brisbane brisbane brisbane britney broadband broadband broadband broadband broadcast broadcast broadcast brow browse brush brush bsd bsd bsd bsd bsd bsd-derived bthbfwdeley btw buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer buffer bug bug bug bug build build build building built built bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulk bulletin bulletin bulletin bulletin bulletin bulletin bulletins bulletins bulletins bulletins bulletins bulletins bulletins bulletins bulletins bulletins busy but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but but bvlive01.iss.net by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by by bytes bytes c-client c-client c.diff c06 c07 c07-sip ca-2001-18 ca-2001-18 ca-2001-18.html ca-2001-20 ca-2001-20 ca-2001-20 ca-2001-20.html ca-2002-03 ca-2002-19 ca-2002-22 ca-2002-22 ca-2002-22.html ca-2002-31 ca-2002-31 ca-2002-31.html ca-2002-32 ca-2002-32 ca-2002-32.html ca-2002-36 ca-2002-36.html ca-2002-37 ca-2002-37.html ca-2003-02 ca-2003-02.html ca-2003-03 ca-2003-03.html ca-2003-04 ca-2003-04.html ca-2003-06 ca-2003-06 ca-2003-06 ca-2003-06.html ca-2003-06.html ca-2003-07 ca-2003-07 ca-2003-07 ca-2003-07 ca-2003-07 ca-2003-07.html ca-2003-07.html ca-2003-08 ca-2003-08 ca-2003-08 ca-2003-08 ca-2003-08.html ca-2003-08.html ca-2003-09 ca-2003-09 ca-2003-09 ca-2003-09 ca-2003-09.html ca-2003-09.html ca-2003-10 ca-2003-10 ca-2003-10.html ca-2003-11 ca-2003-11 ca-2003-11.html ca-2003-12 ca-2003-12 ca-2003-12.html cache cache cache cache cache cached cached cached caching calendar calendar calendar calendar calendar calendar calendar calendarevolution calendarexch calendarlotus calendars calendars call call call call call call call call call call call call call call call call call call call call call call call call call call call call called called called called called called called called calls calls calls calls calls came came came came came can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can can't can't can't can't can-2002-0029 can-2002-1219 can-2002-1220 can-2002-1221 can-2002-1272 can-2002-1272 can-2002-1272 can-2002-1272 can-2002-1337 can-2003-0028 can-2003-0109 can-2003-0109 can-2003-0161 canaveral.indigo.cert.org canaveral.indigo.cert.org canaveral.indigo.cert.org canaveral.indigo.cert.org canaveral.indigo.cert.org canaveral.indigo.cert.org canaveral.indigo.cert.org canaveral.indigo.cert.org canaveral.indigo.cert.org canaveral.indigo.cert.org canaveral.indigo.cert.org canaveral.indigo.cert.org canaveral.indigo.cert.org canaveral.indigo.cert.org canaveral.indigo.cert.org canaveral.indigo.cert.org canaveral.indigo.cert.org canaveral.indigo.cert.org canaveral.indigo.cert.org canaveral.indigo.cert.org candidate candidate cannot cannot capabilites capabilites capabilities capabilities capabilities capabilities capabilities capabilities capabilities capabilities capabilities capabilities capabilities capabilities capabilities capabilities capabilities capabilities capabilities capabilities capability capability capability capability capability capability capability capability capability capability capability capability capability capability capability capability capability capability capability capability capability capable capable capacity capacity carcass carcass carcass carcass carcass card care care careful carefully carefully carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie carnegie case case case case cases cast cause cause cause cause cause cause cause cause cause cause cause cause cause cause cause cause cause caused caused causing causing causing cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cc cclient ccn celebs celest celest's celestial celestial celestial celestial celestial celestial celestial celestial celestial celestial celestial celestial celestial celestial celestial celestial celestial celestial celestialwizard celestialwizard celestialwizard celestialwizard celestialwizard celestialwizard celestialwizard celestialwizard celestialwizard celestialwizard celestialwizard celestialwizard celestialwizard cell center center center center center center center center center center center center center center center center center center center center center center center center center center center center center center center center center central central ceo ceo ceo ceo ceo cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert cert-advisory cert-advisory cert-advisory cert-advisory cert-advisory cert-advisory cert-advisory cert-advisory cert-advisory cert-advisory cert-advisory cert-advisory cert-advisory cert-advisory cert-advisory cert-advisory cert-advisory cert-advisory cert-advisory cert-advisory cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert.org cert_pgp.key cert_pgp.key cert_pgp.key cert_pgp.key cert_pgp.key cert_pgp.key cert_pgp.key cert_pgp.key cert_pgp.key cert_pgp.key cert_rpt_02.html cert_stats.html certain certain certainly certainly certainly certainly certainly certainly cexchangeemail cexchangeemail cexchangeemail cexchangeemail cexchangeemail cexchangeemail cexchangeemail cexchangeemail cexchangeemail cexchangeemail cexchangeemail cgi cgi cgi cgi cgi-bin cgi-bin cgi-bin cgi-bin cgi-bin cgi-bin cgi-bin cgi-bin chad challenger change change change changed changed changes changes changes changes changes changes changes changes changes changes changes changes channel channel channel channel channels chapter chapter chapter char char char char char char char char char char char character character character characteristics charset charset charset charset charset charset charset charset charset charset charset charset charset charset charset charset charset charset charset charset charset charset charset charset charset charset charter chat check check check check check check check check check_inbox_mail check_inbox_mail check_new checked checked checking checklist checklist checknew checknew checknew checknew checknew checknew checknew checknew checknew checks cheers cheers chips chips choice choice choose chosen cifs cifs cisco cisco cited claim claimed claimed clarification clarify class class class class class class class class class class class class class classes classes classes classes classes classes classes classifications claus claus clavister clavister clearly clever clicks clicks clien client client client client client client client client client client clients clients clients close cns code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code code coder coding coding com com come comer comer comes comes coming command commands commands commands comments comments comments comments comments comments comments comments comments comments comments comments comments comments comments comments comments comments comments commercial commercial commercial commercial common common common common common common commonly commonly commonly commonly commonly communicate communicate communication communication communication communication community community community community compact company company company company company company company company company company's company's compatibility compatibility compete compiled compiled compiled compiled compiled compiled complete complete complete complete complete complete complete complete complete complete complete complicated component components comprised compromise compromise compromise compromise compromise compromise compromise compromise compromise compromise compromised compromised compromised compromised compromised compromised compromised compromised compromised compromised compromised compromised compromised compromised compromised computer computer computer computer computer computer computer computer computer computer computer computer computers computers computers computers computers computing computing computing computing computing computing concentrated concept concern conclusive concrete concurrent condition condition condition condition conditions conditions conditions conditions conditions conditions conditions conditions conditions conditions conditions conditions conducted conducts conectiva conectiva confidential config config config configurable configurable configuration configuration configurations configured configured configured confirm conflict confused confused confusing confusion connect connect connect_to_exchange connect_to_exchange connecting connection connection connection connection-oriented connection-oriented connections connections connections connectivity connects consider consider consider consider consider consider consider consideration considered consist consistency consistent consistent consists consortium consortium consortium consortium consortium constant constructed constructed constructor constucting constuction consult contact contact contact contact contact contact contact contact contact contact contact contact contact contact contact contact contact contact contact contacted contacts contain contain contain contain contain contain contain contain contain contain container container containing containing contains contains contains contains contains contains contains contains contains contains contains contains contains contains contains contains contains content content content content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-length content-md5 content-transfer-encoding content-transfer-encoding content-transfer-encoding content-transfer-encoding content-transfer-encoding content-transfer-encoding content-transfer-encoding content-transfer-encoding content-transfer-encoding content-transfer-encoding content-type content-type content-type content-type content-type content-type content-type content-type content-type content-type content-type content-type content-type content-type content-type content-type content-type content-type content-type content-type content-type content-type content-type content-type content-type content-type content-type content-type content-types content-types contents contents contents contents contents contents contents contents context context continue continue continuing continuing continuous contribute contribute contribute control control control control control control control control control control control control control control control control control control control control control control control controllers controllers controlling convention converting convince cool cool cool cool cooperating cooperation coordinating coordinating coordination coordination coordination coordination coordination coordination coordination coordination coordination coordination coordination coordination coordination coordination coordination coordination coordination coordination coordination coordination coordination coordination coordination coordination coordination coordination coordination coordination coordination coordination coordination coordination copied copies copies copies copies copy copy copy copy copy copyleft copyright copyright copyright copyright copyright copyright copyright copyright copyright copyright copyright copyright copyright copyright copyright copyright copyright copyright copyright copyright copyright copyright copyright copyright core core core core core core core core core core core core core core core core core core core core core core core core core core core core core core core core core core core core_action core_action core_action core_action core_action core_action core_fini core_fini core_init corel corel corporate corporation corporation corporation corporation corporation corporation corporation corporation correct correct correct correct correct correct correct correct corrected corrections corrections correctly correctly correctly corresponds corresponds corruption could could could could could could could could could could could could could could could could could could could could could could could could could could could could could could could could could could counter counter countermeasures course course course courses courses courses courses courses cout cpu cracking crafted crafted crash crash crash crash crash crash cray cray cray cray cray cray create create create create create create created created creating crispin critical critiques crocker cross cryptographically cs-2002-04 cs-2003-01 cs-2003-01 cs-2003-01.html cst cst cst cst cst cst cst cst culminating current current current current current current current_activity.html currently currently currently currently currently currently currently currently currently currently currently currently currently currently currently currently currently currently currently currently customer customers customers customers customers cve cve cve cve cve cve.mitre.org cve.mitre.org cve.mitre.org cvename.cgi cvename.cgi cvename.cgi cvs cvs cvs cvs cvs cvs cvs cvsroot cvsroot cvsroot cvsroot cvsroot cvsweb.cgi cvsweb.cgi cvsweb.cgi cvsweb.cgi cvsweb.cgi cya cygwin cygwin cygwin1.dll d7d0fdy5u2sy3kk daemon daemon daemon daemon daemon daemon daemon daemon daemon daemon daemonised daev damn danyliw data data data data data data data data data database database database database database database databases date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date date-handle date-handle date-handle date-handle date-handle date-handle dave day day day day days days days dbar5cjjjs dbar5cjjjs dbm dbncdsyq62m dcom dcom dcom dcom dcom dcom-clone ddos ddos ddos ddos ddos ddos de-reference de-reference de-reference deal dealing deals debian debian debian debian debian debian debian debian debian debian debian debian debian decent decent decide decide decide decide decide declaration declarations decnet decrement decremented defacement default default default default default default default default.asp default.aspx default.aspx default.aspx default.aspx default.aspx defect definately definately define define define define define define defines definetally definetly defining defining defining definite definite definite definite definite definitely definitely definitions definitions definitive degradation degradation degree delete delete delete delete delete delete deletes deletes deletes delivered-to delivered-to delivered-to delivered-to delivered-to delivered-to delivered-to delivered-to delivered-to delivery delivery delivery delivery delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date delivery-date deloder deloder deloder deloder deloder deloder deloder deloder denial denial denial denial denial denial denial denial denial denial denial denial-of-service denial-of-service denial-of-service denial-of-service denial-of-service denial-of-service denial-of-service denial-of-service denial-of-service denial-of-service denial_of_service.html density dependency dependency dependency depending depending depends deploy deployed dereference derived des des des des des des des des des des described described described described described described described described described described described described described describes describes describing describing describing describing describing description description description description description description description description description description description description description descriptions descriptive descriptive design design design design designed designed designed desktop desktop desktop desktop desktop desktop desktop desktop destroy detached detail detail detail detail detailed detailed detailed detailed detailing details details details details details details.aspx detect detect detected detection determine determine determine determine determine determined determined dev developer developer developers developers developers developing developing development development development development development development development development development development development development development development developments device device device devices devices devices devices devices dgbi dialog dialup dictates dictionary did didn't didn't didn't diff diff diff difference different different different different different different different different difficult difficulty diffs digest digital digital direct directed directed directed directed directed directed directly directly directly directory directory disable disable disable disable disable disable disable disable disable disable disable disable disabled disabling disabling disabling disabling disadvantages disadvantages disadvantages disclaimer disclaimer disclaimers disclaimers disclaimers disclaimers disclaimers disclaimers disclaimers disclaimers disclaimers disclaimers disclose disclosure discovered discovered discovered discovered discovered discovered discovered discovered discovered discovered discovered discoveries discovering discovering discovering discovering discovery discuss discuss discussed discussed discussed discusses discussion discussion--but display displaylang disrupt disrupt disrupt disrupt distinct distinct distinct distribute distributed distributed distributed distributed distributed distributed distributes distribution distributions distributions distributions distributions ditto ditto dll dll dlls dns dns dns dns dns dns dns dns dns dns dns dns dns dns dns dns dns dns dns dns.pdf do do do do do do do do do do do do do do do do do do do do do do do do doable doc doc document document document document document document document document document document document document document document document document document document document document document document documentation documentation documentation documentation documentation documentation documentation documentation documentation documentation documented documenting documenting documents documents documents does does does does does does does does does does does does does does does does does does does does does does does does does doesn't doesn't doesn't doesn't doesn't doesn't doh doh doing doing dointerface dole domain domain domain domain domain domain domain domain domain domain domain domain domain domains domino domino domino domino domino domino domino domino domino domino domino domino domino domino domino domino domino domino domino domino don't don't don't don't don't don't don't don't don't don't don't don't don't don't don't don't don't don't don't don't done done done done done done done done done dont dont dont dont dos_trends.pdf double-free double-free double-free doubt dougherty douglas douglas down down downgrading downgrading download downloads downloads downstream draft draw draw drive drop dropped drops drops drops dual-booting due due duplicate duplicated during during during during during during during during during during during during during during during during dvldr32.exe dvldr32.exe dwuu4w6nc8 dwuu4w6nc8 dymically dynamic dynamically dynamically dynamically dynamically dzq4smrocgeamjtvndzyp e-mail e-mail e-mail e-mailing e-mails e.g e.g e.g e0xjut e602 each each each each each each each each each each each each each each each each each earlier earlier earlier earlier earlier earlier easier easier easier easier easier east east east east east east east east easy easy ed.ac.uk ed.ac.uk ed.ac.uk ed.ac.uk ed.ac.uk ed.ac.uk ed.ac.uk edition edition editor edns0 edt edt edt edt edt edt edt edt edt edt eeye eeye effect effectively efforts efix efixes eg eg eggert egress egress egress egress egress eh eh ehhh ehhh eisa8 either either either either either either either either either either either either either either either either el el el el el elaboration elaboration elaboration elaboration elaboration electronic electronic electronic elements elements elements eliminate else else else else else else's em email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email email-handle email-handle email-handle email-handle email-handle email-handle emailexch emails emails emailunix emailunix emanating emergencies emergencies emergencies emergencies emergencies emergencies emergencies emergencies emergencies emergencies employer employer employing emulate en en en en en en en en en en en en en en en en en en en en en en en en en en en en en en-us en-us en-us en-us enable enable enable enabled enabled enabled enabled enabled enabled encapsulate encapsulate encapsulate encapsulate encapsulate encapsulate encapsulation encapsulation encoded encoding encoding encoding encoding encoding encoding encourage encouraged encouraged encouraged encouraged encouraged encouraged encouraged encourages encourages encourages encourages encrypt encrypt encrypt encrypt encrypt encrypt encrypt encrypt encrypt encrypt encryption encryption encryption encryption encryption encryption encryption encryption encryption encryption end end end end end end end end end end end engine engineering engineering engineering engineering engineering engineering engineering engineering engineering engineering engineering engineering engineering engineering engineering engineering engineering engineering engineering engineering engineering engineering engineering engineering engineering enlighten enlighten enough enough enriched ensure ensure ensure ensure entering enterprise enters enters enticing entire envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to envelope-to environment environment envision equivalences er eric eric errata errata errata errata errata errata errata errors errors errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to errors-to es escalating escwngixvg8 esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp esmtp especially especially essence essentially est est est est est est est est est est est est est est est est est established established etc etc etc etc etc etc etc etc etc etc etc etc etc etc etc etc etc etc etc etc etc etc etc etc etc etc etc etc etc etc etc etc etc europe europe evaluation even even even even even even even even eventually every everyday everyone everything everything everything evidence evolution evolution evolution ews ews exacerbated exact exact exactly examine examine example example example example examples examples examples examples examples examples examples examples excellent except except exceptions excess exch exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchange exchangemail exclusivity exclusivity exclusivity exclusivity exclusivity exclusivity exclusivity exclusivity exclusivity exclusivity execs execute execute execute execute execute execute execute execute execute execute execute execute execute execute execute execute execute execute execution execution execution execution execution exercise exhibit exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exim exists exists exists exists exists exists exit exited exp exp expanding expected expected expected expected experience experience experience experiment experiment expire expiry expiry expiry explicitly explicitly explicitly explicitly exploit exploit exploit exploit exploit exploit exploit exploit exploit exploit exploit exploitable exploitable exploitable exploitable exploitation exploitation exploitation exploitation exploitation exploitation exploitation exploitation exploitation exploitation exploitation exploitation exploitation exploitation exploited exploited exploited exploited exploited exploiting exploiting exploiting exploiting exploiting exploiting exploits explorer.exe export expose exposed exposed exposed exposure exposures exposures express expressed expressed expressed expressed expressed expressed expressed expressed expressed expressed extend extended extensible extension extension extension extension extensions extensions extensions extensions extent external external external external external external.server.telinco.net external.server.telinco.net external.server.telinco.net external.server.telinco.net externally externally extra extra extremely f5 f5 faa05344 faa05373 faa09489 facility fact fact fail fails fails fails fails fair fairly fall familiar familiar family family familyid far far far farrell farrell farrell farrell farrell farrell farrell farrell farrell fault fax fax fax fax fax fax fax fax fax fax fbgs3t feasibility features feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb feb february february february february february february feedback feedback feedback feedback feedback feel feel feel feel fellow fetch fetch fetch fetch fetched fetched fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.0.3 fetchmail-5.9.0 fetchmail-5.9.0 fetchmail-5.9.0 fetchmail-5.9.0 fetchmail-5.9.0 fetchmail-5.9.0 fetchmail-5.9.0 fetchmail-5.9.0 fetchmail-5.9.0 fetchmail-5.9.0 few few few few field field field field field field figure figure figured file file file file file file file file file file file file file file file file file file file file file file file file file file file file file file file file-sharing filename filename files files files files files files files files files files files files files filter filtering filtering filtering filtering filtering filtering filtering filtering filtering filtering filtering filtering filtering filters filters filters filters filters finally find findnew findnew findnew fine fine fine fine fine finlay finlay finlay finlay firewall firewall firewall firewall firewall firewall firewall firewalls firewalls firmware first first first first fit fit fit fitness fitness fitness fitness fitness fitness fitness fitness fitness fitness fix fix fix fix fixed fixed fixes fixes flow flow flow flow flow fly focus focused folder foldername folders folders folders folders folders folks folks follow follow follow follow follow following following following following following following following following following following following following following following following following following following following following following following following following following following following following following following following following follows follows follows foo foobar footprint for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for for fork form formalized formalized formalized format format format format format format format format format format format format format format formats formats formats formatted found found found found found found found found found found found found found found found foundation foundation foundation fprintf fragment fragment framework framework framework framework framework framework framework free free free free free free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 free5946793-2 freebsd freebsd-sa-02 freed freedom freedom freedom freedom freedom freedom freedom freedom freedom freedom freezes frequent frequently frequently frequently frequently fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri fri friday friday friday friday friday friday friday friday friday friday friendly friends from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from from fsalert ftp ftp ftp ftp ftp ftp ftp ftp ftp ftp ftp ftp ftp ftp ftp ftp ftp ftp ftp ftp ftp.isi.edu ftp.sendmail.org ftp.sendmail.org ftp.sendmail.org ftp.sendmail.org ftp.sendmail.org ftp.software.ibm.com fujitsu fujitsu fujitsu fujitsu's full full full full fullest fully fun fun fun fun fun function function function function function function function function function function function function function function function function functional functionalities functionality functionality functionality functionality functionality functionality functionality functionality functionality functionality functions functions functions functions functions functions functions funny funny furnished furnished furnished furnished furnished furnished furnished furnished furnished furnished furnished furnished furnished furnished furnished furnished furnished furnished furnished furnished further further further further further further further further further further further furthering furthering furthermore furthermore furthermore future fw fw fwlink gae7lr813506 gain gain gain gain gain gain gain gain gain gain gain gain gaining gaining galff2f09722 game gateway gatewaying gateways gather gauntlet gee general general general general general general general generally generate generate generated generously generously geocrawler.com geocrawler.com geocrawler.com get get get get get get get get get get get get get get get get get get get get get get get get get_date get_date get_date get_mail get_mail get_new_messages get_new_messages gets gets gets getting getting getting getting getting getting getting getting getting getting getting getting gibabit give given given given given given gives gives giving gkuasz5 glibc glibc glibc glibc glibc glibc glibc glibc glibc global global global global glue gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt gmt-4 gmt-4 gmt-4 gmt-4 gmt-4 gmt-4 gmt-4 gmt-4 gmt-4 gmt-4 gmt-5 gmt-5 gmt-5 gmt-5 gmt-5 gmt-5 gmt-5 gmt-5 gmt-5 gmt-5 gnome gnome gnome gnome gnome gnome gnome gnome gnome gnu gnu gnu gnu gnu gnu gnu gnu gnu gnu gnu gnu gnustep go go go go go go go-mhs go.microsoft.com goal goal goals god godblessyou goes goes goes going going going going going going going going going going going going going gold good good good good good good good good good good good got gpl.html gr2000 graphical great great great great great great greg greg group group group group group group group group group group groups groupware groupware gt-bot gt-bot gt-bot gt-bot gtk gtk gtk gtk gtk gtk gtk gtk gtk gtk guaranteed guess guess guidelines h1lfoct05572 h23i6pe08387 h2bm2sb00787 h2hj67t09681 h2jjqgn20834 h2lk2fo09587 h2qgffc22224 h2tjucl30759 h_setreturnurl habit hack hacked hacker had had half half hammered hand handle handle handled handler handler handles handling handling handling handling happier happier happy happy happy happy happy harmful has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has has hash hashing hasn't hassell hat hat hat hat hat hat hat hat hat hat hat hat hat hat hat hat hat hate have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have have haven't haven't having having having having having havrilla hayes hbfj hbpvxv3v0wyix39u3dh header header header header header header header header headers headers headers headers headers headers headers heard heard heavy hebrew hectic hehe hell hell hell hell helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo helo help help help help help help help help help help help help hence here here here here here here here here here here's hereby hernan hernan hewlett hewlett hewlett-packard hewlett-packard hewlett-packard hewlett-packard hewlett-packard hewlett-packard hewlett-packard hi hi hi hidden hidden hidden hide high high high high high high high high-impact high-order highest hired his his his history history history history history history history history history history history history history history history history history history history history history history history history history history hitachi hitachi's hits hkxybmvx0lgrdyvmjo hmm hmm hmm hmm hmm holidays holidays holidays holidays holidays holidays holidays holidays holidays holidays holyrood.ed.ac.uk holyrood.ed.ac.uk holyrood.ed.ac.uk holyrood.ed.ac.uk holyrood.ed.ac.uk holyrood.ed.ac.uk home home home home home home home home home home home home home home home home home home home.tampabay.rr.com home.tampabay.rr.com home.tampabay.rr.com home.tampabay.rr.com home.tampabay.rr.com home_networks.html homecomputersecurity homer.mmm.co.uk homer.mmm.co.uk homer.mmm.co.uk homer.mmm.co.uk homer.mmm.co.uk homer.mmm.co.uk homer.mmm.co.uk homer.mmm.co.uk homer.mmm.co.uk homer.mmm.co.uk homeusers hood hope hope hopefully hopefully hopefully horton host host host host host host host host host host host host hosts hosts hosts hosts hosts hosts hosts hotline hotline hotline hotline hotline hotline hotline hotline hotline hotline hotline hotline hotline hotline hotline hotline hotline hotline hotline hotline hotline hotline hotline hotline hotline hotline hotline hotline hotline hotline hours hours hours hours hours hours hours hours hours hours householder how how how how how how how how how how how how how how how how how how how how how how how how how however however however however however however however however however however however however however however however hp hp hp hp hp hp hp hp hp hp hp hp hp's hp's hp-mpe hp-ux hp.com hqmsgsrf00.autodesk.com hqmsgsrf00.autodesk.com hqmsgsrf00.autodesk.com hqmsgsrf00.autodesk.com hqmsgsrf00.autodesk.com hqmsgsrf00.autodesk.com hqmsgsrf00.autodesk.com hqmsgsrf00.autodesk.com hqmsgsrf00.autodesk.com hqmsgsrf00.autodesk.com hqmsgsrf00.autodesk.com hqmsgsrf00.autodesk.com hqmsgsrf00.autodesk.com hqmsgsrf00.autodesk.com html html html html html html html html html html.charters html.charters http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http http huge huge hunt i'd i'd i'd i'd i'd i'd i'd i'd i'd i'd i'll i'll i'll i'll i'll i'll i'll i'll i'll i'll i'll i'll i'll i'll i'll i'll i'm i'm i'm i'm i'm i'm i'm i'm i'm i'm i'm i'm i'm i'm i'm i'm i'm i'm i'm i'm i'm i'm i'm i'm i'm i'm i'm i've i've i've i've i've i've i've i've i've i've i've i've i've i've i've i've i've i've i've i've i've i've i've i've i've i've i.e i.e i.e i.e i.e i.e i.e i.e i.e i.e i386 i386 i686 i686 iaa02452 iaa06053 iaa09617 iaa29620 iaa31120 iaa31137 ian ian ian ian ian ian ian ian ian ibm ibm ibm ibm ibm ibm icapabilitycalendar icapabilityemail icapabilityemail icapabilityemail icapabilitytasks icmp icmp id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id id idea idea idea idea idea idea idea idea ideal ideally ideas ident ident ident ident ident ident ident ident identifier identity ie ie ietf if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if if ignore ihavenopass ii ii ii ii ii ii ii ii ii iii iii iii iii iii iii iii iii iii iis iis iis iis iis iis iis iis iis iis iis iis iis iis iis iis iis iis iis im im im im.yahoo.com imagine imagining imagining imap imap imap imap imap imap imap2 imap2bis imap4 imap4 imap4 imho imho impact impact impact impact impact impact impact impact impact impact impact impact impact impact impact impact impact impact impact impacted impacts impacts impacts impacts implement implement implement implement implement implement implement implement implement implementation implementation implementation implementation implementation implementation implementation implementation implementation implementation-wise implementations implementations implementations implementations implementations implementations implementations implementations implementations implementations implementations implementations implementations implementations implementations implementations implementations implemented implemented implemented implemented implemented implementing implementing implementing implements implications implied implied implied implied implied implied implied implied implied implied import important important important important impossible improperly improperly in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in in-2000-02 in-2000-02 in-2000-02.html in-2000-03 in-2000-03 in-2000-03.html in-2002-03 in-2002-03 in-2002-03.html in-2002-06 in-2002-06 in-2002-06.html in-notes in-reply-to in-reply-to in-reply-to in-reply-to in-reply-to in-reply-to inadequately inbound inbound inbound inbound inbound inbox inbox inbox inbox inbox inbox inbox inbox inbox inbox inbox inbox inbox inbox inbox inc inc inc inc inc inc inc inc inc inc inc inc inc inc inc inc inc inc inc inc inc inc inc inc inc inc inc inc.'s inc.'s inc.'s incident incident incident incident_notes incident_notes incident_notes incident_notes incident_notes incidentally incidents include include include include include include include include include include include include include include include include include include included included included included includes includes includes includes includes includes includes includes includes including including including including including including including including including including including including including including including including including including including including including including including including inclusion incomplete incorporate incorporating increase increase increased increased increased increased increased increases increases increasing increasing indeed independant independent index.phps index.phps indexing indicate indicate indicated indicates indicates indicator indirectly individual individual individual infect infected infected infected infected infecting infection information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information information infrastructure infringement infringement infringement infringement infringement infringement infringement infringement infringement infringement ingress ingress ingress ingress ingress ingress ingress ingrian ingrian inherently init initial initial initial initial initial initial initial initial initial initialization initiate initiate initiate initiate initiated initiated initiating initiation initiation initiation initiation initiation initiation initiation initiation initiation initiation initiation initiation initiation initiation initiation initiation initiation inotes inotes inotes inotes inotes inside inst.exe install install install installation installations installed installed installed installed installed installed installed installing installing installing installs instance instance instance instant instant instant instant instead instead instead institute institute institute institute institute institute institute institute institute institute institute institute institute institute institute institute institute institute institute institute instructions instructions instructions int int int int int int int int int int int int integer integer integer integer integer integer integration intelligence intended intenet interact interact interactive interchange interchange interested interested interested interesting interesting interface interface interface interface interfaces interfaces interfaces interfaces interfaces interfacing interfacing interfacing interfacing interior interior interior interior intermediary internail internal internal internal internal internal internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet internet-connected internetworking internetworking interpretation interpreted interruptions into into into into into into into into into intruder intruder intruder intruder intruder intruder intruder intruder intruder-developed intruders intruders intruders intruders intruders intruders intruders intruders intruders intruders invalid invalid invalid invalid invalid investigate investigate investigated investigating investigating investigating investigating investigating investigating investigation invite invoked invoked invoked invoked invoked invoked invoked invoked invoked invoked invoked involve involved involved involved involved involving involving ip ip ip ip ip ip ip ip ip ip ipc ipc ipfilter ipso iptel irc irc irc irc irc irc irc irc irc irc irc irc irc-pitchfork irc-pitschfork irix is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is is isc isc isc isc isc isc isc isc isc isc's isi isi isi iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk iskra.connectfree.co.uk isn't isn't isn't isn't isn't isn't isn't isn't isn't iso iso iso-8859-1 iso-8859-1 iso-8859-1 iso-8859-1 iso-8859-1 iso-8859-1 iso-8859-1 iss issen issen issue issue issue issue issue issue issue issue issue issue issue issue issue issue issue issue issue issue issue issue issue issue issue issued issued issued issued issued issued issues issues issues issues issues issues issues issues issues issues issues issues issues issues issues issues issues issues issues issues issues issues issues issues issues issues issues issues issues issuing it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it it's it's it's it's it's it's it's it's item item item items items its its its its its its its its itself itself itself itself iv ix ix ixs4u50qpnhufw iy38434 iy38524 iy39231 iy40500 iy40501 iy40502 jaa00676 jaa11248 jaa32485 jaa32514 jack january january jason jason jeff jeffrey jeffrey jg_soft jgsoft.net joe joe joe joe joe joe joe joe joe joe joe joe joe joe joe joe joe joe joe joe joe joe joins joke joke jsp judgements july jump junk just just just just just just just just just just just just just just just just just just just just just just just just-send-8 kaa01541 kaa03626 kaa03653 kaa07427 kab kadmind kadmind kadmind kadmind kadmind kb kb kb kb kb kde's keep keep keep keep keep keep keep keep keep keep keep keep keep keep keep keep keep keep keeping keeping keeping kept kerberos kerberos kerberos kerberos key key key key key key key key key key key key keys keys kick kick-ass kind kind kind kind kind kind kind kind kind kind kind kind kind kind kind kind kind kind kind kind kind kind kits kits kits kiz kiz kiz kiz kludge know know know know know know know know know know know know know know know know know know know know know know know know know know know know know know know know know know know know know know know know know know know know know know know knowledge knowledge knowledge knowledge knowledge knowledge knowledge knowledgebase known known known known known known known known known known known knows knows korean krb5 kspr5dfjtr kspr5dfjtr kspr5htlw6 kspr5htlw6 kspr5htqhs kspr5htqhs kspr5hupek kspr5hupek kspr5huq59 kspr5huq59 laa02661 laa11000 laa11022 laa11169 laa11195 laa21446 laboratory laboratory lan language languages lanza large large large large large large large large large large last last last last last last last last last last last last last lately later later later later later later later latest latest launch launch launch launching lawsuit lay layer layer layout layout layout ldap ldap ldap ldap ldapv3 ldd lead lead lead lead lead leading leak leakage learn learn learn learn learn learn learning learning learning learning least least least least least leave leave leaves leaves leaving legal legible legitimate length length lengthy less less let let let let let's let's level level level levels leverage lib lib-mail-cclient-perl libc libc libc libc libc libc libc libnsl libraries libraries libraries libraries libraries libraries libraries libraries libraries libraries libraries libraries libraries libraries libraries libraries libraries libraries libraries libraries libraries library library library library library library library library library library library library library library library library library library libresolv libroxen-webmail libs libs libs libs like like like like like like like like like like like like like like like like like like like like like like like like like like like like likely likely likely likely likely likely likewise likewise likewise likewise limit limit limited limited limited limited limited limited limited limited limited limited limited limited limited limiting limiting line lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines lines linked linked linked linked linked linked linked linked linked linked linked linked linked linked linked linked linkid linking linking links links links linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux linux lioten lioten list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list list-archive list-archive list-archive list-archive list-archive list-archive list-archive list-archive list-archive list-help list-help list-help list-help list-help list-help list-help list-help list-help list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-id list-owner list-owner list-owner list-owner list-owner list-owner list-owner list-owner list-owner list-post list-post list-post list-post list-post list-post list-post list-post list-post list-subscribe list-subscribe list-subscribe list-subscribe list-subscribe list-subscribe list-subscribe list-subscribe list-subscribe list-unsubscribe list-unsubscribe list-unsubscribe list-unsubscribe list-unsubscribe list-unsubscribe list-unsubscribe list-unsubscribe list-unsubscribe listed listed listed listed listed listed listed listed listed listed listed listed listen listen listen listening listening listening listening listening listhdrs listhdrs listhdrs listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo listinfo lists lists lists lists lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net lists.sourceforge.net little little little little little little little ln lnchuser lnchuser lnchuser lnchuser lnchuser lnchuser lnchuser lnchuser lnchuser lnchuser load load load load load load load load loaded loaded loaded loaded local local local local local local local local local local local local local local local local localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localhost localmail localmail localmail located located located location location locations locations locations locations locator locator locator locator locator lockdown lockdown lockdown lockdown log log login login login login long long long long long long long long-run longer longer longer look look look look look look look look looking looking looking looking looks looks looks lookups lookups lookups loony losing loss lot lot lot lot lot lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus lotus-60dos.txt lotus-hostlocbo.txt lotus-inotesclientaxbo.txt lotus-inotesoflow.txt lotus-inotesoflow.txt love lower-level lower-level lower-level ltd ltd ltd ltd ltd lucas.ucs.ed.ac.uk lucas.ucs.ed.ac.uk lucas.ucs.ed.ac.uk lucas.ucs.ed.ac.uk lucas.ucs.ed.ac.uk lucas.ucs.ed.ac.uk lucas.ucs.ed.ac.uk lucas.ucs.ed.ac.uk lucas.ucs.ed.ac.uk lucas.ucs.ed.ac.uk lucas.ucs.ed.ac.uk lucas.ucs.ed.ac.uk lucas.ucs.ed.ac.uk lucas.ucs.ed.ac.uk lucent lucent lying m4 m420-032 m431-002 m500-006 maa13557 maa13583 maa25924 maa26013 mac mac mac mac mac mac mac mac machine machine machine machine machine machine machine machine machines machines machines machines machines machines machines macmime macro macros mactinosh made made made made made made made maik mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail mail-11 mail-safe mail.mmm.co.uk mail.mmm.co.uk mail.mmm.co.uk mail.mmm.co.uk mail.mmm.co.uk mail.mmm.co.uk mail.mmm.co.uk mail.mmm.co.uk mail.mmm.co.uk mail.mmm.co.uk mail1.postnet.com mail1.postnet.com mail1.postnet.com mail1.postnet.com mail1.postnet.com mail1.postnet.com mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail1.sourceforge.net mail2.postnet.com mail2.postnet.com mail2.postnet.com mail2.postnet.com mail2.postnet.com mail2.postnet.com mail2.postnet.com mail2.postnet.com mail2.postnet.com mail2.postnet.com mail2.postnet.com mail2.postnet.com mail2.postnet.com mail2.postnet.com mail2.postnet.com mail2.postnet.com mail2.postnet.com mail2.postnet.com mailbox mailbox mailbox mailbox mailbox mailbox mailbox mailbox mailboxes mailboxes mailboxes maildrops maildrops maildrops mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailing mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailman mailspool mailto mailto main main main main main.exe maintain maintains maintenance majordomo majordomo majordomo majordomo majordomo majordomo majordomo majordomo majordomo majordomo majority make make make make make make make make make make make make make make make make make make make make make make make make make make make make make make make make make make make make make make makefile makes makes makes makes makes makes makes makes makes makes makes makes makes makes making making making malformed malformed malformed malformed malicious malicious malicious malicious malicious malicious malicious malicious malicious malicious malicious malicious malicious malicious malicious malicious malicious malicious malicious malicious malicious management manages manages manages manages managing managing managing_dos.pdf mandrake mandrake manion manipulate manner manner manually many many many many many many many many many many many many many many many many mapped mapping mapping mapping mapping mapping mapping mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar mar29 march march march march march march march march march march march march mark mars matching material material material material material material material material material material material material material material material material material material material material matter matter matter matter matter matter matter matter matter matter mature max_int may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may may maybe maybe maybe maybe maybe maybe maybe maybe mbmsl7d2qamcuznczq5 mbox mcgrath me me me me me me me me me me me me me mean mean mean mean mean mean mean means means means measure mechanism mechanism mechanism mechanisms mechanisms mechanisms media mediateam medium medium-sized medium-sized meeting meeting meeting meetings meetings meetings mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon mellon memory memory memory memory memory memory memory memory mentioned mentioned mentioned mentioned mentioned mentioned mentioned mentioned mentioned mentioned mentioned mentioned merchantability merchantability merchantability merchantability merchantability merchantability merchantability merchantability merchantability merchantability merge merge merge merlin.hatfields.com.au merlin.hatfields.com.au merlin.hatfields.com.au merlin.hatfields.com.au merlin.hatfields.com.au merlin.hatfields.com.au merlin.hatfields.com.au merlin.hatfields.com.au merlin.hatfields.com.au merlin.hatfields.com.au merlin.hatfields.com.au merlin.hatfields.com.au merlin.hatfields.com.au merlin.hatfields.com.au merlin.hatfields.com.au merlin.hatfields.com.au merlin.hatfields.com.au merlin.hatfields.com.au merlin.hatfields.com.au merlin.hatfields.com.au merlin.hatfields.com.au merlin.hatfields.com.au merlin.hatfields.com.au message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-id message-oriented message-oriented messages messages messages messages messages messages messages messages messages messages messages messages messages messages messages messages messages messages messages messages messages messages messages messaging messaging messaging messaging messenger methinks method methods methods methods methods methods methods methods methods methods methods methods methods methods methods mh michal michal microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft microsoft's microsoft's microsoft.com microsystems microsystems microsystems microsystems microsystems microsystems middle middle midst might might might might might might might might might might might migrating millerp mime mime mime mime mime mime mime mime mime mime mime mime mime mime mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mime-version mine mine mine mine mine mine miscellaneous miscellaneous miscellaneous miscellaneous miscellaneous miscellaneous miscellaneous miscellaneous miscellaneous miscellaneous miscellaneous miscellaneous miscellaneous miscellaneous mit mit mitigate mitigation mitigation mitkrb5-sa-2003-003-xdr.txt mk mlfl mmm.co.uk mmm.co.uk mmm.co.uk mmm.co.uk mmm.co.uk mmm.co.uk mmm.co.uk mmm.co.uk mmm.co.uk mobile.att.net mode models modified module module module module module module module module module module module module module module module module module module module module module module module module module module module module module module module module module module module module module module module module module module module module module module module's module's module_action module_capability_load modules modules modules modules modules modules modules modules modules modules modules modules modules modules modules modules modules modules modules modules modules modules modules modules modules modules modules modules modules modules modules modules modules modules modules modules molotov.home.net molotov.home.net molotov.home.net molotov.home.net molotov.home.net molotov.home.net momentum momentum mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon mon monday monday monday monday monday monday monday monday monday monday monitor monitoring monkey monkey monkey monkey monkey monster montavista montavista months moore more more more more more more more more more more more more more more more more more more more more more more more more more more more more more more more more more more more more more more more more more more more more more more most most most most most most most most most most most most most most most most most most most most most most most motnt02-148.postnet.com motnt02-148.postnet.com motnt02-148.postnet.com motnt04-100.postnet.com motnt04-100.postnet.com motnt04-100.postnet.com motnt04-23.postnet.com motnt05-71.postnet.com mouthful move movemail mozilla mozilla mozilla mozilla mozilla mozilla mozilla mozilla mozilla mozilla mp mpp ms ms ms-rpc ms-rpc ms-sql ms-sql ms03-007 ms03-007.asp msantana msantana msantana msantana msantana msde msde mta mta mta mta mta mta mta mta mta mta mta mta mta mtas mtas mtas mtas mtp-nimail mua much much much much much much much much much much much much much much multimedia multimedia multiple multiple multiple multiple multiple multiple multiple multiple multiple multiple multiple multiple multiple multiple multiple multiple multiple multiple multiple multiple multiple multiple multiple multiple multiple multiple multiple multiple multiple multiplex multipurpose munging must must must must must must must mutt mutt my my my my my my my my my my my my my my my my my my my my my my my my my my mypass mypass123 mypc mypc123 mysql mysql naa07988 name name name name name name name name name name name name name name name name name name name name name name name name name name name named named named named named named named named names names names names names nameserver nameserver nameserver nameservers naming narayanan nastiness nat nayxdx34qbkg9iwvrxtgzkh nbt neat nec nec nec necessarily necessarily necessary necessary necessary necessary necessary necessary necessary need need need need need need need need need need need need need need need need need need need need need need need need need need need need need need need need need need need need need need needed needed needs needs needs needs needs needs needs needs neither net net net net net net net netapp netapp netbios netbios netbsd netbsd netbsd netfilter netfilter.org netscreen netscreen network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network network networking networking networks networks networks networks networks networks networks networks networks networks networks networks networks networks networks networks networks never never nevermind nevermind nevertheless nevertheless nevertheless nevertheless nevertheless new new new new new new new new new new new new new new new new new new new new new new new new new new new new new0godrj newest newly newly news next next next next next next next next-by-date next-by-thread nextgen ngs ngs ngs ngs ngs ngs ngs ngs ngs nice nice nice nice nice nice nice nice nisr17022003a nisr17022003b nisr17022003b nisr17022003d nisr17022003e nix nmap no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no no nobody nokia nokia nokia nokia nokia nokia nokis nominum nominum nominum nominum nominum's non-ascii non-ascii non-authorized non-authorized non-existent non-existent non-existent non-existent non-existent non-recursive non-recursive non-spam non-spam none nonstop noone nor normal normal normal normal normal normal normal normal normal normal normal nortel nortel nortel nortel nortel north not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not not note note note note note note note note note note note note note note note note note note note note note note note note noted noted notes notes notes notes notes notes notes notes notes notes notes notes notes notes notes notes notes notes notes notes notes notes noteworthy nothing nothing nothing nothing notice notice notice noticed noticed noticed notifications notifications notified notified notifying nov nov nov nov nov nov nov nov nov nov nov nov novell novell november november november november november now now now now now now now now now now now now now now now now now now now now now now now ns0.connectfree.co.uk ns0.connectfree.co.uk ns1.autodesk.com ns1.autodesk.com ns1.autodesk.com ns1.autodesk.com ns1.autodesk.com ns1.autodesk.com ns1.autodesk.com ns1.autodesk.com ns1.autodesk.com ns1.autodesk.com ns1.autodesk.com ns1.autodesk.com ns1.autodesk.com ns1.autodesk.com ns1.autodesk.com ns1.autodesk.com ns1.autodesk.com ns1.autodesk.com ns1.autodesk.com ns1.autodesk.com ns1.autodesk.com nt nt nt nt nt nt nt nt nt nt nt nt nt nt ntdll.dll ntdll.dll ntksu4a2henojjgumreg72h7xg null null null null null null null null null number number number number number number number number number number number number number number number number number numerous numerous nuts nuts nuts nxdomain o.s o.s o3m01dtlzvmn083tqn22zxl oaa22817 oaa22846 oaa22853 oaa22882 oar oaunjirmgdtr object object object object object objective-c objective-c objective-c objective-c objective-c objective-c objective-c objective-c objective-c objective-c objects observed obtain obtain obtain obtain obtained obtained obtained obtained obtained obtained obtained obtained obtained obtained obvious obviously obviously obviously obviously obviously obviously obviously occasionally occur occur occurred octets of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of of off off off off-site offer offered offered office office office office office office office office office office office office office official official official officially often oh oid oid ok ok ok ok old old older older olivier omniswitch omniswitch omniswitch omniswitch omniswitch omniswitch omniswitch_7000_brief omniswitch_7000_brief.pdf omnithread_rt.dll on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on on once once once once once one one one one one one one one one one one one one one one one one one one one one one one one one one one one-liner ones ongoing online online online only only only only only only only only only only only only only only onto oo oo oo oo oo oo oo oo oo oo oo oo oo-ish open-source open-source open-source opendocument opened opened opening openmail opens openvms openwall openwall openwall openwall operating operating operating operating operating operating operating operating operating operating operating operation operation operation operation operation operation operation operational operations operations operations opinion opinions opinions opposed opposed opt opt opt opt option option option option options options options options oqxuhve7wthj or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or or oracle orangutan orangutan orangutan orangutan orangutan orbit order order order order order order organisation organization organization organization organization organization organization organization organization organization organizations organizations organizations organizations oriented oriented oriented origin original original original original original original original original original originally originally originally originally os os os os os os os os os os os os other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other other_sources others others others others others others oulu oulu oulu our our our our our our our our our our our our our our our our our our our our our our our our our our our our our our our our our our our our our our our our our our our our our our our our our our our our ouspg ouspg ouspg ouspg ouspg ouspg ouspg ouspg ouspg ouspg ouspg's out out out out out out out out out out out out out out out out out out out-of-net outbound outermost outermost outlined outlined outlook outlook outlook outlook outlook outlook outlook outlook outlook outside outside outside over over over over over over over over over over over over over over over over over over over overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflows overflows overflows overflows overflows overly overly overly overly overly oversight overview overview overview overview overview overview overview overview overview own own owner p961 pa pa pa pa pa pa pa pa pa pa paa23486 paa23525 paa26676 paa26702 pack pack package package package package package packages packages packages packages packages packard packard packet packet packet packet packet packet page page page page page page page page page pages pages pages pages pain panel paper paper paper paper paradigm parallel parameter paridaens parsing parsing part part part part part part part part part partial partial particular particular particular particular particular particular particular particular particular particular particular particular particular particular particular particular particular particular particular particular particular particular particular particular particularly partridge pass pass pass pass pass pass pass pass passed passes passing passive passwd password password password password password password password.asp passwords passwords passwords passwords passwords passwords passwords passwords passwords passwords passwords passwords passwords passwords passwords past past past past pat patch patch patch patch patch patch patch patch patch patch patch patch patch patch patch patch patch patch patch patch patch patch patch patch patch patch patch patch patch patch patch patch patch patch patched patched patched patched patched patched patched patched patches patches patches patches patches patches patches patches patches patches patches patches patches patches patches patches patches patches patches patches patches patches patches patches patches patches patches patches patches.sgi.com patent patent patent patent patent patent patent patent patent patent patent patent patent patent patent patent patent patent patent patent patent path path path patrick paul payload payload pays pbeczsnvxerg7pthft8ee9olr pc pc pcmail pd4vldvjqhe pdf pdf pdf pdf pdf pdf pdf pdf pdf pdf pdf peace peace peace peace peace pending pending pending people people people people people people people people people per per-host perform perform perform performance performed performed perhaps perimeter perimeter perimeter perimeter perl perl perl perl perl perl perl perl perl perl perl perl perl perl permit permitted person personal personal personal personal personal personally personally personally personally personally personnel personnel personnel personnel personnel personnel personnel personnel personnel personnel perspective perspective pfhu pfoz pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp pgp phew phone phone phone phone phone phone phone phone phone phone phones php php php php php php php php php pics piece pieces pim pine pipes pittsburgh pittsburgh pittsburgh pittsburgh pittsburgh pittsburgh pittsburgh pittsburgh pittsburgh pittsburgh place place place place place place place place place placing plain plain plain plain plain plain plain plain plain plain plain plain plain plain plain plain plain plain plain plain plain plain plain plain plain plain plan planning planning platform platform platform-independent platforms platforms platforms platforms platforms platforms platforms platforms play playstation playstation please please please please please please please please please please please please please please please please please please please please please please please please please please please please please please please please please please please please please please please please please please please please plug plugin plus plus pm pm point point point point pointer pointers pointers pointing poisoning poke poking poking policies policy policy policy poll poorly poorly poorly poorly pop pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3 pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk pop3.connectfree.co.uk popular popular popular popular popular popular popular port port port port port port portable portion ports ports ports ports ports ports ports possible possible possible possible possible possible possible possible possible possible possible possible possible possible possible possible possibly possibly possibly possibly possibly possibly possibly possibly possibly possibly post post post post post postal postal postal postal postal postal postal postal postal postal posted postel postel postfix posting posting posting posting posting posting posting posting posting posting posting posting postmaster potato potato-head potential potential potential potential potential potential potential potentially power power powerful powerful powerful powerful powerful ppp-1-240.cvx4.telinco.net ppp-1-240.cvx4.telinco.net practice practice practice practice practices pre-authentication pre-configured pre-loaded pre-programmed pre-release precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence precedence prefer prefer prefer prefer prefer prefer prefer prefer prefer prefer prefer preliminary preparing preprocessing prescan.tar.gz.uu prescan.tar.gz.uu.asc presence present presented presetfields presetfields president president president president president president president president president president president president pretty pretty pretty pretty pretty prevent prevent prevent prevent preventing prevents previous previous previously previously-cached prime prime principle principles principles printer printer printer prioity prior prior prior prior prior prior prior prior prior prior prior prior prior prior prior prior prior priority priority private privilege privileged privileged privileges privileges privileges privileges privileges privileges privileges privileges privileges privileges privileges privileges privileges privileges privileges privileges privileges pro pro pro pro probability probably probably probably probably probably probably probably problem problem problem problem problem problem problem problem problem problem problem problem problem problem problem problem problems problems problems problems problems procedural procedural procedure procedure procedure process process process process process process process process process process process processor procmail produced produced produced producing product product product product product product product product product product products products products products products products products products products products products products products products products products products products products products products products products products products products products products products products products products products products products products products prog prog prog program program program program program program program program program program programmer programmers programming programming programming programming programming programs programs programs programs programs progress progs prohibit prohibit project project project project project project project project project project project project project project project project project project....so propagate propagated propagation proper proper properly properly properly properly properly properly proposed proposed proposed proposed proposed proposed proposes proposing protect protect protected protected protected protected protected protected protected protection protector protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol protocol-wise protocols protocols protocols protocols protos protos protos protos protos provide provide provide provide provide provide provide provide provide provide provide provide provided provided provided provided provided provided provided provided provided provided provided provided provided provided provided provided provided provider providers provides provides providing providing provisioned proxies pry16zmvs9ratwwryu psexec.exe psexec.exe psirt pst pst pst pst pst pst pst pst pst pst pst pst pst pst pst pst pt0a pub pub pub pub pub pub-cgi public public public public public public public public public public public public public public public public public public public public public publications publications publications publications publications publications publications publications publications publications publicly publicly publicly published published published publishing publishing pulling purge purge purge purpose purpose purpose purpose purpose purpose purpose purpose purpose purpose purpose put put put put put put put put puts puts putting pw pw123 pwd q314984 qaa00405 qaa00634 qaa00647 qaa00650 qaa08723 qaa17662 qaa17680 qaa18468 qaa18495 qaa21122 qaa21361 qaa21623 qaa21931 qaa22573 qaa23003 qaa25545 qaa25590 qaa25653 qaa25674 qaa25716 qaa25956 qaa25986 qaa26228 qaa26254 qaa26529 qaa29074 qaa29734 qaa29759 qmail qmail qmail qmail qmail qmail qmail qmail qmail qmail qmail qmail quarter queries queries queries query querying quick quit quits quits quits quits quits quota quota qwer r1 r1 r1 r1 r1 r2 r2 r2 r2 r2 r5 r5fixlist.nsf r7-0010 r7-0010.html r7-0011 r7-0011.html r7-0012 r7-0012.html raa03048 raa13232 rafail rafail ram ran range ranges ranges ranging rapid7 rapid7 rapid7 rapid7 rapid7 rapid7 rapid7 rates rather rather rather rather rather ratio re re re re re re re re re re re re re re re re re re re re re re re re re re re re re re re reach read read read read read read read read read read read read read read-only readability readability readability reading real realize realize really really really really reason reasonably reasons reassembly reassembly receive received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received received receiving receiving receiving recent recent recent recent recent recent recent recently recently reckon recommend recommendations recommendations recommended recommends recommends recommends recommends recommends recommends recommends recommends recommends recompile recompile recompile recompile recompiled recompiled recompiled recompiled reconfiguration record record record record record record recorded recorded records records records records recover recovering recovering recovering recu-make-cons-harm.html recurring recursion recursion recursion recursive red red red red red red red red red red red red red red red red red redskins reduce reduce reduced reduces redundant refcount refcount refer reference reference reference reference referenced references references references references references references references references references references references references references references references references references referred refresh regard regarding regarding regarding regarding regarding regarding regarding regarding regarding regarding regarding regards regards regenerating regions registered registered registered registered registered registered registered registered registered registered registered registration registration registry registry registry registry registry regression regularly regularly reing reiterate related related relationship relationship relative relay relay relays release release release release release release release release release release release release release release release release release release release release release release release.asp released released released released released released released released released releaseid releases releases releases releases releases releases relevant relevant relevant relevant relevant rely rely rely rely remedied remember remember remember remote remote remote remote remote remote remote remote remote remote remote remote remote remote remote remote remote remote remote remote remote remote remote remote remote remote remote remote remote remote remote remote remote remote remotely remotely remotely remotely remove remove remove remove removed removing renamed repeat repeat repeat replicate replicating reply reply reply reply reply reply reply-to report report report report report report report report report report reported reported reported reported reported reported reported reported reported reported reported reported reported reported reported reported reporters reporting reporting reporting reporting reporting reporting reporting reports reports reports reports reports reports reports reports reports reports reports reports reports represent representation representation request request request request requests requests requests requests requests requests requests requests require require require require require required required required required required required requirements requirements requires research research research research research research research research researched researchers researchers researching reside reside resistant resolution resolution resolve resolve resolved resolved resolver resolver resolver resolver resolver resolver resolver resolver resolver resolver resolver resolver resolver resolver resolvers resource resources respect respect respect respect respect respect respect respect respect respect responding response response response response response response response responses responses responses responses responses responses responses responses responses responsible rest restart restart restarted restarted restarted restrict restricted restricting result result result result result result result result resulted resulted resulting resulting results results results results results results results results results results results results retrieval retrieve.pl retriever retrival return return return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path return-path returned returns returns returns reverse reverse reverse-engineering review review reviewed revised revised revised revised revised revised revised revised revision revision revision revision revision revision revision revision revision revision revision revision revision revision revision revision revision revision revision revision revision revision revision revision revision revision rfc rfc rfc rfc rfc rfc rfc rfc rfc rfc rfc rfc rfc rfc rfc rfc rfc-822 rfc-822 rfc-822 rfc1327 rfc1831 rfc1831.txt rfc1832 rfc1832.txt rfc2279 rfc2327 rfc2518 rfc2671 rfc2671.txt rfc3261 rfc3261 rfc3261.txt rfcs rfcs rfcs rhn.redhat.com rhn.redhat.com rhn.redhat.com rhn.redhat.com rhn.redhat.com rhn.redhat.com rhsa-2002-119.html rhsa-2002-133.html rhsa-2003-073.html rhsa-2003-074.html rhsa-2003-120.html rhsa-2003-121.html rhsksj right riley risk risk risk risk risk risk river river river rmch ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro ro roland role role-playing roll roll roman root root root root root root root root root root root root root root root root rotten rotten rotten rotten rotten route route router router router router router routines routines routines routines routing routing routing roxen roxen rpc rpc rpc rpc rpc rpc rpc rpc rpc rpc rpc rpc rpc rpc rpc rpcbind rpms rpms rpms rpms rpms rpms rr rr rr rule rule rules run run run run run run run run run run runasuser runasuser runasuser runasuser rundll32.exe running running running running running running running running running running running running running running running running running running running running running running running running running running running running running running running runs runs runs s_viewname saa00584 saa00592 saa00600 saa00617 saa00624 saa00627 saa00627 saa00635 saa00643 saa00670 saa00673 saa00759 saa00777 saa00780 saa00783 saa00796 saa00812 saa00815 saa00828 saa03084 saa17900 saa18696 sadly safe said said said said said samba samba samba samba samba samba samba same same same same same same same same santana santana santana santana santana santana sapphire sat sat sat sat sat sat sat sat sat sat sat sat sat sat sat sat sat sat sat sat sat sat sat sat sat sat sathya sathya sathya sathya sathya sathya sathya sathya sathya sathya sathya sathya satisfied save save saves saw say say say say say say say say saying saying scanning scanning scanning scanning scanning scanning scanning scanning scanning scheduled scid scid scid scid scid scope screen screen screen screen screen screenshots script scripted sd sdbot sdbot sdbot sdbot sdp search search search search search search search search seblug seblug seblug seblug seblug seblug seblug sec sec4 secret secret secret section section section section section section section section section section section section section sections sections secure secure secure secure secure secureworx secureworx securing securing security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security security-alert securitypatch see see see see see see see see see see see see see see see see see see see see see see see see see see see see see see seem seems seen seen segmentation selected self-documenting self-documenting self-propagating self-propagating self-propagating self-propagating self-propagating self-propagating semi-intelligent send send send send send send send send send send send send send send send_message sender sender sender sender sender sender sender sender sender sender sender sender sender sender sender sender sender sender sender sender sender sender sender sender sender sender sender sender sender sender sender sender sender sender sender sending sending sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail sendmail_efix.tar.z sense sensitive sensitive sensitive sensitive sensitive sensitive sensitive sensitive sensitive sensitive sensitive sensitive sensitive sensitive sensitive sent sent sent sent sent sent sent sent sent sent sent sent sent sent sent sent sent sent separate ser series series series series series serious serious serious serve serve server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server server-side server-side servers servers servers servers servers servers servers servers servers servers servers servers servers servers servers servers servers servers servers servers servers servers servers servers servers service service service service service service service service service service service service service service service service service service service service service service service service service service service service service service service service service service service service service service service service service service service service service service service services services services services services services services services services services services services services services services services services services services services services services services services services services services services services services services services services servlets session session session session session session session session session session session session session session session session session session sessions sessions sessions set set set set set set set set sets settings setup several several several several several sex sgi sgi sgi sgi sgi sgi sgi sgi sgi sgi sh sh shabby shabby shapiro shapiro share share share share shared shares shares shares shares shares shares shares shares shares shares shares shares shares shares shares shares shares shares shares shares shares shares shares shares shares sharing sharing sharing shawn shawn sheets shell shell shell shell ship ship shipped shipped ships shmem shortly shots shots shots shots shots should should should should should should should should should should should should should should should should should should should should should should should should should should should shouldn't shouldn't shouldn't side side sidewinder sig sig sig sig sig sig sig sig sigfile sigfile sigfile signature signature signature signature signature signature signature signature signature signature signature signature signature signature signature signature signature signature signature signature signature signature signature signature signatures signed signed signed signed signed signed signed signed signed signed signed signed signed signed significant significant significantly significantly signs similar similar similar simple simple simple simpler simpler simplifying since since since since since since since since since since since since since since since since since since since single single single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop single-drop sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip sip-based sip-charter.html sip-charter.html sip-enabled sip-enabled sip-enabled sip-enabled sip-enabled sip-t site site site site site site site site site site site site site site site site site site site site site site site site site site site site site site site site site's site's sites sites sites sites sites sites sites sites sites sites sites sites situations six sizable size size size size size size size sized sizes skills slacke-worm.exe slackor slackor slackor slackor slackor slammer.asp slow small smb smb smb smb smb smb smb smb smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp smtp snip snip snmp so so so so so so so so so so so so so so so so so so so so so so so so so so so so so so so so so so so social social social socks software software software software software software software software software software software software software software software software software software software software software software software software software software software software software software software software software software software software software software software software software software software software software software software software's software's software's software's software's solaris solution solution solution solution solution solution solution solution solution solution solution solution solution solution solve some some some some some some some some some some some some some some some some some some some some some some some some some some some some some some some some some some some some some some some some someone someone someone someone someone someone someone someone someone someone someone someone someone something something something something something something something something something something's somewhere soon soon soon soon soon soon soon soon soon sort sort sort sounds sounds sounds source source source source source source source source source source source source source source source source source source source sourceforge sourceforge sourceforge sourceforge sourceforge sourceforge sourceforge sourceforge sourceforge sourceforge sourceforge sourceforge.net sources sources sources.redhat.com sources.redhat.com sources.redhat.com sources.redhat.com sources.redhat.com south south south south south south south sp space space space space space space space space space space space space space space space space sparc sparc speak speak spec spec spec spec spec spec special specially specially specially specially-crafted specially-crafted specially-crafted specific specific specific specific specific specific specific specific specific specific specific specific specifically specifically specifically specifically specification specification specification specifications specified specified specified specifies specify specifying specs specs specs spectactular speed speed speed speed speling speling sponsorship sponsorship sponsorship sponsorship sponsorship sponsorship sponsorship sponsorship sponsorship sponsorship spoofing spoofing spool spot spr's sprs spx sql sql sql sql sql sql sql sqlslammer ssh ssh ssh ssh ssh ssh ssi ssi ssrt2402 ssrt2408 ssrt2439 ssrt3469 stab stack standard standard standard standard standard standard standard standard standard standard standard standard standard standardization standardization standardization standardization standardizing standards standarf start start start start start start start start start start start started started started started starting starting starts starts starts startup statement statement statement statement statement statement statement statements statements states static static statically statically statically statically statically statically statistics stats status status status status status status status status status status status status status status status status status status status status status status status status status status status status status status status status status status status status status status status status status status status status stay stdout steps steps steps steps steps steps stick still still still still still still still still stinking stlnet.com stlnet.com stlnet.com stlnet.com stlnet.com stlnet.com stlnet.com stlnet.com stlnet.com stlnet.com stlnet.com stlnet.com stlnet.com stlnet.com stlnet.com stlnet.com stlnet.com stlnet.com stlnet.com stlnet.com stlnet.com stlnet.com stlnet.com stlnet.com stlnet.com stonegate stonegate stonesoft stonesoft's stop storage stored stored story strategy strcmp strcmp streams strong strong strong strong strongly strongly strongly strongly strongly strongly strongly strongly strongly strongly strongly strongly strongly struct struct stuart stuart stuart stuart stuart stub stub stub stuff stuff stuff stuff stuff stuff stuff stuff stuff stuff stuff stuff stuff stuff stuff stuff stuff stuff stuff stuff stuff style style style style style style style style style stylesheets sub-domains subfolders subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subject subscribe subscribe subscribe subscribe subscribe subscribe subscribe subscribe subscribe subscribe subscribe subscribe subscribe subscribe subscribe subscribe subscribe subscribe subscribe subscribe subsequent subset succeed succeptable success successful successful successful successful successful successful successful successfully successfully succession succession such such such such such such such such such such such such such suggest suggested suggestions suggestions suggestions suggests suite suite suite suite suite suite suite suite suite suites summaries summaries summaries summaries summarise summary summary summary summary summary summary summary summer summer sun sun sun sun sun sun sun sun sun sun sun sun sun sun sun sun sun sun sun sun sun sun sun sun sun sun sun sun sun sun sun sun sun sun sunrpc sunrpc sunrpc sunrpc sunrpc sunrpc sunrpc sunrpc sunrpc sunrpc sunrpc sunrpc sunrpc-derived sunrpc-derived sunsolve.sun.com sunsolve.sun.com super super super-coders super-coders supplied support support support support support support support support support support support support support support support support support support support support support.microsoft.com support.microsoft.com support.microsoft.com support.microsoft.com support.microsoft.com supported supported supported supporting supports suppose supposed sure sure sure sure sure surely survey susceptible susceptible susceptible suspect swg21104543 swg21104543 switch switch switch switch switch switch switch switch switch switch switch switches switches switching sybase symantec symantec symantec syntax syntax syntax syntax syntax sysinternals.com system system system system system system system system system system system system system system system system system system system system system system system system system system system system system system system system system system system system system system system system system system system system system system system system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net system.connectfree.net systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems systems t9fjns1srrz taa01164 taa01341 taa09174 taa09228 tables tagged tagged tags tags take taken taken taken taken taken takes taking taking taking taking taking taking taking taking talk talk talk talk talk talk talking target target targeted targeting targeting targeting targeting targeting targets task tasks tasks tcp tcp tcp tcp tcp tcp tcp tcp tcp tcp tcp tcp tcp tcp tcp tcp tcp tcp tcp tcp tcp tcp tcp tcp tcp tcp team team team team team team team team team team team tech tech tech_tips tech_tips tech_tips tech_tips technet technet technet technical technical technical technical technical technical technical technical technical technical techniques techniques technology teeth telephony tell tell tell tell tell telling telnet telnet temp temp123 template temporary temporary tend tended terminate test test test test test test test test test test-suite test123 tested tested testing testing testing testing text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text text-based texts textual than than than than than than than than than than than than than than than than than than than than than than thank thank thank thank thank thanks thanks thanks thanks thanks thanks thanks thanks thanks thanks that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that that's that's that's that's that's that's that's that's that's that's that's the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the the their their their their their their their their their their their their their their their their their their their their their their their their their their their their their their their their their their their their their them them them them them them them them them them them them them them them themeselves themselves themselves then then then then then then then then then then then then then then then then then then then then theory there there there there there there there there there there there there there there there there there there there there there there there there there there there therefore therefore therefore therefore therefore therefore these these these these these these these these these these these these these these these these these these these these these these these these these these these these these these these these these these these these these these these these these these these these these these these they they they they they they they they they they they they they they they they they they they they they they they'd they'd they'd things things things things things things things things things think think think think think think think think think think think think think think think think think think think think think thinking thinking thinking thinks thinks this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this this those those those those those though though though though though thought thought thought thoughts thoughts thoughts thoughts thoughts thoughts thoughts thousands thousands thousands thousands threaded threat threats threats throttling through through through through through through through through through through through through through through through through through through through through thru thru thru thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thu thus thus thus thus thus thus thus thus time time time time time time time time time time time time time time time times times times timing tips tls tm to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to to todos todos todos todos todos todos todos todos todos todos todos todos together together told too too too too too too too too too too too took tool tool tool tool tool tool tool tool tool tool tool tool tool tool tool tool tools tools tools tools tools tools tools tools tools tools tools tools tools tools tools top topic topic topic topic topic topic tops-20 tops-20 tops-20 torture totally track track track tracked tracked tracking tracking tracking trademark trademark trademark trademark trademark trademark trademark trademark trademark trademark trademark trademark trademark trademark trademark trademark trademark trademark trademark trademark traffic traffic traffic traffic traffic traffic traffic traffic traffic traffic traffic traffic traffic traffic traffic traffic traffic traits transfer transfer transfer transfer transfer transfer transfer transfer transfer transfer transformation transformation transition transition translation transmission transmitted transparency transport transport trap tree treeview trend trends trends trigger trigger triggered triggered triggered triggered triggered triggered trouble trouble troy troy troy troy troy troy troy troy troy troy troy troy troy troy troy troy tru64 true true true trust trusted try try trying trying trying trying tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tue tutorial tvadr9bwrqct6 two two two two two two two two two type type type type type type type type type type type type type typed typed typed types types types types types types types typically typically typically typically typically typically typically typically typically typically typically typically typically typically typically typically typically typically u.s u.s u.s u.s u.s u.s u.s u.s u.s u.s u.s u.s u.s u.s u.s u.s u.s u.s u.s u.s u.s.a u.s.a u.s.a u.s.a u.s.a u.s.a u.s.a u.s.a u.s.a u.s.a u4s2 u5z1fvzrqpztnbetrvos7cn8 u7wk u_int u_int u_int uaa00881 uaa00884 uaa00887 uaa00976 uaa01231 uaa01239 ucsb udp udp udp udp udp udp udp ugly uh ui ui ui ui ui ui ui uid uid uid unacceptably unauthenticated unauthorized unauthorized unauthorized unauthorized unauthorized unauthorized unavailable under under under under under under under under under under undergoing understand understand understand understand understand undetected undetected unexpected unicode unicode unicos unicos unicos universal university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university university unix unix unix unix unix unix unix unix unix unix unix unknown unknown unless unless unlikely unlikely unlikely unnecessary unpatched unprotected unprotected unread unsigned unsigned unsigned unstable unstable until until until until until until until until until until until until untrusted unusually up up up up up up up up up up up up up up up up up up up up up up up up up up up up up up up up up up up up update update update update update update update update update update update update update updated updated updated updated updated updated updated updated updated updated updated updated updated updated updated updated updated updated updated updated updates updates upgrade upgrade upgrade upgrade upgrade upgrade upgrade upgrade upgrade upgrade upgrade upgrade upgrade upgraded upgrading upon upon upon urge urge urge urge urge urge urge urge urge urge urgency urgency urgent urity url url url url url url url url url url url urls urlscan urlscan urlscan us us us us us us us us us us us us us us us us-ascii us-ascii us-ascii us-ascii us-ascii us-ascii us-ascii us-ascii us-ascii us-ascii us-ascii us-ascii us-ascii us-ascii us-ascii us-ascii us-ascii us-ascii us-ascii usage usage use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use use useable used used used used used used used used used used used used used used used used used used used used used used used used used used used used useful useful usenet user user user user user user user user user user user user user user user user user user user user user-created userdb username usernames usernames users users users users users users users users users users users users users users users users users users users users users users users users users users users users users uses uses uses uses uses uses uses uses uses uses using using using using using using using using using using using using using using using using using using using using using using using using using using using using using using using using using using using using using using using using using using using using using usr usual usually utf-7 utf-8 utilized utilizes uucp uucp uxp uxp uxp v2.0 vaa01295 vaa05338 vaa05368 vaa05741 vaa05767 vaa06088 vaa06113 vaa11771 vaa11796 values var variable variables variants varied variety variety variety variety variety variety variety various various various various various various various various various various vary vary vary vary varying vcards vector vendor vendor vendor vendor vendor vendor vendor vendor vendor vendor vendor vendor vendor vendor vendor vendor vendor vendor vendor vendor vendor vendor vendor vendor vendor vendor vendor vendor vendor vendor vendor vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors vendors version version version version version version version version version version version version version version version version version version version version version version version version version version version version version version version versions versions versions versions versions versions versions versions versions versions versions versions versions versions versions versions versions versions versions versions versions versions versions versions versions versions versions versions versions versions versions versions versions versions versions very very very very very very very very very very vi via via via via via via via via via via via via via via via via via via via vice-versa victim victim victim victim victim victim victim victim victim victim view view view virtual virtual virus virus virus viruses.html vision visit visit vlucas1.ucs.ed.ac.uk vnc vnc vnc vnc vnc vnc vnc vnc vnchooks.dll vnuog2fm4bcsue7h voice voip volume volume volumes volumes volumes volunteer vote vote vote vote vote vpn vpn vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vu vulnerabilites vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerabilities vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerability vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vulnerable vuls vuls vuls vuls vuls vuls vuls vuls vuls vuls vuls vuls vuls vuls vuls vuls vuls vuls vuls vx-works w32 w32 w32 w32 w32 w32 w32 w32 w32 w32 w32 w32 w32 w32 w32 w32.slammer w5nhmvu4y81t waa00662 waa01338 waa01363 waa03288 waa13353 waa13378 waa13662 waa13684 wait waiting want want want want want want want want want want want want want want want want want want want want wants warranties warranties warranties warranties warranties warranties warranties warranties warranties warranties warrants warranty warranty warranty warranty warranty warranty warranty warranty warranty warranty warranty warranty warranty warranty warranty warranty warranty warranty warranty warranty warranty warranty warranty warranty warranty warranty warranty warranty warranty warranty wary was was was was was was was was was was was was was was was was was was was was was was was was washington wasn't wasn't watching way way way way way way way way ways ways we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we we'd we'd we'll we'll we'll we'll we're we're we're we're we're we're we're we're we're we're we're we're we're we've weak weak weak weak weak weak weakly weasel web web web web web web web web web web web web web web web web web web web web web web web web web web web web web web web web web web web web web web web web web web web web web web web web web web web-based web-page web.mit.edu web.mit.edu web.mit.edu web1.workspot.net web1.workspot.net web1.workspot.net web1.workspot.net web1304.mail.yahoo.com web1304.mail.yahoo.com web1304.mail.yahoo.com web1304.mail.yahoo.com web2.workspot.net web2.workspot.net web2.workspot.net web2.workspot.net web2.workspot.net web2.workspot.net web2.workspot.net web2.workspot.net web2.workspot.net web2.workspot.net webdav webdav webdav webdav webdav webdav webmail wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wed wednesday wednesday weekend weekends weekends weekends weekends weekends weekends weekends weekends weekends weekends weeks weeks weeks weeks welcome well well well well well well well well well well well well well well well well well well-chosen well-received were were were were were wet wet wet wet wet wet wet wet wet wet what what what what what what what what what what what what what what what what what what what what what what what what what what what what what what what what what what what what what what what what what what what what what's what's what's what's what's what's what's what's what's what's what's whatever whatever whatever whatever whatever whatever whatever whatever whatever whatnot whatnot when when when when when when when when when when when when when when when when when when when when when when when when when when when whenever whenever whenever where where where where where where where where where where where where where where where whether whether whether whether whether whether whether whether which which which which which which which which which which which which which which which which which which which which which which which which which which which which which which which which which which which while while while who who who who who who who who who who's who's whoever whole whom why why wicllfvvf5jpa wide wide widely widely widespread widespread will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will will win win32 win98 win98 win98 win98 win98 win98 win98 win98 wind wind wind windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows windows wipes wireline wiretap wish wish wish wish wish wish with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with with within within within within without without without without without without wivlm wizard wizard wizard wizard wizard wizard wizard wizard wizard wizard wizard wizard wizard wizard wizard wizard wizard wizard wnxijdk0gj57jbou6zdhhcaijg5se won't wonder wood wood wood wood wood wood word words words words work work work work work work work work work work work work work work work work work work work workaround workaround workaround workaround workarounds workarounds working working working working working working working workstation workstation workstations workstations world worm worm worm worm worm worm worm worm worm worm worm worm worry worrying would would would would would would would would would would would would would would would would would would would would would would would would would would would would would would would would would would would would would would would would wouldn't write write write write write write write write write write write write write writing writing writing writing writing written written written written written written written written written written written written wrong wrong wrong wrong wrote wrote wrote wrote wrote wrote wrote wrote wrote wrote wrote wrote wrote wrote wrote wrote wrote wrote wrote wrote wrote www www www www-10.lotus.com www.canb.auug.org.au www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cert.org www.cisco.com www.ee.oulu.fi www.ee.oulu.fi www.ee.oulu.fi www.eeye.com www.geocrawler.com www.geocrawler.com www.geocrawler.com www.geocrawler.com www.gnu.org www.ibm.com www.ibm.com www.ibm.com www.ibm.com www.ibm.com www.ibm.com www.ibm.com www.ibm.com www.ietf.org www.ietf.org www.ietf.org www.ietf.org www.ietf.org www.ind.alcatel.com www.iptel.org www.isc.org www.isc.org www.isc.org www.isc.org www.isc.org www.iss.net www.jgsoft.net www.kb.cert.org www.kb.cert.org www.kb.cert.org www.kb.cert.org www.kb.cert.org www.kb.cert.org www.kb.cert.org www.kb.cert.org www.kb.cert.org www.kb.cert.org www.kb.cert.org www.kb.cert.org www.kb.cert.org www.kb.cert.org www.kb.cert.org www.kb.cert.org www.kb.cert.org www.kb.cert.org www.kb.cert.org www.microsoft.com www.microsoft.com www.microsoft.com www.microsoft.com www.nextgenss.com www.nextgenss.com www.nextgenss.com www.nextgenss.com www.nextgenss.com www.openwall.com www.rapid7.com www.rapid7.com www.rapid7.com www.sendmail.com www.sendmail.com www.sendmail.com www.sendmail.com www.sendmail.org www.sendmail.org www.sendmail.org www.sendmail.org www.sendmail.org www.sendmail.org www.sgi.com www.sgi.com www.uk.research.att.com www.workspot.net www.workspot.net www.workspot.net www.workspot.net www.workspot.net www.workspot.net www.workspot.net x-accept-language x-accept-language x-accept-language x-accept-language x-accept-language x-accept-language x-accept-language x-accept-language x-accept-language x-accept-language x-authentication-warning x-authentication-warning x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-beenthere x-keywords x-keywords x-keywords x-keywords x-keywords x-keywords x-mailer x-mailer x-mailer x-mailer x-mailer x-mailer x-mailer x-mailer x-mailer x-mailer x-mailer x-mailer x-mailer x-mailer x-mailer x-mailer x-mailer x-mailer x-mailer x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-mailman-version x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-pop3-rcpt x-ref x-ref x-status x-status x-status x-status x-status x-status x-status x-uid x-uid x-uid x-uid x-uid x-uid x.25 x.400 x.400 x.400 x.400 x.400 x.400 x.400 x.400 x.400 x.400 x.400 x.400 x.400 x.400 x.400 x.400 x.400 x11 x11 x_handy x_handy x_handy x_inline xaa02105 xaa02131 xaa03198 xaa03226 xaa03565 xaa21075 xaa21847 xaa22149 xaa29253 xaa29282 xaa29768 xaa29786 xdr xdr xdr xdr xdr xdr xdr xdr xdr xdr xdr xdr xdr xdr.h xdr.h xdr.x_handy xdr.xdr_ops.x_inline xdr_mem.c xdr_mem.c xdr_mem.c xdr_rec.c xdr_rec.c xdr_sizeof xdr_sizeof xdr_sizeof.c xdr_stdio xdr_stdio.c xdrmem_getbytes xdrmem_getbytes xdrmem_getbytes xdrmem_getbytes xdrmem_getbytes xdrmem_getbytes xdrmem_getint32 xdrmem_getlong xdrmem_inline xdrmem_inline xdrmem_putbytes xdrmem_putint32 xdrmem_putlong xdrmem_setpos xdrrec_inline xdrstdio_inline xerox xerox xforce xforce xp xp xp xp xp xp xp xp xpc xqropqun25m xxx yaar yaar yaar yahoo yahoo yeah yeah yeah yeah yeah yeah yet yet yet yet yet yet yet yet yfb381fvuwc yield ylt7 yobf5hqgxd8 you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you you're you're your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your your yours yup yxcv zalewski zalewski zappa zlwf zones zowae5 zxcv =?UTF-8?B?LSBJZ25pdGluZyB0aGUgd2Vi?= qsf-1.2.7/test/t01-dbcreate0000644000076400007640000000033710510551626013203 0ustar awaw#!/bin/sh # # TEST: Database creation: rm -f $TESTDB ./mboxsplit 1 < .test-spam | $PROG -d $BACKEND:$TESTDB -m -w 2 test $BACKEND = MySQL && exit 0 test $BACKEND = mysql && exit 0 cat $TESTDB >/dev/null 2>&1 qsf-1.2.7/test/t12-benchmark0000644000076400007640000000026610240756217013372 0ustar awaw#!/bin/sh # # TEST: Benchmarking mode: rm -f $TESTDB trace MALLOC_CHECK_=2 export MALLOC_CHECK_ $PROG -d $BACKEND:$TESTDB -B .test-spam .test-non-spam 10 >/dev/null qsf-1.2.7/test/t11-allowlistdel0000644000076400007640000000025710242202732014124 0ustar awaw#!/bin/sh # # TEST: Allow-list removal: $PROG -d $BACKEND:$TESTDB -me test@tEst.com if $PROG -d $BACKEND:$TESTDB -te test@tesT.com; then exit 1 else exit 0 fi qsf-1.2.7/test/t15-headermarker0000644000076400007640000000111010470423216014055 0ustar awaw#!/bin/sh # # TEST: Spam header marker: rm -f $TESTDB ./mboxsplit 1 < .test-spam | $PROG -d $BACKEND:$TESTDB -m -w 2 ISSPAM=0 ./mboxsplit 1 < .test-spam | $PROG -d $BACKEND:$TESTDB | grep 'X-Spam: YES' >/dev/null && ISSPAM=1 test $ISSPAM -eq 1 ISSPAM=0 ./mboxsplit 1 < .test-spam | $PROG -d $BACKEND:$TESTDB -H 'LONGER TEST STRING' | grep 'X-Spam: LONGER TEST STRING' >/dev/null && ISSPAM=1 test $ISSPAM -eq 1 BADHEADER=0 ./mboxsplit 1 < .test-spam | $PROG -d $BACKEND:$TESTDB -H 'LONGER TEST STRING' | grep 'X-Spam: YES' >/dev/null && BADHEADER=1 test $BADHEADER -eq 0 qsf-1.2.7/test/t14-rfc8220000644000076400007640000000414210301706467012445 0ustar awaw#!/bin/sh # # TEST: Tokenising message attachments: rm -f $TESTDB MALLOC_CHECK_=2 export MALLOC_CHECK_ cat > $TESTDB < /dev/null echo $ECHO_N "SKIPPED $ECHO_C" exit 0 fi $PROG -d $BACKEND:$TESTDB -D | sed 's/SINCEPRUNE.*/SINCEPRUNE 1/' \ | grep SINCEPRUNE > .testdump-b $PROG -d $BACKEND:$TESTDB -D | sed 's/SINCEPRUNE.*/SINCEPRUNE 500/' > .testdump-a $PROG -d $BACKEND:$TESTDB -R < .testdump-a ./mboxsplit 1 < .test-non-spam \ | $PROG -d $BACKEND:$TESTDB -m >/dev/null ./mboxsplit 1 < .test-non-spam \ | $PROG -d $BACKEND:$TESTDB -m >/dev/null $PROG -d $BACKEND:$TESTDB -D | grep SINCEPRUNE > .testdump-a cmp -s .testdump-a .testdump-b rm -f .testdump-a .testdump-b qsf-1.2.7/test/t10-allowlistadd0000644000076400007640000000027210242202672014107 0ustar awaw#!/bin/sh # # TEST: Allow-list addition: $PROG -d $BACKEND:$TESTDB -Me test@Test.com $PROG -d $BACKEND:$TESTDB -te test@test.com $PROG -d $BACKEND:$TESTDB -te TeSt@TEST.com qsf-1.2.7/test/t06-dumprestore0000644000076400007640000000053210554266213014010 0ustar awaw#!/bin/sh # # TEST: Dump and restore: $PROG -d $BACKEND:$TESTDB -D > .testdump-a $PROG -d $BACKEND:$TESTDB -D | sed 1,2d | sort > .testdump-b rm -f $TESTDB $PROG -d $BACKEND:$TESTDB -R < .testdump-a $PROG -d $BACKEND:$TESTDB -D | sed 1,2d | sort > .testdump-c cmp .testdump-b .testdump-c rm -f .testdump-a .testdump-b .testdump-c qsf-1.2.7/test/t17-denylistadd0000644000076400007640000000027610507215774013756 0ustar awaw#!/bin/sh # # TEST: Deny-list addition: $PROG -d $BACKEND:$TESTDB -ymme test@Test.com $PROG -d $BACKEND:$TESTDB -yte test@test.com $PROG -d $BACKEND:$TESTDB -yte TeSt@TEST.com qsf-1.2.7/test/t04-training0000644000076400007640000000026610240756215013252 0ustar awaw#!/bin/sh # # TEST: Training mode: rm -f $TESTDB trace MALLOC_CHECK_=2 export MALLOC_CHECK_ $PROG -d $BACKEND:$TESTDB -T .test-spam .test-non-spam 10 >/dev/null qsf-1.2.7/test/t09-gtube0000644000076400007640000000043410211420125012531 0ustar awaw#!/bin/sh # # TEST: GTUBE: echo > .testdump-a echo 'XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X' >> .testdump-a $PROG -d $BACKEND:$TESTDB -s < .testdump-a > .testdump-b grep SPAM .testdump-b >/dev/null rm -f .testdump-a .testdump-b