"Fossies" - the Fresh Open Source Software Archive

Member "mairix-0.24/dirscan.c" (13 Aug 2017, 10191 Bytes) of package /linux/privat/mairix-0.24.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dirscan.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.23_vs_0.24.

    1 /*
    2   mairix - message index builder and finder for maildir folders.
    3 
    4  **********************************************************************
    5  * Copyright (C) Richard P. Curnow  2002,2003,2004,2005,2006,2007
    6  *
    7  * This program is free software; you can redistribute it and/or modify
    8  * it under the terms of version 2 of the GNU General Public License as
    9  * published by the Free Software Foundation.
   10  *
   11  * This program is distributed in the hope that it will be useful, but
   12  * WITHOUT ANY WARRANTY; without even the implied warranty of
   13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   14  * General Public License for more details.
   15  *
   16  * You should have received a copy of the GNU General Public License along
   17  * with this program; if not, write to the Free Software Foundation, Inc.,
   18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   19  *
   20  **********************************************************************
   21  */
   22 
   23 /* Traverse a directory tree and find maildirs, then list files in them. */
   24 
   25 #include <sys/types.h>
   26 #include <sys/stat.h>
   27 #include <ctype.h>
   28 #include <unistd.h>
   29 #include <dirent.h>
   30 #include <assert.h>
   31 #include "mairix.h"
   32 
   33 struct msgpath_array *new_msgpath_array(void)/*{{{*/
   34 {
   35   struct msgpath_array *result;
   36   result = new(struct msgpath_array);
   37   result->paths = NULL;
   38   result->n = 0;
   39   result->max = 0;
   40   return result;
   41 }
   42 /*}}}*/
   43 void free_msgpath_array(struct msgpath_array *x)/*{{{*/
   44 {
   45   int i;
   46   if (x->paths) {
   47     for (i=0; i<x->n; i++) {
   48       switch (x->paths[i].type) {
   49         case MTY_FILE:
   50         case MTY_IMAP:
   51           free(x->paths[i].src.mpf.path);
   52           break;
   53         case MTY_MBOX:
   54           break;
   55         case MTY_DEAD:
   56           break;
   57       }
   58     }
   59     free(x->paths);
   60   }
   61   free(x);
   62 }
   63 /*}}}*/
   64 static void add_file_to_list(char *x, struct msgpath_array *arr, enum folder_type ft) {/*{{{*/
   65   char *y = new_string(x);
   66   if (arr->n == arr->max) {
   67     arr->max += 1024;
   68     arr->paths = grow_array(struct msgpath,    arr->max, arr->paths);
   69   }
   70   arr->paths[arr->n].type = MTY_FILE;
   71   arr->paths[arr->n].src.mpf.path = y;
   72   arr->paths[arr->n].source_ft = ft;
   73   ++arr->n;
   74   return;
   75 }
   76 /*}}}*/
   77 static void get_maildir_message_paths(char *folder, struct msgpath_array *arr)/*{{{*/
   78 {
   79   char *subdir, *fname;
   80   int i;
   81   static char *subdirs[] = {"new", "cur"};
   82   DIR *d;
   83   struct dirent *de;
   84   int folder_len = strlen(folder);
   85 
   86   /* FIXME : just store mdir-rooted paths in array and have common prefix elsewhere. */
   87 
   88   subdir = new_array(char, folder_len + 6);
   89   fname = new_array(char, folder_len + 8 + NAME_MAX);
   90   for (i=0; i<2; i++) {
   91     strcpy(subdir, folder);
   92     strcat(subdir, "/");
   93     strcat(subdir, subdirs[i]);
   94     d = opendir(subdir);
   95     if (d) {
   96       while ((de = readdir(d))) {
   97         /* TODO : Perhaps we ought to do some validation on the path here?
   98            i.e. check that the filename looks valid for a maildir message. */
   99         if (!strcmp(de->d_name, ".") ||
  100             !strcmp(de->d_name, "..")) {
  101           continue;
  102         }
  103         strcpy(fname, subdir);
  104         strcat(fname, "/");
  105         strcat(fname, de->d_name);
  106         add_file_to_list(fname, arr, FT_MAILDIR);
  107       }
  108       closedir(d);
  109     }
  110   }
  111   free(subdir);
  112   free(fname);
  113   return;
  114 }
  115 /*}}}*/
  116 int valid_mh_filename_p(const char *x)/*{{{*/
  117 {
  118   const char *p;
  119 
  120   if (!*x) return 0; /* Must not be empty */
  121   p = x;
  122   while (*p) {
  123     if (!isdigit(*p)) {
  124       /* Handle MH folders generated by Evolution, which have '.' on the ends
  125        * of the numerical filenames for the messages. */
  126       if ((p[0] == '.') && (p[1] == 0)) return 1;
  127       else return 0;
  128     }
  129     p++;
  130   }
  131   return 1;
  132 }
  133 /*}}}*/
  134 static void get_mh_message_paths(char *folder, struct msgpath_array *arr)/*{{{*/
  135 {
  136   char *fname;
  137   DIR *d;
  138   struct dirent *de;
  139   int folder_len = strlen(folder);
  140 
  141   fname = new_array(char, folder_len + 8 + NAME_MAX);
  142   d = opendir(folder);
  143   if (d) {
  144     while ((de = readdir(d))) {
  145       if (!strcmp(de->d_name, ".") ||
  146           !strcmp(de->d_name, "..")) {
  147         continue;
  148       }
  149       strcpy(fname, folder);
  150       strcat(fname, "/");
  151       strcat(fname, de->d_name);
  152       if (valid_mh_filename_p(de->d_name)) {
  153         add_file_to_list(fname, arr, FT_MH);
  154       }
  155     }
  156     closedir(d);
  157   }
  158   free(fname);
  159   return;
  160 }
  161 /*}}}*/
  162 static int child_stat(const char *base, const char *child, struct stat *sb)/*{{{*/
  163 {
  164   int result = 0;
  165   char *scratch;
  166   int len;
  167 
  168   len = strlen(base) + strlen(child) + 2;
  169   scratch = new_array(char, len);
  170 
  171   strcpy(scratch, base);
  172   strcat(scratch, "/");
  173   strcat(scratch, child);
  174 
  175   result = stat(scratch, sb);
  176   free(scratch);
  177   return result;
  178 }
  179 /*}}}*/
  180 static int has_child_file(const char *base, const char *child)/*{{{*/
  181 {
  182   int result = 0;
  183   int status;
  184   struct stat sb;
  185 
  186   status = child_stat(base, child, &sb);
  187   if ((status >= 0) && S_ISREG(sb.st_mode)) {
  188     result = 1;
  189   }
  190 
  191   return result;
  192 }
  193 /*}}}*/
  194 static int has_child_dir(const char *base, const char *child)/*{{{*/
  195 {
  196   int result = 0;
  197   int status;
  198   struct stat sb;
  199 
  200   status = child_stat(base, child, &sb);
  201   if ((status >= 0) && S_ISDIR(sb.st_mode)) {
  202     result = 1;
  203   }
  204 
  205   return result;
  206 }
  207 /*}}}*/
  208 static enum traverse_check scrutinize_maildir_entry(int parent_is_maildir, const char *de_name)/*{{{*/
  209 {
  210   if (parent_is_maildir) {
  211     /* Process any subdirectory that's not part of this maildir itself. */
  212     if (!strcmp(de_name, "new") ||
  213         !strcmp(de_name, "cur") ||
  214         !strcmp(de_name, "tmp")) {
  215       return TRAV_IGNORE;
  216     } else {
  217       return TRAV_PROCESS;
  218     }
  219   } else {
  220     return TRAV_PROCESS;
  221   }
  222 }
  223 /*}}}*/
  224 static int filter_is_maildir(const char *path, const struct stat *sb)/*{{{*/
  225 {
  226   if (S_ISDIR(sb->st_mode)) {
  227     if (has_child_dir(path, "new") &&
  228         has_child_dir(path, "tmp") &&
  229         has_child_dir(path, "cur")) {
  230       return 1;
  231     }
  232   }
  233   return 0;
  234 }
  235 /*}}}*/
  236 struct traverse_methods maildir_traverse_methods = {/*{{{*/
  237   .filter = filter_is_maildir,
  238   .scrutinize = scrutinize_maildir_entry
  239 };
  240 /*}}}*/
  241 static enum traverse_check scrutinize_mh_entry(int parent_is_mh, const char *de_name)/*{{{*/
  242 {
  243   /* Have to allow sub-folders within a folder until we think of a better
  244    * solution.  */
  245   if (valid_mh_filename_p(de_name)) {
  246     return TRAV_IGNORE;
  247   } else {
  248     return TRAV_PROCESS;
  249   }
  250 }
  251 /*}}}*/
  252 static int filter_is_mh(const char *path, const struct stat *sb)/*{{{*/
  253 {
  254   int result = 0;
  255   if (S_ISDIR(sb->st_mode)) {
  256     /* TODO : find a way of making this more scalable?  e.g. if a folder of a
  257      * particular subtype is found once, try that subtype first later, since
  258      * the user presumably uses a consistent MH-subtype (i.e. a single MUA). */
  259     if (has_child_file(path, ".xmhcache") ||
  260         has_child_file(path, ".mh_sequences") ||
  261         /* Sylpheed */
  262         has_child_file(path, ".sylpheed_cache") ||
  263         has_child_file(path, ".sylpheed_mark") ||
  264         /* claws-mail */
  265         has_child_file(path, ".claws_cache") ||
  266         has_child_file(path, ".claws_mark") ||
  267         /* NNML (Gnus) */
  268         has_child_file(path, ".marks") ||
  269         has_child_file(path, ".overview") ||
  270         /* Evolution */
  271         has_child_file(path, "cmeta") ||
  272         has_child_file(path, "summary") ||
  273         /* Mew */
  274         has_child_file(path, ".mew-summary") ||
  275         /* ezmlm/archive */
  276         has_child_file(path, "index")
  277         ) {
  278       result = 1;
  279     }
  280   }
  281   return result;
  282 }
  283 /*}}}*/
  284 struct traverse_methods mh_traverse_methods = {/*{{{*/
  285   .filter = filter_is_mh,
  286   .scrutinize = scrutinize_mh_entry
  287 };
  288 /*}}}*/
  289 #if 0
  290 static void scan_directory(char *folder_base, char *this_folder, enum folder_type ft, struct msgpath_array *arr)/*{{{*/
  291 {
  292   DIR *d;
  293   struct dirent *de;
  294   struct stat sb;
  295   char *fname, *sname;
  296   char *name;
  297   int folder_base_len = strlen(folder_base);
  298   int this_folder_len = strlen(this_folder);
  299 
  300   name = new_array(char, folder_base_len + this_folder_len + 2);
  301   strcpy(name, folder_base);
  302   strcat(name, "/");
  303   strcat(name, this_folder);
  304 
  305   switch (ft) {
  306     case FT_MAILDIR:
  307       if (looks_like_maildir(folder_base, this_folder)) {
  308         get_maildir_message_paths(folder_base, this_folder, arr);
  309       }
  310       break;
  311     case FT_MH:
  312       get_mh_message_paths(folder_base, this_folder, arr);
  313       break;
  314     default:
  315       break;
  316   }
  317 
  318   fname = new_array(char, strlen(name) + 2 + NAME_MAX);
  319   sname = new_array(char, this_folder_len + 2 + NAME_MAX);
  320 
  321   d = opendir(name);
  322   if (d) {
  323     while ((de = readdir(d))) {
  324       if (!strcmp(de->d_name, ".") ||
  325           !strcmp(de->d_name, "..")) {
  326         continue;
  327       }
  328 
  329       strcpy(fname, name);
  330       strcat(fname, "/");
  331       strcat(fname, de->d_name);
  332 
  333       strcpy(sname, this_folder);
  334       strcat(sname, "/");
  335       strcat(sname, de->d_name);
  336 
  337       if (stat(fname, &sb) >= 0) {
  338         if (S_ISDIR(sb.st_mode)) {
  339           scan_directory(folder_base, sname, ft, arr);
  340         }
  341       }
  342     }
  343     closedir(d);
  344   }
  345 
  346   free(fname);
  347   free(sname);
  348   free(name);
  349   return;
  350 }
  351 /*}}}*/
  352 #endif
  353 /*{{{ void build_message_list */
  354 void build_message_list(char *folder_base, char *folders, enum folder_type ft,
  355     struct msgpath_array *msgs,
  356     struct globber_array *omit_globs)
  357 {
  358   char **raw_paths, **paths;
  359   int n_raw_paths, n_paths, i;
  360 
  361   split_on_colons(folders, &n_raw_paths, &raw_paths);
  362   switch (ft) {
  363     case FT_MAILDIR:
  364       glob_and_expand_paths(folder_base, raw_paths, n_raw_paths, &paths, &n_paths, &maildir_traverse_methods, omit_globs);
  365       for (i=0; i<n_paths; i++) {
  366         get_maildir_message_paths(paths[i], msgs);
  367       }
  368       break;
  369     case FT_MH:
  370       glob_and_expand_paths(folder_base, raw_paths, n_raw_paths, &paths, &n_paths, &mh_traverse_methods, omit_globs);
  371       for (i=0; i<n_paths; i++) {
  372         get_mh_message_paths(paths[i], msgs);
  373       }
  374       break;
  375     default:
  376       assert(0);
  377       break;
  378   }
  379 
  380   if (paths) free(paths);
  381 
  382   return;
  383 }
  384 /*}}}*/
  385 
  386 #ifdef TEST
  387 int main (int argc, char **argv)
  388 {
  389   int i;
  390   struct msgpath_array *arr;
  391 
  392   arr = build_message_list(".");
  393 
  394   for (i=0; i<arr->n; i++) {
  395     printf("%08lx %s\n", arr->paths[i].mtime, arr->paths[i].path);
  396   }
  397 
  398   free_msgpath_array(arr);
  399 
  400   return 0;
  401 }
  402 #endif
  403 
  404