Some people use notmuch with non-maildir files, (for example, email
messages in MH format, or else cool things like using sluk[*] to suck
down feeds into a format that notmuch can index).
To better support uses like that, don't do any renaming for files that
are not in a directory named either "new" or "cur".
[*] https://github.com/krl/sluk/
-static char *
-maildir_get_subdir (char *filename)
+/* Is the given filename within a maildir directory?
+ *
+ * Specifically, is the final directory component of 'filename' either
+ * "cur" or "new". If so, return a pointer to that final directory
+ * component within 'filename'. If not, return NULL.
+ *
+ * A non-NULL return value is guaranteed to be a valid string pointer
+ * pointing to the characters "new/" or "cur/", (but not
+ * NUL-terminated).
+ */
+static const char *
+_filename_is_in_maildir (const char *filename)
- char *p, *subdir = NULL;
-
- p = filename + strlen (filename) - 1;
- while (p > filename + 3 && *p != '/')
- p--;
- if (*p == '/') {
- subdir = p - 3;
- if (subdir > filename && *(subdir - 1) != '/')
- subdir = NULL;
+ const char *slash, *dir = NULL;
+
+ /* Find the last '/' separating directory from filename. */
+ slash = strrchr (filename, '/');
+ if (slash == NULL)
+ return NULL;
+
+ /* Jump back 4 characters to where the previous '/' will be if the
+ * directory is named "cur" or "new". */
+ if (slash - filename < 4)
+ return NULL;
+
+ slash -= 4;
+
+ if (*slash != '/')
+ return NULL;
+
+ dir = slash + 1;
+
+ if (STRNCMP_LITERAL (dir, "cur/") == 0 ||
+ STRNCMP_LITERAL (dir, "new/") == 0)
+ {
+ return dir;
}
/* XXX: Needs to ensure that existing, unsupported flags in the
}
/* XXX: Needs to ensure that existing, unsupported flags in the
notmuch_filenames_t *filenames;
char flags[ARRAY_SIZE(flag2tag)+1];
const char *filename, *p;
notmuch_filenames_t *filenames;
char flags[ARRAY_SIZE(flag2tag)+1];
const char *filename, *p;
- char *filename_new, *subdir = NULL;
+ char *filename_new, *dir;
int ret;
maildir_get_new_flags (message, flags);
int ret;
maildir_get_new_flags (message, flags);
{
filename = notmuch_filenames_get (filenames);
{
filename = notmuch_filenames_get (filenames);
+ if (! _filename_is_in_maildir (filename))
+ continue;
+
p = strstr(filename, ":2,");
if ((p && strcmp (p+3, flags) == 0) ||
(!p && flags[0] == '\0'))
p = strstr(filename, ":2,");
if ((p && strcmp (p+3, flags) == 0) ||
(!p && flags[0] == '\0'))
filename_new[p-filename] = '\0';
/* If message is in new/ move it under cur/. */
filename_new[p-filename] = '\0';
/* If message is in new/ move it under cur/. */
- subdir = maildir_get_subdir (filename_new);
- if (subdir && memcmp (subdir, "new/", 4) == 0)
- memcpy (subdir, "cur/", 4);
+ dir = (char *) _filename_is_in_maildir (filename_new);
+ if (dir && STRNCMP_LITERAL (dir, "new/") == 0)
+ memcpy (dir, "cur/", 4);
strcpy (filename_new+(p-filename), ":2,");
strcpy (filename_new+(p-filename)+3, flags);
strcpy (filename_new+(p-filename), ":2,");
strcpy (filename_new+(p-filename)+3, flags);
#define COMPILE_TIME_ASSERT(pred) ((void)sizeof(char[1 - 2*!(pred)]))
#define COMPILE_TIME_ASSERT(pred) ((void)sizeof(char[1 - 2*!(pred)]))
+#define STRNCMP_LITERAL(var, literal) \
+ strncmp ((var), (literal), sizeof (literal) - 1)
+
/* There's no point in continuing when we've detected that we've done
* something wrong internally (as opposed to the user passing in a
* bogus value).
/* There's no point in continuing when we've detected that we've done
* something wrong internally (as opposed to the user passing in a
* bogus value).
*
* Specifically, for each filename corresponding to this message:
*
*
* Specifically, for each filename corresponding to this message:
*
- * Rename the file so that its filename ends with the sequence ":2,"
- * followed by zero or more of the following single-character flags
- * (in ASCII order):
+ * If the filename is not in a maildir directory, do nothing.
+ * (A maildir directory is determined as a directory named "new" or
+ * "cur".)
+ *
+ * If the filename is in a maildir directory, rename the file so that
+ * its filename ends with the sequence ":2," followed by zero or more
+ * of the following single-character flags (in ASCII order):
*
* 'D' iff the message has the "draft" tag
* 'F' iff the message has the "flagged" tag
*
* 'D' iff the message has the "draft" tag
* 'F' iff the message has the "flagged" tag
test_expect_equal "$output" "No new mail. Detected 1 file rename.
thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Message to lose maildir info (inbox)"
test_expect_equal "$output" "No new mail. Detected 1 file rename.
thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; Message to lose maildir info (inbox)"
-add_message [subject]='"Non-maildir message"' [dir]=notmaildir/new [filename]='non-maildir-message'
+add_message [subject]='"Non-maildir message"' [dir]=notmaildir [filename]='non-maildir-message'
expected=$(notmuch search --output=files subject:"Non-maildir message")
test_expect_success "Can remove unread tag from message in non-maildir directory" 'notmuch tag -unread subject:"Non-maildir message"'
expected=$(notmuch search --output=files subject:"Non-maildir message")
test_expect_success "Can remove unread tag from message in non-maildir directory" 'notmuch tag -unread subject:"Non-maildir message"'