Exemple #1
0
void dspam_do_msg(long msgnum, void *userdata) 
{
	char *msgtext;
	DSPAM_CTX *CTX;               	/* DSPAM Context */
	struct CtdlMessage *msg;
	struct _ds_spam_signature SIG;        /* signature */

	CTX = *(DSPAM_CTX**) userdata;
	msg = CtdlFetchMessage(msgnum, 0);
	if (msg == NULL) return;


	/* Message */
	CC->redirect_buffer = malloc(SIZ);
	CC->redirect_len = 0;
	CC->redirect_alloc = SIZ;
	CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_ALL, 0, 1, 0);
	msgtext = CC->redirect_buffer;
// don't need?	msglen = CC->redirect_len;
	CC->redirect_buffer = NULL;
	CC->redirect_len = 0;
	CC->redirect_alloc = 0;

	/* Call DSPAM's processor with the message text */
	if (dspam_process (CTX, msgtext) != 0)
	{
		free(msgtext);
		syslog(LOG_CRIT, "ERROR: dspam_process failed");
		return;
	}
	if (CTX->signature == NULL)
	{
		syslog(LOG_CRIT,"No signature provided\n");
	}
	else
	{
/* Copy to a safe place */
		// TODO: len -> cm_fields?
		msg->cm_fields[eErrorMsg] = malloc (CTX->signature->length * 2);
		size_t len = CtdlEncodeBase64(msg->cm_fields[eErrorMsg], CTX->signature->data, CTX->signature->length, 0);

		if (msg->cm_fields[eErrorMsg][len - 1] == '\n') {
			msg->cm_fields[eErrorMsg][len - 1] = '\0';
		}
	}
	free(msgtext);

	SIG.length = CTX->signature->length;
	/* Print processing results */
	syslog(LOG_DEBUG, "Probability: %2.4f Confidence: %2.4f, Result: %s\n",
		CTX->probability,
		CTX->confidence,
		(CTX->result == DSR_ISSPAM) ? "Spam" : "Innocent");

	//// todo: put signature into the citadel message
	//// todo: save message; destroy message.
}
Exemple #2
0
/*
 * Index or de-index a message.  (op == 1 to index, 0 to de-index)
 */
void ft_index_message(long msgnum, int op) {
	int num_tokens = 0;
	int *tokens = NULL;
	int i, j;
	struct cdbdata *cdb_bucket;
	StrBuf *msgtext;
	char *txt;
	int tok;
	struct CtdlMessage *msg = NULL;

	msg = CtdlFetchMessage(msgnum, 1, 1);
	if (msg == NULL) {
		syslog(LOG_ERR, "ft_index_message() could not load msg %ld", msgnum);
		return;
	}

	if (!CM_IsEmpty(msg, eSuppressIdx)) {
		syslog(LOG_DEBUG, "ft_index_message() excluded msg %ld", msgnum);
		CM_Free(msg);
		return;
	}

	syslog(LOG_DEBUG, "ft_index_message() %s msg %ld", (op ? "adding" : "removing") , msgnum);

	/* Output the message as text before indexing it, so we don't end up
	 * indexing a bunch of encoded base64, etc.
	 */
	CC->redirect_buffer = NewStrBufPlain(NULL, SIZ);
	CtdlOutputPreLoadedMsg(msg, MT_CITADEL, HEADERS_ALL, 0, 1, 0);
	CM_Free(msg);
	msgtext = CC->redirect_buffer;
	CC->redirect_buffer = NULL;
	if (msgtext != NULL) {
		syslog(LOG_DEBUG, "Wordbreaking message %ld (%d bytes)", msgnum, StrLength(msgtext));
	}
	txt = SmashStrBuf(&msgtext);
	wordbreaker(txt, &num_tokens, &tokens);
	free(txt);

	syslog(LOG_DEBUG, "Indexing message %ld [%d tokens]", msgnum, num_tokens);
	if (num_tokens > 0) {
		for (i=0; i<num_tokens; ++i) {

			/* Add the message to the relevant token bucket */

			/* search for tokens[i] */
			tok = tokens[i];

			if ( (tok >= 0) && (tok <= 65535) ) {
				/* fetch the bucket, Liza */
				if (ftc_msgs[tok] == NULL) {
					cdb_bucket = cdb_fetch(CDB_FULLTEXT, &tok, sizeof(int));
					if (cdb_bucket != NULL) {
						ftc_num_msgs[tok] = cdb_bucket->len / sizeof(long);
						ftc_msgs[tok] = (long *)cdb_bucket->ptr;
						cdb_bucket->ptr = NULL;
						cdb_free(cdb_bucket);
					}
					else {
						ftc_num_msgs[tok] = 0;
						ftc_msgs[tok] = malloc(sizeof(long));
					}
				}
	
	
				if (op == 1) {	/* add to index */
					++ftc_num_msgs[tok];
					ftc_msgs[tok] = realloc(ftc_msgs[tok],
								ftc_num_msgs[tok]*sizeof(long));
					ftc_msgs[tok][ftc_num_msgs[tok] - 1] = msgnum;
				}
	
				if (op == 0) {	/* remove from index */
					if (ftc_num_msgs[tok] >= 1) {
						for (j=0; j<ftc_num_msgs[tok]; ++j) {
							if (ftc_msgs[tok][j] == msgnum) {
								memmove(&ftc_msgs[tok][j], &ftc_msgs[tok][j+1], ((ftc_num_msgs[tok] - j - 1)*sizeof(long)));
								--ftc_num_msgs[tok];
								--j;
							}
						}
					}
				}
			}
			else {
				syslog(LOG_ALERT, "Invalid token %d !!", tok);
			}
		}

		free(tokens);
	}
}
Exemple #3
0
/*
 * imap_do_search() calls imap_do_search_msg() to search an individual
 * message after it has been fetched from the disk.  This function returns
 * nonzero if there is a match.
 *
 * supplied_msg MAY be used to pass a pointer to the message in memory,
 * if for some reason it's already been loaded.  If not, the message will
 * be loaded only if one or more search criteria require it.
 */
