+static void
+_get_maildir_flag_actions (notmuch_message_t *message,
+ char **to_set_ret,
+ char **to_clear_ret)
+{
+ char *to_set, *to_clear;
+ notmuch_tags_t *tags;
+ const char *tag;
+ unsigned i;
+
+ to_set = talloc_strdup (message, "");
+ to_clear = talloc_strdup (message, "");
+
+ /* First, find flags for all set tags. */
+ for (tags = notmuch_message_get_tags (message);
+ notmuch_tags_valid (tags);
+ notmuch_tags_move_to_next (tags))
+ {
+ tag = notmuch_tags_get (tags);
+
+ for (i = 0; i < ARRAY_SIZE (flag2tag); i++) {
+ if (strcmp (tag, flag2tag[i].tag) == 0) {
+ if (flag2tag[i].inverse)
+ to_clear = talloc_asprintf_append (to_clear,
+ "%c",
+ flag2tag[i].flag);
+ else
+ to_set = talloc_asprintf_append (to_set,
+ "%c",
+ flag2tag[i].flag);
+ }
+ }
+ }
+
+ /* Then, find the flags for all tags not present. */
+ for (i = 0; i < ARRAY_SIZE (flag2tag); i++) {
+ if (flag2tag[i].inverse) {
+ if (strchr (to_clear, flag2tag[i].flag) == NULL)
+ to_set = talloc_asprintf_append (to_set, "%c", flag2tag[i].flag);
+ } else {
+ if (strchr (to_set, flag2tag[i].flag) == NULL)
+ to_clear = talloc_asprintf_append (to_clear, "%c", flag2tag[i].flag);
+ }
+ }
+
+ *to_set_ret = to_set;
+ *to_clear_ret = to_clear;
+}
+
+/* Given 'filename' and a set of maildir flags to set and to clear,
+ * compute the new maildir filename.
+ *
+ * If the existing filename is in the directory "new", the new
+ * filename will be in the directory "cur".
+ *
+ * After a sequence of ":2," in the filename, any subsequent
+ * single-character flags will be added or removed according to the
+ * characters in flags_to_set and flags_to_clear. Any existing flags
+ * not mentioned in either string will remain. The final list of flags
+ * will be in ASCII order.
+ *
+ * If the original flags seem invalid, (repeated characters or
+ * non-ASCII ordering of flags), this function will return NULL
+ * (meaning that renaming would not be safe and should not occur).
+ */
+static char*
+_new_maildir_filename (void *ctx,
+ const char *filename,
+ const char *flags_to_set,
+ const char *flags_to_clear)
+{
+ const char *info, *flags;
+ unsigned int flag, last_flag;
+ char *filename_new, *dir;
+ char flag_map[128];
+ int flags_in_map = 0;
+ unsigned int i;
+ char *s;
+
+ memset (flag_map, 0, sizeof (flag_map));
+
+ info = strstr (filename, ":2,");
+
+ if (info == NULL) {
+ info = filename + strlen(filename);
+ } else {
+ flags = info + 3;
+
+ /* Loop through existing flags in filename. */
+ for (flags = info + 3, last_flag = 0;
+ *flags;
+ last_flag = flag, flags++)
+ {
+ flag = *flags;
+
+ /* Original flags not in ASCII order. Abort. */
+ if (flag < last_flag)
+ return NULL;
+
+ /* Non-ASCII flag. Abort. */
+ if (flag > sizeof(flag_map) - 1)
+ return NULL;
+
+ /* Repeated flag value. Abort. */
+ if (flag_map[flag])
+ return NULL;
+
+ flag_map[flag] = 1;
+ flags_in_map++;
+ }
+ }
+
+ /* Then set and clear our flags from tags. */
+ for (flags = flags_to_set; *flags; flags++) {
+ flag = *flags;
+ if (flag_map[flag] == 0) {
+ flag_map[flag] = 1;
+ flags_in_map++;
+ }
+ }
+
+ for (flags = flags_to_clear; *flags; flags++) {
+ flag = *flags;
+ if (flag_map[flag]) {
+ flag_map[flag] = 0;
+ flags_in_map--;
+ }
+ }
+
+ filename_new = (char *) talloc_size (ctx,
+ info - filename +
+ strlen (":2,") + flags_in_map + 1);
+ if (unlikely (filename_new == NULL))
+ return NULL;
+
+ strncpy (filename_new, filename, info - filename);
+ filename_new[info - filename] = '\0';
+
+ strcat (filename_new, ":2,");
+
+ s = filename_new + strlen (filename_new);
+ for (i = 0; i < sizeof (flag_map); i++)
+ {
+ if (flag_map[i]) {
+ *s = i;
+ s++;
+ }
+ }
+ *s = '\0';
+
+ /* If message is in new/ move it under cur/. */
+ dir = (char *) _filename_is_in_maildir (filename_new);
+ if (dir && STRNCMP_LITERAL (dir, "new/") == 0)
+ memcpy (dir, "cur/", 4);
+
+ return filename_new;
+}
+