From 9c45d9ad13fdf439d44d7443ae75da15ea0223ed Mon Sep 17 00:00:00 2001 From: Sam Varshavchik Date: Mon, 19 Aug 2013 16:39:41 -0400 Subject: Initial checkin Imported from subversion report, converted to git. Updated all paths in scripts and makefiles, reflecting the new directory hierarchy. --- imap/search.c | 1066 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1066 insertions(+) create mode 100644 imap/search.c (limited to 'imap/search.c') diff --git a/imap/search.c b/imap/search.c new file mode 100644 index 0000000..e532dcd --- /dev/null +++ b/imap/search.c @@ -0,0 +1,1066 @@ +/* +** Copyright 1998 - 2009 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#include "rfc822/rfc822.h" +#include "rfc822/rfc822hdr.h" +#include "rfc822/rfc2047.h" +#include "rfc2045/rfc2045.h" +#include "unicode/unicode.h" +#include "numlib/numlib.h" +#include "searchinfo.h" +#include "imapwrite.h" +#include "imaptoken.h" +#include "imapscanclient.h" + + +extern time_t rfc822_parsedt(const char *); +extern struct imapscaninfo current_maildir_info; +extern char *current_mailbox; + +extern int get_flagname(const char *, struct imapflags *); +extern void get_message_flags( struct imapscanmessageinfo *, + char *, struct imapflags *); +extern int valid_keyword(const char *kw); + +static void fill_search_preparse(struct searchinfo *); + +static void fill_search_veryquick(struct searchinfo *, + unsigned long, struct imapflags *); + +static void fill_search_quick(struct searchinfo *, + unsigned long, struct stat *); + +static void fill_search_header(struct searchinfo *, + const char *, + struct rfc2045 *, FILE *, + struct imapscanmessageinfo *); + +static void fill_search_body(struct searchinfo *, + struct rfc2045 *, FILE *, + struct imapscanmessageinfo *); + +static int search_evaluate(struct searchinfo *); + +static void search_callback(struct searchinfo *, struct searchinfo *, int, + unsigned long, void *); + +/* +** search_internal() does the main heavylifting of searching the +** maildir for qualifying messages. It calls a callback function +** when a matching message is found. +** +** For a plain SEARCH, the callback function merely prints the message +** number. +*/ + +void dosearch(struct searchinfo *si, struct searchinfo *sihead, + const char *charset, int isuid) +{ + search_internal(si, sihead, charset, isuid, search_callback, 0); +} + +static void search_callback(struct searchinfo *si, struct searchinfo *sihead, + int isuid, unsigned long i, void *dummy) +{ + writes(" "); + writen(isuid ? current_maildir_info.msgs[i].uid:i+1); +} + +static void search_oneatatime(struct searchinfo *si, + unsigned long i, + struct searchinfo *sihead, + const char *charset, int isuid, + void (*callback_func)(struct searchinfo *, + struct searchinfo *, int, + unsigned long, void *), + void *voidarg); + +static void search_byKeyword(struct searchinfo *tree, + struct searchinfo *keyword, + struct searchinfo *sihead, + const char *charset, int isuid, + void (*callback_func)(struct searchinfo *, + struct searchinfo *, int, + unsigned long, void *), + void *voidarg); + +void search_internal(struct searchinfo *si, struct searchinfo *sihead, + const char *charset, int isuid, + void (*callback_func)(struct searchinfo *, + struct searchinfo *, int, + unsigned long, void *), + void *voidarg) +{ + unsigned long i; + struct searchinfo *p; + + for (p=sihead; p; p=p->next) + fill_search_preparse(p); + + /* Shortcuts for keyword-based searches */ + + if (si->type == search_msgkeyword && si->bs == NULL && si->ke) + search_byKeyword(NULL, si, sihead, charset, isuid, + callback_func, voidarg); + else if (si->type == search_and && + si->a->type == search_msgkeyword && si->a->bs == NULL + && si->a->ke) + search_byKeyword(si->b, si->a, sihead, charset, isuid, + callback_func, voidarg); + else for (i=0; ike->firstMsg; kme; kme=kme->keywordNext) + { + unsigned long n=kme->libmail_kwMessagePtr->u.userNum; + if (!tree) + { + (*callback_func)(keyword, keyword, isuid, n, voidarg); + continue; + } + + search_oneatatime(tree, n, sihead, charset, isuid, + callback_func, voidarg); + } +} + +/* +** Evaluate the search tree for a given message. +*/ + +static void search_oneatatime(struct searchinfo *si, + unsigned long i, + struct searchinfo *sihead, + const char *charset, int isuid, + void (*callback_func)(struct searchinfo *, + struct searchinfo *, int, + unsigned long, void *), + void *voidarg) +{ +struct searchinfo *p; +struct imapflags flags; +int fd; +FILE *fp; +struct stat stat_buf; +int rc; + + { + for (p=sihead; p; p=p->next) + p->value= -1; /* Search result unknown */ + + /* First, see if non-content search will be sufficient */ + + get_message_flags(current_maildir_info.msgs+i, 0, &flags); + + for (p=sihead; p; p=p->next) + fill_search_veryquick(p, i, &flags); + + if ((rc=search_evaluate(si)) >= 0) + { + if (rc > 0) + (*callback_func)(si, sihead, isuid, i, + voidarg); + return; + } + + fd=imapscan_openfile(current_mailbox, + ¤t_maildir_info, i); + if (fd < 0) return; + + if ((fp=fdopen(fd, "r")) == 0) + write_error_exit(0); + + if (fstat(fileno(fp), &stat_buf)) + { + fclose(fp); + return; + } + + /* First, see if non-content search will be sufficient */ + + for (p=sihead; p; p=p->next) + fill_search_quick(p, i, &stat_buf); + + if ((rc=search_evaluate(si)) < 0) + { + /* No, search the headers then */ + /* struct rfc2045 *rfcp=rfc2045_fromfp(fp); */ + struct rfc2045 *rfcp=rfc2045header_fromfp(fp); + + fill_search_header(sihead, charset, rfcp, fp, + current_maildir_info.msgs+i); + rc=search_evaluate(si); + rfc2045_free(rfcp); + + if (rc < 0) + { + /* Ok, search message contents */ + struct rfc2045 *rfcp=rfc2045_fromfp(fp); + + fill_search_body(sihead, rfcp, fp, + current_maildir_info.msgs+i); + + /* + ** If there are still UNKNOWN nodes, change + ** them to fail. + */ + + for (p=sihead; p; p=p->next) + if (p->value < 0) + p->value=0; + + rc=search_evaluate(si); + rfc2045_free(rfcp); + } + /* rfc2045_free(rfcp); */ + } + + if (rc > 0) + { + (*callback_func)(si, sihead, isuid, i, voidarg); + } + fclose(fp); + close(fd); + } +} + +/* Check if the given index is included in the specified message set */ + +static int is_in_set(const char *msgset, unsigned long n) +{ +unsigned long i, j; + + while (isdigit((int)(unsigned char)*msgset)) + { + i=0; + while (isdigit((int)(unsigned char)*msgset)) + { + i=i*10 + (*msgset++-'0'); + } + if (*msgset != ':') + j=i; + else + { + j=0; + ++msgset; + if (*msgset == '*') + { + ++msgset; + /* + ** Ok, we don't really need to know the upper + ** end, just hack it. + */ + j=i; + if (j < n) + j=n; + } + else + while (isdigit((int)(unsigned char)*msgset)) + { + j=j*10 + (*msgset++-'0'); + } + } + if (n >= i && n <= j) return (1); + if (*msgset == 0 || *msgset++ != ',') break; + } + return (0); +} + +/* +** Search date comparisons compare the dates only, not the time. +** We convert all timestamps to midnight GMT on their respective dates. +** Use convenient RFC822 functions for that purpose. +*/ + +static time_t decode_date(char *p) +{ +char *s=malloc(strlen(p)+sizeof(" 00:00:00")); +unsigned i; +time_t t; + + if (!s) write_error_exit(0); + + /* Convert to format rfc822_parsedt likes */ + + for (i=1; p[i] != ' '; i++) + { + if (!p[i]) break; + } + memcpy(s, p, i); + strcpy(s+i, " 00:00:00"); + while (i) + { + if (s[--i] == '-') + s[i]=' '; + } + + t=rfc822_parsedt(s); + free(s); + return (t); +} + +/* Given a time_t that falls on, say, 3-Aug-1999 9:50:43 local time, +** calculate the time_t for midnight 3-Aug-1999 UTC. Search date comparisons +** are done against midnight UTCs */ + +static time_t timestamp_to_day(time_t t) +{ +char buf1[60], buf2[80]; + + rfc822_mkdate_buf(t, buf1); /* Converts to local time */ + (void)strtok(buf1, " "); /* Skip weekday */ + strcpy(buf2, strtok(0, " ")); + strcat(buf2, " "); + strcat(buf2, strtok(0, " ")); + strcat(buf2, " "); + strcat(buf2, strtok(0, " ")); + strcat(buf2, " 00:00:00"); + return (rfc822_parsedt(buf2)); +} + +static char *timestamp_for_sorting(time_t t) +{ +struct tm *tm=localtime(&t); +char buf[200]; + + buf[0]=0; + if ( strftime(buf, sizeof(buf), "%Y.%m.%d.%H.%M.%S", tm) == 0) + buf[0]=0; + return (my_strdup(buf)); +} + +static void fill_search_preparse(struct searchinfo *p) +{ + switch (p->type) { + case search_msgflag: + { + struct imapflags flags; + + memset(&flags, 0, sizeof(flags)); + p->ke=NULL; + + if (get_flagname(p->as, &flags) == 0) + { + p->bs=malloc(sizeof(flags)); + + if (!p->bs) + write_error_exit(0); + + memcpy(p->bs, &flags, sizeof(flags)); + } + } + break; + + case search_msgkeyword: + p->ke=NULL; + if (valid_keyword(p->as)) + p->ke=libmail_kweFind(current_maildir_info + .keywordList, + p->as, 0); + break; + default: + break; + } +} + +/* Evaluate non-content search nodes */ + +static void fill_search_veryquick(struct searchinfo *p, + unsigned long msgnum, struct imapflags *flags) +{ + switch (p->type) { + case search_msgflag: + { + struct imapflags *f=(struct imapflags *)p->bs; + + p->value=0; + if (strcmp(p->as, "\\RECENT") == 0 && + current_maildir_info.msgs[msgnum].recentflag) + p->value=1; + + if (f) + { + if (f->seen && flags->seen) + p->value=1; + if (f->answered && flags->answered) + p->value=1; + if (f->deleted && flags->deleted) + p->value=1; + if (f->flagged && flags->flagged) + p->value=1; + if (f->drafts && flags->drafts) + p->value=1; + } + break; + } + + case search_msgkeyword: + p->value=0; + if (p->ke) + { + struct libmail_kwMessage *km= + current_maildir_info.msgs[msgnum] + .keywordMsg; + struct libmail_kwMessageEntry *kme; + + for (kme=km ? km->firstEntry:NULL; + kme; kme=kme->next) + if (strcasecmp(keywordName(kme-> + libmail_keywordEntryPtr), + keywordName(p->ke))==0) + { + p->value=1; + break; + } + } + break; + case search_messageset: + if (is_in_set(p->as, msgnum+1)) + p->value=1; + else + p->value=0; + break; + case search_all: + p->value=1; + break; + case search_uid: + if (is_in_set(p->as, current_maildir_info.msgs[msgnum].uid)) + p->value=1; + else + p->value=0; + break; + case search_reverse: + p->value=1; + break; + default: + break; + } +} + +static void fill_search_quick(struct searchinfo *p, + unsigned long msgnum, struct stat *stat_buf) +{ + switch (p->type) { + case search_before: + p->value=0; + { + time_t t=decode_date(p->as); + + if (t && timestamp_to_day(stat_buf->st_mtime) < t) + p->value=1; + } + break; + case search_since: + p->value=0; + { + time_t t=decode_date(p->as); + + if (t && timestamp_to_day(stat_buf->st_mtime) >= t) + p->value=1; + } + break; + case search_on: + p->value=0; + { + time_t t=decode_date(p->as); + + if (t && timestamp_to_day(stat_buf->st_mtime) == t) + p->value=1; + } + break; + case search_smaller: + p->value=0; + { + unsigned long n; + + if (sscanf(p->as, "%lu", &n) > 0 && + stat_buf->st_size < n) + p->value=1; + } + break; + case search_larger: + p->value=0; + { + unsigned long n; + + if (sscanf(p->as, "%lu", &n) > 0 && + stat_buf->st_size > n) + p->value=1; + } + break; + case search_orderedsubj: + case search_references1: + case search_references2: + case search_references3: + case search_references4: + case search_arrival: + case search_cc: + case search_date: + case search_from: + case search_reverse: + case search_size: + case search_to: + + /* DUMMY nodes for SORT/THREAD. Make sure that the + ** dummy node is CLEARed */ + + if (p->as) + { + free(p->as); + p->as=0; + } + + if (p->bs) + { + free(p->bs); + p->bs=0; + } + + switch (p->type) { + case search_arrival: + p->as=timestamp_for_sorting(stat_buf->st_mtime); + p->value=1; + break; + case search_size: + { + char buf[NUMBUFSIZE], buf2[NUMBUFSIZE]; + char *q; + + libmail_str_size_t(stat_buf->st_size, buf); + sprintf(buf2, "%*s", (int)(sizeof(buf2)-1), buf); + for (q=buf2; *q == ' '; *q++='0') + ; + p->as=my_strdup(buf2); + p->value=1; + } + break; + default: + break; + } + break; + default: + break; + } +} + +/* Evaluate search results. Returns: 0 - false, 1 - true, -1 - unknown +** (partial search on message metadata, like size or flags, in hopes of +** preventing a search +** of message contents). +*/ + +static int search_evaluate(struct searchinfo *si) +{ +int rc, rc2; + + switch (si->type) { + case search_orderedsubj: /* DUMMIES for THREAD and SORT */ + case search_references1: + case search_references2: + case search_references3: + case search_references4: + case search_arrival: + case search_cc: + case search_date: + case search_from: + case search_reverse: + case search_size: + case search_to: + rc = search_evaluate(si->a); + if (rc == 0) return 0; + if (si->value < 0) return (-1); + break; + case search_not: + rc=search_evaluate(si->a); + if (rc >= 0) rc= 1-rc; + break; + case search_and: + rc=search_evaluate(si->a); + rc2=search_evaluate(si->b); + + rc= rc > 0 && rc2 > 0 ? 1: + rc == 0 || rc2 == 0 ? 0:-1; + break; + case search_or: + rc=search_evaluate(si->a); + rc2=search_evaluate(si->b); + + rc= rc > 0 || rc2 > 0 ? 1: + rc == 0 && rc2 == 0 ? 0:-1; + break; + default: + rc=si->value; + break; + } + return (rc); +} + +/* ------- header search -------- */ + +struct fill_search_header_info { + + struct searchinfo *si; + + char *utf8buf; + size_t utf8buflen; + size_t utf8bufsize; +}; + +static int headerfilter_func(const char *name, const char *value, void *arg); +static int fill_search_header_utf8(const char *, size_t, void *); +static int fill_search_header_done(const char *, void *); + +static void fill_search_header(struct searchinfo *si, + const char *charset, + struct rfc2045 *rfcp, FILE *fp, + struct imapscanmessageinfo *mi) +{ + struct searchinfo *sip; + struct rfc2045src *src; + struct rfc2045_decodemsgtoutf8_cb decodecb; + struct fill_search_header_info decodeinfo; + + /* Consider the following dummy nodes as evaluated */ + + for (sip=si; sip; sip=sip->next) + switch (sip->type) { + case search_orderedsubj: + case search_references1: + case search_references2: + case search_references3: + case search_references4: + case search_cc: + case search_date: + case search_from: + case search_to: + sip->value=1; + break; + default: + break; + } + + search_set_charset_conv(si, charset); + + src=rfc2045src_init_fd(fileno(fp)); + + if (!src) + return; + + memset(&decodecb, 0, sizeof(decodecb)); + memset(&decodeinfo, 0, sizeof(decodeinfo)); + + decodeinfo.si=si; + + decodecb.flags=RFC2045_DECODEMSG_NOBODY + | RFC2045_DECODEMSG_NOHEADERNAME; + decodecb.headerfilter_func=headerfilter_func; + decodecb.output_func=fill_search_header_utf8; + decodecb.headerdone_func=fill_search_header_done; + decodecb.arg=&decodeinfo; + + rfc2045_decodemsgtoutf8(src, rfcp, &decodecb); + rfc2045src_deinit(src); + if (decodeinfo.utf8buf) + free(decodeinfo.utf8buf); +} + +static int headerfilter_func(const char *name, const char *value, void *arg) +{ + struct fill_search_header_info *decodeinfo= + (struct fill_search_header_info *)arg; + struct searchinfo *sip; + const char *p; + int isto=rfc822hdr_namecmp(name, "to"); + int iscc=rfc822hdr_namecmp(name, "cc"); + int isfrom=rfc822hdr_namecmp(name, "from"); + int isinreplyto=rfc822hdr_namecmp(name, "in-reply-to"); + int isdate=rfc822hdr_namecmp(name, "date"); + + int isreferences=rfc822hdr_namecmp(name, "references"); + int ismessageid=rfc822hdr_namecmp(name, "message-id"); + + for (sip=decodeinfo->si; sip; sip=sip->next) + { + if (sip->type == search_text && sip->value <= 0) + { + /* + ** Full message search. Reset the search engine, + ** feed it "Headername: " + */ + + maildir_search_reset(&sip->sei); + + for (p=name; *p; p++) + { + maildir_search_step_unicode_lc(&sip->sei, + (unsigned char) + *p); + if (maildir_search_found(&sip->sei)) + sip->value=1; + } + for (p=": "; *p; p++) + { + maildir_search_step_unicode_lc(&sip->sei, + (unsigned char) + *p); + if (maildir_search_found(&sip->sei)) + sip->value=1; + } + } + + if ( (sip->type == search_cc && iscc == 0 && sip->as == 0) + || + (sip->type == search_from && isfrom == 0 && sip->as == 0) + || + (sip->type == search_to && isto == 0 && sip->as == 0) + || + (sip->type == search_references1 && isinreplyto == 0 + && sip->bs == 0)) + { + struct rfc822t *t; + struct rfc822a *a; + char *s; + + t=rfc822t_alloc_new(value, NULL, NULL); + if (!t) write_error_exit(0); + a=rfc822a_alloc(t); + if (!a) write_error_exit(0); + s=a->naddrs > 0 ? rfc822_getaddr(a, 0):strdup(""); + rfc822a_free(a); + rfc822t_free(t); + if (!s) write_error_exit(0); + + if (sip->type == search_references1) + { + sip->bs=malloc(strlen(s)+3); + if (!sip->bs) + write_error_exit(0); + strcat(strcat(strcpy(sip->bs, "<"), s), ">"); + free(s); + } + else + sip->as=s; + } + + switch (sip->type) { + case search_orderedsubj: + + if (isdate == 0 && sip->bs == 0) + { + sip->bs=strdup(value); + if (!sip->bs) + write_error_exit(0); + } + break; + + case search_date: + + if (isdate == 0 && sip->as == 0) + { + time_t msg_time=rfc822_parsedt(value); + + sip->as=timestamp_for_sorting(msg_time); + } + break; + + case search_sentbefore: + case search_sentsince: + case search_senton: + + if (sip->value > 0) + break; + + if (isdate == 0) + { + time_t given_time=decode_date(sip->as); + time_t msg_time=rfc822_parsedt(value); + + if (given_time == 0 || msg_time == 0) + break; + + msg_time=timestamp_to_day(msg_time); + sip->value=0; + if ((sip->type == search_sentbefore && + msg_time < given_time) || + (sip->type == search_sentsince&& + msg_time>=given_time)|| + (sip->type == search_senton && + msg_time == given_time)) + sip->value=1; + } + break; + + case search_references1: + if (isreferences == 0 && sip->as == 0) + { + sip->as=strdup(value); + if (!sip->as) + write_error_exit(0); + } + break; + case search_references2: + if (isdate == 0 && sip->as == 0) + { + sip->as=strdup(value); + if (!sip->as) + write_error_exit(0); + } + break; + case search_references4: + if (ismessageid == 0 && sip->as == 0) + { + sip->as=strdup(value); + if (!sip->as) + write_error_exit(0); + } + break; + default: + break; + } + } + decodeinfo->utf8buflen=0; + return 1; +} + +static int fill_search_header_utf8(const char *str, size_t cnt, void *arg) +{ + struct fill_search_header_info *decodeinfo= + (struct fill_search_header_info *)arg; + + if (decodeinfo->utf8bufsize - decodeinfo->utf8buflen < cnt) + { + size_t newsize=decodeinfo->utf8buflen + cnt*2; + char *p=decodeinfo->utf8buf + ? realloc(decodeinfo->utf8buf, newsize): + malloc(newsize); + + if (!p) + write_error_exit(0); + decodeinfo->utf8buf=p; + decodeinfo->utf8bufsize=newsize; + } + + if (cnt) + memcpy(decodeinfo->utf8buf+decodeinfo->utf8buflen, str, cnt); + decodeinfo->utf8buflen += cnt; + return 0; +} + +static int fill_search_header_done(const char *name, void *arg) +{ + struct fill_search_header_info *decodeinfo= + (struct fill_search_header_info *)arg; + struct searchinfo *sip; + int issubject=rfc822hdr_namecmp(name, "subject"); + size_t j; + libmail_u_convert_handle_t conv; + unicode_char *ucptr; + size_t ucsize; + int rc; + + if (decodeinfo->utf8buflen && + decodeinfo->utf8buf[decodeinfo->utf8buflen-1] == '\n') + --decodeinfo->utf8buflen; + + fill_search_header_utf8("", 1, arg); + + for (sip=decodeinfo->si; sip; sip=sip->next) + switch (sip->type) { + case search_references3: + if (issubject == 0 && sip->as == 0) + { + sip->as=strdup(decodeinfo->utf8buf); + if (!sip->as) + write_error_exit(0); + } + break; + case search_orderedsubj: + + if (issubject == 0 && sip->as == 0) + { + int dummy; + + sip->as=rfc822_coresubj(decodeinfo->utf8buf, + &dummy); + if (!sip->as) + write_error_exit(0); + } + break; + case search_header: + + if (sip->cs == NULL || rfc822hdr_namecmp(sip->cs, name)) + break; + + /* FALLTHRU */ + + case search_text: + if (sip->value > 0) + break; + + maildir_search_reset(&sip->sei); + + conv=libmail_u_convert_tou_init("utf-8", &ucptr, + &ucsize, 0); + + if (!conv) + break; + + rc=libmail_u_convert(conv, decodeinfo->utf8buf, + decodeinfo->utf8buflen-1); + + if (libmail_u_convert_deinit(conv, NULL)) + break; + + if (rc) + { + free(ucptr); + break; + } + + for (j=0; j<=ucsize; ++j) + { + maildir_search_step_unicode_lc(&sip->sei, + j == ucsize + ? ' ': + ucptr[j]); + if (maildir_search_found(&sip->sei)) + { + sip->value=1; + break; + } + } + free(ucptr); + break; + default: + break; + } + + + return 0; +} + +struct fill_search_body_info { + + struct searchinfo *si; + libmail_u_convert_handle_t toucs4_handle; + +}; + +static int fill_search_body_utf8(const char *str, size_t n, void *arg); +static int fill_search_body_ucs4(const char *str, size_t n, void *arg); + +static void fill_search_body(struct searchinfo *si, + struct rfc2045 *rfcp, FILE *fp, + struct imapscanmessageinfo *mi) +{ + struct rfc2045src *src; + struct rfc2045_decodemsgtoutf8_cb decodecb; + struct fill_search_body_info decodeinfo; + struct searchinfo *sip; + + src=rfc2045src_init_fd(fileno(fp)); + + if (!src) + return; + + memset(&decodecb, 0, sizeof(decodecb)); + memset(&decodeinfo, 0, sizeof(decodeinfo)); + + decodecb.flags=RFC2045_DECODEMSG_NOHEADERS; + decodecb.output_func=fill_search_body_utf8; + decodecb.arg=&decodeinfo; + + decodeinfo.si=si; + + if ((decodeinfo.toucs4_handle= + libmail_u_convert_init("utf-8", + libmail_u_ucs4_native, + fill_search_body_ucs4, + &decodeinfo)) == NULL) + { + write_error_exit("libmail_u_convert_init"); + } + + for (sip=decodeinfo.si; sip; sip=sip->next) + if ((sip->type == search_text || sip->type == search_body) + && sip->value <= 0) + { + rfc2045_decodemsgtoutf8(src, rfcp, &decodecb); + break; + } + + libmail_u_convert_deinit(decodeinfo.toucs4_handle, NULL); + + rfc2045src_deinit(src); +} + +static int fill_search_body_utf8(const char *str, size_t n, void *arg) +{ + struct fill_search_body_info *decodeinfo= + (struct fill_search_body_info *)arg; + + return libmail_u_convert(decodeinfo->toucs4_handle, str, n); +} + +static int fill_search_body_ucs4(const char *str, size_t n, void *arg) +{ + struct fill_search_body_info *decodeinfo= + (struct fill_search_body_info *)arg; + struct searchinfo *sip; + const unicode_char *u=(const unicode_char *)str; + int notfound=1; + + n /= 4; + + for (sip=decodeinfo->si; sip; sip=sip->next) + if ((sip->type == search_text || sip->type == search_body) + && sip->value <= 0) + { + size_t i; + + notfound=0; + + for (i=0; isei, u[i]); + + if (maildir_search_found(&sip->sei)) + { + sip->value=1; + break; + } + } + } + + return notfound; +} -- cgit v1.2.3