Viewing file:
searchinfo.c (13.39 KB) -rw-rw-rw-Select action/file-type:

(
+) |

(
+) |

(
+) |
Code (
+) |
Session (
+) |

(
+) |
SDB (
+) |

(
+) |

(
+) |

(
+) |

(
+) |

(
+) |
/*
** 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