diff options
Diffstat (limited to 'imap/searchinfo.c')
| -rw-r--r-- | imap/searchinfo.c | 689 |
1 files changed, 689 insertions, 0 deletions
diff --git a/imap/searchinfo.c b/imap/searchinfo.c new file mode 100644 index 0000000..0f43ad2 --- /dev/null +++ b/imap/searchinfo.c @@ -0,0 +1,689 @@ +/* +** Copyright 1998 - 2010 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include "unicode/unicode.h" +#include "searchinfo.h" +#include "imapwrite.h" +#include "imaptoken.h" + + +struct searchinfo *alloc_search(struct searchinfo **head) +{ +struct searchinfo *si=(struct searchinfo *)malloc(sizeof(**head)); + + if (si == 0) write_error_exit(0); + memset(si, 0, sizeof(*si)); + maildir_search_init(&si->sei); + si->next= *head; + *head=si; + return (si); +} + +void free_search(struct searchinfo *si) +{ +struct searchinfo *p; + + while (si) + { + p=si->next; + if (si->as) free(si->as); + if (si->bs) free(si->bs); + if (si->cs) free(si->cs); + + maildir_search_destroy(&si->sei); + + free(si); + si=p; + } +} + +static struct searchinfo *alloc_search_andlist(struct searchinfo **); +static struct searchinfo *alloc_search_notkey(struct searchinfo **); +static struct searchinfo *alloc_search_key(struct searchinfo **); + +struct searchinfo *alloc_parsesearch(struct searchinfo **head) +{ +struct searchinfo *si; + + *head=0; + if ((si=alloc_search_andlist(head)) == 0) + { + free_search(*head); + return (0); + } + return (si); +} + +struct searchinfo *alloc_searchextra(struct searchinfo *top, + struct searchinfo **head, search_type t) +{ + struct searchinfo *si; + + if (t == search_references1) + { + /* Automatically add third and second dummy node */ + + top=alloc_searchextra(top, head, search_references4); + top=alloc_searchextra(top, head, search_references3); + top=alloc_searchextra(top, head, search_references2); + } + si=alloc_search(head); + si->type=t; + si->a=top; + return (si); +} + +static struct searchinfo *alloc_search_andlist(struct searchinfo **head) +{ +struct searchinfo *si, *a, *b; +struct imaptoken *t; + + si=alloc_search_notkey(head); + if (!si) return (0); + while ((t=currenttoken())->tokentype != IT_RPAREN && t->tokentype != + IT_EOL) + { + if ((a=alloc_search_notkey(head)) == 0) return (0); + b=alloc_search(head); + b->type=search_and; + b->a=si; + b->b=a; + si=b; + } + return (si); +} + +static struct searchinfo *alloc_search_notkey(struct searchinfo **head) +{ +struct imaptoken *t=currenttoken(); + + if (t->tokentype == IT_ATOM && strcmp(t->tokenbuf, "NOT") == 0) + { + struct searchinfo *si=alloc_search(head); + + si->type=search_not; + nexttoken(); + if ((si->a=alloc_search_key(head)) == 0) + return (0); + return (si); + } + return (alloc_search_key(head)); +} + +static struct searchinfo *alloc_search_key(struct searchinfo **head) +{ +struct imaptoken *t=currenttoken(); +struct searchinfo *si; +const char *keyword; + + if (t->tokentype == IT_LPAREN) + { + nexttoken(); + if ((si=alloc_search_andlist(head)) == 0 || + currenttoken()->tokentype != IT_RPAREN) + return (0); + nexttoken(); + return (si); + } + + if (t->tokentype != IT_ATOM && t->tokentype != IT_NUMBER) + return (0); + + keyword=t->tokenbuf; + + if (strcmp(keyword, "ALL") == 0) + { + struct searchinfo *si; + + (si=alloc_search(head))->type=search_all; + nexttoken(); + return (si); + } + + if (strcmp(keyword, "OR") == 0) + { + struct searchinfo *si; + + si=alloc_search(head); + si->type=search_or; + nexttoken(); + if ((si->a=alloc_search_notkey(head)) == 0 || + (si->b=alloc_search_notkey(head)) == 0) return (0); + return (si); + } + + if (strcmp(keyword, "HEADER") == 0) + { + struct imaptoken *t; + struct searchinfo *si; + + si=alloc_search(head); + si->type=search_header; + t=nexttoken_okbracket(); + if (t->tokentype != IT_ATOM && + t->tokentype != IT_NUMBER && + t->tokentype != IT_QUOTED_STRING) + return (0); + si->cs=strdup(t->tokenbuf); + if (!si->cs) + write_error_exit(0); + t=nexttoken_okbracket(); + if (t->tokentype != IT_ATOM && + t->tokentype != IT_NUMBER && + t->tokentype != IT_QUOTED_STRING) + return (0); + si->as=my_strdup(t->tokenbuf); + nexttoken(); + return (si); + } + + if (strcmp(keyword, "BCC") == 0 || + strcmp(keyword, "CC") == 0 || + strcmp(keyword, "FROM") == 0 || + strcmp(keyword, "TO") == 0 || + strcmp(keyword, "SUBJECT") == 0) + { + struct imaptoken *t; + struct searchinfo *si; + + si=alloc_search(head); + si->type=search_header; + si->cs=my_strdup(keyword); + t=nexttoken_okbracket(); + if (t->tokentype != IT_ATOM && + t->tokentype != IT_NUMBER && + t->tokentype != IT_QUOTED_STRING) + return (0); + si->as=my_strdup(t->tokenbuf); + nexttoken(); + return (si); + } + + if (strcmp(keyword, "BEFORE") == 0) + { + struct imaptoken *t; + struct searchinfo *si; + + si=alloc_search(head); + si->type=search_before; + t=nexttoken(); + if (t->tokentype != IT_ATOM && + t->tokentype != IT_NUMBER && + t->tokentype != IT_QUOTED_STRING) + return (0); + si->as=my_strdup(t->tokenbuf); + nexttoken(); + return (si); + } + + if (strcmp(keyword, "BODY") == 0) + { + struct imaptoken *t; + struct searchinfo *si; + + si=alloc_search(head); + si->type=search_body; + t=nexttoken_okbracket(); + if (t->tokentype != IT_ATOM && + t->tokentype != IT_NUMBER && + t->tokentype != IT_QUOTED_STRING) + return (0); + si->as=my_strdup(t->tokenbuf); + nexttoken(); + return (si); + } + if (strcmp(keyword, "LARGER") == 0) + { + struct imaptoken *t; + struct searchinfo *si; + + si=alloc_search(head); + si->type=search_larger; + t=nexttoken(); + if (t->tokentype != IT_NUMBER) + return (0); + si->as=my_strdup(t->tokenbuf); + nexttoken(); + return (si); + } + + if (strcmp(keyword, "ON") == 0) + { + struct imaptoken *t; + struct searchinfo *si; + + si=alloc_search(head); + si->type=search_on; + t=nexttoken(); + if (t->tokentype != IT_ATOM && + t->tokentype != IT_NUMBER && + t->tokentype != IT_QUOTED_STRING) + return (0); + si->as=my_strdup(t->tokenbuf); + nexttoken(); + return (si); + } + + if (strcmp(keyword, "SENTBEFORE") == 0) + { + struct imaptoken *t; + struct searchinfo *si; + + si=alloc_search(head); + si->type=search_sentbefore; + t=nexttoken(); + if (t->tokentype != IT_ATOM && + t->tokentype != IT_NUMBER && + t->tokentype != IT_QUOTED_STRING) + return (0); + si->as=my_strdup(t->tokenbuf); + nexttoken(); + return (si); + } + + if (strcmp(keyword, "SENTON") == 0) + { + struct imaptoken *t; + struct searchinfo *si; + + si=alloc_search(head); + si->type=search_senton; + t=nexttoken(); + if (t->tokentype != IT_ATOM && + t->tokentype != IT_NUMBER && + t->tokentype != IT_QUOTED_STRING) + return (0); + si->as=my_strdup(keyword); + nexttoken(); + return (si); + } + + if (strcmp(keyword, "SENTSINCE") == 0) + { + struct imaptoken *t; + struct searchinfo *si; + + si=alloc_search(head); + si->type=search_sentsince; + t=nexttoken(); + if (t->tokentype != IT_ATOM && + t->tokentype != IT_NUMBER && + t->tokentype != IT_QUOTED_STRING) + return (0); + si->as=my_strdup(t->tokenbuf); + nexttoken(); + return (si); + } + + if (strcmp(keyword, "SINCE") == 0) + { + struct imaptoken *t; + struct searchinfo *si; + + si=alloc_search(head); + si->type=search_since; + t=nexttoken(); + if (t->tokentype != IT_ATOM && + t->tokentype != IT_NUMBER && + t->tokentype != IT_QUOTED_STRING) + return (0); + si->as=my_strdup(t->tokenbuf); + nexttoken(); + return (si); + } + + if (strcmp(keyword, "SMALLER") == 0) + { + struct imaptoken *t; + struct searchinfo *si; + + si=alloc_search(head); + si->type=search_smaller; + t=nexttoken(); + if (t->tokentype != IT_NUMBER) + return (0); + si->as=my_strdup(t->tokenbuf); + nexttoken(); + return (si); + } + + if (strcmp(keyword, "TEXT") == 0) + { + struct imaptoken *t; + struct searchinfo *si; + + si=alloc_search(head); + si->type=search_text; + t=nexttoken_okbracket(); + if (t->tokentype != IT_ATOM && + t->tokentype != IT_NUMBER && + t->tokentype != IT_QUOTED_STRING) + return (0); + si->as=my_strdup(t->tokenbuf); + nexttoken(); + return (si); + } + + if (strcmp(keyword, "UID") == 0) + { + struct searchinfo *si; + struct imaptoken *t; + + si=alloc_search(head); + si->type=search_uid; + t=nexttoken(); + if (!ismsgset(t)) + return (0); + si->as=my_strdup(t->tokenbuf); + nexttoken(); + return (si); + } + + if (strcmp(keyword, "KEYWORD") == 0 + || strcmp(keyword, "UNKEYWORD") == 0) + { + int isnot= *keyword == 'U'; + struct imaptoken *t; + struct searchinfo *si; + + si=alloc_search(head); + si->type=search_msgkeyword; + t=nexttoken_okbracket(); + if (t->tokentype != IT_ATOM && + t->tokentype != IT_NUMBER && + t->tokentype != IT_QUOTED_STRING) + return (0); + si->as=my_strdup(t->tokenbuf); + nexttoken(); + + if (isnot) + { + struct searchinfo *si2=alloc_search(head); + + si2->type=search_not; + si2->a=si; + si=si2; + } + return (si); + } + if (strcmp(keyword, "ANSWERED") == 0 || + strcmp(keyword, "DELETED") == 0 || + strcmp(keyword, "DRAFT") == 0 || + strcmp(keyword, "FLAGGED") == 0 || + strcmp(keyword, "RECENT") == 0 || + strcmp(keyword, "SEEN") == 0) + { + struct searchinfo *si; + + si=alloc_search(head); + si->type=search_msgflag; + if ((si->as=malloc(strlen(keyword)+2)) == 0) + write_error_exit(0); + si->as[0]='\\'; + strcpy(si->as+1, keyword); + nexttoken(); + return (si); + } + + if (strcmp(keyword, "UNANSWERED") == 0 || + strcmp(keyword, "UNDELETED") == 0 || + strcmp(keyword, "UNDRAFT") == 0 || + strcmp(keyword, "UNFLAGGED") == 0 || + strcmp(keyword, "UNSEEN") == 0) + { + struct searchinfo *si; + struct searchinfo *si2; + + si=alloc_search(head); + si->type=search_msgflag; + if ((si->as=malloc(strlen(keyword))) == 0) + write_error_exit(0); + si->as[0]='\\'; + strcpy(si->as+1, keyword+2); + nexttoken(); + + si2=alloc_search(head); + si2->type=search_not; + si2->a=si; + return (si2); + } + + if (strcmp(keyword, "NEW") == 0) + { + struct searchinfo *si, *si2; + + si=alloc_search(head); + si->type=search_and; + si2=si->a=alloc_search(head); + si2->type=search_msgflag; + si2->as=my_strdup("\\RECENT"); + si2=si->b=alloc_search(head); + si2->type=search_not; + si2=si2->a=alloc_search(head); + si2->type=search_msgflag; + si2->as=my_strdup("\\SEEN"); + nexttoken(); + return (si); + } + + if (strcmp(keyword, "OLD") == 0) + { + struct searchinfo *si, *si2; + + si=alloc_search(head); + si->type=search_not; + si2=si->a=alloc_search(head); + si2->type=search_msgflag; + si2->as=my_strdup("\\RECENT"); + nexttoken(); + return (si); + } + + if (ismsgset(t)) + { + si=alloc_search(head); + si->type=search_messageset; + si->as=my_strdup(t->tokenbuf); + nexttoken(); + return (si); + } + + return (0); +} + +/* +** We are about to search in charset 'textcharset'. Make sure that all +** search_text nodes in the search string are in that character set. +*/ + +void search_set_charset_conv(struct searchinfo *si, const char *charset) +{ + for (; si; si=si->next) + { + if (si->type != search_text && si->type != search_body + && si->type != search_header) + continue; + if (si->value > 0) + continue; /* Already found, no need to do this again */ + + if (maildir_search_start_str_chset(&si->sei, + si->as ? si->as:"", + charset)) + { + si->value=0; + continue; + } + } +} + + +#if 0 + +void debug_search(struct searchinfo *si) +{ + if (!si) return; + + switch (si->type) { + case search_messageset: + writes("MESSAGE SET: "); + writes(si->as); + return; + case search_all: + writes("ALL"); + return; + case search_msgflag: + writes("FLAG \""); + writeqs(si->as); + writes("\""); + return; + case search_msgkeyword: + writes("KEYWORD \""); + writeqs(si->as); + writes("\""); + return; + case search_not: + writes("NOT ("); + debug_search(si->a); + writes(")"); + return; + case search_and: + writes("AND ("); + debug_search(si->a); + writes(", "); + debug_search(si->b); + writes(")"); + return; + case search_or: + writes("OR ("); + debug_search(si->a); + writes(", "); + debug_search(si->b); + writes(")"); + return; + case search_header: + writes("HEADER \""); + writeqs(si->cs); + writes("\" \""); + writeqs(si->bs); + writes("\""); + return; + case search_before: + writes("BEFORE \""); + writeqs(si->as); + writes("\""); + return; + case search_body: + writes("BODY \""); + writeqs(si->as); + writes("\""); + return; + case search_larger: + writes("LARGER \""); + writeqs(si->as); + writes("\""); + return; + case search_on: + writes("ON \""); + writeqs(si->as); + writes("\""); + return; + case search_sentbefore: + writes("SENTBEFORE \""); + writeqs(si->as); + writes("\""); + return; + case search_senton: + writes("SENTON \""); + writeqs(si->as); + writes("\""); + return; + case search_sentsince: + writes("SENTSINCE \""); + writeqs(si->as); + writes("\""); + return; + case search_since: + writes("SINCE \""); + writeqs(si->as); + writes("\""); + return; + case search_smaller: + writes("SMALLER \""); + writeqs(si->as); + writes("\""); + return; + case search_text: + writes("TEXT \""); + writeqs(si->as); + writes("\""); + return; + case search_uid: + writes("UID \""); + writeqs(si->as); + writes("\""); + return; + case search_orderedsubj: + writes("ORDEREDSUBJ "); + debug_search(si->a); + return; + case search_references1: + writes("REFERENCES[References/In-Reply-To]="); + writeqs(si->as ? si->as:""); + writes("/"); + writeqs(si->bs ? si->bs:""); + writes(" "); + debug_search(si->a); + return; + case search_references2: + writes("REFERENCES[Date:]="); + writeqs(si->as ? si->as:""); + writes(" "); + debug_search(si->a); + return; + case search_references3: + writes("REFERENCES[Subject]="); + writeqs(si->as ? si->as:""); + writes(" "); + debug_search(si->a); + return; + case search_references4: + writes("REFERENCES[Message-ID]="); + writeqs(si->as ? si->as:""); + writes(" "); + debug_search(si->a); + return; + case search_arrival: + writes("ARRIVAL"); + return; + case search_cc: + writes("CC"); + return; + case search_date: + writes("DATE"); + return; + case search_from: + writes("FROM"); + return; + case search_reverse: + writes("REVERSE"); + return; + case search_size: + writes("SIZE"); + return; + case search_to: + writes("TO"); + return; + } +} + +#endif |
