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