X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmsgbase.c;h=1a1f984f1aa6368ddf770f9307bbb0bb59443e97;hb=8896f6d392af58e432577e100353f5ffb4d02e21;hp=bdee54e1ef4ed50ac94469979d0a06c50c0b4373;hpb=79311f2b6fc6116e321f900def542c1a48fee0cc;p=citadel.git diff --git a/citadel/msgbase.c b/citadel/msgbase.c index bdee54e1e..1a1f984f1 100644 --- a/citadel/msgbase.c +++ b/citadel/msgbase.c @@ -52,6 +52,11 @@ #include "euidindex.h" #include "journaling.h" #include "citadel_dirs.h" +#include "serv_network.h" + +#ifdef HAVE_LIBSIEVE +# include "serv_sieve.h" +#endif /* HAVE_LIBSIEVE */ long config_msgnum; struct addresses_to_be_filed *atbf = NULL; @@ -504,14 +509,14 @@ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums, * API function to perform an operation for each qualifying message in the * current room. (Returns the number of messages processed.) */ -int CtdlForEachMessage(int mode, long ref, +int CtdlForEachMessage(int mode, long ref, char *search_string, char *content_type, struct CtdlMessage *compare, void (*CallBack) (long, void *), void *userdata) { - int a; + int a, i, j; struct visit vbuf; struct cdbdata *cdbfr; long *msglist = NULL; @@ -523,6 +528,8 @@ int CtdlForEachMessage(int mode, long ref, int is_seen = 0; long lastold = 0L; int printed_lastold = 0; + int num_search_msgs = 0; + long *search_msgs = NULL; /* Learn about the user and room in question */ get_mm(); @@ -587,7 +594,45 @@ int CtdlForEachMessage(int mode, long ref, } } + /* If a search string was specified, get a message list from + * the full text index and remove messages which aren't on both + * lists. + * + * How this works: + * Since the lists are sorted and strictly ascending, and the + * output list is guaranteed to be shorter than or equal to the + * input list, we overwrite the bottom of the input list. This + * eliminates the need to memmove big chunks of the list over and + * over again. + */ + if ( (num_msgs > 0) && (mode == MSGS_SEARCH) && (search_string) ) { + ft_search(&num_search_msgs, &search_msgs, search_string); + if (num_search_msgs > 0) { + int orig_num_msgs; + + orig_num_msgs = num_msgs; + num_msgs = 0; + for (i=0; ilogged_in)) && (!(CC->internal_pgm))) { cprintf("%d not logged in\n", ERROR + NOT_LOGGED_IN); return; } + if ( (mode == MSGS_SEARCH) && (!config.c_enable_fulltext) ) { + cprintf("%d Full text index is not enabled on this server.\n", + ERROR + CMD_NOT_SUPPORTED); + return; + } + if (with_template) { unbuffer_output(); cprintf("%d Send template then receive message list\n", @@ -695,7 +751,8 @@ void cmd_msgs(char *cmdbuf) } CtdlForEachMessage(mode, - cm_ref, + ( (mode == MSGS_SEARCH) ? 0 : cm_ref ), + ( (mode == MSGS_SEARCH) ? search_string : NULL ), NULL, template, (with_headers ? headers_listing : simple_listing), @@ -1152,6 +1209,12 @@ void fixed_output(char *name, char *filename, char *partnum, char *disp, * The client is elegant and sophisticated and wants to be choosy about * MIME content types, so figure out which multipart/alternative part * we're going to send. + * + * We use a system of weights. When we find a part that matches one of the + * MIME types we've declared as preferential, we can store it in ma->chosen_part + * and then set ma->chosen_pref to that MIME type's position in our preference + * list. If we then hit another match, we only replace the first match if + * the preference value is lower. */ void choose_preferred(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, char *cbcharset, size_t length, @@ -1166,8 +1229,12 @@ void choose_preferred(char *name, char *filename, char *partnum, char *disp, if (ma->is_ma > 0) { for (i=0; ipreferred_formats, '|'); ++i) { extract_token(buf, CC->preferred_formats, i, '|', sizeof buf); + lprintf(CTDL_DEBUG, "Is <%s> == <%s> ??\n", buf, cbtype); if ( (!strcasecmp(buf, cbtype)) && (!ma->freeze) ) { - safestrncpy(ma->chosen_part, partnum, sizeof ma->chosen_part); + if (i < ma->chosen_pref) { + safestrncpy(ma->chosen_part, partnum, sizeof ma->chosen_part); + ma->chosen_pref = i; + } } } } @@ -1527,6 +1594,12 @@ int CtdlOutputPreLoadedMsg( else if (i == 'Y') { cprintf("CC: %s%s", mptr, nl); } + else if (i == 'P') { + cprintf("Return-Path: %s%s", mptr, nl); + } + else if (i == 'V') { + cprintf("Envelope-To: %s%s", mptr, nl); + } else if (i == 'U') { cprintf("Subject: %s%s", mptr, nl); subject_found = 1; @@ -1703,6 +1776,7 @@ START_TEXT: if (mode == MT_MIME) { ma.use_fo_hooks = 0; strcpy(ma.chosen_part, "1"); + ma.chosen_pref = 9999; mime_parser(mptr, NULL, *choose_preferred, *fixed_output_pre, *fixed_output_post, (void *)&ma, 0); @@ -1980,6 +2054,16 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms lprintf(CTDL_DEBUG, "CtdlSaveMsgPointerInRoom() skips repl checks\n"); } + /* Submit this room for net processing */ + network_queue_room(&CC->room, NULL); + +#ifdef HAVE_LIBSIEVE + /* If this is someone's inbox, submit the room for sieve processing */ + if (!strcasecmp(&CC->room.QRname[11], MAILROOM)) { + sieve_queue_room(&CC->room); + } +#endif /* HAVE_LIBSIEVE */ + /* Go back to the room we were in before we wandered here... */ getroom(&CC->room, hold_rm); @@ -2563,7 +2647,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ /* * Convenience function for generating small administrative messages. */ -void quickie_message(char *from, char *to, char *room, char *text, +void quickie_message(char *from, char *fromaddr, char *to, char *room, char *text, int format_type, char *subject) { struct CtdlMessage *msg; @@ -2574,7 +2658,21 @@ void quickie_message(char *from, char *to, char *room, char *text, msg->cm_magic = CTDLMESSAGE_MAGIC; msg->cm_anon_type = MES_NORMAL; msg->cm_format_type = format_type; - msg->cm_fields['A'] = strdup(from); + + if (from != NULL) { + msg->cm_fields['A'] = strdup(from); + } + else if (fromaddr != NULL) { + msg->cm_fields['A'] = strdup(fromaddr); + if (strchr(msg->cm_fields['A'], '@')) { + *strchr(msg->cm_fields['A'], '@') = 0; + } + } + else { + msg->cm_fields['A'] = strdup("Citadel"); + } + + if (fromaddr != NULL) msg->cm_fields['F'] = strdup(fromaddr); if (room != NULL) msg->cm_fields['O'] = strdup(room); msg->cm_fields['N'] = strdup(NODENAME); if (to != NULL) { @@ -2610,6 +2708,7 @@ char *CtdlReadMessageBody(char *terminator, /* token signalling EOT */ char *m; int flushing = 0; int finished = 0; + int dotdot = 0; if (exist == NULL) { m = malloc(4096); @@ -2627,6 +2726,11 @@ char *CtdlReadMessageBody(char *terminator, /* token signalling EOT */ } } + /* Do we need to change leading ".." to "." for SMTP escaping? */ + if (!strcmp(terminator, ".")) { + dotdot = 1; + } + /* flush the input if we have nowhere to store it */ if (m == NULL) { flushing = 1; @@ -2643,6 +2747,13 @@ char *CtdlReadMessageBody(char *terminator, /* token signalling EOT */ strcat(buf, "\n"); } + /* Unescape SMTP-style input of two dots at the beginning of the line */ + if (dotdot) { + if (!strncmp(buf, "..", 2)) { + strcpy(buf, &buf[1]); + } + } + if ( (!flushing) && (!finished) ) { /* Measure the line */ linelen = strlen(buf); @@ -3827,7 +3938,7 @@ char *CtdlGetSysConfig(char *sysconfname) { /* We want the last (and probably only) config in this room */ begin_critical_section(S_CONFIG); config_msgnum = (-1L); - CtdlForEachMessage(MSGS_LAST, 1, sysconfname, NULL, + CtdlForEachMessage(MSGS_LAST, 1, NULL, sysconfname, NULL, CtdlGetSysConfigBackend, NULL); msgnum = config_msgnum; end_critical_section(S_CONFIG);