#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;
* 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;
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();
}
}
+ /* 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; i<orig_num_msgs; ++i) {
+ for (j=0; j<num_search_msgs; ++j) {
+ if (msglist[i] == search_msgs[j]) {
+ msglist[num_msgs++] = msglist[i];
+ }
+ }
+ }
+ }
+ else {
+ num_msgs = 0; /* No messages qualify */
+ }
+ if (search_msgs != NULL) free(search_msgs);
+
+ /* Now that we've purged messages which don't contain the search
+ * string, treat a MSGS_SEARCH just like a MSGS_ALL from this
+ * point on.
+ */
+ mode = MSGS_ALL;
+ }
+
/*
* Now iterate through the message list, according to the
* criteria supplied by the caller.
int with_template = 0;
struct CtdlMessage *template = NULL;
int with_headers = 0;
+ char search_string[1024];
extract_token(which, cmdbuf, 0, '|', sizeof which);
cm_ref = extract_int(cmdbuf, 1);
+ extract_token(search_string, cmdbuf, 1, '|', sizeof search_string);
with_template = extract_int(cmdbuf, 2);
with_headers = extract_int(cmdbuf, 3);
- mode = MSGS_ALL;
strcat(which, " ");
if (!strncasecmp(which, "OLD", 3))
mode = MSGS_OLD;
mode = MSGS_LAST;
else if (!strncasecmp(which, "GT", 2))
mode = MSGS_GT;
+ else if (!strncasecmp(which, "SEARCH", 6))
+ mode = MSGS_SEARCH;
+ else
+ mode = MSGS_ALL;
if ((!(CC->logged_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",
}
CtdlForEachMessage(mode,
- cm_ref,
+ ( (mode == MSGS_SEARCH) ? 0 : cm_ref ),
+ ( (mode == MSGS_SEARCH) ? search_string : NULL ),
NULL,
template,
(with_headers ? headers_listing : simple_listing),
* 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,
if (ma->is_ma > 0) {
for (i=0; i<num_tokens(CC->preferred_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;
+ }
}
}
}
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;
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);
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);
/*
* 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;
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) {
char *m;
int flushing = 0;
int finished = 0;
+ int dotdot = 0;
if (exist == NULL) {
m = malloc(4096);
}
}
+ /* 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;
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);
/* 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);