> 2. MH and mbox folders.
The patch works for MH and mbox folders because the test below checks
the three types of folders:
+ } else if (maildir_folders && member_of (mfolder, maildir_folders) ||
+ mh_folders && member_of (mfolder, mh_folders) ||
+ mboxen && member_of (mfolder, mboxen)) {
I use MH and tested the modified mairix a bit. I threw a few folders
of useless system emails (cron, etc.) into the folder list, one at the
end, one at the beginning, and one in the middle and tried to make
each one the match folder -- got the error msg in each case.
> 1. if the start of the mfolder path matches on anything that has ...
> after it in the folder list
Here is an updated patch (also against 0.15.2) to deal with that
situation. It also handles wildcards and the ../Mail/inbox situation
(by checking inode numbers). I also updated the comments in mairix.c on
'notes on folder management' to agree with what I thought the code did,
but check that I explained it right.
-Sanjoy
--- mairix-0.15.2.orig/search.c
+++ mairix-0.15.2/search.c
@@ -1168,25 +1168,13 @@
}
/*}}}*/
-int search_top(int do_threads, int do_augment, char *database_path, char
*folder_base, char *mfolder, char **argv, enum folder_type ft, int
verbose)/*{{{*/
+int search_top(int do_threads, int do_augment, char *database_path, char
*complete_mfolder, char **argv, enum folder_type ft, int verbose)/*{{{*/
{
struct read_db *db;
- char *complete_mfolder;
- int len;
int result;
db = open_db(database_path);
- if ((mfolder[0] == '/') || (mfolder[0] == '.')) {
- complete_mfolder = new_string(mfolder);
- } else {
- len = strlen(folder_base) + strlen(mfolder) + 2;
- complete_mfolder = new_array(char, len);
- strcpy(complete_mfolder, folder_base);
- strcat(complete_mfolder, "/");
- strcat(complete_mfolder, mfolder);
- }
-
switch (ft) {
case FT_MAILDIR:
maybe_create_maildir(complete_mfolder);
--- mairix-0.15.2.orig/dirscan.c
+++ mairix-0.15.2/dirscan.c
@@ -183,7 +183,7 @@
return result;
}
/*}}}*/
-static int filter_is_maildir(const char *path, struct stat *sb)/*{{{*/
+int filter_is_maildir(const char *path, struct stat *sb)/*{{{*/
{
if (S_ISDIR(sb->st_mode)) {
if (has_child_dir(path, "new") &&
@@ -195,7 +195,7 @@
return 0;
}
/*}}}*/
-static int filter_is_mh(const char *path, struct stat *sb)/*{{{*/
+int filter_is_mh(const char *path, struct stat *sb)/*{{{*/
{
/* At this stage, just check it's a directory. */
if (S_ISDIR(sb->st_mode)) {
--- mairix-0.15.2.orig/mairix.c
+++ mairix-0.15.2/mairix.c
@@ -54,6 +54,55 @@
return 1;
}
/*}}}*/
+
+/* returns 1 iff COMPLETE_MFOLDER (i.e. the match folder with
+ folder_base prepended if needed) matches one of the FOLDERS after
+ expanding the wildcards and recursion. Used to make sure that the
+ match folder will not overwrite a valuable mail file or
+ directory. */
+int member_of (const char *complete_mfolder,
+ const char *folder_base,
+ const char *folders,
+ enum folder_type ft) {
+ char **raw_paths, **paths;
+ int n_raw_paths, n_paths, i;
+
+ if (!folders)
+ return 0;
+ split_on_colons(folders, &n_raw_paths, &raw_paths);
+ switch (ft) {
+ case FT_MAILDIR:
+ glob_and_expand_paths(folder_base, raw_paths, n_raw_paths, &paths,
&n_paths, filter_is_maildir);
+ break;
+ case FT_MH:
+ glob_and_expand_paths(folder_base, raw_paths, n_raw_paths, &paths,
&n_paths, filter_is_mh);
+ break;
+ case FT_MBOX:
+ glob_and_expand_paths(folder_base, raw_paths, n_raw_paths, &paths,
&n_paths, filter_is_file);
+ break;
+ case FT_RAW: /* cannot happen but to keep compiler happy */
+ break;
+ }
+ for (i=0; i<n_paths; i++) {
+ struct stat mfolder_sb, src_folder_sb; /* for checking inode numbers */
+
+ /* if the complete path names are the same, definitely a match */
+ if (strcmp (complete_mfolder, paths[i]) == 0)
+ return 1;
+ /* also a match if they point to the same file or directory but
+ via different routes (e.g. absolute path for one but path with
+ ../.. for the other), so check inode numbers */
+ /* if cannot even get stat() info, probably not wrecking any mail
+ files or dirs, so continue, i.e. skip inode check. */
+ if (stat (complete_mfolder, &mfolder_sb) != 0 ||
+ stat (paths[i], &src_folder_sb) != 0)
+ continue;
+ if (mfolder_sb.st_ino == src_folder_sb.st_ino)
+ return 1;
+ }
+ return 0;
+}
+
static char *copy_value(char *text)/*{{{*/
{
char *p;
@@ -341,20 +390,21 @@
ancestor, because it'll pick up its own mfolders. So, use environment
variables to tailor the folders.
- MAIRIX_FOLDER_BASE is the common ancestor directory of the folders (aka
+ MAIRIX_FOLDER_BASE is the common parent directory of the folders (aka
mutt's 'folder' variable)
- MAIRIX_FOLDERS is a colon-separated list of folders underneath that, with
- the feature that '...' after a component means any maildir underneath that,
- e.g.
+ MAIRIX_MAILDIR_FOLDERS, MAIRIX_MH_FOLDERS, MAIRIX_MBOXEN are
+ colon-separated lists of folders to index, with '...' after a
+ component meaning any maildir underneath it.
- MAIRIX_MFOLDER is the parent of the mfolders underneath the base
-
+ MAIRIX_MFOLDER is the folder to put the match data.
+
+ For example, if
MAIRIX_FOLDER_BASE = "/home/foobar/mail"
MAIRIX_FOLDERS = "inbox:lists...:action:archive..."
MAIRIX_MFOLDER = "mf"
- so /home/foobar/mail/vf/search1/{new,cur,tmp} contain the output for
search1 etc.
+ then /home/foobar/mail/mf/{new,cur,tmp} contain the output of the search.
}}} */
int main (int argc, char **argv)/*{{{*/
@@ -477,6 +527,9 @@
return 0;
} else if (do_search) {
+ int len;
+ char *complete_mfolder;
+
if (!mfolder) {
if (output_folder_type != FT_RAW) {
fprintf(stderr, "No mfolder/MAIRIX_MFOLDER set\n");
@@ -485,7 +538,27 @@
mfolder = new_string("");
}
- return search_top(do_threads, do_augment, database_path, folder_base,
mfolder, argv, output_folder_type, verbose);
+ /* complete_mfolder is needed by search_top() and member_of() so
+ compute it once here rather than in search_top() as well */
+ if ((mfolder[0] == '/') || (mfolder[0] == '.')) {
+ complete_mfolder = new_string(mfolder);
+ } else {
+ len = strlen(folder_base) + strlen(mfolder) + 2;
+ complete_mfolder = new_array(char, len);
+ strcpy(complete_mfolder, folder_base);
+ strcat(complete_mfolder, "/");
+ strcat(complete_mfolder, mfolder);
+ }
+ /* check whether mfolder output would destroy a mail folder or mbox */
+ if (output_folder_type != FT_RAW && /* raw output cannot damage a
folder */
+ (member_of(complete_mfolder,folder_base, maildir_folders, FT_MAILDIR)||
+ member_of (complete_mfolder, folder_base, mh_folders, FT_MH) ||
+ member_of (complete_mfolder, folder_base, mboxen, FT_MBOX))) {
+ fprintf (stderr, "You asked search results to go to the folder
'%s'.\nThat folder appears to be one of the indexed mail folders!\nFor your own
good, I refuse to output search results to an indexed mail folder.\n", mfolder);
+ exit(3);
+ }
+
+ return search_top(do_threads, do_augment, database_path, complete_mfolder,
argv, output_folder_type, verbose);
} else {
if (!maildir_folders && !mh_folders && !mboxen) {
--- mairix-0.15.2.orig/mairix.h
+++ mairix-0.15.2/mairix.h
@@ -253,6 +253,8 @@
void string_list_to_array(struct string_list *list, int *n, char ***arr);
void split_on_colons(const char *str, int *n, char ***arr);
void build_message_list(char *folder_base, char *folders, enum folder_type ft,
struct msgpath_array *msgs);
+int filter_is_maildir(const char *path, struct stat *sb);
+int filter_is_mh(const char *path, struct stat *sb);
/* In rfc822.c */
struct rfc822 *make_rfc822(char *filename);
@@ -291,6 +293,7 @@
void decode_mbox_indices(unsigned int index, unsigned int *mb, unsigned int
*msg);
int verify_mbox_size_constraints(struct database *db);
void glob_and_expand_paths(const char *folder_base, char **paths_in, int n_in,
char ***paths_out, int *n_out, int (*filter)(const char *, struct stat *));
+int filter_is_file(const char *x, struct stat *sb);
/* In glob.c */
struct globber;
@@ -303,7 +306,7 @@
void write_database(struct database *db, char *filename);
/* In search.c */
-int search_top(int do_threads, int do_augment, char *database_path, char
*folder_base, char *mfolder, char **argv, enum folder_type ft, int verbose);
+int search_top(int do_threads, int do_augment, char *database_path, char
*complete_mfolder, char **argv, enum folder_type ft, int verbose);
/* In stats.c */
void get_db_stats(struct database *db);
--- mairix-0.15.2.orig/mbox.c
+++ mairix-0.15.2/mbox.c
@@ -625,7 +625,7 @@
}
}
/*}}}*/
-static int filter_is_file(const char *x, struct stat *sb)/*{{{*/
+int filter_is_file(const char *x, struct stat *sb)/*{{{*/
{
if (S_ISREG(sb->st_mode))
return 1;
--- mairix-0.15.2.orig/mairix.texi
+++ mairix-0.15.2/mairix.texi
@@ -529,6 +529,13 @@
and @samp{.} characters as the @b{mfolder} line in the @file{.mairixrc} file
does.
[EMAIL PROTECTED] will refuse to output search results (whether specified
+by the @samp{-o} or in the @file{.mairixrc} file) into one of the
+folders that are indexed; it figures out that list by looking in the
[EMAIL PROTECTED] file, or in the file you specify using the @samp{-f}
+option. This sanity check prevents you inadvertantly destroying one
+of your important folders (but won't catch all such cases, sadly).
+
The search mode runs when there is at least one search expression. Search
expressions can take forms such as (in increasing order of complexity):
--
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]