Back to index

courier  0.68.2
mailboxlist.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 1998 - 2007 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      <fcntl.h>
00015 #if    HAVE_UNISTD_H
00016 #include      <unistd.h>
00017 #endif
00018 #if HAVE_DIRENT_H
00019 #include <dirent.h>
00020 #define NAMLEN(dirent) strlen((dirent)->d_name)
00021 #else
00022 #define dirent direct
00023 #define NAMLEN(dirent) (dirent)->d_namlen
00024 #if HAVE_SYS_NDIR_H
00025 #include <sys/ndir.h>
00026 #endif
00027 #if HAVE_SYS_DIR_H
00028 #include <sys/dir.h>
00029 #endif
00030 #if HAVE_NDIR_H
00031 #include <ndir.h>
00032 #endif
00033 #endif
00034 #if    HAVE_UTIME_H
00035 #include      <utime.h>
00036 #endif
00037 #if TIME_WITH_SYS_TIME
00038 #include      <sys/time.h>
00039 #include      <time.h>
00040 #else
00041 #if HAVE_SYS_TIME_H
00042 #include      <sys/time.h>
00043 #else
00044 #include      <time.h>
00045 #endif
00046 #endif
00047 
00048 #include      <sys/types.h>
00049 #include      <sys/stat.h>
00050 
00051 #include      "imaptoken.h"
00052 #include      "imapwrite.h"
00053 #include      "imapscanclient.h"
00054 
00055 #include      "mysignal.h"
00056 #include      "imapd.h"
00057 #include      "fetchinfo.h"
00058 #include      "searchinfo.h"
00059 #include      "storeinfo.h"
00060 #include      "mailboxlist.h"
00061 
00062 #include      "maildir/config.h"
00063 #include      "maildir/maildirmisc.h"
00064 #include      "maildir/maildiraclt.h"
00065 #include      "maildir/maildirnewshared.h"
00066 #include      "maildir/maildirinfo.h"
00067 #include      "unicode/unicode.h"
00068 #include      "courierauth.h"
00069 
00070 
00071 static const char hierchs[]={HIERCH, 0};
00072 
00073 extern char *decode_valid_mailbox(const char *, int);
00074 extern dev_t homedir_dev;
00075 extern ino_t homedir_ino;
00076 /*
00077               LIST MAILBOXES
00078 */
00079 
00080 static int do_mailbox_list(int do_lsub, char *qq, int isnullname,
00081                         int (*callback_func)(const char *hiersep,
00082                                           const char *mailbox,
00083                                           int flags,
00084                                           void *void_arg),
00085                         void *void_arg);
00086 
00087 static int shared_index_err_reported=0;
00088 
00089 const char *maildir_shared_index_file()
00090 {
00091        static char *filenamep=NULL;
00092 
00093        if (filenamep == NULL)
00094        {
00095               const char *p=getenv("IMAP_SHAREDINDEXFILE");
00096 
00097               if (p && *p)
00098               {
00099                      const char *q=auth_getoptionenv("sharedgroup");
00100 
00101                      if (!q) q="";
00102 
00103                      filenamep=malloc(strlen(p)+strlen(q)+1);
00104 
00105                      if (!filenamep)
00106                             write_error_exit(0);
00107 
00108                      strcat(strcpy(filenamep, p), q);
00109               }
00110        }
00111 
00112        if (filenamep && !shared_index_err_reported) /* Bitch just once */
00113        {
00114               struct stat stat_buf;
00115 
00116               shared_index_err_reported=1;
00117               if (stat(filenamep, &stat_buf))
00118               {
00119                      fprintf(stderr, "ERR: ");
00120                      perror(filenamep);
00121               }
00122        }
00123 
00124        return filenamep;
00125 }
00126 
00127 /*
00128 **     IMAP sucks.  Here's why.
00129 */
00130 
00131 
00132 int mailbox_scan(const char *reference, const char *name,
00133                int list_options,
00134                int (*callback_func)(const char *hiersep,
00135                                   const char *mailbox,
00136                                   int flags,
00137                                   void *void_arg),
00138                void *void_arg)
00139 {
00140        char   *pattern, *p;
00141        int    nullname= *name == 0;
00142        int    rc;
00143 
00144        pattern=malloc(strlen(reference)+strlen(name)+2);
00145 
00146        strcpy(pattern, reference);
00147 
00148        p=strrchr(pattern, HIERCH);
00149        if (p && p[1] == 0)  *p=0; /* Strip trailing . for now */
00150        if (*pattern)
00151        {
00152               struct maildir_info mi;
00153 
00154               if (maildir_info_imap_find(&mi, pattern,
00155                                       getenv("AUTHENTICATED")))
00156               {
00157                      free(pattern);
00158                      return (0); /* Invalid reference */
00159               }
00160               maildir_info_destroy(&mi);
00161        }
00162 
00163        /* Combine reference and name. */
00164        if (*pattern && *name)
00165               strcat(pattern, hierchs);
00166        strcat(pattern, name);
00167 
00168        if (name && *name)
00169        {
00170        char *s=strrchr(pattern, HIERCH);
00171 
00172               if (s && s[1] == 0)  *s=0;  /* strip trailing . */
00173 
00174        }
00175 
00176        /* Now, do the list */
00177 
00178        rc=do_mailbox_list(list_options, pattern, nullname,
00179                         callback_func, void_arg);
00180        free(pattern);
00181        return (rc);
00182 }
00183 
00184 static int match_mailbox(char *, char *, int flags);
00185 static void match_mailbox_prep(char *);
00186 
00187 /* Check if a folder has any new messages */
00188 
00189 static int hasnewmsgs2(const char *dir)
00190 {
00191 DIR    *dirp=opendir(dir);
00192 struct dirent *de;
00193 
00194        while (dirp && (de=readdir(dirp)) != 0)
00195        {
00196        char   *p;
00197 
00198               if (de->d_name[0] == '.')   continue;
00199               p=strrchr(de->d_name, MDIRSEP[0]);
00200               if (p == 0 || strncmp(p, MDIRSEP "2,", 3) ||
00201                      strchr(p, 'S') == 0)
00202               {
00203                      closedir(dirp);
00204                      return (1);
00205               }
00206        }
00207        if (dirp)     closedir(dirp);
00208        return (0);
00209 }
00210 
00211 static int hasnewmsgs(const char *folder)
00212 {
00213 char *dir=decode_valid_mailbox(folder, 0);
00214 char *subdir;
00215 
00216        if (!dir)     return (0);
00217 
00218        if (is_sharedsubdir(dir))
00219               maildir_shared_sync(dir);
00220 
00221        subdir=malloc(strlen(dir)+sizeof("/cur"));
00222        if (!subdir)  write_error_exit(0);
00223        strcat(strcpy(subdir, dir), "/new");
00224        if (hasnewmsgs2(subdir))
00225        {
00226               free(subdir);
00227               free(dir);
00228               return (1);
00229        }
00230 
00231        strcat(strcpy(subdir, dir), "/cur");
00232        if (hasnewmsgs2(subdir))
00233        {
00234               free(subdir);
00235               free(dir);
00236               return (1);
00237        }
00238 
00239        free(subdir);
00240        free(dir);
00241        return (0);
00242 }
00243 
00244 /* Each folder is listed with the \Noinferiors tag.  Then, for every subfolder
00245 ** we've seen, we need to output a listing for all the higher-level hierarchies
00246 ** with a \Noselect tag.  Therefore, we need to keep track of all the
00247 ** hierarchies we've seen so far.
00248 */
00249 
00250 struct hierlist {
00251        struct hierlist *next;
00252        int flag;
00253        char *hier;
00254        } ;
00255 
00256 static int add_hier(struct hierlist **h, const char *s)
00257 {
00258 struct hierlist *p;
00259 
00260        for (p= *h; p; p=p->next)
00261               if (strcmp(p->hier, s) == 0)       return (1);
00262                      /* Seen this one already */
00263 
00264        if ((p=(struct hierlist *)
00265               malloc( sizeof(struct hierlist)+1+strlen(s))) == 0)
00266                      /* HACK!!!! */
00267               write_error_exit(0);
00268        p->flag=0;
00269        p->hier=(char *)(p+1);
00270        strcpy(p->hier, s);
00271        p->next= *h;
00272        *h=p;
00273        return (0);
00274 }
00275 
00276 static struct hierlist *search_hier(struct hierlist *h, const char *s)
00277 {
00278 struct hierlist *p;
00279 
00280        for (p= h; p; p=p->next)
00281               if (strcmp(p->hier, s) == 0)       return (p);
00282        return (0);
00283 }
00284 
00285 static void hier_entry(char *folder,
00286                      struct hierlist **hierarchies);
00287 
00288 static int has_hier_entry(char *folder,
00289                        struct hierlist **hierarchies);
00290 
00291 static void folder_entry(char *folder, char *pattern,
00292                       int list_options,
00293                       struct hierlist **folders,
00294                       struct hierlist **hierarchies)
00295 {
00296        size_t i;
00297        size_t folder_l=strlen(folder);
00298 
00299        int need_add_hier;
00300        int need_add_folders;
00301 
00302        match_mailbox_prep(folder);
00303 
00304        /* Optimize away folders we don't care about */
00305 
00306        for (i=0; pattern[i]; i++)
00307        {
00308               if ((!(list_options & LIST_CHECK1FOLDER)) &&
00309                   (pattern[i] == '%' || pattern[i] == '*'))
00310               {
00311                      while (i)
00312                      {
00313                             if (pattern[i] == HIERCH)
00314                                    break;
00315                             --i;
00316                      }
00317                      break;
00318               }
00319        }
00320 
00321        if (folder_l <= i)
00322        {
00323               if (memcmp(folder, pattern, folder_l))
00324                      return;
00325 
00326               if (folder_l != i && pattern[folder_l] != HIERCH)
00327                      return;
00328        }
00329        else if (i)
00330        {
00331               if (memcmp(folder, pattern, i))
00332                      return;
00333               if (folder[i] != HIERCH)
00334                      return;
00335        }
00336 
00337        need_add_folders=0;
00338 
00339        if (match_mailbox(folder, pattern, list_options) == 0)
00340               need_add_folders=1;
00341 
00342        need_add_hier=0;
00343        if (!has_hier_entry(folder, hierarchies))
00344               need_add_hier=1;
00345 
00346        if (!need_add_folders && !need_add_hier)
00347               return; /* Nothing to do */
00348 
00349        {
00350               CHECK_RIGHTSM(folder, have_rights, ACL_LOOKUP);
00351 
00352               if (!have_rights[0])
00353                      return;
00354        }
00355 
00356        if (need_add_folders)
00357               (void) add_hier(folders, folder);
00358 
00359        if (need_add_hier)
00360               hier_entry(folder, hierarchies);
00361 }
00362 
00363 static void hier_entry(char *folder,
00364                      struct hierlist **hierarchies)
00365 {
00366        unsigned i;
00367 
00368        for (i=0; folder[i]; i++)
00369        {
00370               if (folder[i] != HIERCH)    continue;
00371               folder[i]=0;
00372               (void)add_hier(hierarchies, folder);
00373               folder[i]=HIERCH;
00374        }
00375 }
00376 
00377 static int has_hier_entry(char *folder,
00378                        struct hierlist **hierarchies)
00379 {
00380        unsigned i;
00381 
00382        for (i=0; folder[i]; i++)
00383        {
00384               if (folder[i] != HIERCH)    continue;
00385               folder[i]=0;
00386               if (!search_hier(*hierarchies, folder))
00387               {
00388                      folder[i]=HIERCH;
00389                      return (0);
00390               }
00391               folder[i]=HIERCH;
00392        }
00393        return (1);
00394 }
00395 
00396 struct list_sharable_info {
00397        char *pattern;
00398        struct hierlist **folders, **hierarchies;
00399        int flags;
00400        int (*callback_func)(const char *hiersep,
00401                           const char *mailbox,
00402                           int flags,
00403                           void *void_arg);
00404        void *cb_arg;
00405        } ;
00406 
00407 static void list_sharable(const char *n,
00408        void *voidp)
00409 {
00410 struct list_sharable_info *ip=(struct list_sharable_info *)voidp;
00411 char   *p=malloc(strlen(n)+sizeof("shared."));
00412 
00413        if (!p)       write_error_exit(0);
00414 
00415        strcat(strcpy(p, "shared."), n);
00416 
00417        folder_entry(p, ip->pattern, ip->flags,
00418                    ip->folders, ip->hierarchies);
00419 
00420        free(p);
00421 }
00422 
00423 static void list_subscribed(char *hier,
00424                          int flags,
00425                          struct hierlist **folders,
00426                          struct hierlist **hierarchies)
00427 {
00428 char   buf[BUFSIZ];
00429 FILE   *fp;
00430 
00431        fp=fopen(SUBSCRIBEFILE, "r");
00432        if (fp)
00433        {
00434               while (fgets(buf, sizeof(buf), fp) != 0)
00435               {
00436                      char *q=strchr(buf, '\n');
00437 
00438                      if (q) *q=0;
00439 
00440                      if (*hier == '#')
00441                      {
00442                             if (*buf != '#')
00443                                    continue;
00444                      }
00445                      else
00446                      {
00447                             if (*buf == '#')
00448                                    continue;
00449                      }
00450 
00451                      folder_entry(buf, hier, flags,
00452                                  folders, hierarchies);
00453               }
00454               fclose(fp);
00455        }
00456 }
00457 
00458 static void maildir_scan(const char *inbox_dir,
00459                       const char *inbox_name,
00460                       struct list_sharable_info *shared_info)
00461 {
00462        DIR    *dirp;
00463        struct dirent *de;
00464 
00465        /* Scan maildir, looking for .subdirectories */
00466 
00467        dirp=opendir(inbox_dir && inbox_dir ? inbox_dir:".");
00468        while (dirp && (de=readdir(dirp)) != 0)
00469        {
00470        char   *p;
00471 
00472               if (de->d_name[0] != '.' ||
00473                   strcmp(de->d_name, "..") == 0)
00474                      continue;
00475 
00476               if ((p=malloc(strlen(de->d_name)+strlen(inbox_name)+10)) == 0)
00477                                    /* A bit too much, that's OK */
00478                      write_error_exit(0);
00479 
00480               strcpy(p, inbox_name);
00481 
00482               if (strcmp(de->d_name, "."))
00483                      strcat(p, de->d_name);
00484 
00485               folder_entry(p, shared_info->pattern, shared_info->flags,
00486                           shared_info->folders,
00487                           shared_info->hierarchies);
00488               free(p);
00489        }
00490 
00491        if (dirp)     closedir(dirp);
00492 }
00493 
00494 /* List the #shared hierarchy */
00495 
00496 struct list_newshared_info {
00497        const char *acc_pfix;
00498        const char *skipped_pattern;
00499        struct list_sharable_info *shared_info;
00500        struct maildir_shindex_cache *parentCache;
00501        int dorecurse;
00502 };
00503 
00504 static int list_newshared_cb(struct maildir_newshared_enum_cb *cb);
00505 static int list_newshared_skipcb(struct maildir_newshared_enum_cb *cb);
00506 static int list_newshared_skiplevel(struct maildir_newshared_enum_cb *cb);
00507 
00508 static int list_newshared_shortcut(const char *skipped_pattern,
00509                                struct list_sharable_info *shared_info,
00510                                const char *current_namespace,
00511                                struct maildir_shindex_cache *parentCache,
00512                                const char *indexfile,
00513                                const char *subhierarchy);
00514 
00515 static int list_newshared(const char *skipped_pattern,
00516                        struct list_sharable_info *shared_info)
00517 {
00518        return list_newshared_shortcut(skipped_pattern, shared_info,
00519                                    NEWSHARED,
00520                                    NULL, NULL, NULL);
00521 }
00522 
00523 static int list_newshared_shortcut(const char *skipped_pattern,
00524                                struct list_sharable_info *shared_info,
00525                                const char *acc_pfix,
00526                                struct maildir_shindex_cache *parentCache,
00527                                const char *indexfile,
00528                                const char *subhierarchy)
00529 {
00530        struct list_newshared_info lni;
00531        int rc;
00532        struct maildir_shindex_cache *curcache=NULL;
00533 
00534        lni.acc_pfix=acc_pfix;
00535        lni.skipped_pattern=skipped_pattern;
00536        lni.shared_info=shared_info;
00537        lni.dorecurse=1;
00538 
00539        /* Try for some common optimization, to avoid expanding the
00540        ** entire #shared hierarchy, taking advantage of the cache list.
00541        */
00542 
00543        for (;;)
00544        {
00545               const char *p;
00546               size_t i;
00547               char *q;
00548               int eof;
00549 
00550               if (strcmp(skipped_pattern, "%") == 0)
00551               {
00552                      lni.dorecurse=0;
00553                      break;
00554               }
00555 
00556               if (strncmp(skipped_pattern, "%" HIERCHS,
00557                          sizeof("%" HIERCHS)-1) == 0)
00558               {
00559                      curcache=maildir_shared_cache_read(parentCache,
00560                                                     indexfile,
00561                                                     subhierarchy);
00562                      if (!curcache)
00563                             return 0;
00564 
00565                      lni.acc_pfix=acc_pfix;
00566                      lni.skipped_pattern=skipped_pattern
00567                             + sizeof("%" HIERCHS)-1;
00568                      lni.parentCache=curcache;
00569 
00570                      for (i=0; i<curcache->nrecords; i++)
00571                      {
00572                             if (i == 0)
00573                             {
00574                                    curcache->indexfile.startingpos=0;
00575                                    rc=maildir_newshared_nextAt(&curcache->indexfile,
00576                                                             &eof,
00577                                                             list_newshared_skiplevel,
00578                                                             &lni);
00579                             }
00580                             else
00581                                    rc=maildir_newshared_next(&curcache->indexfile,
00582                                                           &eof,
00583                                                           list_newshared_skiplevel,
00584                                                           &lni);
00585 
00586                             if (rc || eof)
00587                             {
00588                                    fprintf(stderr, "ERR:maildir_newshared_next failed: %s\n",
00589                                           strerror(errno));
00590                                    break;
00591                             }
00592                      }
00593                      return 0;
00594               }
00595 
00596               for (p=skipped_pattern; *p; p++)
00597                      if (*p == HIERCH ||
00598                          ((lni.shared_info->flags & LIST_CHECK1FOLDER) == 0
00599                           && (*p == '*' || *p == '%')))
00600                             break;
00601 
00602               if (*p && *p != HIERCH)
00603                      break;
00604 
00605               curcache=maildir_shared_cache_read(parentCache, indexfile,
00606                                              subhierarchy);
00607               if (!curcache)
00608                      return 0;
00609 
00610               for (i=0; i < curcache->nrecords; i++)
00611               {
00612                      char *n=maildir_info_imapmunge(curcache->records[i]
00613                                                  .name);
00614 
00615                      if (!n)
00616                             write_error_exit(0);
00617 
00618                      if (strlen(n) == p-skipped_pattern &&
00619                          strncmp(n, skipped_pattern, p-skipped_pattern) == 0)
00620                      {
00621                             free(n);
00622                             break;
00623                      }
00624                      free(n);
00625               }
00626 
00627               if (i >= curcache->nrecords) /* not found */
00628                      return 0;
00629 
00630               if (*p)
00631                      ++p;
00632 
00633 
00634               q=malloc(strlen(acc_pfix)+(p-skipped_pattern)+1);
00635               if (!q)
00636               {
00637                      write_error_exit(0);
00638               }
00639               strcpy(q, acc_pfix);
00640               strncat(q, skipped_pattern, p-skipped_pattern);
00641 
00642               lni.acc_pfix=q;
00643               lni.skipped_pattern=p;
00644               lni.parentCache=curcache;
00645 
00646               curcache->indexfile.startingpos=curcache->records[i].offset;
00647 
00648               rc=maildir_newshared_nextAt(&curcache->indexfile, &eof,
00649                                        list_newshared_skipcb, &lni);
00650               free(q);
00651               return rc;
00652 
00653        }
00654 
00655        if (!indexfile)
00656               indexfile=maildir_shared_index_file();
00657 
00658        rc=maildir_newshared_enum(indexfile, list_newshared_cb, &lni);
00659 
00660        return rc;
00661 }
00662 
00663 static int list_newshared_cb(struct maildir_newshared_enum_cb *cb)
00664 {
00665        const char *name=cb->name;
00666        const char *homedir=cb->homedir;
00667        const char *maildir=cb->maildir;
00668        struct list_newshared_info *lni=
00669               (struct list_newshared_info *)cb->cb_arg;
00670        char *n=maildir_info_imapmunge(name);
00671        int rc;
00672 
00673        if (!n)
00674               write_error_exit(0);
00675 
00676        if (homedir == NULL)
00677        {
00678               struct list_newshared_info new_lni= *lni;
00679               char *new_pfix=malloc(strlen(lni->acc_pfix)+
00680                                   strlen(n)+2);
00681               if (!new_pfix)
00682                      write_error_exit(0);
00683 
00684               strcat(strcpy(new_pfix, lni->acc_pfix), n);
00685 
00686               free(n);
00687               n=new_pfix;
00688               new_lni.acc_pfix=n;
00689               add_hier(lni->shared_info->hierarchies, n);
00690               hier_entry(n, lni->shared_info->hierarchies);
00691               strcat(n, hierchs);
00692               rc=lni->dorecurse ?
00693                      maildir_newshared_enum(maildir, list_newshared_cb,
00694                                           &new_lni):0;
00695        }
00696        else
00697        {
00698               char *new_pfix;
00699               struct stat stat_buf;
00700 
00701               new_pfix=maildir_location(homedir, maildir);
00702 
00703               if (stat(new_pfix, &stat_buf) < 0 ||
00704                   /* maildir inaccessible, perhaps another server? */
00705 
00706                   (stat_buf.st_dev == homedir_dev &&
00707                    stat_buf.st_ino == homedir_ino))
00708                   /* Exclude ourselves from the shared list */
00709               {
00710                      free(new_pfix);
00711                      free(n);
00712                      return 0;
00713               }
00714               free(new_pfix);
00715 
00716               new_pfix=malloc(strlen(lni->acc_pfix)+
00717                                   strlen(n)+1);
00718               if (!new_pfix)
00719                      write_error_exit(0);
00720 
00721               strcat(strcpy(new_pfix, lni->acc_pfix), n);
00722 
00723               free(n);
00724               n=new_pfix;
00725 
00726               new_pfix=malloc(strlen(homedir)+strlen(maildir)+2);
00727 
00728               if (!new_pfix)
00729                      write_error_exit(0);
00730 
00731               if (*maildir == '/')
00732                      strcpy(new_pfix, maildir);
00733               else
00734                      strcat(strcat(strcpy(new_pfix, homedir), "/"),
00735                             maildir);
00736 
00737               /*            if (lni->dorecurse) */
00738 
00739               maildir_scan(new_pfix, n, lni->shared_info);
00740 #if 0
00741               else
00742               {
00743                      folder_entry(n, lni->shared_info->pattern,
00744                                  lni->shared_info->flags,
00745                                  lni->shared_info->folders,
00746                                  lni->shared_info->hierarchies);
00747               }
00748 #endif
00749 
00750               free(new_pfix);
00751               rc=0;
00752        }
00753        free(n);
00754        return rc;
00755 }
00756 
00757 static int list_newshared_skiplevel(struct maildir_newshared_enum_cb *cb)
00758 {
00759        struct list_newshared_info *lni=
00760               (struct list_newshared_info *)cb->cb_arg;
00761        char *n=maildir_info_imapmunge(cb->name);
00762 
00763        char *p=malloc(strlen(lni->acc_pfix)+strlen(n)+sizeof(HIERCHS));
00764        int rc;
00765        const char *save_skip;
00766 
00767        if (!n || !p)
00768               write_error_exit(0);
00769 
00770        strcat(strcat(strcpy(p, lni->acc_pfix), n), HIERCHS);
00771        free(n);
00772 
00773        save_skip=lni->acc_pfix;
00774        lni->acc_pfix=p;
00775 
00776        rc=list_newshared_skipcb(cb);
00777        lni->acc_pfix=save_skip;
00778        free(p);
00779        return rc;
00780 }
00781 
00782 static int list_newshared_skipcb(struct maildir_newshared_enum_cb *cb)
00783 {
00784        struct list_newshared_info *lni=
00785               (struct list_newshared_info *)cb->cb_arg;
00786        char *dir;
00787        char *inbox_name;
00788 
00789        if (cb->homedir == NULL)
00790               return list_newshared_shortcut(lni->skipped_pattern,
00791                                           lni->shared_info,
00792                                           lni->acc_pfix,
00793                                           lni->parentCache,
00794                                           cb->maildir,
00795                                           cb->name);
00796 
00797        inbox_name=my_strdup(lni->acc_pfix);
00798 
00799        dir=strrchr(inbox_name, HIERCH);
00800        if (dir && dir[1] == 0)
00801               *dir=0; /* Strip trailing hier separator */
00802 
00803        dir=malloc(strlen(cb->homedir)+strlen(cb->maildir)+2);
00804 
00805        if (!dir)
00806        {
00807               free(inbox_name);
00808               write_error_exit(0);
00809        }
00810 
00811        if (*cb->maildir == '/')
00812               strcpy(dir, cb->maildir);
00813        else
00814               strcat(strcat(strcpy(dir, cb->homedir), "/"), cb->maildir);
00815 
00816        maildir_scan(dir, inbox_name, lni->shared_info);
00817        free(dir);
00818        free(inbox_name);
00819        return 0;
00820 }
00821 
00822 static int do_mailbox_list(int list_options, char *pattern, int isnullname,
00823                         int (*callback_func)(const char *hiersep,
00824                                           const char *mailbox,
00825                                           int flags,
00826                                           void *void_arg),
00827                         void *void_arg)
00828 {
00829 int    found_hier=MAILBOX_NOSELECT;
00830 int    is_interesting;
00831 int    i,j,bad_pattern;
00832 struct hierlist *hierarchies, *folders, *hp;
00833 struct list_sharable_info shared_info;
00834 
00835 const char *obsolete;
00836 int check_all_folders=0;
00837 char hiersepbuf[8];
00838 int callback_rc=0;
00839 
00840        obsolete=getenv("IMAP_CHECK_ALL_FOLDERS");
00841        if (obsolete && atoi(obsolete))
00842               check_all_folders=1;
00843 
00844        obsolete=getenv("IMAP_OBSOLETE_CLIENT");
00845 
00846        if (obsolete && atoi(obsolete) == 0)
00847               obsolete=0;
00848 
00849        /* Allow up to ten wildcards */
00850 
00851        for (i=j=0; pattern[i]; i++)
00852               if (pattern[i] == '*' || pattern[i] == '%')      ++j;
00853        bad_pattern= j > 10;
00854 
00855        if (list_options & LIST_CHECK1FOLDER)
00856               bad_pattern=0;
00857 
00858        if (bad_pattern)
00859        {
00860               errno=EINVAL;
00861               return -1;
00862        }
00863 
00864        hierarchies=0;
00865        folders=0;
00866 
00867        match_mailbox_prep(pattern);
00868 
00869        shared_info.pattern=pattern;
00870        shared_info.folders= &folders;
00871        shared_info.hierarchies= &hierarchies;
00872        shared_info.flags=list_options;
00873        shared_info.callback_func=callback_func;
00874        shared_info.cb_arg=void_arg;
00875 
00876        if (!(list_options & LIST_SUBSCRIBED))
00877        {
00878               if (strncmp(pattern, NEWSHARED,
00879                          sizeof(NEWSHARED)-1) == 0)
00880               {
00881                      list_newshared(pattern +
00882                                    sizeof(NEWSHARED)-1,
00883                                    &shared_info);
00884               }
00885               else
00886               {
00887                      maildir_scan(".", INBOX, &shared_info);
00888 
00889                      /* List sharable maildirs */
00890 
00891                      maildir_list_sharable( ".", &list_sharable,
00892                                           &shared_info );
00893               }
00894        }
00895        else
00896        {
00897               list_subscribed(pattern, list_options, &folders, &hierarchies);
00898 
00899               /* List shared folders */
00900 
00901               maildir_list_shared( ".", &list_sharable,
00902                                  &shared_info );
00903        }
00904 
00905        while ((hp=folders) != 0)
00906        {
00907               struct hierlist *d;
00908               int mb_flags;
00909 
00910               folders=hp->next;
00911 
00912               is_interesting= -1;
00913 
00914               if (strcmp(hp->hier, INBOX) == 0 || check_all_folders)
00915                      is_interesting=hasnewmsgs(hp->hier);
00916 
00917               strcat(strcat(strcpy(hiersepbuf, "\""), hierchs), "\"");
00918 
00919               mb_flags=0;
00920 
00921               if (is_interesting == 0)
00922               {
00923                      mb_flags|=MAILBOX_UNMARKED;
00924               }
00925               if (is_interesting > 0)
00926               {
00927                      mb_flags|=MAILBOX_MARKED;
00928               }
00929 
00930               if ((d=search_hier(hierarchies, hp->hier)) == 0)
00931               {
00932                      mb_flags |=
00933                             obsolete ? MAILBOX_NOINFERIORS:MAILBOX_NOCHILDREN;
00934               }
00935               else
00936               {
00937                      d->flag=1;
00938                      if (!obsolete)
00939                             mb_flags |= MAILBOX_CHILDREN;
00940               }
00941 
00942               if (isnullname)
00943                      found_hier=mb_flags;
00944               else
00945                      if (callback_rc == 0)
00946                             callback_rc=(*callback_func)
00947                                    (hiersepbuf, hp->hier,
00948                                     mb_flags | list_options, void_arg);
00949               free(hp);
00950        }
00951 
00952        while ((hp=hierarchies) != 0)
00953        {
00954               hierarchies=hp->next;
00955 
00956               match_mailbox_prep(hp->hier);
00957 
00958               if (match_mailbox(hp->hier, pattern, list_options) == 0
00959                   && hp->flag == 0)
00960               {
00961                      int mb_flags=MAILBOX_NOSELECT;
00962 
00963                      if (!obsolete)
00964                             mb_flags |= MAILBOX_CHILDREN;
00965 
00966                      if (isnullname)
00967                             found_hier=mb_flags;
00968                      else 
00969                      {
00970                             strcat(strcat(strcpy(hiersepbuf, "\""),
00971                                          hierchs), "\"");
00972 
00973                             if (callback_rc == 0)
00974                                    callback_rc=(*callback_func)
00975                                           (hiersepbuf,
00976                                            hp->hier,
00977                                            mb_flags | list_options,
00978                                            void_arg);
00979                      }
00980               }
00981               free(hp);
00982        }
00983 
00984        if (isnullname)
00985        {
00986               const char *namesp="";
00987 
00988               if (strncmp(pattern, NEWSHARED, sizeof(NEWSHARED)-1) == 0)
00989                      namesp=NEWSHARED;
00990 
00991               strcat(strcat(strcpy(hiersepbuf, "\""), hierchs), "\"");
00992 
00993               if (callback_rc == 0)
00994                      callback_rc=(*callback_func)
00995                             (hiersepbuf, namesp, found_hier | list_options,
00996                              void_arg);
00997        }
00998        return callback_rc;
00999 }
01000 
01001 static int match_recursive(char *, char *, int);
01002 
01003 static void match_mailbox_prep(char *name)
01004 {
01005        size_t i;
01006 
01007        /* First component, INBOX, is case insensitive */
01008 
01009        if (
01010 #if    HAVE_STRNCASECMP
01011            strncasecmp(name, INBOX, sizeof(INBOX)-1) == 0
01012 #else
01013            strnicmp(name, INBOX, sizeof(INBOX)-1) == 0
01014 #endif
01015            )
01016               for (i=0; name[i] && name[i] != HIERCH; i++)
01017                      name[i]=toupper( (int)(unsigned char)name[i] );
01018 
01019        /* ... except that "shared" should be lowercase ... */
01020 
01021        if (memcmp(name, "SHARED", 6) == 0)
01022               memcpy(name, "shared", 6);
01023 }
01024 
01025 static int match_mailbox(char *name, char *pattern, int list_options)
01026 {
01027         if (list_options & LIST_CHECK1FOLDER)
01028                 return strcmp(name, pattern);
01029 
01030        return (match_recursive(name, pattern, HIERCH));
01031 }
01032 
01033 static int match_recursive(char *name, char *pattern, int hierch)
01034 {
01035        for (;;)
01036        {
01037               if (*pattern == '*')
01038               {
01039                      do
01040                      {
01041                             if (match_recursive(name, pattern+1,
01042                                    hierch) == 0)
01043                                    return (0);
01044                      } while (*name++);
01045                      return (-1);
01046               }
01047               if (*pattern == '%')
01048               {
01049                      do
01050                      {
01051                             if (match_recursive(name, pattern+1, hierch)
01052                                    == 0) return (0);
01053                             if (*name == hierch) break;
01054                      } while (*name++);
01055                      return (-1);
01056               }
01057               if (*name == 0 && *pattern == 0)   break;
01058               if (*name == 0 || *pattern == 0)   return (-1);
01059               if (*name != *pattern)      return (-1);
01060               ++name;
01061               ++pattern;
01062        }
01063        return (0);
01064 }