diff options
| author | Sam Varshavchik | 2013-08-19 16:39:41 -0400 | 
|---|---|---|
| committer | Sam Varshavchik | 2013-08-25 14:43:51 -0400 | 
| commit | 9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch) | |
| tree | 7a81a04cb51efb078ee350859a64be2ebc6b8813 /imap/search.c | |
| parent | a9520698b770168d1f33d6301463bb70a19655ec (diff) | |
| download | courier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2 | |
Initial checkin
Imported from subversion report, converted to git. Updated all paths in
scripts and makefiles, reflecting the new directory hierarchy.
Diffstat (limited to 'imap/search.c')
| -rw-r--r-- | imap/search.c | 1066 | 
1 files changed, 1066 insertions, 0 deletions
| 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	<stdio.h> +#include	<string.h> +#include	<stdlib.h> +#include	<ctype.h> +#include	<time.h> +#if	HAVE_UNISTD_H +#include	<unistd.h> +#endif +#include	<errno.h> +#include	<sys/types.h> +#include	<sys/stat.h> +#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; i<current_maildir_info.nmessages; i++) +		search_oneatatime(si, i, sihead, charset, isuid, +				  callback_func, 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) +{ +	struct libmail_kwMessageEntry *kme; + +	for (kme=keyword->ke->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; i<n; i++) +			{ +				maildir_search_step_unicode_lc(&sip->sei, u[i]); + +				if (maildir_search_found(&sip->sei)) +				{ +					sip->value=1; +					break; +				} +			} +		} + +	return notfound; +} | 