int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg,
			int num_items, ConstStr *itemlist, int is_uid) {

	citimap *Imap = IMAP;
	int match = 0;
	int is_not = 0;
	int is_or = 0;
	int pos = 0;
	int i;
	char *fieldptr;
	struct CtdlMessage *msg = NULL;
	int need_to_free_msg = 0;

	if (num_items == 0) {
		return(0);
	}
	msg = supplied_msg;

	/* Initially we start at the beginning. */
	pos = 0;

	/* Check for the dreaded NOT criterion. */
	if (!strcasecmp(itemlist[0].Key, "NOT")) {
		is_not = 1;
		pos = 1;
	}

	/* Check for the dreaded OR criterion. */
	if (!strcasecmp(itemlist[0].Key, "OR")) {
		is_or = 1;
		pos = 1;
	}

	/* Now look for criteria. */
	if (!strcasecmp(itemlist[pos].Key, "ALL")) {
		match = 1;
		++pos;
	}
	
	else if (!strcasecmp(itemlist[pos].Key, "ANSWERED")) {
		if (Imap->flags[seq-1] & IMAP_ANSWERED) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "BCC")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			fieldptr = rfc822_fetch_field(msg->cm_fields[eMesageText], "Bcc");
			if (fieldptr != NULL) {
				if (bmstrcasestr(fieldptr, itemlist[pos+1].Key)) {
					match = 1;
				}
				free(fieldptr);
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "BEFORE")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			if (!CM_IsEmpty(msg, eTimestamp)) {
				if (imap_datecmp(itemlist[pos+1].Key,
						atol(msg->cm_fields[eTimestamp])) < 0) {
					match = 1;
				}
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "BODY")) {

		/* If fulltext indexing is active, on this server,
		 *  all messages have already been qualified.
		 */
		if (config.c_enable_fulltext) {
			match = 1;
		}

		/* Otherwise, we have to do a slow search. */
		else {
			if (msg == NULL) {
				msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
				need_to_free_msg = 1;
			}
			if (msg != NULL) {
				if (bmstrcasestr(msg->cm_fields[eMesageText], itemlist[pos+1].Key)) {
					match = 1;
				}
			}
		}

		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "CC")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			fieldptr = msg->cm_fields[eCarbonCopY];
			if (fieldptr != NULL) {
				if (bmstrcasestr(fieldptr, itemlist[pos+1].Key)) {
					match = 1;
				}
			}
			else {
				fieldptr = rfc822_fetch_field(msg->cm_fields[eMesageText], "Cc");
				if (fieldptr != NULL) {
					if (bmstrcasestr(fieldptr, itemlist[pos+1].Key)) {
						match = 1;
					}
					free(fieldptr);
				}
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "DELETED")) {
		if (Imap->flags[seq-1] & IMAP_DELETED) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "DRAFT")) {
		if (Imap->flags[seq-1] & IMAP_DRAFT) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "FLAGGED")) {
		if (Imap->flags[seq-1] & IMAP_FLAGGED) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "FROM")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			if (bmstrcasestr(msg->cm_fields[eAuthor], itemlist[pos+1].Key)) {
				match = 1;
			}
			if (bmstrcasestr(msg->cm_fields[erFc822Addr], itemlist[pos+1].Key)) {
				match = 1;
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "HEADER")) {

		/* We've got to do a slow search for this because the client
		 * might be asking for an RFC822 header field that has not been
		 * converted into a Citadel header field.  That requires
		 * examining the message body.
		 */
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}

		if (msg != NULL) {
	
			CC->redirect_buffer = NewStrBufPlain(NULL, SIZ);
			CtdlOutputPreLoadedMsg(msg, MT_RFC822, HEADERS_FAST, 0, 1, 0);
	
			fieldptr = rfc822_fetch_field(ChrPtr(CC->redirect_buffer), itemlist[pos+1].Key);
			if (fieldptr != NULL) {
				if (bmstrcasestr(fieldptr, itemlist[pos+2].Key)) {
					match = 1;
				}
				free(fieldptr);
			}
	
			FreeStrBuf(&CC->redirect_buffer);
		}

		pos += 3;	/* Yes, three */
	}

	else if (!strcasecmp(itemlist[pos].Key, "KEYWORD")) {
		/* not implemented */
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "LARGER")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			if (msg->cm_lengths[eMesageText] > atoi(itemlist[pos+1].Key)) {
				match = 1;
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "NEW")) {
		if ( (Imap->flags[seq-1] & IMAP_RECENT) && (!(Imap->flags[seq-1] & IMAP_SEEN))) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "OLD")) {
		if (!(Imap->flags[seq-1] & IMAP_RECENT)) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "ON")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			if (!CM_IsEmpty(msg, eTimestamp)) {
				if (imap_datecmp(itemlist[pos+1].Key,
						atol(msg->cm_fields[eTimestamp])) == 0) {
					match = 1;
				}
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "RECENT")) {
		if (Imap->flags[seq-1] & IMAP_RECENT) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "SEEN")) {
		if (Imap->flags[seq-1] & IMAP_SEEN) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "SENTBEFORE")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			if (!CM_IsEmpty(msg, eTimestamp)) {
				if (imap_datecmp(itemlist[pos+1].Key,
						atol(msg->cm_fields[eTimestamp])) < 0) {
					match = 1;
				}
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "SENTON")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			if (!CM_IsEmpty(msg, eTimestamp)) {
				if (imap_datecmp(itemlist[pos+1].Key,
						atol(msg->cm_fields[eTimestamp])) == 0) {
					match = 1;
				}
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "SENTSINCE")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			if (!CM_IsEmpty(msg, eTimestamp)) {
				if (imap_datecmp(itemlist[pos+1].Key,
						atol(msg->cm_fields[eTimestamp])) >= 0) {
					match = 1;
				}
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "SINCE")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			if (!CM_IsEmpty(msg, eTimestamp)) {
				if (imap_datecmp(itemlist[pos+1].Key,
						atol(msg->cm_fields[eTimestamp])) >= 0) {
					match = 1;
				}
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "SMALLER")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			if (msg->cm_lengths[eMesageText] < atoi(itemlist[pos+1].Key)) {
				match = 1;
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "SUBJECT")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			if (bmstrcasestr(msg->cm_fields[eMsgSubject], itemlist[pos+1].Key)) {
				match = 1;
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "TEXT")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			for (i='A'; i<='Z'; ++i) {
				if (bmstrcasestr(msg->cm_fields[i], itemlist[pos+1].Key)) {
					match = 1;
				}
			}
		}
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "TO")) {
		if (msg == NULL) {
			msg = CtdlFetchMessage(Imap->msgids[seq-1], 1);
			need_to_free_msg = 1;
		}
		if (msg != NULL) {
			if (bmstrcasestr(msg->cm_fields[eRecipient], itemlist[pos+1].Key)) {
				match = 1;
			}
		}
		pos += 2;
	}

	/* FIXME this is b0rken.  fix it. */
	else if (imap_is_message_set(itemlist[pos].Key)) {
		if (is_msg_in_sequence_set(itemlist[pos].Key, seq)) {
			match = 1;
		}
		pos += 1;
	}

	/* FIXME this is b0rken.  fix it. */
	else if (!strcasecmp(itemlist[pos].Key, "UID")) {
		if (is_msg_in_sequence_set(itemlist[pos+1].Key, Imap->msgids[seq-1])) {
			match = 1;
		}
		pos += 2;
	}

	/* Now here come the 'UN' criteria.  Why oh why do we have to
	 * implement *both* the 'UN' criteria *and* the 'NOT' keyword?  Why
	 * can't there be *one* way to do things?  More gratuitous complexity.
	 */

	else if (!strcasecmp(itemlist[pos].Key, "UNANSWERED")) {
		if ((Imap->flags[seq-1] & IMAP_ANSWERED) == 0) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "UNDELETED")) {
		if ((Imap->flags[seq-1] & IMAP_DELETED) == 0) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "UNDRAFT")) {
		if ((Imap->flags[seq-1] & IMAP_DRAFT) == 0) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "UNFLAGGED")) {
		if ((Imap->flags[seq-1] & IMAP_FLAGGED) == 0) {
			match = 1;
		}
		++pos;
	}

	else if (!strcasecmp(itemlist[pos].Key, "UNKEYWORD")) {
		/* FIXME */
		pos += 2;
	}

	else if (!strcasecmp(itemlist[pos].Key, "UNSEEN")) {
		if ((Imap->flags[seq-1] & IMAP_SEEN) == 0) {
			match = 1;
		}
		++pos;
	}

	/* Remember to negate if we were told to */
	if (is_not) {
		match = !match;
	}

	/* Keep going if there are more criteria! */
	if (pos < num_items) {

		if (is_or) {
			match = (match || imap_do_search_msg(seq, msg,
				num_items - pos, &itemlist[pos], is_uid));
		}
		else {
			match = (match && imap_do_search_msg(seq, msg,
				num_items - pos, &itemlist[pos], is_uid));
		}

	}

	if (need_to_free_msg) {
		CM_Free(msg);
	}
	return(match);
}
Exemple #4
0
void network_process_digest(SpoolControl *sc, struct CtdlMessage *omsg, long *delete_after_send)
{

	struct CtdlMessage *msg = NULL;

	if (sc->Users[digestrecp] == NULL)
		return;

	/* If there are digest recipients, we have to build a digest */
	if (sc->digestfp == NULL) {
		
		sc->digestfp = create_digest_file(&sc->room, 1);

		if (sc->digestfp == NULL)
			return;

		sc->haveDigest = ftell(sc->digestfp) > 0;
		if (!sc->haveDigest) {
			fprintf(sc->digestfp, "Content-type: text/plain\n\n");
		}
		sc->haveDigest = 1;
	}

	msg = CM_Duplicate(omsg);
	if (msg != NULL) {
		sc->haveDigest = 1;
		fprintf(sc->digestfp,
			" -----------------------------------"
			"------------------------------------"
			"-------\n");
		fprintf(sc->digestfp, "From: ");
		if (!CM_IsEmpty(msg, eAuthor)) {
			fprintf(sc->digestfp,
				"%s ",
				msg->cm_fields[eAuthor]);
		}
		if (!CM_IsEmpty(msg, erFc822Addr)) {
			fprintf(sc->digestfp,
				"<%s> ",
				msg->cm_fields[erFc822Addr]);
		}
		else if (!CM_IsEmpty(msg, eNodeName)) {
			fprintf(sc->digestfp,
				"@%s ",
				msg->cm_fields[eNodeName]);
		}
		fprintf(sc->digestfp, "\n");
		if (!CM_IsEmpty(msg, eMsgSubject)) {
			fprintf(sc->digestfp,
				"Subject: %s\n",
				msg->cm_fields[eMsgSubject]);
		}

		CC->redirect_buffer = NewStrBufPlain(NULL, SIZ);

		safestrncpy(CC->preferred_formats,
			    "text/plain",
			    sizeof CC->preferred_formats);

		CtdlOutputPreLoadedMsg(msg,
				       MT_CITADEL,
				       HEADERS_NONE,
				       0, 0, 0);

		StrBufTrim(CC->redirect_buffer);
		fwrite(HKEY("\n"), 1, sc->digestfp);
		fwrite(SKEY(CC->redirect_buffer), 1, sc->digestfp);
		fwrite(HKEY("\n"), 1, sc->digestfp);

		FreeStrBuf(&CC->redirect_buffer);

		sc->num_msgs_spooled += 1;
		CM_Free(msg);
	}
}