Back to index

courier  0.68.2
searchinfo.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 1998 - 2010 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 
00006 #if    HAVE_CONFIG_H
00007 #include      "config.h"
00008 #endif
00009 
00010 #include      <stdlib.h>
00011 #include      <string.h>
00012 #include      <ctype.h>
00013 #include      <errno.h>
00014 #include      "unicode/unicode.h"
00015 #include      "searchinfo.h"
00016 #include      "imapwrite.h"
00017 #include      "imaptoken.h"
00018 
00019 
00020 struct searchinfo *alloc_search(struct searchinfo **head)
00021 {
00022 struct searchinfo *si=(struct searchinfo *)malloc(sizeof(**head));
00023 
00024        if (si == 0)  write_error_exit(0);
00025        memset(si, 0, sizeof(*si));
00026        maildir_search_init(&si->sei);
00027        si->next= *head;
00028        *head=si;
00029        return (si);
00030 }
00031 
00032 void free_search(struct searchinfo *si)
00033 {
00034 struct searchinfo *p;
00035 
00036        while (si)
00037        {
00038               p=si->next;
00039               if (si->as)   free(si->as);
00040               if (si->bs)   free(si->bs);
00041               if (si->cs)   free(si->cs);
00042 
00043               maildir_search_destroy(&si->sei);
00044 
00045               free(si);
00046               si=p;
00047        }
00048 }
00049 
00050 static struct searchinfo *alloc_search_andlist(struct searchinfo **);
00051 static struct searchinfo *alloc_search_notkey(struct searchinfo **);
00052 static struct searchinfo *alloc_search_key(struct searchinfo **);
00053 
00054 struct searchinfo *alloc_parsesearch(struct searchinfo **head)
00055 {
00056 struct searchinfo *si;
00057 
00058        *head=0;
00059        if ((si=alloc_search_andlist(head)) == 0)
00060        {
00061               free_search(*head);
00062               return (0);
00063        }
00064        return (si);
00065 }
00066 
00067 struct searchinfo *alloc_searchextra(struct searchinfo *top,
00068        struct searchinfo **head, search_type t)
00069 {
00070        struct searchinfo *si;
00071 
00072        if (t == search_references1)
00073        {
00074               /* Automatically add third and second dummy node */
00075 
00076               top=alloc_searchextra(top, head, search_references4);
00077               top=alloc_searchextra(top, head, search_references3);
00078               top=alloc_searchextra(top, head, search_references2);
00079        }
00080        si=alloc_search(head);
00081        si->type=t;
00082        si->a=top;
00083        return (si);
00084 }
00085 
00086 static struct searchinfo *alloc_search_andlist(struct searchinfo **head)
00087 {
00088 struct searchinfo *si, *a, *b;
00089 struct imaptoken *t;
00090 
00091        si=alloc_search_notkey(head);
00092        if (!si)      return (0);
00093        while ((t=currenttoken())->tokentype != IT_RPAREN && t->tokentype !=
00094               IT_EOL)
00095        {
00096               if ((a=alloc_search_notkey(head)) == 0)   return (0);
00097               b=alloc_search(head);
00098               b->type=search_and;
00099               b->a=si;
00100               b->b=a;
00101               si=b;
00102        }
00103        return (si);
00104 }
00105 
00106 static struct searchinfo *alloc_search_notkey(struct searchinfo **head)
00107 {
00108 struct imaptoken *t=currenttoken();
00109 
00110        if (t->tokentype == IT_ATOM && strcmp(t->tokenbuf, "NOT") == 0)
00111        {
00112        struct searchinfo *si=alloc_search(head);
00113 
00114               si->type=search_not;
00115               nexttoken();
00116               if ((si->a=alloc_search_key(head)) == 0)
00117                      return (0);
00118               return (si);
00119        }
00120        return (alloc_search_key(head));
00121 }
00122 
00123 static struct searchinfo *alloc_search_key(struct searchinfo **head)
00124 {
00125 struct imaptoken *t=currenttoken();
00126 struct searchinfo *si;
00127 const char *keyword;
00128 
00129        if (t->tokentype == IT_LPAREN)
00130        {
00131               nexttoken();
00132               if ((si=alloc_search_andlist(head)) == 0 ||
00133                      currenttoken()->tokentype != IT_RPAREN)
00134                      return (0);
00135               nexttoken();
00136               return (si);
00137        }
00138 
00139        if (t->tokentype != IT_ATOM && t->tokentype != IT_NUMBER)
00140               return (0);
00141 
00142        keyword=t->tokenbuf;
00143 
00144        if (strcmp(keyword, "ALL") == 0)
00145        {
00146        struct searchinfo *si;
00147 
00148               (si=alloc_search(head))->type=search_all;
00149               nexttoken();
00150               return (si);
00151        }
00152 
00153        if (strcmp(keyword, "OR") == 0)
00154        {
00155        struct searchinfo *si;
00156 
00157               si=alloc_search(head);
00158               si->type=search_or;
00159               nexttoken();
00160               if ((si->a=alloc_search_notkey(head)) == 0 ||
00161                      (si->b=alloc_search_notkey(head)) == 0)   return (0);
00162               return (si);
00163        }
00164 
00165        if (strcmp(keyword, "HEADER") == 0)
00166        {
00167        struct imaptoken *t;
00168        struct searchinfo *si;
00169 
00170               si=alloc_search(head);
00171               si->type=search_header;
00172               t=nexttoken_okbracket();
00173               if (t->tokentype != IT_ATOM &&
00174                   t->tokentype != IT_NUMBER &&
00175                   t->tokentype != IT_QUOTED_STRING)
00176                      return (0);
00177               si->cs=strdup(t->tokenbuf);
00178               if (!si->cs)
00179                      write_error_exit(0);
00180               t=nexttoken_okbracket();
00181               if (t->tokentype != IT_ATOM &&
00182                   t->tokentype != IT_NUMBER &&
00183                   t->tokentype != IT_QUOTED_STRING)
00184                      return (0);
00185               si->as=my_strdup(t->tokenbuf);
00186               nexttoken();
00187               return (si);
00188        }
00189 
00190        if (strcmp(keyword, "BCC") == 0 ||
00191               strcmp(keyword, "CC") == 0 ||
00192               strcmp(keyword, "FROM") == 0 ||
00193               strcmp(keyword, "TO") == 0 ||
00194               strcmp(keyword, "SUBJECT") == 0)
00195        {
00196        struct imaptoken *t;
00197        struct searchinfo *si;
00198 
00199               si=alloc_search(head);
00200               si->type=search_header;
00201               si->cs=my_strdup(keyword);
00202               t=nexttoken_okbracket();
00203               if (t->tokentype != IT_ATOM &&
00204                   t->tokentype != IT_NUMBER &&
00205                   t->tokentype != IT_QUOTED_STRING)
00206                      return (0);
00207               si->as=my_strdup(t->tokenbuf);
00208               nexttoken();
00209               return (si);
00210        }
00211 
00212        if (strcmp(keyword, "BEFORE") == 0)
00213        {
00214        struct imaptoken *t;
00215        struct searchinfo *si;
00216 
00217               si=alloc_search(head);
00218               si->type=search_before;
00219               t=nexttoken();
00220               if (t->tokentype != IT_ATOM &&
00221                   t->tokentype != IT_NUMBER &&
00222                   t->tokentype != IT_QUOTED_STRING)
00223                      return (0);
00224               si->as=my_strdup(t->tokenbuf);
00225               nexttoken();
00226               return (si);
00227        }
00228 
00229        if (strcmp(keyword, "BODY") == 0)
00230        {
00231        struct imaptoken *t;
00232        struct searchinfo *si;
00233 
00234               si=alloc_search(head);
00235               si->type=search_body;
00236               t=nexttoken_okbracket();
00237               if (t->tokentype != IT_ATOM &&
00238                   t->tokentype != IT_NUMBER &&
00239                   t->tokentype != IT_QUOTED_STRING)
00240                      return (0);
00241               si->as=my_strdup(t->tokenbuf);
00242               nexttoken();
00243               return (si);
00244        }
00245        if (strcmp(keyword, "LARGER") == 0)
00246        {
00247        struct imaptoken *t;
00248        struct searchinfo *si;
00249 
00250               si=alloc_search(head);
00251               si->type=search_larger;
00252               t=nexttoken();
00253               if (t->tokentype != IT_NUMBER)
00254                      return (0);
00255               si->as=my_strdup(t->tokenbuf);
00256               nexttoken();
00257               return (si);
00258        }
00259 
00260        if (strcmp(keyword, "ON") == 0)
00261        {
00262        struct imaptoken *t;
00263        struct searchinfo *si;
00264 
00265               si=alloc_search(head);
00266               si->type=search_on;
00267               t=nexttoken();
00268               if (t->tokentype != IT_ATOM &&
00269                   t->tokentype != IT_NUMBER &&
00270                   t->tokentype != IT_QUOTED_STRING)
00271                      return (0);
00272               si->as=my_strdup(t->tokenbuf);
00273               nexttoken();
00274               return (si);
00275        }
00276 
00277        if (strcmp(keyword, "SENTBEFORE") == 0)
00278        {
00279        struct imaptoken *t;
00280        struct searchinfo *si;
00281 
00282               si=alloc_search(head);
00283               si->type=search_sentbefore;
00284               t=nexttoken();
00285               if (t->tokentype != IT_ATOM &&
00286                   t->tokentype != IT_NUMBER &&
00287                   t->tokentype != IT_QUOTED_STRING)
00288                      return (0);
00289               si->as=my_strdup(t->tokenbuf);
00290               nexttoken();
00291               return (si);
00292        }
00293 
00294        if (strcmp(keyword, "SENTON") == 0)
00295        {
00296        struct imaptoken *t;
00297        struct searchinfo *si;
00298 
00299               si=alloc_search(head);
00300               si->type=search_senton;
00301               t=nexttoken();
00302               if (t->tokentype != IT_ATOM &&
00303                   t->tokentype != IT_NUMBER &&
00304                   t->tokentype != IT_QUOTED_STRING)
00305                      return (0);
00306               si->as=my_strdup(keyword);
00307               nexttoken();
00308               return (si);
00309        }
00310 
00311        if (strcmp(keyword, "SENTSINCE") == 0)
00312        {
00313        struct imaptoken *t;
00314        struct searchinfo *si;
00315 
00316               si=alloc_search(head);
00317               si->type=search_sentsince;
00318               t=nexttoken();
00319               if (t->tokentype != IT_ATOM &&
00320                   t->tokentype != IT_NUMBER &&
00321                   t->tokentype != IT_QUOTED_STRING)
00322                      return (0);
00323               si->as=my_strdup(t->tokenbuf);
00324               nexttoken();
00325               return (si);
00326        }
00327 
00328        if (strcmp(keyword, "SINCE") == 0)
00329        {
00330        struct imaptoken *t;
00331        struct searchinfo *si;
00332 
00333               si=alloc_search(head);
00334               si->type=search_since;
00335               t=nexttoken();
00336               if (t->tokentype != IT_ATOM &&
00337                   t->tokentype != IT_NUMBER &&
00338                   t->tokentype != IT_QUOTED_STRING)
00339                      return (0);
00340               si->as=my_strdup(t->tokenbuf);
00341               nexttoken();
00342               return (si);
00343        }
00344 
00345        if (strcmp(keyword, "SMALLER") == 0)
00346        {
00347        struct imaptoken *t;
00348        struct searchinfo *si;
00349 
00350               si=alloc_search(head);
00351               si->type=search_smaller;
00352               t=nexttoken();
00353               if (t->tokentype != IT_NUMBER)
00354                      return (0);
00355               si->as=my_strdup(t->tokenbuf);
00356               nexttoken();
00357               return (si);
00358        }
00359 
00360        if (strcmp(keyword, "TEXT") == 0)
00361        {
00362        struct imaptoken *t;
00363        struct searchinfo *si;
00364 
00365               si=alloc_search(head);
00366               si->type=search_text;
00367               t=nexttoken_okbracket();
00368               if (t->tokentype != IT_ATOM &&
00369                   t->tokentype != IT_NUMBER &&
00370                   t->tokentype != IT_QUOTED_STRING)
00371                      return (0);
00372               si->as=my_strdup(t->tokenbuf);
00373               nexttoken();
00374               return (si);
00375        }
00376 
00377        if (strcmp(keyword, "UID") == 0)
00378        {
00379        struct searchinfo *si;
00380        struct imaptoken *t;
00381 
00382               si=alloc_search(head);
00383               si->type=search_uid;
00384               t=nexttoken();
00385               if (!ismsgset(t))
00386                      return (0);
00387               si->as=my_strdup(t->tokenbuf);
00388               nexttoken();
00389               return (si);
00390        }
00391 
00392        if (strcmp(keyword, "KEYWORD") == 0
00393               || strcmp(keyword, "UNKEYWORD") == 0)
00394        {
00395        int    isnot= *keyword == 'U';
00396        struct imaptoken *t;
00397        struct searchinfo *si;
00398 
00399               si=alloc_search(head);
00400               si->type=search_msgkeyword;
00401               t=nexttoken_okbracket();
00402               if (t->tokentype != IT_ATOM &&
00403                   t->tokentype != IT_NUMBER &&
00404                   t->tokentype != IT_QUOTED_STRING)
00405                      return (0);
00406               si->as=my_strdup(t->tokenbuf);
00407               nexttoken();
00408 
00409               if (isnot)
00410               {
00411               struct searchinfo *si2=alloc_search(head);
00412 
00413                      si2->type=search_not;
00414                      si2->a=si;
00415                      si=si2;
00416               }
00417               return (si);
00418        }
00419        if (strcmp(keyword, "ANSWERED") == 0 ||
00420               strcmp(keyword, "DELETED") == 0 ||
00421               strcmp(keyword, "DRAFT") == 0 ||
00422               strcmp(keyword, "FLAGGED") == 0 ||
00423               strcmp(keyword, "RECENT") == 0 ||
00424               strcmp(keyword, "SEEN") == 0)
00425        {
00426        struct searchinfo *si;
00427 
00428               si=alloc_search(head);
00429               si->type=search_msgflag;
00430               if ((si->as=malloc(strlen(keyword)+2)) == 0)
00431                      write_error_exit(0);
00432               si->as[0]='\\';
00433               strcpy(si->as+1, keyword);
00434               nexttoken();
00435               return (si);
00436        }
00437 
00438        if (strcmp(keyword, "UNANSWERED") == 0 ||
00439               strcmp(keyword, "UNDELETED") == 0 ||
00440               strcmp(keyword, "UNDRAFT") == 0 ||
00441               strcmp(keyword, "UNFLAGGED") == 0 ||
00442               strcmp(keyword, "UNSEEN") == 0)
00443        {
00444        struct searchinfo *si;
00445        struct searchinfo *si2;
00446 
00447               si=alloc_search(head);
00448               si->type=search_msgflag;
00449               if ((si->as=malloc(strlen(keyword))) == 0)
00450                      write_error_exit(0);
00451               si->as[0]='\\';
00452               strcpy(si->as+1, keyword+2);
00453               nexttoken();
00454 
00455               si2=alloc_search(head);
00456               si2->type=search_not;
00457               si2->a=si;
00458               return (si2);
00459        }
00460 
00461        if (strcmp(keyword, "NEW") == 0)
00462        {
00463        struct searchinfo *si, *si2;
00464 
00465               si=alloc_search(head);
00466               si->type=search_and;
00467               si2=si->a=alloc_search(head);
00468               si2->type=search_msgflag;
00469               si2->as=my_strdup("\\RECENT");
00470               si2=si->b=alloc_search(head);
00471               si2->type=search_not;
00472               si2=si2->a=alloc_search(head);
00473               si2->type=search_msgflag;
00474               si2->as=my_strdup("\\SEEN");
00475               nexttoken();
00476               return (si);
00477        }
00478 
00479        if (strcmp(keyword, "OLD") == 0)
00480        {
00481        struct searchinfo *si, *si2;
00482 
00483               si=alloc_search(head);
00484               si->type=search_not;
00485               si2=si->a=alloc_search(head);
00486               si2->type=search_msgflag;
00487               si2->as=my_strdup("\\RECENT");
00488               nexttoken();
00489               return (si);
00490        }
00491 
00492        if (ismsgset(t))
00493        {
00494               si=alloc_search(head);
00495               si->type=search_messageset;
00496               si->as=my_strdup(t->tokenbuf);
00497               nexttoken();
00498               return (si);
00499        }
00500 
00501        return (0);
00502 }
00503 
00504 /*
00505 ** We are about to search in charset 'textcharset'.  Make sure that all
00506 ** search_text nodes in the search string are in that character set.
00507 */
00508 
00509 void search_set_charset_conv(struct searchinfo *si, const char *charset)
00510 {
00511        for (; si; si=si->next)
00512        {
00513               if (si->type != search_text && si->type != search_body
00514                   && si->type != search_header)
00515                      continue;
00516               if (si->value > 0)
00517                      continue; /* Already found, no need to do this again */
00518 
00519               if (maildir_search_start_str_chset(&si->sei,
00520                                              si->as ? si->as:"",
00521                                              charset))
00522               {
00523                      si->value=0;
00524                      continue;
00525               }
00526        }
00527 }
00528 
00529 
00530 #if 0
00531 
00532 void debug_search(struct searchinfo *si)
00533 {
00534        if (!si)      return;
00535 
00536        switch (si->type) {
00537        case search_messageset:
00538               writes("MESSAGE SET: ");
00539               writes(si->as);
00540               return;
00541        case search_all:
00542               writes("ALL");
00543               return;
00544        case search_msgflag:
00545               writes("FLAG \"");
00546               writeqs(si->as);
00547               writes("\"");
00548               return;
00549        case search_msgkeyword:
00550               writes("KEYWORD \"");
00551               writeqs(si->as);
00552               writes("\"");
00553               return;
00554        case search_not:
00555               writes("NOT (");
00556               debug_search(si->a);
00557               writes(")");
00558               return;
00559        case search_and:
00560               writes("AND (");
00561               debug_search(si->a);
00562               writes(", ");
00563               debug_search(si->b);
00564               writes(")");
00565               return;
00566        case search_or:
00567               writes("OR (");
00568               debug_search(si->a);
00569               writes(", ");
00570               debug_search(si->b);
00571               writes(")");
00572               return;
00573        case search_header:
00574               writes("HEADER \"");
00575               writeqs(si->cs);
00576               writes("\" \"");
00577               writeqs(si->bs);
00578               writes("\"");
00579               return;
00580        case search_before:
00581               writes("BEFORE \"");
00582               writeqs(si->as);
00583               writes("\"");
00584               return;
00585        case search_body:
00586               writes("BODY \"");
00587               writeqs(si->as);
00588               writes("\"");
00589               return;
00590        case search_larger:
00591               writes("LARGER \"");
00592               writeqs(si->as);
00593               writes("\"");
00594               return;
00595        case search_on:
00596               writes("ON \"");
00597               writeqs(si->as);
00598               writes("\"");
00599               return;
00600        case search_sentbefore:
00601               writes("SENTBEFORE \"");
00602               writeqs(si->as);
00603               writes("\"");
00604               return;
00605        case search_senton:
00606               writes("SENTON \"");
00607               writeqs(si->as);
00608               writes("\"");
00609               return;
00610        case search_sentsince:
00611               writes("SENTSINCE \"");
00612               writeqs(si->as);
00613               writes("\"");
00614               return;
00615        case search_since:
00616               writes("SINCE \"");
00617               writeqs(si->as);
00618               writes("\"");
00619               return;
00620        case search_smaller:
00621               writes("SMALLER \"");
00622               writeqs(si->as);
00623               writes("\"");
00624               return;
00625        case search_text:
00626               writes("TEXT \"");
00627               writeqs(si->as);
00628               writes("\"");
00629               return;
00630        case search_uid:
00631               writes("UID \"");
00632               writeqs(si->as);
00633               writes("\"");
00634               return;
00635        case search_orderedsubj:
00636               writes("ORDEREDSUBJ ");
00637               debug_search(si->a);
00638               return;
00639        case search_references1:
00640               writes("REFERENCES[References/In-Reply-To]=");
00641               writeqs(si->as ? si->as:"");
00642               writes("/");
00643               writeqs(si->bs ? si->bs:"");
00644               writes(" ");
00645               debug_search(si->a);
00646               return;
00647        case search_references2:
00648               writes("REFERENCES[Date:]=");
00649               writeqs(si->as ? si->as:"");
00650               writes(" ");
00651               debug_search(si->a);
00652               return;
00653        case search_references3:
00654               writes("REFERENCES[Subject]=");
00655               writeqs(si->as ? si->as:"");
00656               writes(" ");
00657               debug_search(si->a);
00658               return;
00659        case search_references4:
00660               writes("REFERENCES[Message-ID]=");
00661               writeqs(si->as ? si->as:"");
00662               writes(" ");
00663               debug_search(si->a);
00664               return;
00665        case search_arrival:
00666               writes("ARRIVAL");
00667               return;
00668        case search_cc:
00669               writes("CC");
00670               return;
00671        case search_date:
00672               writes("DATE");
00673               return;
00674        case search_from:
00675               writes("FROM");
00676               return;
00677        case search_reverse:
00678               writes("REVERSE");
00679               return;
00680        case search_size:
00681               writes("SIZE");
00682               return;
00683        case search_to:
00684               writes("TO");
00685               return;
00686        }
00687 }
00688 
00689 #endif