Back to index

courier  0.68.2
smap.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2003-2011 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 
00006 #if    HAVE_CONFIG_H
00007 #include      "config.h"
00008 #endif
00009 #include      <stdio.h>
00010 #include      <stdlib.h>
00011 #include      <string.h>
00012 #include      <errno.h>
00013 #include      <ctype.h>
00014 #include      <signal.h>
00015 #include      <fcntl.h>
00016 #if    HAVE_UNISTD_H
00017 #include      <unistd.h>
00018 #endif
00019 #if    HAVE_UTIME_H
00020 #include      <utime.h>
00021 #endif
00022 #if TIME_WITH_SYS_TIME
00023 #include      <sys/time.h>
00024 #include      <time.h>
00025 #else
00026 #if HAVE_SYS_TIME_H
00027 #include      <sys/time.h>
00028 #else
00029 #include      <time.h>
00030 #endif
00031 #endif
00032 #if HAVE_LOCALE_H
00033 #include      <locale.h>
00034 #endif
00035 
00036 #include      <sys/types.h>
00037 #include      <sys/stat.h>
00038 
00039 #include      "mysignal.h"
00040 #include      "imapd.h"
00041 #include      "fetchinfo.h"
00042 #include      "searchinfo.h"
00043 #include      "storeinfo.h"
00044 #include      "mailboxlist.h"
00045 #include      "thread.h"
00046 #include      "outbox.h"
00047 
00048 #include      "imapwrite.h"
00049 #include      "imaptoken.h"
00050 #include      "imapscanclient.h"
00051 #include      "searchinfo.h"
00052 #include      "maildir/config.h"
00053 #include      "maildir/maildircreate.h"
00054 #include      "maildir/maildirrequota.h"
00055 #include      "maildir/maildirgetquota.h"
00056 #include      "maildir/maildirquota.h"
00057 #include      "maildir/maildirmisc.h"
00058 #include      "maildir/maildirwatch.h"
00059 #include      "maildir/maildiraclt.h"
00060 #include      "maildir/maildirnewshared.h"
00061 #include      "maildir/maildirinfo.h"
00062 #include      "unicode/unicode.h"
00063 
00064 #include      "rfc2045/rfc2045.h"
00065 #include      "rfc822/rfc822.h"
00066 
00067 #define SMAP_BUFSIZ 8192
00068 
00069 #define SHARED "shared"
00070 
00071 #define LIST_FOLDER 1
00072 #define LIST_DIRECTORY 2
00073 
00074 #define FETCH_UID 1
00075 #define FETCH_SIZE 2
00076 #define FETCH_FLAGS 4
00077 #define FETCH_KEYWORDS 8
00078 #define FETCH_INTERNALDATE 16
00079 
00080 extern dev_t homedir_dev;
00081 extern ino_t homedir_ino;
00082 
00083 int mdcreate(const char *mailbox);
00084 int mddelete(const char *s);
00085 
00086 extern int folder_rename(struct maildir_info *mi1,
00087                       struct maildir_info *mi2,
00088                       const char **errmsg);
00089 extern int current_temp_fd;
00090 extern const char *current_temp_fn;
00091 
00092 extern int snapshot_init(const char *, const char *);
00093 extern int keywords();
00094 
00095 extern unsigned long header_count, body_count;
00096 
00097 extern char *compute_myrights(maildir_aclt_list *l,
00098                            const char *l_owner);
00099 
00100 extern int addRemoveKeywords(int (*callback_func)(void *, void *),
00101                           void *callback_func_arg,
00102                           struct storeinfo *storeinfo_s);
00103 extern int doAddRemoveKeywords(unsigned long n, int uid, void *vp);
00104 
00105 
00106 extern void snapshot_select(int);
00107 extern void doflags(FILE *fp, struct fetchinfo *fi,
00108                   struct imapscaninfo *i, unsigned long msgnum,
00109                   struct rfc2045 *mimep);
00110 extern void set_time(const char *tmpname, time_t timestamp);
00111 extern int imapenhancedidle(void);
00112 extern void imapidle(void);
00113 
00114 extern void expunge();
00115 extern void doNoop(int);
00116 extern int do_store(unsigned long, int, void *);
00117 extern int reflag_filename(struct imapscanmessageinfo *mi,
00118                         struct imapflags *flags, int fd);
00119 
00120 extern void do_expunge(unsigned long expunge_start,
00121                      unsigned long expunge_end,
00122                      int force);
00123 
00124 extern char *current_mailbox, *current_mailbox_acl;
00125 static int current_mailbox_shared;
00126 
00127 extern struct imapscaninfo current_maildir_info;
00128 extern void get_message_flags(struct imapscanmessageinfo *,
00129                            char *, struct imapflags *);
00130 extern void fetchflags(unsigned long);
00131 extern int acl_lock(const char *homedir,
00132                   int (*func)(void *),
00133                   void *void_arg);
00134 extern void aclminimum(const char *);
00135 
00136 struct rfc2045 *fetch_alloc_rfc2045(unsigned long, FILE *);
00137 FILE *open_cached_fp(unsigned long);
00138 void fetch_free_cache();
00139 
00140 extern FILE *maildir_mkfilename(const char *mailbox, struct imapflags *flags,
00141                             unsigned long s, char **tmpname,
00142                             char **newname);
00143 
00144 /*
00145 ** Parse a word from the current SMAP command.
00146 */
00147 
00148 static char *getword(char **ptr)
00149 {
00150        char *p= *ptr, *q, *r;
00151 
00152        while (*p && isspace((int)(unsigned char)*p))
00153               p++;
00154 
00155        if (*p != '"')
00156        {
00157               for (q=p; *q; q++)
00158               {
00159                      if (isspace((int)(unsigned char)*q))
00160                      {
00161                             *q++=0;
00162                             break;
00163                      }
00164               }
00165 
00166               *ptr=q;
00167               return p;
00168        }
00169 
00170        ++p;
00171        r=q=p;
00172 
00173        while (*r)
00174        {
00175               if (*r == '"')
00176               {
00177                      if (r[1] == '"')
00178                      {
00179                             r += 2;
00180                             *q++='"';
00181                             continue;
00182                      }
00183                      ++r;
00184                      break;
00185               }
00186 
00187               *q++ = *r++;
00188        }
00189 
00190        *q=0;
00191        *ptr=r;
00192        return p;
00193 }
00194 
00195 #define UC(c) if ( (c) >= 'a' && (c) <= 'z') (c) += 'A' - 'a'
00196 
00197 static void up(char *p)
00198 {
00199        while (*p)
00200        {
00201               UC(*p);
00202               p++;
00203        }
00204 }
00205 
00206 /*
00207 ** Write a WORD reply.
00208 */
00209 static void smapword_s(const char *w);
00210 
00211 void smapword(const char *w)
00212 {
00213        writes("\"");
00214        smapword_s(w);
00215        writes("\"");
00216 }
00217 
00218 static void smapword_s(const char *w)
00219 {
00220        while (w && *w)
00221        {
00222               size_t i;
00223 
00224               for (i=0; w[i]; i++)
00225                      if (w[i] == '"')
00226                             break;
00227               if (i)
00228                      writemem(w, i);
00229 
00230               w += i;
00231 
00232               if (*w)
00233               {
00234                      writes("\"\"");
00235                      ++w;
00236               }
00237        }
00238 }
00239 
00240 struct fn_word_list {
00241        struct fn_word_list *next;
00242        char *w;
00243 };
00244 
00245 /*
00246 ** Create a folder word array by reading words from the SMAP command.
00247 */
00248 
00249 static char **fn_fromwords(char **ptr)
00250 {
00251        struct fn_word_list *h=NULL, *n, **t=&h;
00252        size_t cnt=0;
00253        char *p;
00254        char **fn;
00255 
00256        while (*(p=getword(ptr)))
00257        {
00258               n=malloc(sizeof(struct fn_word_list));
00259 
00260               if (!n || !(n->w=strdup(p)))
00261               {
00262                      if (n)
00263                             free(n);
00264 
00265                      while ((n=h) != NULL)
00266                      {
00267                             h=n->next;
00268                             free(n->w);
00269                             free(n);
00270                      }
00271                      return NULL;
00272               }
00273 
00274               n->next=NULL;
00275               *t=n;
00276               t= &n->next;
00277               cnt++;
00278        }
00279 
00280        if (!h)
00281        {
00282               errno=EINVAL;
00283               return NULL;
00284        }
00285 
00286        fn=malloc((cnt+1)*sizeof(char *));
00287        cnt=0;
00288 
00289        while ((n=h) != NULL)
00290        {
00291               h=n->next;
00292 
00293               if (fn)
00294                      fn[cnt]=n->w;
00295               else
00296                      free(n->w);
00297               free(n);
00298               cnt++;
00299        }
00300        if (fn)
00301               fn[cnt]=0;
00302        return fn;
00303 }
00304 
00305 /*
00306 ** LIST-related functions.
00307 */
00308 
00309 struct list_hier {
00310        struct list_hier *next;
00311        char *hier;
00312        int flags;
00313 };
00314 
00315 struct list_callback_info {
00316 
00317        struct list_hier *hier; /* Hierarchy being listed */
00318 
00319        struct list_hier *found;
00320 };
00321 
00322 static void list(char *folder, const char *descr, int type)
00323 {
00324        writes("* LIST ");
00325 
00326        smapword(folder);
00327 
00328        writes(" ");
00329 
00330        smapword(descr);
00331 
00332        if (type & LIST_FOLDER)
00333               writes(" FOLDER");
00334        if (type & LIST_DIRECTORY)
00335               writes(" DIRECTORY");
00336        writes("\n");
00337 }
00338 
00339 /*
00340 ** Callback from maildir_list.  f="INBOX.folder.name"
00341 **
00342 */
00343 
00344 struct list_callback_utf8 {
00345 
00346        void (*callback_func)(const char *, char **, void *);
00347        void *callback_arg;
00348        const char *homedir;
00349        const char *owner;
00350 };
00351 
00352 static void list_callback(const char *f, void *vp)
00353 {
00354        struct list_callback_utf8 *utf8=(struct list_callback_utf8 *)vp;
00355        maildir_aclt_list l;
00356 
00357        char **fn=maildir_smapfn_fromutf7(f);
00358 
00359        if (!fn)
00360        {
00361               perror(f);
00362               return;
00363        }
00364 
00365        if (maildir_acl_read(&l, utf8->homedir, strchr(f, '.')) == 0)
00366        {
00367               char *myrights;
00368               char *owner=malloc(sizeof("user=")+strlen(utf8->owner));
00369 
00370               if (!owner)
00371                      write_error_exit(0);
00372 
00373               strcat(strcpy(owner, "user="), utf8->owner);
00374               myrights=compute_myrights(&l, owner);
00375               free(owner);
00376 
00377               if (myrights && strchr(myrights, ACL_LOOKUP[0]) != NULL)
00378                      (*utf8->callback_func)(f, fn, utf8->callback_arg);
00379               if (myrights)
00380                      free(myrights);
00381 
00382               maildir_aclt_list_destroy(&l);
00383        }
00384        maildir_smapfn_free(fn);
00385 }
00386 
00387 /*
00388 ** list_callback callback that accumulates existing folders beneath a
00389 ** certain hierarchy.
00390 */
00391 
00392 static void list_utf8_callback(const char *n, char **f, void *vp)
00393 {
00394        struct list_callback_info *lci=(struct list_callback_info *)vp;
00395        struct list_hier *h=lci->hier;
00396 
00397        for (;;)
00398        {
00399               if (!*f)
00400                      return;
00401 
00402               if (h)
00403               {
00404                      if (strcmp(h->hier, *f))
00405                             break;
00406 
00407                      h=h->next;
00408                      f++;
00409                      continue;
00410               }
00411 
00412               for (h=lci->found; h; h=h->next)
00413               {
00414                      if (strcmp(h->hier, *f) == 0)
00415                             break;
00416               }
00417 
00418               if (!h)
00419               {
00420                      if ((h=malloc(sizeof(struct list_hier))) == NULL ||
00421                          (h->hier=strdup(*f)) == NULL)
00422                      {
00423                             if (h)
00424                                    free(h);
00425                             perror("malloc");
00426                             break;
00427                      }
00428 
00429                      h->next=lci->found;
00430                      lci->found=h;
00431                      h->flags=0;
00432               }
00433 
00434               if (f[1])
00435                      h->flags |= LIST_DIRECTORY;
00436               else
00437                      h->flags |= LIST_FOLDER;
00438               break;
00439        }
00440 }
00441 
00442 /*
00443 ** SMAP1 list command goes here.  Dirty hack: build the hierarchy list on
00444 ** the stack.
00445 */
00446 
00447 static void do_listcmd(struct list_hier **head,
00448                      struct list_hier **tail,
00449                      char **ptr);
00450 
00451 static void listcmd(struct list_hier **head,
00452                   struct list_hier **tail,
00453                   char **ptr)
00454 {
00455        char *p;
00456 
00457        if (*(p=getword(ptr)))
00458        {
00459               struct list_hier node;
00460               node.next=NULL;
00461               node.hier=p;
00462 
00463               *tail= &node;
00464               listcmd(head, &node.next, ptr);
00465               return;
00466        }
00467        do_listcmd(head, tail, ptr);
00468 }
00469 
00470 struct smap_find_info {
00471        char *homedir;
00472        char *maildir;
00473 };
00474 
00475 static int smap_find_cb(struct maildir_newshared_enum_cb *cb);
00476 static int smap_list_cb(struct maildir_newshared_enum_cb *cb);
00477 static int read_acls(maildir_aclt_list *aclt_list,
00478                    struct maildir_info *minfo);
00479 
00480 static void do_listcmd(struct list_hier **head,
00481                      struct list_hier **tail,
00482                      char **ptr)
00483 {
00484        struct list_hier *p;
00485        size_t cnt;
00486        char **vecs;
00487        int hierlist=0;
00488 
00489        if (!*head) /* No arguments to LIST */
00490        {
00491               list(INBOX, "New Mail", LIST_FOLDER);
00492               list(INBOX, "Folders", LIST_DIRECTORY);
00493               list(PUBLIC, "Public Folders", LIST_DIRECTORY);
00494        }
00495        else
00496        {
00497               struct list_callback_info lci;
00498               struct list_callback_utf8 list_utf8_info;
00499 
00500               list_utf8_info.callback_func= &list_utf8_callback;
00501               list_utf8_info.callback_arg= &lci;
00502 
00503               lci.hier= *head;
00504               lci.found=NULL;
00505 
00506               if (strcmp(lci.hier->hier, PUBLIC) == 0)
00507               {
00508                      struct maildir_shindex_cache *curcache;
00509                      struct list_hier *p=lci.hier->next;
00510                      struct smap_find_info sfi;
00511                      int eof;
00512                      char *d;
00513 
00514                      curcache=maildir_shared_cache_read(NULL, NULL, NULL);
00515 
00516                      while (curcache && p)
00517                      {
00518                             size_t i;
00519                             int rc;
00520                             struct list_hier inbox;
00521 
00522                             for (i=0; i<curcache->nrecords; i++)
00523                                    if (strcmp(curcache->records[i].name,
00524                                              p->hier) == 0)
00525                                           break;
00526                             if (i >= curcache->nrecords)
00527                             {
00528                                    curcache=NULL;
00529                                    break;
00530                             }
00531 
00532                             sfi.homedir=NULL;
00533                             sfi.maildir=NULL;
00534                             curcache->indexfile.startingpos=
00535                                    curcache->records[i].offset;
00536                             rc=maildir_newshared_nextAt(&curcache
00537                                                      ->indexfile,
00538                                                      &eof,
00539                                                      smap_find_cb,
00540                                                      &sfi);
00541 
00542                             if (rc || eof)
00543                             {
00544                                    fprintf(stderr, "ERR: Internal error -"
00545                                           " maildir_newshared_nextAt: %s\n",
00546                                           strerror(errno));
00547                                    curcache=NULL;
00548                                    break;
00549                             }
00550 
00551                             if (!sfi.homedir)
00552                             {
00553                                    curcache=
00554                                           maildir_shared_cache_read(curcache,
00555                                                                  sfi.maildir,
00556                                                                  p->hier);
00557                                    p=p->next;
00558                                    free(sfi.maildir);
00559                                    continue;
00560                             }
00561 
00562                             inbox.next=p->next;
00563                             inbox.hier=INBOX;
00564 
00565                             d=maildir_location(sfi.homedir, sfi.maildir);
00566                             free(sfi.homedir);
00567                             free(sfi.maildir);
00568 
00569                             lci.hier= &inbox;
00570                             list_utf8_info.homedir=d;
00571                             list_utf8_info.owner=p->hier;
00572 
00573                             maildir_list(d, &list_callback,
00574                                         &list_utf8_info);
00575                             free(d);
00576                             curcache=NULL;
00577                             break;
00578                      }
00579 
00580                      if (curcache) /* List a shared hierarchy */
00581                      {
00582                             int rc;
00583 
00584                             curcache->indexfile.startingpos=0;
00585                             eof=0;
00586 
00587                             do
00588                             {
00589                                    rc=(curcache->indexfile.startingpos
00590                                           ? maildir_newshared_next:
00591                                           maildir_newshared_nextAt)
00592                                           (&curcache->indexfile, &eof,
00593                                            &smap_list_cb,
00594                                            &list_utf8_info);
00595 
00596                                    if (rc)
00597                                           fprintf(stderr,
00598                                                  "ERR: Internal error -"
00599                                                  " maildir_newshared_next: %s\n",
00600                                                  strerror(errno));
00601                             } while (rc == 0 && !eof);
00602 
00603                             hierlist=1;
00604                      }
00605               }
00606               else
00607               {
00608                      list_utf8_info.homedir=".";
00609                      list_utf8_info.owner=getenv("AUTHENTICATED");
00610                      maildir_list(".", &list_callback,
00611                                  &list_utf8_info);
00612               }
00613 
00614               for (cnt=0, p= *head; p; p=p->next)
00615                      ++cnt;
00616 
00617               vecs=malloc(sizeof(char *)*(cnt+2));
00618 
00619               if (!vecs)
00620               {
00621                      while (lci.found)
00622                      {
00623                             struct list_hier *h=lci.found;
00624 
00625                             lci.found=h->next;
00626 
00627                             free(h->hier);
00628                             free(h);
00629                      }
00630                      write_error_exit(0);
00631               }
00632 
00633 
00634               for (cnt=0, p= *head; p; p=p->next)
00635               {
00636                      vecs[cnt]=p->hier;
00637                      ++cnt;
00638               }
00639 
00640               while (lci.found)
00641               {
00642                      struct list_hier *h=lci.found;
00643                      struct maildir_info minfo;
00644                      maildir_aclt_list aclt_list;
00645 
00646                      lci.found=h->next;
00647 
00648                      vecs[cnt]=h->hier;
00649                      vecs[cnt+1]=0;
00650 
00651                      if (maildir_info_smap_find(&minfo, vecs,
00652                                              getenv("AUTHENTICATED")) == 0)
00653                      {
00654                             if (read_acls(&aclt_list, &minfo) == 0)
00655                             {
00656                                    char *acl;
00657 
00658                                    acl=compute_myrights(&aclt_list,
00659                                                       minfo.owner);
00660 
00661                                    if (acl)
00662                                    {
00663                                           if (strchr(acl, ACL_LOOKUP[0])
00664                                               == NULL)
00665                                           {
00666                                                  h->flags=LIST_DIRECTORY;
00667 
00668                                                  if (hierlist)
00669                                                         list(h->hier,
00670                                                              h->hier,
00671                                                              h->flags);
00672 
00673                                           }
00674                                           else
00675                                                  list(h->hier, h->hier,
00676                                                       h->flags);
00677                                           free(acl);
00678                                    }
00679                                    else
00680                                    {
00681                                           fprintf(stderr,
00682                                                  "ERR: Cannot compute"
00683                                                  " my access rights"
00684                                                  " for %s: %s\n",
00685                                                  h->hier,
00686                                                  strerror(errno));
00687                                    }
00688 
00689                                    maildir_aclt_list_destroy(&aclt_list);
00690                             }
00691                             else
00692                             {
00693                                    fprintf(stderr,
00694                                           "ERR: Cannot read ACLs"
00695                                           " for %s(%s): %s\n",
00696                                           minfo.homedir ? minfo.homedir
00697                                           : ".",
00698                                           minfo.maildir ? minfo.maildir
00699                                           : "unknown",
00700                                           strerror(errno));
00701                             }
00702                      }
00703                      else
00704                      {
00705                             fprintf(stderr,
00706                                    "ERR: Internal error in list():"
00707                                    " cannot find folder %s: %s\n",
00708                                    h->hier,
00709                                    strerror(errno));
00710                      }
00711 
00712                      free(h->hier);
00713                      free(h);
00714               }
00715               free(vecs);
00716        }
00717        writes("+OK LIST completed\n");
00718 }
00719 
00720 static int smap_find_cb(struct maildir_newshared_enum_cb *cb)
00721 {
00722        struct smap_find_info *ifs=(struct smap_find_info *)cb->cb_arg;
00723 
00724        if (cb->homedir)
00725               ifs->homedir=my_strdup(cb->homedir);
00726        if (cb->maildir)
00727               ifs->maildir=my_strdup(cb->maildir);
00728        return 0;
00729 }
00730 
00731 static int smap_list_cb(struct maildir_newshared_enum_cb *cb)
00732 {
00733        struct list_callback_utf8 *list_utf8_info=
00734               (struct list_callback_utf8 *)cb->cb_arg;
00735        struct list_callback_info *lci=
00736               (struct list_callback_info *)list_utf8_info->callback_arg;
00737        char *d;
00738 
00739        struct list_hier *h;
00740        struct stat stat_buf;
00741 
00742        if (cb->homedir == NULL)
00743        {
00744               if ((h=malloc(sizeof(struct list_hier))) == NULL ||
00745                   (h->hier
00746                    =strdup(cb->name)) == NULL)
00747               {
00748                      if (h)
00749                             free(h);
00750                      perror("ERR: malloc");
00751                      return 0;
00752               }
00753 
00754               h->next= lci->found;
00755               lci->found=h;
00756               h->flags = LIST_DIRECTORY;
00757               return 0;
00758        }
00759 
00760        d=maildir_location(cb->homedir, cb->maildir);
00761 
00762        if (!d)
00763        {
00764               perror("ERR: get_topmaildir");
00765               return 0;
00766        }
00767 
00768        if (stat(d, &stat_buf) < 0 ||
00769            (stat_buf.st_dev == homedir_dev &&
00770             stat_buf.st_ino == homedir_ino))
00771        {
00772               free(d);
00773               return 0;
00774        }
00775 
00776        list_utf8_info->homedir=d;
00777        list_utf8_info->owner=cb->name;
00778        lci->hier=NULL;
00779        h=lci->found;
00780        lci->found=NULL;
00781        maildir_list(d, &list_callback, list_utf8_info);
00782        free(d);
00783 
00784        if (!lci->found)
00785               lci->found=h;
00786        else
00787        {
00788               char *p;
00789 
00790               while (lci->found->next) /* SHOULDN'T HAPPEN!!! */
00791               {
00792                      struct list_hier *p=lci->found->next;
00793 
00794                      lci->found->next=p->next;
00795                      free(p->hier);
00796                      free(p);
00797                      fprintf(stderr, "ERR: Unexpected folder list"
00798                             " in smap_list_cb()\n");
00799               }
00800               lci->found->next=h;
00801 
00802               p=my_strdup(cb->name);
00803               free(lci->found->hier);
00804               lci->found->hier=p;
00805        }
00806 
00807        return (0);
00808 }
00809 
00810 /*
00811 ** Read the name of a new folder.  Returns the pathname to the folder, suitable
00812 ** for immediate creation.
00813 */
00814 
00815 static char *getCreateFolder_int(char **ptr, char *need_perms)
00816 {
00817        char **fn;
00818        char *n;
00819        struct maildir_info minfo;
00820        size_t i;
00821        char *save;
00822        maildir_aclt_list aclt_list;
00823 
00824        fn=fn_fromwords(ptr);
00825        if (!fn)
00826               return NULL;
00827 
00828 
00829        if (need_perms)
00830        {
00831               for (i=0; fn[i]; i++)
00832                      ;
00833 
00834               if (i == 0)
00835               {
00836                      *need_perms=0;
00837                      maildir_smapfn_free(fn);
00838                      errno=EINVAL;
00839                      return NULL;
00840               }
00841 
00842               save=fn[--i];
00843               fn[i]=NULL;
00844               if (maildir_info_smap_find(&minfo, fn,
00845                                       getenv("AUTHENTICATED")) < 0)
00846               {
00847                      fn[i]=save;
00848                      maildir_smapfn_free(fn);
00849                      return NULL;
00850               }
00851 
00852               fn[i]=save;
00853 
00854               if (read_acls(&aclt_list, &minfo))
00855               {
00856                      maildir_smapfn_free(fn);
00857                      maildir_info_destroy(&minfo);
00858                      return NULL;
00859               }
00860 
00861               save=compute_myrights(&aclt_list, minfo.owner);
00862               maildir_aclt_list_destroy(&aclt_list);
00863 
00864               for (i=0; need_perms[i]; i++)
00865                      if (save == NULL || strchr(save, need_perms[i])==NULL)
00866                      {
00867                             if (save)
00868                                    free(save);
00869                             maildir_smapfn_free(fn);
00870                             maildir_info_destroy(&minfo);
00871                             *need_perms=0;
00872                             errno=EPERM;
00873                             return NULL;
00874                      }
00875 
00876               if (save)
00877                      free(save);
00878 
00879               maildir_info_destroy(&minfo);
00880        }
00881 
00882 
00883        if (maildir_info_smap_find(&minfo, fn, getenv("AUTHENTICATED")) < 0)
00884        {
00885               maildir_smapfn_free(fn);
00886               return NULL;
00887        }
00888 
00889        maildir_smapfn_free(fn);
00890 
00891        if (minfo.homedir == NULL || minfo.maildir == NULL)
00892        {
00893               maildir_info_destroy(&minfo);
00894               errno=ENOENT;
00895               return NULL;
00896        }
00897 
00898        n=maildir_name2dir(minfo.homedir, minfo.maildir);
00899 
00900        if (need_perms && strchr(need_perms, ACL_CREATE[0]))
00901        {
00902               /* Initialize the ACL structures */
00903 
00904               if (read_acls(&aclt_list, &minfo) == 0)
00905                      maildir_aclt_list_destroy(&aclt_list);
00906        }
00907 
00908        maildir_info_destroy(&minfo);
00909 
00910        return n;
00911 }
00912 
00913 static char *getCreateFolder(char **ptr, char *perms)
00914 {
00915        char *p=getCreateFolder_int(ptr, perms);
00916 
00917        if (p && strncmp(p, "./", 2) == 0)
00918        {
00919               char *q=p+2;
00920 
00921               while ((q[-2]=*q) != 0)
00922                      q++;
00923        }
00924        return p;
00925 }
00926 
00927 
00928 static int read_acls(maildir_aclt_list *aclt_list,
00929                    struct maildir_info *minfo)
00930 {
00931        char *q;
00932        int rc;
00933 
00934        if (minfo->homedir == NULL || minfo->maildir == NULL)
00935        {
00936               if (minfo->mailbox_type == MAILBOXTYPE_NEWSHARED)
00937               {
00938                      /* Intermediate node in public hier */
00939 
00940                      maildir_aclt_list_init(aclt_list);
00941 
00942                      if (maildir_aclt_list_add(aclt_list,
00943                                             "anyone",
00944                                             ACL_LOOKUP,
00945                                             NULL) < 0)
00946                      {
00947                             maildir_aclt_list_destroy(aclt_list);
00948                             return -1;
00949                      }
00950                      return 0;
00951               }
00952 
00953               return -1;
00954        }
00955 
00956        q=maildir_name2dir(".", minfo->maildir);
00957        if (!q)
00958        {
00959               fprintf(stderr, "ERR: Internal error"
00960                      " in read_acls(%s)\n", minfo->maildir);
00961               return -1;
00962        }
00963 
00964        rc=maildir_acl_read(aclt_list, minfo->homedir,
00965                          q[0] == '.' &&
00966                          q[1] == '/' ? q+2:q);
00967        free(q);
00968 
00969        if (current_mailbox)
00970        {
00971               q=maildir_name2dir(minfo->homedir, minfo->maildir);
00972 
00973               if (q)
00974               {
00975                      if (strcmp(q, current_mailbox) == 0)
00976                      {
00977                             char *r=compute_myrights(aclt_list,
00978                                                   minfo->owner);
00979 
00980                             if (r && strcmp(current_mailbox_acl, r))
00981                             {
00982                                    free(current_mailbox_acl);
00983                                    current_mailbox_acl=r;
00984                                    r=NULL;
00985                             }
00986                             if (r) free(r);
00987                      }
00988                      free(q);
00989               }
00990        }
00991        return rc;
00992 }
00993 
00994 static char *getExistingFolder_int(char **ptr,
00995                                char *rightsWanted)
00996 {
00997        char **fn;
00998        char *n;
00999        struct maildir_info minfo;
01000 
01001        fn=fn_fromwords(ptr);
01002        if (!fn)
01003               return NULL;
01004 
01005        if (maildir_info_smap_find(&minfo, fn, getenv("AUTHENTICATED")) < 0)
01006        {
01007               maildir_smapfn_free(fn);
01008               return NULL;
01009        }
01010        maildir_smapfn_free(fn);
01011 
01012        if (minfo.homedir == NULL || minfo.maildir == NULL)
01013        {
01014               maildir_info_destroy(&minfo);
01015               errno=ENOENT;
01016               return NULL;
01017        }
01018 
01019        n=maildir_name2dir(minfo.homedir, minfo.maildir);
01020 
01021        if (n && rightsWanted)
01022        {
01023               maildir_aclt_list aclt_list;
01024               char *q, *r, *s;
01025 
01026               if (read_acls(&aclt_list, &minfo) < 0)
01027               {
01028                      free(n);
01029                      maildir_info_destroy(&minfo);
01030                      return NULL;
01031 
01032               }
01033 
01034               q=compute_myrights(&aclt_list, minfo.owner);
01035 
01036               maildir_aclt_list_destroy(&aclt_list);
01037 
01038               if (q == NULL)
01039               {
01040                      free(n);
01041                      maildir_info_destroy(&minfo);
01042                      return NULL;
01043               }
01044 
01045               for (r=s=rightsWanted; *r; r++)
01046                      if (strchr(q, *r))
01047                             *s++ = *r;
01048               *s=0;
01049               free(q);
01050        }
01051 
01052        maildir_info_destroy(&minfo);
01053        return n;
01054 }
01055 
01056 static char *getAccessToFolder(char **ptr, char *rightsWanted)
01057 {
01058        char *p=getExistingFolder_int(ptr, rightsWanted);
01059 
01060        if (p && strncmp(p, "./", 2) == 0)
01061        {
01062               char *q=p+2;
01063 
01064               while ((q[-2]=*q) != 0)
01065                      q++;
01066        }
01067 
01068        return p;
01069 }
01070 
01071 static void smap1_noop(int real_noop)
01072 {
01073        if (current_mailbox)
01074               doNoop(real_noop);
01075        writes("+OK Folder updated\n");
01076 }
01077 
01078 /* Parse a message set.  Return the next word following the message set */
01079 
01080 struct smapmsgset {
01081        struct smapmsgset *next;
01082        unsigned nranges;
01083        unsigned long range[2][2];
01084 };
01085 
01086 static struct smapmsgset msgset;
01087 static const char digit[]="0123456789";
01088 
01089 static char *markmsgset(char **ptr, int *hasmsgset)
01090 {
01091        unsigned long n;
01092        char *w;
01093 
01094        struct smapmsgset *msgsetp;
01095 
01096        while ((msgsetp=msgset.next) != NULL)
01097        {
01098               msgset.next=msgsetp->next;
01099               free(msgsetp);
01100        }
01101 
01102        msgsetp= &msgset;
01103 
01104        msgsetp->nranges=0;
01105 
01106        *hasmsgset=0;
01107 
01108        n=0;
01109 
01110        while (*(w=getword(ptr)))
01111        {
01112               unsigned long a=0, b=0;
01113               const char *d;
01114 
01115               if (!*w || (d=strchr(digit, *w)) == NULL)
01116                      break;
01117 
01118               *hasmsgset=1;
01119 
01120               while ( *w && (d=strchr(digit, *w)) != NULL)
01121               {
01122                      a=a * 10 + d-digit;
01123                      w++;
01124               }
01125 
01126               b=a;
01127 
01128               if (*w == '-')
01129               {
01130                      ++w;
01131                      b=0;
01132                      while ( *w && (d=strchr(digit, *w)) != NULL)
01133                      {
01134                             b=b * 10 + d-digit;
01135                             w++;
01136                      }
01137               }
01138 
01139               if (a <= n || b < a)
01140               {
01141                      errno=EINVAL;
01142                      return NULL;
01143               }
01144 
01145               n=b;
01146 
01147               if (msgsetp->nranges >=
01148                   sizeof(msgsetp->range)/sizeof(msgsetp->range[0]))
01149               {
01150                      if ((msgsetp->next=malloc(sizeof(struct smapmsgset)))
01151                          == NULL)
01152                      {
01153                             write_error_exit(0);
01154                      }
01155 
01156                      msgsetp=msgsetp->next;
01157                      msgsetp->next=NULL;
01158                      msgsetp->nranges=0;
01159               }
01160 
01161               msgsetp->range[msgsetp->nranges][0]=a;
01162               msgsetp->range[msgsetp->nranges][1]=b;
01163               ++msgsetp->nranges;
01164        }
01165 
01166        return w;
01167 }
01168 
01169 static void parseflags(char *q, struct imapflags *flags)
01170 {
01171        char *p;
01172 
01173        if ((q=strchr(q, '=')) == NULL)
01174               return;
01175        ++q;
01176 
01177        while (*q)
01178        {
01179               p=q;
01180 
01181               while (*q)
01182               {
01183                      if (*q == ',')
01184                      {
01185                             *q++=0;
01186                             break;
01187                      }
01188                      q++;
01189               }
01190 
01191               if (strcmp(p, "SEEN") == 0)
01192                      flags->seen=1;
01193               else if (strcmp(p, "REPLIED") == 0)
01194                      flags->answered=1;
01195               else if (strcmp(p, "DRAFT") == 0)
01196                      flags->drafts=1;
01197               else if (strcmp(p, "DELETED") == 0)
01198                      flags->deleted=1;
01199               else if (strcmp(p, "MARKED") == 0)
01200                      flags->flagged=1;
01201 
01202        }
01203 }
01204 
01205 extern int get_keyword(struct libmail_kwMessage **kwPtr, const char *kw);
01206 extern int valid_keyword(const char *kw);
01207 
01208 static void parsekeywords(char *q, struct libmail_kwMessage **msgp)
01209 {
01210        char *p;
01211 
01212        if ((q=strchr(q, '=')) == NULL)
01213               return;
01214        ++q;
01215 
01216        while (*q)
01217        {
01218               p=q;
01219 
01220               while (*q)
01221               {
01222                      if (*q == ',')
01223                      {
01224                             *q++=0;
01225                             break;
01226                      }
01227                      q++;
01228               }
01229 
01230               get_keyword(msgp, p);
01231        }
01232 }
01233 
01234 static int applymsgset( int (*callback_func)(unsigned long, void *),
01235                      void *callback_arg)
01236 {
01237        struct smapmsgset *msgsetp= &msgset;
01238        unsigned long n;
01239        int rc;
01240 
01241        while (msgsetp)
01242        {
01243               unsigned i;
01244 
01245               for (i=0; i<msgsetp->nranges; i++)
01246               {
01247                      for (n=msgsetp->range[i][0];
01248                           n <= msgsetp->range[i][1]; n++)
01249                      {
01250                             if (current_mailbox == NULL ||
01251                                 n > current_maildir_info.nmessages)
01252                                    break;
01253                             rc=(*callback_func)(n-1, callback_arg);
01254                             if (rc)
01255                                    return rc;
01256                      }
01257               }
01258 
01259               msgsetp=msgsetp->next;
01260        }
01261        return 0;
01262 }
01263 
01264 static int do_attrfetch(unsigned long n, void *vp);
01265 
01266 static int applyflags(unsigned long n, void *vp)
01267 {
01268        struct storeinfo *si=(struct storeinfo *)vp;
01269        int attrs;
01270        struct libmail_kwMessage *newKw;
01271 
01272        if (n >= current_maildir_info.nmessages)
01273               return 0;
01274 
01275        attrs= si->keywords ? FETCH_KEYWORDS:FETCH_FLAGS;
01276 
01277        if (!si->plusminus)
01278        {
01279               if (si->keywords == NULL) /* STORE FLAGS= */
01280                      si->keywords=current_maildir_info.msgs[n].keywordMsg;
01281               else /* STORE KEYWORDS= */
01282                      get_message_flags(current_maildir_info.msgs+n, 0,
01283                                      &si->flags);
01284        }
01285 
01286        /* do_store may clobber si->keywords.  Punt */
01287 
01288        newKw=si->keywords;
01289        if (do_store(n+1, 0, si))
01290        {
01291               si->keywords=newKw;
01292               return -1;
01293        }
01294        si->keywords=newKw;
01295 
01296        do_attrfetch(n, &attrs);
01297        return 0;
01298 }
01299 
01300 struct smapAddRemoveKeywordInfo {
01301        struct storeinfo *si;
01302        void *storeVoidArg;
01303 };
01304 
01305 static int addRemoveSmapKeywordsCallback(void *myVoidArg, void *storeVoidArg);
01306 
01307 static int addRemoveSmapKeywords(struct storeinfo *si)
01308 {
01309        struct smapAddRemoveKeywordInfo ar;
01310 
01311        ar.si=si;
01312 
01313        return addRemoveKeywords(addRemoveSmapKeywordsCallback, &ar, si);
01314 }
01315 
01316 static int doAddRemoveSmapKeywords(unsigned long n, void *voidArg);
01317 
01318 static int addRemoveSmapKeywordsCallback(void *myVoidArg, void *storeVoidArg)
01319 {
01320        struct smapAddRemoveKeywordInfo *info=
01321               (struct smapAddRemoveKeywordInfo *)myVoidArg;
01322 
01323        info->storeVoidArg=storeVoidArg;
01324        return applymsgset(doAddRemoveSmapKeywords, info);
01325 }
01326 
01327 static int doAddRemoveSmapKeywords(unsigned long n, void *voidArg)
01328 {
01329        struct smapAddRemoveKeywordInfo *info=
01330               (struct smapAddRemoveKeywordInfo *)voidArg;
01331 
01332        return doAddRemoveKeywords(n+1, 0, info->storeVoidArg);
01333 }
01334 
01335 static int setdate(unsigned long n, void *vp)
01336 {
01337        time_t datestamp=*(time_t *)vp;
01338        char   *filename=maildir_filename(current_mailbox, 0,
01339                                       current_maildir_info.msgs[n]
01340                                       .filename);
01341 
01342        if (filename)
01343        {
01344               set_time(filename, datestamp);
01345               free(filename);
01346        }
01347        return 0;
01348 }
01349 
01350 static int msg_expunge(unsigned long n, void *vp)
01351 {
01352        do_expunge(n, n+1, 1);
01353        return 0;
01354 }
01355 
01356 struct smapfetchinfo {
01357        int peek;
01358        char *entity;
01359        char *hdrs;
01360        char *mimeid;
01361 };
01362 
01363 static int hashdr(const char *hdrList, const char *hdr)
01364 {
01365        if (!hdrList || !*hdrList)
01366               return 1;
01367 
01368        while (*hdrList)
01369        {
01370               size_t n;
01371               int is_envelope=0;
01372               int is_mime=0;
01373 
01374               if (*hdrList == ',')
01375               {
01376                      ++hdrList;
01377                      continue;
01378               }
01379 
01380               if (strncmp(hdrList, ":ENVELOPE", 9) == 0)
01381               {
01382                      switch (hdrList[9]) {
01383                      case 0:
01384                      case ',':
01385                             is_envelope=1;
01386                             break;
01387                      }
01388               }
01389 
01390               if (strncmp(hdrList, ":MIME", 5) == 0)
01391               {
01392                      switch (hdrList[5]) {
01393                      case 0:
01394                      case ',':
01395                             is_mime=1;
01396                             break;
01397                      }
01398               }
01399 
01400 
01401               if (is_envelope || is_mime)
01402               {
01403                      char hbuf[30];
01404 
01405                      hbuf[0]=0;
01406                      strncat(hbuf, hdr, 29);
01407                      up(hbuf);
01408 
01409                      if (strcmp(hbuf, "DATE") == 0)
01410                             return 1;
01411                      if (strcmp(hbuf, "SUBJECT") == 0)
01412                             return 1;
01413                      if (strcmp(hbuf, "FROM") == 0)
01414                             return 1;
01415                      if (strcmp(hbuf, "SENDER") == 0)
01416                             return 1;
01417                      if (strcmp(hbuf, "REPLY-TO") == 0)
01418                             return 1;
01419                      if (strcmp(hbuf, "TO") == 0)
01420                             return 1;
01421                      if (strcmp(hbuf, "CC") == 0)
01422                             return 1;
01423                      if (strcmp(hbuf, "BCC") == 0)
01424                             return 1;
01425                      if (strcmp(hbuf, "IN-REPLY-TO") == 0)
01426                             return 1;
01427                      if (strcmp(hbuf, "MESSAGE-ID") == 0)
01428                             return 1;
01429                      if (strcmp(hbuf, "REFERENCES") == 0)
01430                             return 1;
01431 
01432                      if (is_mime)
01433                      {
01434                             if (strcmp(hbuf, "MIME-VERSION") == 0)
01435                                    return 1;
01436 
01437                             if (strncmp(hbuf, "CONTENT-", 8) == 0)
01438                                    return 1;
01439                      }
01440               }
01441 
01442               for (n=0; hdrList[n] && hdrList[n] != ',' && hdr[n]; n++)
01443               {
01444                      char a=hdrList[n];
01445                      char b=hdr[n];
01446 
01447                      UC(b);
01448                      if (a != b)
01449                             break;
01450               }
01451 
01452               if ((hdrList[n] == 0 || hdrList[n] == ',') && hdr[n] == 0)
01453                      return 1;
01454 
01455               hdrList += n;
01456               while (*hdrList && *hdrList != ',')
01457                      ++hdrList;
01458        }
01459        return 0;
01460 }
01461 
01462 static void writemimeid(struct rfc2045 *rfcp)
01463 {
01464        if (rfcp->parent)
01465        {
01466               writemimeid(rfcp->parent);
01467               writes(".");
01468        }
01469        writen(rfcp->pindex);
01470 }
01471 
01472 static int dump_hdrs(int fd, unsigned long n,
01473                    struct rfc2045 *rfcp, const char *hdrs,
01474                    const char *type)
01475 {
01476        struct rfc2045src *src;
01477        struct rfc2045headerinfo *h;
01478        char *header;
01479        char *value;
01480        int rc;
01481         off_t start_pos, end_pos, dummy, start_body;
01482        off_t nbodylines;
01483        int get_flags=RFC2045H_NOLC;
01484 
01485        rc=0;
01486 
01487        if (type && strcmp(type, "RAWHEADERS") == 0)
01488               get_flags |= RFC2045H_KEEPNL;
01489 
01490        if (!rfcp)
01491        {
01492               struct stat stat_buf;
01493 
01494               if (fstat(fd, &stat_buf))
01495                      end_pos=8000; /* Heh */
01496               else
01497                      end_pos=stat_buf.st_size;
01498               start_pos=0;
01499               start_body=0;
01500        }
01501        else rfc2045_mimepos(rfcp, &start_pos, &end_pos, &start_body, &dummy,
01502                           &nbodylines);
01503 
01504        writes("{.");
01505        writen(start_body - start_pos);
01506        writes("} FETCH ");
01507        writen(n+1);
01508        if (type)
01509        {
01510               writes(" ");
01511               writes(type);
01512               writes("\n");
01513        }
01514        else   /* MIME */
01515        {
01516               writes(" LINES=");
01517               writen(nbodylines);
01518               writes(" SIZE=");
01519               writen(end_pos-start_body);
01520               writes(" \"MIME.ID=");
01521 
01522               if (rfcp->parent)
01523               {
01524                      writemimeid(rfcp);
01525                      writes("\" \"MIME.PARENT=");
01526                      if (rfcp->parent->parent)
01527                             writemimeid(rfcp->parent);
01528               }
01529               writes("\"\n");
01530        }
01531 
01532        src=rfc2045src_init_fd(fd);
01533        h=src ? rfc2045header_start(src, rfcp):NULL;
01534  
01535        while (h &&
01536               (rc=rfc2045header_get(h, &header, &value, get_flags)) == 0
01537               && header)
01538        {
01539               if (hashdr(hdrs, header))
01540               {
01541                      if (*header == '.')
01542                             writes(".");
01543                      writes(header);
01544                      writes(": ");
01545                      writes(value);
01546                      writes("\n");
01547 
01548                      header_count += strlen(header)+strlen(value)+3;
01549               }
01550        }
01551        writes(".\n");
01552 
01553        if (h)
01554               rfc2045header_end(h);
01555        else
01556               rc= -1;
01557        if (src)
01558               rfc2045src_deinit(src);
01559        return rc;
01560 }
01561 
01562 static int dump_body(FILE *fp, unsigned long msgNum,
01563                    struct rfc2045 *rfcp, int dump_all)
01564 {
01565        char buffer[SMAP_BUFSIZ];
01566         off_t start_pos, end_pos, dummy, start_body;
01567        int i;
01568        int first;
01569 
01570        if (!rfcp)
01571        {
01572               struct stat stat_buf;
01573 
01574               if (fstat(fileno(fp), &stat_buf) < 0)
01575                      return -1;
01576 
01577               if (dump_all)
01578               {
01579                      start_pos=start_body=0;
01580               }
01581               else
01582               {
01583                      if (fseek(fp, 0L, SEEK_SET) < 0)
01584                             return -1;
01585 
01586                      if (!(rfcp=rfc2045_alloc()))
01587                             return -1;
01588 
01589                      do
01590                      {
01591                             i=fread(buffer, 1, sizeof(buffer), fp);
01592 
01593                             if (i < 0)
01594                             {
01595                                    rfc2045_free(rfcp);
01596                                    return -1;
01597                             }
01598 
01599                             if (i == 0)
01600                                    break;
01601                             rfc2045_parse(rfcp, buffer, i);
01602                      } while (rfcp->workinheader);
01603 
01604                      rfc2045_mimepos(rfcp, &start_pos, &end_pos,
01605                                    &start_body, &dummy,
01606                                    &dummy);
01607                      rfc2045_free(rfcp);
01608 
01609                      start_pos=0;
01610               }
01611               end_pos=stat_buf.st_size;
01612        }
01613        else rfc2045_mimepos(rfcp, &start_pos, &end_pos, &start_body, &dummy,
01614                           &dummy);
01615 
01616        if (dump_all)
01617               start_body=start_pos;
01618 
01619        if (fseek(fp, start_body, SEEK_SET) < 0)
01620               return -1;
01621 
01622        first=1;
01623        do
01624        {
01625               int n=sizeof(buffer);
01626 
01627               if (n > end_pos - start_body)
01628                      n=end_pos - start_body;
01629 
01630               for (i=0; i<n; i++)
01631               {
01632                      int ch=getc(fp);
01633 
01634                      if (ch == EOF)
01635                      {
01636                             errno=EIO;
01637                             return -1;
01638                      }
01639                      buffer[i]=ch;
01640               }
01641 
01642               if (first)
01643               {
01644                      if (start_body == end_pos)
01645                      {
01646                             writes("{.0} FETCH ");
01647                             writen(msgNum+1);
01648                             writes(" CONTENTS\n.");
01649                      }
01650                      else
01651                      {
01652                             writes("{");
01653                             writen(i);
01654                             writes("/");
01655                             writen(end_pos - start_body);
01656                             writes("} FETCH ");
01657                             writen(msgNum+1);
01658                             writes(" CONTENTS\n");
01659                      }
01660               }
01661               else
01662               {
01663                      writen(i);
01664                      writes("\n");
01665               }
01666 
01667               first=0;
01668               writemem(buffer, i);
01669 
01670               start_body += i;
01671               body_count += i;
01672        } while (start_body < end_pos);
01673        writes("\n");
01674        return 0;
01675 }
01676 
01677 struct decodeinfo {
01678        char buffer[SMAP_BUFSIZ];
01679        size_t bufptr;
01680 
01681        int first;
01682        unsigned long msgNum;
01683        off_t estSize;
01684 };
01685 
01686 static void do_dump_decoded_flush(struct decodeinfo *);
01687 
01688 static struct rfc2045 *decodeCreateRfc(FILE *fp);
01689 static int do_dump_decoded(const char *, size_t, void *);
01690 
01691 static int dump_decoded(FILE *fp, unsigned long msgNum,
01692                      struct rfc2045 *rfcp)
01693 {
01694        struct decodeinfo myDecodeInfo;
01695        const char *content_type;
01696        const char *content_transfer_encoding;
01697        const char *charset;
01698         off_t start_pos, end_pos, dummy, start_body;
01699 
01700        struct rfc2045src *src;
01701        struct rfc2045 *myrfcp=NULL;
01702        int fd;
01703        int i;
01704 
01705        if (!rfcp)
01706        {
01707               rfcp=myrfcp=decodeCreateRfc(fp);
01708               if (!rfcp)
01709                      return -1;
01710        }
01711 
01712        if ((fd=dup(fileno(fp))) < 0)
01713        {
01714               if (myrfcp)
01715                      rfc2045_free(myrfcp);
01716               return -1;
01717        }
01718 
01719        myDecodeInfo.first=1;
01720        myDecodeInfo.msgNum=msgNum;
01721        myDecodeInfo.bufptr=0;
01722 
01723        rfc2045_mimeinfo(rfcp, &content_type, &content_transfer_encoding,
01724                       &charset);
01725        rfc2045_mimepos(rfcp, &start_pos, &end_pos, &start_body, &dummy,
01726                      &dummy);
01727        myDecodeInfo.estSize=end_pos - start_body;
01728 
01729        if (content_transfer_encoding
01730            && strlen(content_transfer_encoding) == 6)
01731        {
01732               char buf[7];
01733 
01734               strcpy(buf, content_transfer_encoding);
01735               up(buf);
01736 
01737               if (strcmp(buf, "BASE64") == 0)
01738                      myDecodeInfo.estSize = myDecodeInfo.estSize / 4 * 3;
01739 
01740               /* Better estimate of base64 content */
01741        }
01742 
01743        src=rfc2045src_init_fd(fd);
01744 
01745        i=src ? rfc2045_decodemimesection(src, rfcp, &do_dump_decoded,
01746                                      &myDecodeInfo):-1;
01747 
01748        do_dump_decoded_flush(&myDecodeInfo);
01749 
01750        if (src)
01751               rfc2045src_deinit(src);
01752 
01753        close(fd);
01754 
01755        if (i == 0 && myDecodeInfo.first) /* Empty body, punt */
01756        {
01757               writes("{.0} FETCH ");
01758               writen(msgNum+1);
01759               writes(" CONTENTS\n.");
01760        }
01761        writes("\n");
01762        if (myrfcp)
01763               rfc2045_free(myrfcp);
01764        return i;
01765 }
01766 
01767 /* Dummy up a rfc2045 structure for retrieving the entire msg body */
01768 
01769 static struct rfc2045 *decodeCreateRfc(FILE *fp)
01770 {
01771        char buffer[SMAP_BUFSIZ];
01772        struct stat stat_buf;
01773        int i;
01774        struct rfc2045 *myrfcp;
01775 
01776        if (fstat(fileno(fp), &stat_buf) < 0)
01777               return NULL;
01778 
01779        if (fseek(fp, 0L, SEEK_SET) < 0)
01780               return NULL;
01781 
01782        if (!(myrfcp=rfc2045_alloc()))
01783               return NULL;
01784 
01785        do
01786        {
01787               i=fread(buffer, 1, sizeof(buffer), fp);
01788 
01789               if (i < 0)
01790               {
01791                      rfc2045_free(myrfcp);
01792                      return NULL;
01793                      }
01794 
01795               if (i == 0)
01796                      break;
01797               rfc2045_parse(myrfcp, buffer, i);
01798        } while (myrfcp->workinheader);
01799 
01800        myrfcp->endpos=stat_buf.st_size;
01801        return myrfcp;
01802 }
01803 
01804 static int do_dump_decoded(const char *chunk, size_t chunkSize,
01805                         void *vp)
01806 {
01807        struct decodeinfo *myDecodeInfo=(struct decodeinfo *) vp;
01808 
01809        while (chunkSize)
01810        {
01811               size_t n;
01812 
01813               if (myDecodeInfo->bufptr >= sizeof(myDecodeInfo->buffer))
01814                      do_dump_decoded_flush(myDecodeInfo);
01815 
01816               n=sizeof(myDecodeInfo->buffer)-myDecodeInfo->bufptr;
01817 
01818               if (n > chunkSize)
01819                      n=chunkSize;
01820               memcpy(myDecodeInfo->buffer + myDecodeInfo->bufptr, chunk, n);
01821               myDecodeInfo->bufptr += n;
01822               chunk += n;
01823               chunkSize -= n;
01824        }
01825        return 0;
01826 }
01827 
01828 static void do_dump_decoded_flush(struct decodeinfo *myDecodeInfo)
01829 {
01830        size_t chunkSize= myDecodeInfo->bufptr;
01831 
01832        myDecodeInfo->bufptr=0;
01833 
01834        if (chunkSize == 0)
01835               return;
01836 
01837        if (myDecodeInfo->first)
01838        {
01839               myDecodeInfo->first=0;
01840               writes("{");
01841               writen(chunkSize);
01842               writes("/");
01843               writen(myDecodeInfo->estSize);
01844               writes("} FETCH ");
01845               writen(myDecodeInfo->msgNum+1);
01846               writes(" CONTENTS\n");
01847        }
01848        else
01849        {
01850               writen(chunkSize);
01851               writes("\n");
01852        }
01853        writemem(myDecodeInfo->buffer, chunkSize);
01854        body_count += chunkSize;
01855 }
01856 
01857 static int mime(int fd, unsigned long n,
01858               struct rfc2045 *rfcp, const char *hdrs)
01859 {
01860        int rc=dump_hdrs(fd, n, rfcp, hdrs, NULL);
01861 
01862        if (rc)
01863               return rc;
01864 
01865        for (rfcp=rfcp->firstpart; rfcp; rfcp=rfcp->next)
01866               if (!rfcp->isdummy)
01867               {
01868                      rc=mime(fd, n, rfcp, hdrs);
01869                      if (rc)
01870                             return rc;
01871               }
01872 
01873        return 0;
01874 }
01875 
01876 /*
01877 ** Find the specified MIME id.
01878 */
01879 
01880 static struct rfc2045 *findmimeid(struct rfc2045 *rfcp,
01881                               const char *mimeid)
01882 {
01883        unsigned long n;
01884 
01885        while (mimeid && *mimeid)
01886        {
01887               const char *d;
01888 
01889               n=0;
01890 
01891               if (strchr(digit, *mimeid) == NULL)
01892                      return NULL;
01893 
01894               while (*mimeid && (d=strchr(digit, *mimeid)) != NULL)
01895               {
01896                      n=n * 10 + d-digit;
01897                      mimeid++;
01898               }
01899 
01900               while (rfcp)
01901               {
01902                      if (!rfcp->isdummy && rfcp->pindex == n)
01903                             break;
01904                      rfcp=rfcp->next;
01905               }
01906 
01907               if (!rfcp)
01908                      return NULL;
01909 
01910               if (*mimeid == '.')
01911               {
01912                      ++mimeid;
01913                      rfcp=rfcp->firstpart;
01914               }
01915        }
01916        return rfcp;
01917 }
01918 
01919 static int do_fetch(unsigned long n, void *vp)
01920 {
01921        struct smapfetchinfo *fi=(struct smapfetchinfo *)vp;
01922        FILE *fp=open_cached_fp(n);
01923        int rc=0;
01924 
01925        if (!fp)
01926               return -1;
01927 
01928        if (strcmp(fi->entity, "MIME") == 0)
01929        {
01930               struct rfc2045 *rfcp=fetch_alloc_rfc2045(n, fp);
01931               int fd;
01932 
01933               if (!rfcp)
01934                      return -1;
01935 
01936               fd=dup(fileno(fp));
01937               if (fd < 0)
01938                      return -1;
01939 
01940               rc=mime(fd, n, rfcp, fi->hdrs);
01941               close(fd);
01942        }
01943        else if (strcmp(fi->entity, "HEADERS") == 0 ||
01944                strcmp(fi->entity, "RAWHEADERS") == 0)
01945        {
01946               int fd;
01947               struct rfc2045 *rfcp;
01948 
01949               fd=dup(fileno(fp));
01950               if (fd < 0)
01951                      return -1;
01952 
01953               if (!fi->mimeid || !*fi->mimeid)
01954                      rfcp=NULL;
01955               else
01956               {
01957                      rfcp=fetch_alloc_rfc2045(n, fp);
01958 
01959                      rfcp=findmimeid(rfcp, fi->mimeid);
01960 
01961                      if (!rfcp)
01962                      {
01963                             close(fd);
01964                             errno=EINVAL;
01965                             return -1;
01966                      }
01967               }
01968 
01969               rc=dump_hdrs(fd, n, rfcp, fi->hdrs, fi->entity);
01970               close(fd);
01971        }
01972        else if (strcmp(fi->entity, "BODY") == 0
01973                || strcmp(fi->entity, "ALL") == 0)
01974        {
01975               struct rfc2045 *rfcp;
01976 
01977               if (!fi->mimeid || !*fi->mimeid)
01978                      rfcp=NULL;
01979               else
01980               {
01981                      rfcp=fetch_alloc_rfc2045(n, fp);
01982 
01983                      rfcp=findmimeid(rfcp, fi->mimeid);
01984 
01985                      if (!rfcp)
01986                      {
01987                             errno=EINVAL;
01988                             return -1;
01989                      }
01990               }
01991 
01992               rc=dump_body(fp, n, rfcp, fi->entity[0] == 'A');
01993        }
01994        else if (strcmp(fi->entity, "BODY.DECODED") == 0)
01995        {
01996               struct rfc2045 *rfcp;
01997 
01998               if (!fi->mimeid || !*fi->mimeid)
01999                      rfcp=NULL;
02000               else
02001               {
02002                      rfcp=fetch_alloc_rfc2045(n, fp);
02003 
02004                      rfcp=findmimeid(rfcp, fi->mimeid);
02005 
02006                      if (!rfcp)
02007                      {
02008                             errno=EINVAL;
02009                             return -1;
02010                      }
02011               }
02012 
02013               rc=dump_decoded(fp, n, rfcp);
02014        }
02015        else
02016        {
02017               rc=0;
02018        }
02019 
02020        if (rc == 0 && !fi->peek)
02021        {
02022               struct imapflags     flags;
02023 
02024               get_message_flags(current_maildir_info.msgs+n,
02025                               0, &flags);
02026               if (!flags.seen)
02027               {
02028                      flags.seen=1;
02029                      reflag_filename(&current_maildir_info.msgs[n],
02030                                    &flags, fileno(fp));
02031                      current_maildir_info.msgs[n].changedflags=1;
02032               }
02033        }
02034 
02035        if (current_maildir_info.msgs[n].changedflags)
02036               fetchflags(n);
02037 
02038        return rc;
02039 }
02040 
02041 void smap_fetchflags(unsigned long n)
02042 {
02043        int items=FETCH_FLAGS | FETCH_KEYWORDS;
02044 
02045        do_attrfetch(n, &items);
02046 }
02047 
02048 static int do_attrfetch(unsigned long n, void *vp)
02049 {
02050        int items=*(int *)vp;
02051 
02052        if (n >= current_maildir_info.nmessages)
02053               return 0;
02054 
02055        writes("* FETCH ");
02056        writen(n+1);
02057 
02058        if (items & FETCH_FLAGS)
02059        {
02060               char   buf[256];
02061 
02062               get_message_flags(current_maildir_info.msgs+n, buf, 0);
02063 
02064               writes(" FLAGS=");
02065               writes(buf);
02066 
02067               current_maildir_info.msgs[n].changedflags=0;
02068        }
02069 
02070        if ((items & FETCH_KEYWORDS) && keywords())
02071        {
02072               struct libmail_kwMessageEntry *kme;
02073 
02074               writes(" \"KEYWORDS=");
02075 
02076               if (current_maildir_info.msgs[n].keywordMsg &&
02077                   current_maildir_info.msgs[n].keywordMsg->firstEntry)
02078               {
02079                      const char *p="";
02080 
02081                      for (kme=current_maildir_info.msgs[n]
02082                                  .keywordMsg->firstEntry;
02083                           kme; kme=kme->next)
02084                      {
02085                             writes(p);
02086                             p=",";
02087                             writes(keywordName(kme->libmail_keywordEntryPtr));
02088                      }
02089               }
02090               writes("\"");
02091        }
02092 
02093        if (items & FETCH_UID)
02094        {
02095               char *p, *q;
02096 
02097               writes(" \"UID=");
02098 
02099               p=current_maildir_info.msgs[n].filename;
02100 
02101               q=strrchr(p, MDIRSEP[0]);
02102               if (q)
02103                      *q=0;
02104               smapword_s(p);
02105               if (q)
02106                      *q=MDIRSEP[0];
02107               writes("\"");
02108        }
02109 
02110        if (items & FETCH_SIZE)
02111        {
02112               char *p=current_maildir_info.msgs[n].filename;
02113               unsigned long cnt;
02114 
02115               if (maildir_parsequota(p, &cnt))
02116               {
02117                      FILE *fp=open_cached_fp(n);
02118                      struct stat stat_buf;
02119 
02120                      if (fp && fstat(fileno(fp), &stat_buf) == 0)
02121                             cnt=stat_buf.st_size;
02122                      else
02123                             cnt=0;
02124               }
02125 
02126               writes(" SIZE=");
02127               writen(cnt);
02128        }
02129 
02130        if (items & FETCH_INTERNALDATE)
02131        {
02132               struct stat stat_buf;
02133               FILE *fp=open_cached_fp(n);
02134 
02135               if (fp && fstat(fileno(fp), &stat_buf) == 0)
02136               {
02137                      char buf[256];
02138 
02139                      rfc822_mkdate_buf(stat_buf.st_mtime, buf);
02140                      writes(" \"INTERNALDATE=");
02141                      smapword_s(buf);
02142                      writes("\"");
02143               }
02144        }
02145        writes("\n");
02146        return 0;
02147 }
02148 
02149 struct add_rcptlist {
02150        struct add_rcptlist *next;
02151        char *rcptto;
02152 };
02153 
02154 static unsigned long add_msg(FILE *fp, const char *format,
02155                           char *buffer,
02156                           size_t bufsize)
02157 {
02158        unsigned long n=0;
02159 
02160        writes("> Go ahead\n");
02161        writeflush();
02162 
02163        if (*format == '.')
02164        {
02165               int last_eol=1;
02166               int dot_stuffed=0;
02167               int counter=-1;
02168 
02169               for (;;)
02170               {
02171                      char c;
02172 
02173                      if ( ((counter=counter + 1 ) % 8192) == 0)
02174                             read_timeout(60);
02175 
02176                      c=READ();
02177 
02178                      if (c == '\r')
02179                             continue;
02180 
02181                      if (dot_stuffed && c == '\n')
02182                             break;
02183                      dot_stuffed=0;
02184 
02185                      if (c == '.')
02186                      {
02187                             if (last_eol)
02188                             {
02189                                    dot_stuffed=1;
02190                                    continue;
02191                             }
02192                      }
02193                      last_eol= c == '\n';
02194                      putc( (int)(unsigned char)c, fp);
02195                      n++;
02196               }
02197 
02198               if (!last_eol)
02199               {
02200                      putc('\n', fp);
02201                      n++;
02202               }
02203        }
02204        else
02205        {
02206               unsigned long chunkSize;
02207               char last_char='\n';
02208 
02209               while (sscanf(format, "%lu", &chunkSize) == 1)
02210               {
02211                      while (chunkSize)
02212                      {
02213                             size_t nn=bufsize;
02214                             size_t i;
02215 
02216                             if (nn > chunkSize)
02217                                    nn=(size_t)chunkSize;
02218 
02219                             read_timeout(60);
02220                             nn=doread(buffer, nn);
02221 
02222                             chunkSize -= nn;
02223                             n += nn;
02224 
02225                             for (i=0; i<nn; i++)
02226                             {
02227                                    last_char=buffer[i];
02228 
02229                                    if (last_char == '\r')
02230                                           continue;
02231                                    putc((int)(unsigned char)last_char,
02232                                         fp);
02233                             }
02234                      }
02235 
02236                      read_timeout(60);
02237                      smap_readline(buffer, bufsize);
02238                      format=buffer;
02239               }
02240 
02241               if (last_char != '\n')
02242               {
02243                      putc('\n', fp);
02244                      n++;
02245               }
02246        }
02247 
02248        if (n == 0)
02249        {
02250               ++n;
02251               putc('\n', fp);
02252        }
02253 
02254        if (fflush(fp) < 0 || ferror(fp))
02255               return 0;
02256        return n;
02257 }
02258 
02259 static void adduid(char *n)
02260 {
02261        char *q;
02262 
02263        q=strrchr(n, '/');
02264        if (q)
02265               n=q+1;
02266 
02267        q=strrchr(n, MDIRSEP[0]);
02268        if (q)
02269               *q=0;
02270        writes("* ADD \"UID=");
02271        smapword_s(n);
02272        writes("\"\n");
02273        if (q)
02274               *q=MDIRSEP[0];
02275 }
02276 
02277 static void senderr(char *errmsg)
02278 {
02279        writes("-ERR ");
02280        writes(errmsg);
02281        writes("\n");
02282 }
02283 
02284 static int calc_quota(unsigned long n, void *voidptr)
02285 {
02286        return do_copy_quota_calc(n+1, 0, voidptr);
02287 }
02288 
02289 /* Copy msg to another folder */
02290 
02291 static void copieduid(unsigned long n, char *newname)
02292 {
02293        char *p, *q;
02294 
02295        writes("* COPY ");
02296        writen(n);
02297        writes(" \"NEWUID=");
02298 
02299        p=strrchr(newname, '/')+1;
02300 
02301        if ((q=strrchr(p, MDIRSEP[0])) != NULL)
02302               *q=0;
02303        
02304        smapword_s(p);
02305        writes("\"\n");
02306 }
02307 
02308 static int do_copyKeywords(struct libmail_kwMessage *msg,
02309                         const char *destmailbox,
02310                         const char *newname)
02311 {
02312        char *tmpkname, *newkname;
02313 
02314        if (!msg || !msg->firstEntry)
02315               return 0;
02316 
02317        if (maildir_kwSave(destmailbox, newname,
02318                         msg, &tmpkname, &newkname, 0))
02319        {
02320               perror("maildir_kwSave");
02321               return -1;
02322        }
02323 
02324        rename(tmpkname, newkname);
02325        free(tmpkname);
02326        free(newkname);
02327        return 0;
02328 }
02329 
02330 static void fixnewfilename(char *p)
02331 {
02332        char *q;
02333 
02334        /* Nice hack: */
02335 
02336        q=strrchr(strrchr(p, '/'), MDIRSEP[0]);
02337 
02338        if (strcmp(q, MDIRSEP "2,") == 0)
02339        {
02340               *q=0;
02341               memcpy(strrchr(p, '/')-3, "new", 3);
02342        }
02343 }
02344 
02345 static int do_copymsg(unsigned long n, void *voidptr)
02346 {
02347        char buf[SMAP_BUFSIZ];
02348        struct copyquotainfo *cqinfo=(struct copyquotainfo *)voidptr;
02349        struct imapflags new_flags;
02350        int fd;
02351        struct stat stat_buf;
02352        FILE *fp;
02353        char *tmpname, *newname;
02354 
02355        fd=imapscan_openfile(current_mailbox, &current_maildir_info, n);
02356        if (fd < 0)   return (0);
02357 
02358        if (fstat(fd, &stat_buf) < 0)
02359        {
02360               close(fd);
02361               return (0);
02362        }
02363 
02364        get_message_flags(current_maildir_info.msgs+n, 0, &new_flags);
02365 
02366        fp=maildir_mkfilename(cqinfo->destmailbox,
02367                            &new_flags, stat_buf.st_size,
02368                            &tmpname, &newname);
02369 
02370        fixnewfilename(newname);
02371 
02372        if (!fp)
02373        {
02374               close(fd);
02375               return (-1);
02376        }
02377 
02378        while (stat_buf.st_size)
02379        {
02380        int    n=sizeof(buf);
02381 
02382               if (n > stat_buf.st_size)
02383                      n=stat_buf.st_size;
02384 
02385               n=read(fd, buf, n);
02386 
02387               if (n <= 0 || fwrite(buf, 1, n, fp) != n)
02388               {
02389                      close(fd);
02390                      fclose(fp);
02391                      unlink(tmpname);
02392                      free(tmpname);
02393                      free(newname);
02394                      fprintf(stderr,
02395                      "ERR: error copying a message, user=%s, errno=%d\n",
02396                             getenv("AUTHENTICATED"), errno);
02397 
02398                      return (-1);
02399               }
02400               stat_buf.st_size -= n;
02401        }
02402        close(fd);
02403 
02404        if (fflush(fp) || ferror(fp))
02405        {
02406               fclose(fp);
02407               unlink(tmpname);
02408               free(tmpname);
02409               free(newname);
02410               fprintf(stderr,
02411                      "ERR: error copying a message, user=%s, errno=%d\n",
02412                      getenv("AUTHENTICATED"), errno);
02413               return (-1);
02414        }
02415        fclose(fp);
02416 
02417        if (do_copyKeywords(current_maildir_info.msgs[n].keywordMsg,
02418                          cqinfo->destmailbox,
02419                          strrchr(newname, '/')+1))
02420        {
02421               unlink(tmpname);
02422               free(tmpname);
02423               free(newname);
02424               fprintf(stderr,
02425                      "ERR: error copying keywords, "
02426                      "user=%s, errno=%d\n",
02427                      getenv("AUTHENTICATED"), errno);
02428               return (-1);
02429        }
02430 
02431        current_maildir_info.msgs[n].copiedflag=1;
02432 
02433        maildir_movetmpnew(tmpname, newname);
02434        set_time(newname, stat_buf.st_mtime);
02435        free(tmpname);
02436 
02437        copieduid(n+1, newname);
02438        free(newname);
02439        return 0;
02440 }
02441 
02442 static int do_movemsg(unsigned long n, void *voidptr)
02443 {
02444        char *filename;
02445        struct copyquotainfo *cqinfo=(struct copyquotainfo *)voidptr;
02446        char *newfilename;
02447 
02448        if (n >= current_maildir_info.nmessages)
02449               return 0;
02450 
02451        filename=maildir_filename(current_mailbox, 0,
02452                               current_maildir_info.msgs[n].filename);
02453 
02454        if (!filename)
02455               return 0;
02456 
02457        newfilename=malloc(strlen(cqinfo->destmailbox) + sizeof("/cur")
02458                         + strlen(strrchr(filename, '/')));
02459 
02460        if (!newfilename)
02461        {
02462               free(filename);
02463               write_error_exit(0);
02464        }
02465 
02466        strcat(strcat(strcpy(newfilename, cqinfo->destmailbox),
02467                     "/cur"), strrchr(filename, '/'));
02468 
02469        if (do_copyKeywords(current_maildir_info.msgs[n].keywordMsg,
02470                          cqinfo->destmailbox,
02471                          strrchr(newfilename, '/')+1))
02472        {
02473               fprintf(stderr,
02474                      "ERR: error copying keywords, "
02475                      "user=%s, errno=%d\n",
02476                      getenv("AUTHENTICATED"), errno);
02477 
02478               free(filename);
02479               free(newfilename);
02480               return -1;
02481        }
02482 
02483 
02484        if (maildir_movetmpnew(filename, newfilename) == 0)
02485        {
02486               copieduid(n+1, newfilename);
02487               free(filename);
02488               free(newfilename);
02489               return 0;
02490        }
02491 
02492        if (do_copymsg(n, voidptr))
02493               return -1;
02494 
02495        unlink(filename);
02496        free(filename);
02497        free(newfilename);
02498        return 0;
02499 }
02500 
02501 static struct searchinfo *createSearch2(char *w,
02502                                    struct searchinfo **head, char **ptr);
02503 
02504 static struct searchinfo *createSearch(struct searchinfo **head, char **ptr)
02505 {
02506        char *w=getword(ptr);
02507        struct searchinfo *siAnd, *n;
02508 
02509        up(w);
02510 
02511        if (strcmp(w, "MARKED") == 0)
02512        {
02513               w=getword(ptr);
02514               up(w);
02515 
02516               n=createSearch2(w, head, ptr);
02517 
02518               if (!n)
02519                      return NULL;
02520 
02521               siAnd=alloc_search(head);
02522               siAnd->type=search_and;
02523 
02524               siAnd->b=n;
02525 
02526               siAnd->a=n=alloc_search(head);
02527 
02528               n->type=search_msgflag;
02529               if (!(n->as=strdup("\\FLAGGED")))
02530                      write_error_exit(0);
02531 
02532               return siAnd;
02533        }
02534 
02535        if (strcmp(w, "UNMARKED") == 0)
02536        {
02537               w=getword(ptr);
02538               up(w);
02539 
02540               n=createSearch2(w, head, ptr);
02541 
02542               if (!n)
02543                      return NULL;
02544 
02545               siAnd=alloc_search(head);
02546               siAnd->type=search_and;
02547 
02548               siAnd->b=n;
02549 
02550               siAnd->a=n=alloc_search(head);
02551 
02552               n->type=search_not;
02553 
02554               n=n->a=alloc_search(head);
02555 
02556               n->type=search_msgflag;
02557               if (!(n->as=strdup("\\FLAGGED")))
02558                      write_error_exit(0);
02559 
02560               return siAnd;
02561        }
02562 
02563        if (strcmp(w, "ALL") == 0)
02564        {
02565               w=getword(ptr);
02566               up(w);
02567               return createSearch2(w, head, ptr);
02568        }
02569 
02570        {
02571               char *ww=getword(ptr);
02572               up(ww);
02573               n=createSearch2(ww, head, ptr);
02574 
02575               if (!n)
02576                      return NULL;
02577 
02578               siAnd=alloc_search(head);
02579               siAnd->type=search_and;
02580 
02581               siAnd->b=n;
02582 
02583               siAnd->a=n=alloc_search(head);
02584 
02585               n->type=search_messageset;
02586               if (!(n->as=strdup(w)))
02587                      write_error_exit(0);
02588 
02589               for (ww=n->as; *ww; ww++)
02590                      if (*ww == '-')
02591                             *ww=':';
02592 
02593               if (!ismsgset_str(n->as))
02594               {
02595                      errno=EINVAL;
02596                      return NULL;
02597               }
02598        }
02599        return siAnd;
02600 }
02601 
02602 static struct searchinfo *createSearch2(char *w,
02603                                    struct searchinfo **head, char **ptr)
02604 {
02605        int notflag=0;
02606        struct searchinfo *n;
02607 
02608        if (strcmp(w, "NOT") == 0)
02609        {
02610               notflag=1;
02611               w=getword(ptr);
02612               up(w);
02613        }
02614 
02615        if (strcmp(w, "REPLIED") == 0)
02616        {
02617               n=alloc_search(head);
02618               n->type=search_msgflag;
02619               if (!(n->as=strdup("\\ANSWERED")))
02620                      write_error_exit(0);
02621        }
02622        else if (strcmp(w, "DELETED") == 0)
02623        {
02624               n=alloc_search(head);
02625               n->type=search_msgflag;
02626               if (!(n->as=strdup("\\DELETED")))
02627                      write_error_exit(0);
02628        }
02629        else if (strcmp(w, "DRAFT") == 0)
02630        {
02631               n=alloc_search(head);
02632               n->type=search_msgflag;
02633               if (!(n->as=strdup("\\DRAFT")))
02634                      write_error_exit(0);
02635        }
02636        else if (strcmp(w, "SEEN") == 0)
02637        {
02638               n=alloc_search(head);
02639               n->type=search_msgflag;
02640               if (!(n->as=strdup("\\SEEN")))
02641                      write_error_exit(0);
02642        }
02643        else if (strcmp(w, "KEYWORD") == 0)
02644        {
02645               n=alloc_search(head);
02646               n->type=search_msgkeyword;
02647               if (!(n->as=strdup(getword(ptr))))
02648                      write_error_exit(0);
02649        }
02650        else if (strcmp(w, "FROM") == 0 ||
02651                strcmp(w, "TO") == 0 ||
02652                strcmp(w, "CC") == 0 ||
02653                strcmp(w, "BCC") == 0 ||
02654                strcmp(w, "SUBJECT") == 0)
02655        {
02656               n=alloc_search(head);
02657               n->type=search_header;
02658               if (!(n->cs=strdup(w)))
02659                      write_error_exit(0);
02660               n->as=strdup(getword(ptr));
02661               if (!n->as)
02662                      write_error_exit(0);
02663        }
02664        else if (strcmp(w, "HEADER") == 0)
02665        {
02666               n=alloc_search(head);
02667               n->type=search_header;
02668               if (!(n->cs=strdup(getword(ptr))))
02669                      write_error_exit(0);
02670               up(n->cs);
02671               n->as=strdup(getword(ptr));
02672               if (!n->as)
02673                      write_error_exit(0);
02674        }
02675        else if (strcmp(w, "BODY") == 0)
02676        {
02677               n=alloc_search(head);
02678               n->type=search_body;
02679               n->as=strdup(getword(ptr));
02680               if (!n->as)
02681                      write_error_exit(0);
02682        }
02683        else if (strcmp(w, "TEXT") == 0)
02684        {
02685               n=alloc_search(head);
02686               n->type=search_text;
02687               n->as=strdup(getword(ptr));
02688               if (!n->as)
02689                      write_error_exit(0);
02690        }
02691        else if (strcmp(w, "BEFORE") == 0)
02692        {
02693               n=alloc_search(head);
02694               n->type=search_before;
02695               n->as=strdup(getword(ptr));
02696               if (!n->as)
02697                      write_error_exit(0);
02698        }
02699        else if (strcmp(w, "ON") == 0)
02700        {
02701               n=alloc_search(head);
02702               n->type=search_on;
02703               n->as=strdup(getword(ptr));
02704               if (!n->as)
02705                      write_error_exit(0);
02706        }
02707        else if (strcmp(w, "SINCE") == 0)
02708        {
02709               n=alloc_search(head);
02710               n->type=search_since;
02711               n->as=strdup(getword(ptr));
02712               if (!n->as)
02713                      write_error_exit(0);
02714        }
02715        else if (strcmp(w, "SENTBEFORE") == 0)
02716        {
02717               n=alloc_search(head);
02718               n->type=search_sentbefore;
02719               n->as=strdup(getword(ptr));
02720               if (!n->as)
02721                      write_error_exit(0);
02722        }
02723        else if (strcmp(w, "SENTON") == 0)
02724        {
02725               n=alloc_search(head);
02726               n->type=search_senton;
02727               n->as=strdup(getword(ptr));
02728               if (!n->as)
02729                      write_error_exit(0);
02730        }
02731        else if (strcmp(w, "SINCE") == 0)
02732        {
02733               n=alloc_search(head);
02734               n->type=search_sentsince;
02735               n->as=strdup(getword(ptr));
02736               if (!n->as)
02737                      write_error_exit(0);
02738        }
02739        else if (strcmp(w, "SMALLER") == 0)
02740        {
02741               n=alloc_search(head);
02742               n->type=search_smaller;
02743               n->as=strdup(getword(ptr));
02744               if (!n->as)
02745                      write_error_exit(0);
02746        }
02747        else if (strcmp(w, "LARGER") == 0)
02748        {
02749               n=alloc_search(head);
02750               n->type=search_larger;
02751               n->as=strdup(getword(ptr));
02752               if (!n->as)
02753                      write_error_exit(0);
02754        }
02755        else
02756        {
02757               errno=EINVAL;
02758               return NULL;
02759        }
02760 
02761        if (notflag)
02762        {
02763               struct searchinfo *p=alloc_search(head);
02764 
02765               p->type=search_not;
02766               p->a=n;
02767               n=p;
02768        }
02769        return n;
02770 }
02771 
02772 static int do_copyto(char *toFolder,
02773                    int (*do_func)(unsigned long, void *),
02774                    const char *acls)
02775 {
02776        int has_quota=0;
02777        struct copyquotainfo cqinfo;
02778        struct maildirsize quotainfo;
02779 
02780        cqinfo.destmailbox=toFolder;
02781        cqinfo.nbytes=0;
02782        cqinfo.nfiles=0;
02783        cqinfo.acls=acls;
02784 
02785        if (maildirquota_countfolder(toFolder))
02786        {
02787               if (maildir_openquotafile(&quotainfo, ".") == 0)
02788               {
02789                      if (quotainfo.fd >= 0)
02790                             has_quota=1;
02791                      maildir_closequotafile(&quotainfo);
02792               }
02793 
02794               if (has_quota > 0 && applymsgset( &calc_quota, &cqinfo ))
02795                      has_quota= -1;
02796        }
02797 
02798        if (has_quota > 0 && cqinfo.nfiles > 0)
02799        {
02800               if (maildir_quota_add_start(".", &quotainfo,
02801                                        cqinfo.nbytes,
02802                                        cqinfo.nfiles,
02803                                        getenv("MAILDIRQUOTA")))
02804               {
02805                      errno=ENOSPC;
02806                      return (-1);
02807               }
02808 
02809               maildir_quota_add_end(&quotainfo,
02810                                   cqinfo.nbytes,
02811                                   cqinfo.nfiles);
02812        }
02813 
02814        return applymsgset(do_func, &cqinfo);
02815 }
02816 
02817 static int copyto(char *toFolder, int do_move, const char *acls)
02818 {
02819        if (!do_move)
02820               return do_copyto(toFolder, &do_copymsg, acls);
02821 
02822        if (!current_mailbox_shared &&
02823            maildirquota_countfolder(current_mailbox) ==
02824            maildirquota_countfolder(toFolder))
02825        {
02826               if (do_copyto(toFolder, do_movemsg, acls))
02827                      return -1;
02828 
02829               doNoop(0);
02830               return(0);
02831        }
02832 
02833        if (do_copyto(toFolder, &do_copymsg, acls))
02834               return -1;
02835 
02836        applymsgset(&msg_expunge, NULL);
02837        doNoop(0);
02838        return 0;
02839 }
02840 
02841 struct smap1_search_results {
02842 
02843        unsigned prev_runs;
02844 
02845        unsigned long prev_search_hit;
02846        unsigned long prev_search_hit_start;
02847 };
02848 
02849 static void smap1_search_cb_range(struct smap1_search_results *searchResults)
02850 {
02851        if (searchResults->prev_runs > 100)
02852        {
02853               writes("\n");
02854               searchResults->prev_runs=0;
02855        }
02856 
02857        if (searchResults->prev_runs == 0)
02858               writes("* SEARCH");
02859 
02860        writes(" ");
02861        writen(searchResults->prev_search_hit_start);
02862        if (searchResults->prev_search_hit_start !=
02863            searchResults->prev_search_hit)
02864        {
02865               writes("-");
02866               writen(searchResults->prev_search_hit);
02867        }
02868        ++searchResults->prev_runs;
02869 }
02870 
02871 static void smap1_search_cb(struct searchinfo *si,
02872                          struct searchinfo *sihead,
02873                          int isuid, unsigned long i, void *dummy)
02874 {
02875        struct smap1_search_results *searchResults=
02876               (struct smap1_search_results *)dummy;
02877 
02878        ++i;
02879 
02880        if (searchResults->prev_search_hit == 0)
02881        {
02882               searchResults->prev_search_hit=
02883                      searchResults->prev_search_hit_start=i;
02884               return;
02885        }
02886 
02887        if (i != searchResults->prev_search_hit+1)
02888        {
02889               smap1_search_cb_range(searchResults);
02890               searchResults->prev_search_hit_start=i;
02891        }
02892 
02893        searchResults->prev_search_hit=i;
02894 }
02895 
02896 static void accessdenied(const char *acl_required)
02897 {
02898        writes("-ERR Access denied: ACL \"");
02899        writes(acl_required);
02900        writes("\" is required\n");
02901 }
02902 
02903 static int getacl(const char *ident,
02904                 const maildir_aclt *acl,
02905                 void *cb_arg)
02906 {
02907        int *n=(int *)cb_arg;
02908 
02909        if (*n > 5)
02910        {
02911               writes("\n");
02912               *n=0;
02913        }
02914 
02915        if (*n == 0)
02916               writes("* GETACL");
02917 
02918        writes(" ");
02919        smapword(ident);
02920        writes(" ");
02921        smapword(maildir_aclt_ascstr(acl));
02922        ++*n;
02923        return 0;
02924 }
02925 
02926 struct setacl_info {
02927        struct maildir_info minfo;
02928        char **ptr;
02929 };
02930 
02931 static int dosetdeleteacl(void *cb_arg, int);
02932 
02933 static int setacl(void *cb_arg)
02934 {
02935        return dosetdeleteacl(cb_arg, 0);
02936 }
02937 
02938 static int deleteacl(void *cb_arg)
02939 {
02940        return dosetdeleteacl(cb_arg, 1);
02941 }
02942 
02943 static int dosetdeleteacl(void *cb_arg, int dodelete)
02944 {
02945        struct setacl_info *sainfo=(struct setacl_info *)cb_arg;
02946        char *q;
02947        int cnt;
02948        const char *identifier;
02949        const char *action;
02950        const char *err_failedrights;
02951        char *path;
02952 
02953        maildir_aclt_list aclt_list;
02954 
02955        if (read_acls(&aclt_list, &sainfo->minfo) < 0)
02956        {
02957               writes("-ERR Unable to read existing ACLS: ");
02958               writes(strerror(errno));
02959               writes("\n");
02960               return 0;
02961        }
02962 
02963        q=compute_myrights(&aclt_list,
02964                         sainfo->minfo.owner);
02965 
02966        if (!q || !strchr(q, ACL_ADMINISTER[0]))
02967        {
02968               if (q) free(q);
02969               maildir_aclt_list_destroy(&aclt_list);
02970               accessdenied(ACL_ADMINISTER);
02971               return 0;
02972        }
02973 
02974        free(q);
02975 
02976        while (*(identifier=getword(sainfo->ptr)))
02977        {
02978               if (dodelete)
02979               {
02980                      if (maildir_aclt_list_del(&aclt_list,
02981                                             identifier) < 0)
02982                      {
02983                             maildir_aclt_list_destroy(&aclt_list);
02984                             writes("-ERR Error: ");
02985                             writes(strerror(errno));
02986                             writes("\n");
02987                             return 0;
02988                      }
02989                      continue;
02990               }
02991 
02992               action=getword(sainfo->ptr);
02993 
02994               if (*action == '+')
02995               {
02996                      maildir_aclt newacl;
02997                      const maildir_aclt *oldacl;
02998 
02999                      if (maildir_aclt_init(&newacl,
03000                                          action+1,
03001                                          NULL) < 0)
03002                      {
03003                             maildir_aclt_list_destroy(&aclt_list);
03004                             writes("-ERR Error: ");
03005                             writes(strerror(errno));
03006                             writes("\n");
03007                             return 0;
03008                      }
03009 
03010 
03011                      oldacl=maildir_aclt_list_find(&aclt_list,
03012                                                 identifier
03013                                                 );
03014                      if (oldacl)
03015                      {
03016                             if (maildir_aclt_add(&newacl,
03017                                                NULL,
03018                                                oldacl)
03019                                 < 0)
03020                             {
03021                                    maildir_aclt_destroy(&newacl);
03022                                    maildir_aclt_list_destroy(&aclt_list);
03023                                    writes("-ERR Error: ");
03024                                    writes(strerror(errno));
03025                                    writes("\n");
03026                                    return 0;
03027                             }
03028                      }
03029 
03030                      if (maildir_aclt_list_add(&aclt_list,
03031                                             identifier,
03032                                             NULL,
03033                                             &newacl) < 0)
03034                      {
03035                             maildir_aclt_destroy(&newacl);
03036                             maildir_aclt_list_destroy(&aclt_list);
03037                             writes("-ERR Error: ");
03038                             writes(strerror(errno));
03039                             writes("\n");
03040                             return 0;
03041 
03042                      }
03043                      maildir_aclt_destroy(&newacl);
03044                      continue;
03045               }
03046 
03047               if (*action == '-')
03048               {
03049                      maildir_aclt newacl;
03050                      const maildir_aclt *oldacl;
03051 
03052                      oldacl=maildir_aclt_list_find(&aclt_list,
03053                                                 identifier
03054                                                 );
03055 
03056                      if (!oldacl)
03057                             continue;
03058 
03059                      if (maildir_aclt_init(&newacl,
03060                                          NULL,
03061                                          oldacl) < 0)
03062                      {
03063                             maildir_aclt_list_destroy(&aclt_list);
03064                             writes("-ERR Error: ");
03065                             writes(strerror(errno));
03066                             writes("\n");
03067                             return 0;
03068                      }
03069 
03070 
03071                      if (maildir_aclt_del(&newacl,
03072                                         action+1, NULL)
03073                                 < 0)
03074                      {
03075                             maildir_aclt_destroy(&newacl);
03076                             maildir_aclt_list_destroy(&aclt_list);
03077                             writes("-ERR Error: ");
03078                             writes(strerror(errno));
03079                             writes("\n");
03080                             return 0;
03081                      }
03082 
03083                      if (strlen(maildir_aclt_ascstr(&newacl))
03084                          == 0 ?
03085                          maildir_aclt_list_del(&aclt_list,
03086                                             identifier)
03087                          :maildir_aclt_list_add(&aclt_list,
03088                                              identifier,
03089                                              NULL,
03090                                              &newacl) < 0)
03091                      {
03092                             maildir_aclt_destroy(&newacl);
03093                             maildir_aclt_list_destroy(&aclt_list);
03094                             writes("-ERR Error: ");
03095                             writes(strerror(errno));
03096                             writes("\n");
03097                             return 0;
03098 
03099                      }
03100                      maildir_aclt_destroy(&newacl);
03101                      continue;
03102               }
03103 
03104               if (strlen(action) == 0 ?
03105                   maildir_aclt_list_del(&aclt_list,
03106                                      identifier):
03107                   maildir_aclt_list_add(&aclt_list,
03108                                      identifier,
03109                                      action, NULL) < 0)
03110               {
03111                      maildir_aclt_list_destroy(&aclt_list);
03112                      writes("-ERR Error: ");
03113                      writes(strerror(errno));
03114                      writes("\n");
03115                      return 0;
03116               }
03117        }
03118 
03119        path=maildir_name2dir(".", sainfo->minfo.maildir);
03120 
03121        err_failedrights=NULL;
03122        if (!path ||
03123            maildir_acl_write(&aclt_list, sainfo->minfo.homedir,
03124                            path[0] == '.' && path[1] == '/'
03125                            ? path+2:path,
03126                            sainfo->minfo.owner,
03127                            &err_failedrights))
03128        {
03129               if (path)
03130                      free(path);
03131 
03132               if (err_failedrights)
03133               {
03134                      writes("* ACLMINIMUM ");
03135                      writes(err_failedrights);
03136                      writes(" ");
03137                      aclminimum(err_failedrights);
03138                      writes("\n");
03139               }
03140               writes("-ERR ACL update failed\n");
03141               maildir_aclt_list_destroy(&aclt_list);
03142               return 0;
03143        }
03144 
03145        cnt=0;
03146        maildir_aclt_list_enum(&aclt_list,
03147                             getacl, &cnt);
03148        if (cnt)
03149               writes("\n");
03150        maildir_aclt_list_destroy(&aclt_list);
03151 
03152        /* Reread ACLs if the current mailbox's ACLs have changed */
03153 
03154        if (read_acls(&aclt_list, &sainfo->minfo) < 0)
03155        {
03156               writes("-ERR Unable to re-read ACLS: ");
03157               writes(strerror(errno));
03158               writes("\n");
03159               return 0;
03160        }
03161 
03162        maildir_aclt_list_destroy(&aclt_list);
03163        writes("+OK Updated ACLs\n");
03164        return 0;
03165 }
03166 
03167 static int checkacl(char **folder, struct maildir_info *minfo,
03168                   const char *acls)
03169 {
03170        char *q;
03171 
03172        maildir_aclt_list aclt_list;
03173 
03174        if (maildir_info_smap_find(minfo, folder, getenv("AUTHENTICATED")) < 0)
03175               return -1;
03176 
03177        if (read_acls(&aclt_list, minfo) < 0)
03178        {
03179               maildir_info_destroy(minfo);
03180               return -1;
03181        }
03182 
03183        q=compute_myrights(&aclt_list, minfo->owner);
03184        maildir_aclt_list_destroy(&aclt_list);
03185 
03186        while (*acls)
03187        {
03188               if (q == NULL || strchr(q, *acls) == NULL)
03189               {
03190                      if (q) free(q);
03191                      maildir_info_destroy(minfo);
03192                      return -1;
03193               }
03194               ++acls;
03195        }
03196        if (q)
03197               free(q);
03198        return 0;
03199 }
03200 
03201 void smap()
03202 {
03203        char buffer[8192];
03204        char *ptr;
03205        struct imapflags add_flags;
03206        int in_add=0;
03207        char *add_from=NULL;
03208        char *add_folder=NULL;
03209        time_t add_internaldate=0;
03210        char *add_notify=NULL;
03211        unsigned add_rcpt_count=0;
03212        struct libmail_kwMessage *addKeywords=NULL;
03213 
03214        struct add_rcptlist *add_rcpt_list=NULL;
03215 
03216        char rights_buf[40];
03217 
03218        imapscan_init(&current_maildir_info);
03219        memset(&add_flags, 0, sizeof(add_flags));
03220 
03221 #define GETFOLDER(acl) ( strcpy(rights_buf, (acl)), \
03222                      getAccessToFolder(&ptr, rights_buf))
03223 
03224        for (;;)
03225        {
03226               char *p;
03227 
03228               writeflush();
03229               read_timeout(30 * 60);
03230               smap_readline(buffer, sizeof(buffer));
03231 
03232               ptr=buffer;
03233 
03234               p=getword(&ptr);
03235               up(p);
03236 
03237               if (strcmp(p, "ADD") == 0)
03238               {
03239                      char **argvec;
03240                      const char *okmsg="So far, so good...";
03241                      int err_sent=0;
03242 
03243                      in_add=1;
03244                      while (*(p=getword(&ptr)))
03245                      {
03246                             char *q=strchr(p, '=');
03247 
03248                             if (q)
03249                                    *q++=0;
03250                             up(p);
03251 
03252                             if (strcmp(p, "FOLDER") == 0)
03253                             {
03254                                    if (add_folder)
03255                                           free(add_folder);
03256 
03257                                    add_folder=
03258                                           GETFOLDER(ACL_INSERT
03259                                                    ACL_DELETEMSGS
03260                                                    ACL_SEEN
03261                                                    ACL_WRITE);
03262                                    if (!add_folder)
03263                                    {
03264                                           writes("-ERR Invalid folder: ");
03265                                           writes(strerror(errno));
03266                                           writes("\n");
03267                                           break;
03268                                    }
03269 
03270                                    if (strchr(rights_buf,
03271                                              ACL_INSERT[0])
03272                                        == NULL)
03273                                    {
03274                                           accessdenied(ACL_INSERT);
03275                                           free(add_folder);
03276                                           add_folder=NULL;
03277                                           break;
03278                                    }
03279 
03280                                    okmsg="Will add to this folder";
03281                             }
03282 
03283                             if (strcmp(p, "MAILFROM") == 0 && q)
03284                             {
03285                                    if (add_from)
03286                                           free(add_from);
03287                                    if ((add_from=strdup(q)) == NULL)
03288                                    {
03289                                           writes("-ERR ");
03290                                           writes(strerror(errno));
03291                                           writes("\n");
03292                                           break;
03293                                    }
03294                                    okmsg="MAIL FROM set";
03295                             }
03296 
03297                             if (strcmp(p, "NOTIFY") == 0 && q)
03298                             {
03299                                    if (add_notify)
03300                                           free(add_notify);
03301                                    if ((add_notify=strdup(q)) == NULL)
03302                                    {
03303                                           writes("-ERR ");
03304                                           writes(strerror(errno));
03305                                           writes("\n");
03306                                           break;
03307                                    }
03308                                    okmsg="NOTIFY set";
03309                             }
03310 
03311                             if (strcmp(p, "RCPTTO") == 0 && q)
03312                             {
03313                                    struct add_rcptlist *rcpt=
03314                                           malloc(sizeof(struct
03315                                                        add_rcptlist));
03316 
03317                                    if (rcpt == NULL ||
03318                                        (rcpt->rcptto=strdup(q)) == NULL)
03319                                    {
03320                                           if (rcpt)
03321                                                  free(rcpt);
03322                                           writes("-ERR ");
03323                                           writes(strerror(errno));
03324                                           writes("\n");
03325                                           break;
03326                                    }
03327                                    rcpt->next=add_rcpt_list;
03328                                    add_rcpt_list=rcpt;
03329                                    ++add_rcpt_count;
03330                                    okmsg="RCPT TO set";
03331                             }
03332 
03333                             if (strcmp(p, "FLAGS") == 0 && q)
03334                             {
03335                                    memset(&add_flags, 0,
03336                                           sizeof(add_flags));
03337                                    *--q='=';
03338                                    parseflags(q, &add_flags);
03339 
03340                                    if (strchr(rights_buf,
03341                                              ACL_SEEN[0])
03342                                        == NULL)
03343                                           add_flags.seen=0;
03344                                    if (strchr(rights_buf,
03345                                              ACL_DELETEMSGS[0])
03346                                        == NULL)
03347                                           add_flags.deleted=0;
03348                                    if (strchr(rights_buf,
03349                                              ACL_WRITE[0])
03350                                        == NULL)
03351                                           add_flags.answered=
03352                                                  add_flags.flagged=
03353                                                  add_flags.drafts=0;
03354 
03355                                    okmsg="FLAGS set";
03356                             }
03357 
03358                             if (strcmp(p, "KEYWORDS") == 0 && q &&
03359                                 keywords() && strchr(rights_buf,
03360                                                   ACL_WRITE[0]))
03361                             {
03362                                    if (addKeywords)
03363                                           libmail_kwmDestroy(addKeywords);
03364 
03365                                    addKeywords=libmail_kwmCreate();
03366 
03367                                    if (addKeywords == NULL)
03368                                    {
03369                                           write_error_exit(0);
03370                                    }
03371 
03372                                    *--q='=';
03373                                    parsekeywords(q, &addKeywords);
03374                                    okmsg="KEYWORDS set";
03375                             }
03376 
03377                             if (strcmp(p, "INTERNALDATE") == 0 && q)
03378                             {
03379                                    add_internaldate=rfc822_parsedt(q);
03380 
03381                                    if (add_internaldate)
03382                                           okmsg="INTERNALDATE set";
03383                             }
03384 
03385                             if (p[0] == '{')
03386                             {
03387                                    char *tmpname, *newname;
03388                                    char *s;
03389                                    char *tmpKeywords=NULL;
03390                                    char *newKeywords=NULL;
03391                                    FILE *fp;
03392                                    unsigned long n;
03393 
03394                                    fp=maildir_mkfilename(add_folder
03395                                                        ?add_folder
03396                                                        :".",
03397                                                        &add_flags,
03398                                                        0,
03399                                                        &tmpname,
03400                                                        &newname);
03401 
03402                                    if (!fp)
03403                                    {
03404                                           writes("-ERR ");
03405                                           writes(strerror(errno));
03406                                           writes("\n");
03407                                           break;
03408                                    }
03409 
03410                                    fixnewfilename(newname);
03411 
03412                                    current_temp_fd=fileno(fp);
03413                                    current_temp_fn=tmpname;
03414 
03415                                    n=add_msg(fp, p+1, buffer,
03416                                             sizeof(buffer));
03417 
03418                                    if (n)
03419                                    {
03420                                           s=maildir_requota(newname, n);
03421 
03422                                           if (!s)
03423                                                  n=0;
03424                                           else
03425                                           {
03426                                                  free(newname);
03427                                                  newname=s;
03428                                           }
03429                                    }
03430 
03431                                    current_temp_fd= -1;
03432                                    current_temp_fn= NULL;
03433 
03434                                    if (n > 0 && add_folder &&
03435                                        maildirquota_countfolder(add_folder)
03436                                        && maildirquota_countfile(newname))
03437                                    {
03438                                           struct maildirsize quotainfo;
03439 
03440                                           if (maildir_quota_add_start(add_folder, &quotainfo, n, 1,
03441                                                                    getenv("MAILDIRQUOTA")))
03442                                           {
03443                                                  errno=ENOSPC;
03444                                                  n=0;
03445                                           }
03446                                           else
03447                                                  maildir_quota_add_end(&quotainfo, n, 1);
03448                                    }
03449 
03450                                    fclose(fp);
03451 
03452                                    chmod(tmpname, 0600);
03453 
03454                                    if (add_folder && n && addKeywords)
03455                                    {
03456                                           if (maildir_kwSave(add_folder,
03457                                                            strrchr(newname, '/')+1,
03458                                                            addKeywords,
03459                                                            &tmpKeywords,
03460                                                            &newKeywords,
03461                                                            0))
03462                                           {
03463                                                  tmpKeywords=NULL;
03464                                                  newKeywords=NULL;
03465                                                  n=0;
03466                                                  perror("maildir_kwSave");
03467                                           }
03468                                    }
03469 
03470                                    argvec=NULL;
03471 
03472                                    if (add_rcpt_count > 0 && n)
03473                                    {
03474                                           argvec=malloc(sizeof(char *)
03475                                                        * (add_rcpt_count
03476                                                          +10));
03477 
03478                                           if (!argvec)
03479                                                  n=0;
03480                                    }
03481 
03482                                    if (argvec)
03483                                    {
03484                                           int i=1;
03485                                           struct add_rcptlist *l;
03486 
03487                                           argvec[i++]="-oi";
03488 
03489                                           argvec[i++]="-f";
03490                                           argvec[i++]=add_from
03491                                                  ? add_from:
03492                                                  (char *)
03493                                                  defaultSendFrom();
03494 
03495                                           if (add_notify)
03496                                           {
03497                                                  argvec[i++]="-N";
03498                                                  argvec[i++]=add_notify;
03499                                           }
03500 
03501                                           for (l=add_rcpt_list; l;
03502                                                l=l->next)
03503                                           {
03504                                                  argvec[i++]=l->rcptto;
03505                                           }
03506                                           argvec[i]=0;
03507 
03508                                           i=imapd_sendmsg(tmpname, argvec,
03509                                                         &senderr);
03510                                           free(argvec);
03511                                           if (i)
03512                                           {
03513                                                  n=0;
03514                                                  err_sent=1;
03515                                           }
03516                                    }
03517 
03518                                    if (tmpKeywords)
03519                                    {
03520                                           rename(tmpKeywords,
03521                                                  newKeywords);
03522                                           free(tmpKeywords);
03523                                           free(newKeywords);
03524                                    }
03525 
03526                                    if (add_folder && n)
03527                                    {
03528                                           if (maildir_movetmpnew(tmpname,
03529                                                                newname)
03530                                               )
03531                                                  n=0;
03532                                           else
03533                                           {
03534                                                  if (add_internaldate)
03535                                                         set_time(newname,
03536                                                                 add_internaldate);
03537                                                  adduid(newname);
03538                                           }
03539                                    }
03540 
03541                                    if (n == 0)
03542                                    {
03543                                           unlink(tmpname);
03544                                           free(tmpname);
03545                                           free(newname);
03546                                           if (!err_sent)
03547                                           {
03548                                                  writes("-ERR ");
03549                                                  writes(strerror(errno));
03550                                                  writes("\n");
03551                                           }
03552                                           break;
03553                                    }
03554 
03555                                    unlink(tmpname);
03556 
03557                                    free(tmpname);
03558                                    free(newname);
03559                                    okmsg="Message saved";
03560                                    p=NULL;
03561                                    break;
03562                             }
03563                      }
03564 
03565                      if (p && *p)
03566                             continue; /* Error inside the loop */
03567 
03568                      writes("+OK ");
03569                      writes(okmsg);
03570                      writes("\n");
03571 
03572                      if (p)
03573                             continue;
03574               }
03575 
03576               if (in_add)
03577               {
03578                      struct add_rcptlist *l;
03579 
03580                      while ((l=add_rcpt_list) != NULL)
03581                      {
03582                             add_rcpt_list=l->next;
03583                             free(l->rcptto);
03584                             free(l);
03585                      }
03586                      memset(&add_flags, 0, sizeof(add_flags));
03587                      if (add_from)
03588                             free(add_from);
03589                      if (add_folder)
03590                             free(add_folder);
03591                      if (add_notify)
03592                             free(add_notify);
03593 
03594                      if (addKeywords)
03595                             libmail_kwmDestroy(addKeywords);
03596 
03597                      in_add=0;
03598                      add_from=NULL;
03599                      add_folder=NULL;
03600                      add_internaldate=0;
03601                      add_notify=NULL;
03602                      addKeywords=NULL;
03603                      add_rcpt_count=0;
03604                      if (!p)
03605                             continue; /* Just added a message */
03606               }
03607 
03608               if (strcmp(p, "LOGOUT") == 0)
03609                      break;
03610 
03611               if (strcmp(p, "RSET") == 0)
03612               {
03613                      writes("+OK Reset\n");
03614                      continue;
03615               }
03616 
03617               if (strcmp(p, "GETACL") == 0 ||
03618                   strcmp(p, "ACL") == 0)
03619               {
03620                      char **fn=fn_fromwords(&ptr);
03621                      struct maildir_info minfo;
03622                      maildir_aclt_list aclt_list;
03623                      char *q;
03624                      int cnt;
03625 
03626                      if (!fn)
03627                      {
03628                             writes("-ERR Invalid folder: ");
03629                             writes(strerror(errno));
03630                             writes("\n");
03631                             continue;
03632                      }
03633 
03634                      if (maildir_info_smap_find(&minfo, fn,
03635                                              getenv("AUTHENTICATED"))
03636                          < 0)
03637                      {
03638                             maildir_smapfn_free(fn);
03639                             writes("-ERR Invalid folder: ");
03640                             writes(strerror(errno));
03641                             writes("\n");
03642                             continue;
03643                      }
03644 
03645                      if (read_acls(&aclt_list, &minfo) < 0)
03646                      {
03647                             maildir_info_destroy(&minfo);
03648                             maildir_smapfn_free(fn);
03649                             writes("-ERR Unable to read"
03650                                    " existing ACLS: ");
03651                             writes(strerror(errno));
03652                             writes("\n");
03653                             continue;
03654                      }
03655 
03656                      q=compute_myrights(&aclt_list,
03657                                       minfo.owner);
03658 
03659                      if (!q ||
03660                          strcmp(p, "ACL") ?
03661                          !strchr(q, ACL_ADMINISTER[0])
03662                          :
03663                          !maildir_acl_canlistrights(q)
03664                          )
03665                      {
03666                             if (q) free(q);
03667                             maildir_aclt_list_destroy(&aclt_list);
03668                             maildir_info_destroy(&minfo);
03669                             maildir_smapfn_free(fn);
03670                             accessdenied(ACL_ADMINISTER);
03671                             continue;
03672                      }
03673                      if (strcmp(p, "ACL") == 0)
03674                      {
03675                             writes("* ACL ");
03676                             smapword(q);
03677                             writes("\n");
03678                             free(q);
03679                      }
03680                      else
03681                      {
03682                             free(q);
03683                             cnt=0;
03684                             maildir_aclt_list_enum(&aclt_list,
03685                                                  getacl, &cnt);
03686                             if (cnt)
03687                                    writes("\n");
03688                      }
03689                      maildir_aclt_list_destroy(&aclt_list);
03690                      maildir_info_destroy(&minfo);
03691                      maildir_smapfn_free(fn);
03692                      writes("+OK ACLs retrieved\n");
03693                      continue;
03694               }
03695 
03696               if (strcmp(p, "SETACL") == 0 ||
03697                   strcmp(p, "DELETEACL") == 0)
03698               {
03699                      char **fn=fn_fromwords(&ptr);
03700                      struct setacl_info sainfo;
03701 
03702                      if (!fn)
03703                      {
03704                             writes("-ERR Invalid folder: ");
03705                             writes(strerror(errno));
03706                             writes("\n");
03707                             continue;
03708                      }
03709 
03710                      if (maildir_info_smap_find(&sainfo.minfo,
03711                                              fn, getenv("AUTHENTICATED"))
03712                          < 0)
03713                      {
03714                             maildir_smapfn_free(fn);
03715                             writes("-ERR Invalid folder: ");
03716                             writes(strerror(errno));
03717                             writes("\n");
03718                             continue;
03719                      }
03720 
03721 
03722                      sainfo.ptr= &ptr;
03723 
03724                      acl_lock(sainfo.minfo.homedir,
03725                              *p == 'S' ? setacl:deleteacl,
03726                              &sainfo);
03727 
03728                      maildir_smapfn_free(fn);
03729                      maildir_info_destroy(&sainfo.minfo);
03730                      continue;
03731               }
03732 
03733               if (strcmp(p, "LIST") == 0)
03734               {
03735                      struct list_hier *hier=NULL;
03736 
03737                      listcmd(&hier, &hier, &ptr);
03738                      continue;
03739               }
03740 
03741               if (strcmp(p, "STATUS") == 0)
03742               {
03743                      char *t;
03744                      struct imapscaninfo other_info, *loaded_infoptr,
03745                             *infoptr;
03746                      unsigned long n, i;
03747 
03748                      getword(&ptr);
03749 
03750                      t=GETFOLDER(ACL_LOOKUP);
03751 
03752                      if (!t)
03753                      {
03754                             writes("-ERR Cannot read folder status: ");
03755                             writes(strerror(errno));
03756                             writes("\n");
03757                             continue;
03758                      }
03759 
03760                      if (strchr(rights_buf, ACL_LOOKUP[0]) == NULL)
03761                      {
03762                             accessdenied(ACL_LOOKUP);
03763                             continue;
03764                      }
03765 
03766                      if (current_mailbox &&
03767                          strcmp(current_mailbox, t) == 0)
03768                      {
03769                             loaded_infoptr=0;
03770                             infoptr= &current_maildir_info;
03771                      }
03772                      else
03773                      {
03774                             loaded_infoptr= &other_info;
03775                             infoptr=loaded_infoptr;
03776 
03777                             imapscan_init(loaded_infoptr);
03778 
03779                             if (imapscan_maildir(infoptr, t, 1, 1, NULL))
03780                             {
03781                                    writes("-ERR Cannot read"
03782                                           " folder status: ");
03783                                    writes(strerror(errno));
03784                                    writes("\n");
03785                                    continue;
03786                             }
03787                      }
03788 
03789                      writes("* STATUS EXISTS=");
03790                      writen(infoptr->nmessages+infoptr->left_unseen);
03791 
03792                      n=infoptr->left_unseen, i;
03793 
03794                      for (i=0; i<infoptr->nmessages; i++)
03795                      {
03796                             const char *p=infoptr->msgs[i].filename;
03797 
03798                             p=strrchr(p, MDIRSEP[0]);
03799                             if (p && strncmp(p, MDIRSEP "2,", 3) == 0 &&
03800                                 strchr(p, 'S'))  continue;
03801                             ++n;
03802                      }
03803                      writes(" UNSEEN=");
03804                      writen(n);
03805                      writes("\n+OK Folder status retrieved\n");
03806                      if (loaded_infoptr)
03807                             imapscan_free(loaded_infoptr);
03808                      continue;
03809               }
03810 
03811               if (strcmp(p, "CREATE") == 0)
03812               {
03813                      char *t;
03814 
03815                      strcpy(rights_buf, ACL_CREATE);
03816                      t=getCreateFolder(&ptr, rights_buf);
03817 
03818                      if (t)
03819                      {
03820                             if (mdcreate(t))
03821                             {
03822                                    writes("-ERR Cannot create folder: ");
03823                                    writes(strerror(errno));
03824                                    writes("\n");
03825                             }
03826                             else
03827                             {
03828                                    writes("+OK Folder created\n");
03829                             }
03830                             free(t);
03831                      }
03832                      else
03833                      {
03834                             if (rights_buf[0] == 0)
03835                                    accessdenied(ACL_CREATE);
03836                             else
03837                             {
03838                                    writes("-ERR Cannot create folder: ");
03839                                    writes(strerror(errno));
03840                                    writes("\n");
03841                             }
03842                      }
03843                      continue;
03844               }
03845 
03846               if (strcmp(p, "MKDIR") == 0)
03847               {
03848                      char *t;
03849 
03850                      strcpy(rights_buf, ACL_CREATE);
03851                      t=getCreateFolder(&ptr, rights_buf);
03852 
03853                      if (t)
03854                      {
03855                             writes("+OK Folder created\n");
03856                             free(t);
03857                      }
03858                      else if (rights_buf[0] == 0)
03859                             accessdenied(ACL_CREATE);
03860                      else
03861                      {
03862                             writes("-ERR Cannot create folder: ");
03863                             writes(strerror(errno));
03864                             writes("\n");
03865                      }
03866                      continue;
03867               }
03868 
03869               if (strcmp(p, "RMDIR") == 0)
03870               {
03871                      char *t;
03872 
03873                      strcpy(rights_buf, ACL_DELETEFOLDER);
03874                      t=getCreateFolder(&ptr, rights_buf);
03875 
03876                      if (t)
03877                      {
03878                             writes("+OK Folder deleted\n");
03879                             free(t);
03880                      }
03881                      else if (rights_buf[0] == 0)
03882                             accessdenied(ACL_DELETEFOLDER);
03883                      else
03884                      {
03885                             writes("-ERR Cannot create folder: ");
03886                             writes(strerror(errno));
03887                             writes("\n");
03888                      }
03889                      continue;
03890               }
03891 
03892               if (strcmp(p, "DELETE") == 0)
03893               {
03894                      char **fn;
03895                      char *t=NULL;
03896 
03897                      fn=fn_fromwords(&ptr);
03898 
03899                      if (fn)
03900                      {
03901                             struct maildir_info minfo;
03902 
03903                             if (maildir_info_smap_find(&minfo, fn,
03904                                                     getenv("AUTHENTICATED")) == 0)
03905                             {
03906                                    if (minfo.homedir && minfo.maildir)
03907                                    {
03908                                           maildir_aclt_list list;
03909                                           char *q;
03910 
03911                                           if (strcmp(minfo.maildir,
03912                                                     INBOX) == 0)
03913                                           {
03914                                                  writes("-ERR INBOX may"
03915                                                         " not be deleted\n");
03916                                                  maildir_info_destroy(&minfo);
03917                                                  continue;
03918                                           }
03919 
03920                                           if (read_acls(&list, &minfo)
03921                                               < 0)
03922                                           {
03923                                                  maildir_info_destroy(&minfo);
03924                                                  accessdenied(ACL_DELETEFOLDER);
03925                                                  continue;
03926                                           }
03927 
03928                                           q=compute_myrights(&list,
03929                                                            minfo.owner
03930                                                            );
03931 
03932                                           if (!q ||
03933                                               strchr(q,
03934                                                     ACL_DELETEFOLDER[0])
03935                                               == NULL)
03936                                           {
03937                                                  if (q)
03938                                                         free(q);
03939                                                  maildir_info_destroy(&minfo);
03940                                                  accessdenied(ACL_DELETEFOLDER);
03941                                                  continue;
03942                                           }
03943                                           free(q);
03944                                           maildir_aclt_list_destroy(&list);
03945                                           t=maildir_name2dir(minfo.homedir,
03946                                                            minfo.maildir);
03947                                    }
03948                                    maildir_info_destroy(&minfo);
03949                             }
03950                      }
03951 
03952                      if (t && current_mailbox &&
03953                          strcmp(t, current_mailbox) == 0)
03954                      {
03955                             writes("-ERR Cannot DELETE currently open folder.\n");
03956                             free(t);
03957                             continue;
03958                      }
03959 
03960 
03961                      if (t)
03962                      {
03963                             if (mddelete(t) == 0)
03964                             {
03965                                    maildir_quota_recalculate(".");
03966                                    writes("+OK Folder deleted");
03967                             }
03968                             else
03969                             {
03970                                    writes("-ERR Cannot delete folder: ");
03971                                    writes(strerror(errno));
03972                             }
03973                             writes("\n");
03974                             free(t);
03975 
03976                      }
03977                      else
03978                      {
03979                             if (t)
03980                             {
03981                                    free(t);
03982                                    errno=EINVAL;
03983                             }
03984 
03985                             writes("-ERR Unable to delete folder: ");
03986                             writes(strerror(errno));
03987                             writes("\n");
03988                      }
03989                      continue;
03990               }
03991 
03992               if (strcmp(p, "RENAME") == 0)
03993               {
03994                      struct maildir_info msrc, mdst;
03995                      char **fnsrc, **fndst;
03996                      size_t i;
03997                      char *save;
03998                      const char *errmsg;
03999 
04000                      if ((fnsrc=fn_fromwords(&ptr)) == NULL)
04001                      {
04002                             writes("-ERR ");
04003                             writes(strerror(errno));
04004                             writes("\n");
04005                             continue;
04006                      }
04007 
04008                      if ((fndst=fn_fromwords(&ptr)) == NULL)
04009                      {
04010                             maildir_smapfn_free(fnsrc);
04011                             writes("-ERR ");
04012                             writes(strerror(errno));
04013                             writes("\n");
04014                             continue;
04015                      }
04016 
04017                      for (i=0; fndst[i]; i++)
04018                             ;
04019 
04020                      if (i == 0)
04021                      {
04022                             maildir_smapfn_free(fnsrc);
04023                             maildir_smapfn_free(fndst);
04024                             writes("-ERR Invalid destination folder name\n");
04025                             continue;
04026                      }
04027 
04028                      if (checkacl(fnsrc, &msrc, ACL_DELETEFOLDER))
04029                      {
04030                             maildir_smapfn_free(fnsrc);
04031                             maildir_smapfn_free(fndst);
04032                             accessdenied(ACL_DELETEFOLDER);
04033                             continue;
04034                      }
04035                      save=fndst[--i];
04036                      fndst[i]=NULL;
04037 
04038                      if (checkacl(fndst, &mdst, ACL_CREATE))
04039                      {
04040                             fndst[i]=save;
04041                             maildir_smapfn_free(fnsrc);
04042                             maildir_smapfn_free(fndst);
04043                             maildir_info_destroy(&msrc);
04044                             accessdenied(ACL_CREATE);
04045                             continue;
04046                      }
04047 
04048                      fndst[i]=save;
04049 
04050                      maildir_info_destroy(&mdst);
04051 
04052                      if (maildir_info_smap_find(&mdst, fndst,
04053                                              getenv("AUTHENTICATED")) < 0)
04054                      {
04055                             maildir_smapfn_free(fnsrc);
04056                             maildir_smapfn_free(fndst);
04057                             maildir_info_destroy(&msrc);
04058                             writes("-ERR Internal error in RENAME: ");
04059                             writes(strerror(errno));
04060                             writes("\n");
04061                             continue;
04062                      }
04063 
04064                      if (folder_rename(&msrc, &mdst, &errmsg))
04065                      {
04066                             writes("-ERR ");
04067                             writes(*errmsg == '@' ? errmsg+1:errmsg);
04068                             if (*errmsg == '@')
04069                                    writes(strerror(errno));
04070                             writes("\n");
04071                      }
04072                      else
04073                      {
04074                             writes("+OK Folder renamed.\n");
04075                      }
04076                      maildir_info_destroy(&msrc);
04077                      maildir_info_destroy(&mdst);
04078                      continue;
04079               }
04080 
04081               if (strcmp(p, "OPEN") == 0 ||
04082                   strcmp(p, "SOPEN") == 0)
04083               {
04084                      char **fn;
04085                      char *q;
04086                      const char *snapshot=0;
04087                      struct maildir_info minfo;
04088                      maildir_aclt_list aclt_list;
04089 
04090                      if (current_mailbox)
04091                      {
04092                             free(current_mailbox);
04093                             imapscan_free(&current_maildir_info);
04094                             imapscan_init(&current_maildir_info);
04095                             current_mailbox=0;
04096                      }
04097                      if (current_mailbox_acl)
04098                             free(current_mailbox_acl);
04099                      current_mailbox_acl=NULL;
04100                      current_mailbox_shared=0;
04101 
04102                      fetch_free_cache();
04103 
04104                      if (p[0] == 'S')
04105                             snapshot=getword(&ptr);
04106 
04107                      fn=fn_fromwords(&ptr);
04108 
04109                      if (!fn)
04110                      {
04111                             writes("-ERR Invalid folder: ");
04112                             writes(strerror(errno));
04113                             writes("\n");
04114                             continue;
04115                      }
04116 
04117                      if (maildir_info_smap_find(&minfo, fn,
04118                                              getenv("AUTHENTICATED"))
04119                          < 0)
04120                      {
04121                             maildir_smapfn_free(fn);
04122                             writes("-ERR Invalid folder: ");
04123                             writes(strerror(errno));
04124                             writes("\n");
04125                             continue;
04126                      }
04127 
04128                      if (read_acls(&aclt_list, &minfo) < 0)
04129                      {
04130                             maildir_info_destroy(&minfo);
04131                             maildir_smapfn_free(fn);
04132                             writes("-ERR Unable to read"
04133                                    " existing ACLS: ");
04134                             writes(strerror(errno));
04135                             writes("\n");
04136                             continue;
04137                      }
04138 
04139                      q=compute_myrights(&aclt_list, minfo.owner);
04140                      maildir_aclt_list_destroy(&aclt_list);
04141                      maildir_smapfn_free(fn);
04142 
04143                      if (!q || strchr(q, ACL_READ[0]) == NULL)
04144                      {
04145                             if (q) free(q);
04146                             maildir_info_destroy(&minfo);
04147                             accessdenied(ACL_READ);
04148                             maildir_info_destroy(&minfo);
04149                             continue;
04150                      }
04151                      current_mailbox_acl=q;
04152                      current_mailbox=maildir_name2dir(minfo.homedir,
04153                                                   minfo.maildir);
04154 
04155                      if (current_mailbox == NULL)
04156                      {
04157                             fprintf(stderr, "ERR: Internal error"
04158                                    " in maildir_name2dir(%s,%s)\n",
04159                                    minfo.homedir,
04160                                    minfo.maildir);
04161                             maildir_info_destroy(&minfo);
04162                             continue;
04163                      }
04164                      maildir_info_destroy(&minfo);
04165 
04166                      snapshot_select(snapshot != NULL);
04167 
04168                      if (snapshot_init(current_mailbox, snapshot))
04169                      {
04170                             writes("* SNAPSHOTEXISTS ");
04171                             smapword(snapshot);
04172                             writes("\n");
04173                             smap1_noop(0);
04174                             continue;
04175                      }
04176 
04177                      if (imapscan_maildir(&current_maildir_info,
04178                                         current_mailbox, 0, 0, NULL) == 0)
04179                      {
04180                             snapshot_init(current_mailbox, NULL);
04181                             writes("* EXISTS ");
04182                             writen(current_maildir_info.nmessages);
04183                             writes("\n+OK Folder opened\n");
04184                             continue;
04185                      }
04186 
04187                      writes("-ERR Cannot open the folder: ");
04188                      writes(strerror(errno));
04189                      writes("\n");
04190 
04191                      free(current_mailbox);
04192                      current_mailbox=NULL;
04193                      continue;
04194               }
04195 
04196               if (strcmp(p, "CLOSE") == 0)
04197               {
04198                      if (current_mailbox)
04199                      {
04200                             free(current_mailbox);
04201                             imapscan_free(&current_maildir_info);
04202                             imapscan_init(&current_maildir_info);
04203                             current_mailbox=0;
04204                      }
04205                      writes("+OK Folder closed\n");
04206                      continue;
04207               }
04208 
04209               if (strcmp(p, "NOOP") == 0)
04210               {
04211                      smap1_noop(1);
04212                      continue;
04213               }
04214 
04215               if (strcmp(p, "IDLE") == 0)
04216               {
04217                      if ((p=getenv("IMAP_ENHANCEDIDLE")) == NULL
04218                          || !atoi(p)
04219                          || imapenhancedidle())
04220                             imapidle();
04221 
04222                      read_timeout(60);
04223                      smap_readline(buffer, sizeof(buffer));
04224                      ptr=buffer;
04225                      p=getword(&ptr);
04226                      up(p);
04227                      if (strcmp(p, "RESUME"))
04228                      {
04229                             writes("-ERR RESUME is required to follow IDLE\n");
04230                      }
04231                      else
04232                             writes("+OK Resumed...\n");
04233                      continue;
04234               }
04235 
04236               if (!current_mailbox)
04237                      p=""; /* FALLTHROUGH */
04238 
04239               if (strcmp(p, "EXPUNGE") == 0)
04240               {
04241                      int hasSet;
04242 
04243                      p=markmsgset(&ptr, &hasSet);
04244 
04245                      if (p)
04246                      {
04247                             if (strchr(current_mailbox_acl,
04248                                       ACL_EXPUNGE[0]) == NULL)
04249                             {
04250                                    accessdenied(ACL_EXPUNGE);
04251                                    continue;
04252                             }
04253 
04254                             if (hasSet)
04255                             {
04256                                    if (strchr(current_mailbox_acl,
04257                                              ACL_DELETEMSGS[0]) == NULL)
04258                                    {
04259                                           accessdenied(ACL_DELETEMSGS);
04260                                           continue;
04261                                    }
04262 
04263                                    applymsgset( &msg_expunge, NULL);
04264                             }
04265                             else
04266                                    expunge();
04267                             smap1_noop(0);
04268                             continue;
04269                      }
04270               }
04271 
04272               if (strcmp(p, "STORE") == 0)
04273               {
04274                      struct storeinfo si;
04275                      int dummy;
04276 
04277                      p=markmsgset(&ptr, &dummy);
04278 
04279                      dummy=0;
04280 
04281                      if (!p)
04282                             dummy=1;
04283 
04284                      while (p && *p)
04285                      {
04286                             char *q=strchr(p, '=');
04287 
04288                             if (q)
04289                                    *q=0;
04290                             up(p);
04291                             /* Uppercase only the keyword, for now */
04292                             if (q)
04293                                    *q='=';
04294 
04295                             if (strncmp(p, "FLAGS=", 6) == 0)
04296                             {
04297                                    memset(&si, 0, sizeof(si));
04298                                    up(p);
04299                                    parseflags(p, &si.flags);
04300                                    if ((dummy=applymsgset(&applyflags,
04301                                                         &si)) != 0)
04302                                           break;
04303                             }
04304                             else if (strncmp(p, "+FLAGS=", 7) == 0 ||
04305                                     strncmp(p, "-FLAGS=", 7) == 0)
04306                             {
04307                                    memset(&si, 0, sizeof(si));
04308                                    up(p);
04309                                    si.plusminus=p[0];
04310                                    parseflags(p, &si.flags);
04311                                    if ((dummy=applymsgset(&applyflags,
04312                                                         &si)) != 0)
04313                                           break;
04314                             }
04315                             else if (strncmp(p, "KEYWORDS=", 9) == 0 &&
04316                                     keywords())
04317                             {
04318                                    struct libmail_kwMessage *kwm;
04319 
04320                                    memset(&si, 0, sizeof(si));
04321                                    kwm=si.keywords=libmail_kwmCreate();
04322 
04323                                    if (!kwm)
04324                                           write_error_exit(0);
04325 
04326                                    parsekeywords(p, &si.keywords);
04327                                    dummy=applymsgset(&applyflags,
04328                                                    &si);
04329 
04330                                    libmail_kwmDestroy(kwm);
04331 
04332                                    if (dummy != 0)
04333                                           break;
04334                             }
04335                             else if ((strncmp(p, "+KEYWORDS=", 10) == 0 ||
04336                                      strncmp(p, "-KEYWORDS=", 10) == 0) &&
04337                                     keywords())
04338                             {
04339                                    memset(&si, 0, sizeof(si));
04340                                    si.keywords=libmail_kwmCreate();
04341 
04342                                    if (!si.keywords)
04343                                           write_error_exit(0);
04344                                    si.plusminus=p[0];
04345                                    parsekeywords(p, &si.keywords);
04346                                    dummy=applymsgset(&applyflags,
04347                                                    &si);
04348 
04349                                    if (dummy == 0)
04350                                           dummy=addRemoveSmapKeywords(&si);
04351                                    libmail_kwmDestroy(si.keywords);
04352 
04353                                    if (dummy != 0)
04354                                           break;
04355                             }
04356                             else if (strncmp(p, "INTERNALDATE=", 13) == 0)
04357                             {
04358                                    time_t t;
04359 
04360                                    up(p);
04361 
04362                                    t=rfc822_parsedt(p+13);
04363 
04364                                    if (t &&
04365                                        (dummy=applymsgset(&setdate, &t))
04366                                        != 0)
04367                                           break;
04368                             }
04369 
04370                             p=getword(&ptr);
04371                      }
04372                      if (dummy)
04373                      {
04374                             writes("-ERR Cannot update folder status: ");
04375                             writes(strerror(errno));
04376                             writes("\n");
04377                      }
04378                      else
04379                             writes("+OK Folder status updated\n");
04380                      continue;
04381               }
04382 
04383               if (strcmp(p, "FETCH") == 0)
04384               {
04385                      int dummy;
04386                      struct smapfetchinfo fi;
04387                      int fetch_items=0;
04388 
04389                      for (p=markmsgset(&ptr, &dummy);
04390                           p && *p; p=getword(&ptr))
04391                      {
04392                             if ((fi.entity=strchr(p, '=')) == NULL)
04393                             {
04394                                    up(p);
04395 
04396                                    if (strcmp(p, "UID") == 0)
04397                                           fetch_items |= FETCH_UID;
04398                                    if (strcmp(p, "SIZE") == 0)
04399                                           fetch_items |= FETCH_SIZE;
04400                                    if (strcmp(p, "FLAGS") == 0)
04401                                           fetch_items |= FETCH_FLAGS;
04402                                    if (strcmp(p, "KEYWORDS") == 0)
04403                                           fetch_items |= FETCH_KEYWORDS;
04404                                    if (strcmp(p, "INTERNALDATE") == 0)
04405                                           fetch_items
04406                                                  |= FETCH_INTERNALDATE;
04407                                    continue;
04408                             }
04409 
04410                             *fi.entity++=0;
04411 
04412                             fi.hdrs=strrchr(fi.entity, '(');
04413                             if (fi.hdrs)
04414                             {
04415                                    char *q;
04416 
04417                                    *fi.hdrs++=0;
04418 
04419                                    q=strrchr(fi.hdrs, ')');
04420                                    if (q)
04421                                           *q=0;
04422                                    up(fi.hdrs);
04423                             }
04424 
04425                             fi.mimeid=strrchr(fi.entity, '[');
04426                             if (fi.mimeid)
04427                             {
04428                                    char *q;
04429 
04430                                    *fi.mimeid++=0;
04431                                    q=strrchr(fi.mimeid, ']');
04432                                    if (q)
04433                                           *q=0;
04434                             }
04435 
04436                             up(p);
04437 
04438                             if (strcmp(p, "CONTENTS") == 0 ||
04439                                 strcmp(p, "CONTENTS.PEEK") == 0)
04440                             {
04441                                    fi.peek=strchr(p, '.') != NULL;
04442                                    if (applymsgset(&do_fetch, &fi) == 0)
04443                                    {
04444                                           continue;
04445                                    }
04446                             }
04447                             else
04448                             {
04449                                    continue;
04450                             }
04451 
04452                             writes("-ERR Cannot retrieve message: ");
04453                             writes(strerror(errno));
04454                             writes("\n");
04455                             break;
04456                      }
04457 
04458                      if (!p || !*p)
04459                      {
04460                             if (fetch_items &&
04461                                 applymsgset(&do_attrfetch, &fetch_items))
04462                             {
04463                                    writes("-ERR Cannot retrieve message: ");
04464                                    writes(strerror(errno));
04465                                    writes("\n");
04466                             }
04467                             else
04468                                    writes("+OK Message retrieved.\n");
04469                      }
04470                      continue;
04471               }
04472 
04473               if (strcmp(p, "COPY") == 0
04474                   || strcmp(p, "MOVE") == 0)
04475               {
04476                      int dummy;
04477                      int domove= *p == 'M';
04478 
04479                      p=markmsgset(&ptr, &dummy);
04480 
04481                      if (dummy && *p == 0)
04482                      {
04483                             p=GETFOLDER(ACL_INSERT
04484                                        ACL_DELETEMSGS
04485                                        ACL_SEEN
04486                                        ACL_WRITE);
04487 
04488                             if (p)
04489                             {
04490                                    if (strchr(rights_buf, ACL_INSERT[0])
04491                                        == NULL)
04492                                    {
04493                                           free(p);
04494                                           accessdenied(ACL_INSERT);
04495                                           continue;
04496                                    }
04497 
04498                                    if (copyto(p, domove, rights_buf) == 0)
04499                                    {
04500                                           free(p);
04501                                           writes("+OK Messages copied.\n"
04502                                                  );
04503                                           continue;
04504                                    }
04505                                    free(p);
04506                             }
04507 
04508                             writes("-ERR Cannot copy messages: ");
04509                             writes(strerror(errno));
04510                             writes("\n");
04511                             continue;
04512                      }
04513                      writes("-ERR Syntax error.\n");
04514                      continue;
04515               }
04516 
04517               if (strcmp(p, "SEARCH") == 0)
04518               {
04519                      struct searchinfo *searchInfo=NULL;
04520                      struct searchinfo *si;
04521                      struct smap1_search_results searchResults;
04522 
04523                      if ((si=createSearch(&searchInfo, &ptr)) == NULL)
04524                      {
04525                             writes("-ERR SEARCH failed: ");
04526                             writes(strerror(errno));
04527                             writes("\n");
04528                             free_search(searchInfo);
04529                             continue;
04530                      }
04531 
04532                      searchResults.prev_runs=0;
04533                      searchResults.prev_search_hit=0;
04534                      searchResults.prev_search_hit_start=0;
04535 
04536                      search_internal(si, searchInfo, "utf-8", 0,
04537                                    smap1_search_cb, &searchResults);
04538 
04539                      if (searchResults.prev_search_hit)
04540                             smap1_search_cb_range(&searchResults);
04541 
04542                      if (searchResults.prev_runs)
04543                             writes("\n");
04544 
04545                      writes("+OK Search completed.\n");
04546                      free_search(searchInfo);
04547                      continue;
04548               }
04549 
04550 
04551               writes("-ERR Syntax error.\n");
04552        }
04553 
04554        writes("* BYE Courier-SMAP server shutting down\n"
04555               "+OK LOGOUT completed\n");
04556        writeflush();
04557 }