break;
#ifdef USE_NOTMUCH
- case OP_MAIN_VFOLDER_FROM_QUERY:
+ case OP_MAIN_MODIFY_LABELS:
+ if (Context->magic != M_NOTMUCH) {
+ mutt_message _("No virtual folder, aborting.");
+ break;
+ }
+ CHECK_MSGCOUNT;
+ CHECK_VISIBLE;
+ buf[0] = '\0';
+ if (mutt_get_field ("Add/remove labels: ", buf, sizeof (buf), 0) != 0 || !buf[0])
+ {
+ mutt_message _("No labels, aborting.");
+ break;
+ }
+ if (tag && !option (OPTAUTOTAG))
+ {
+ char msgbuf[STRING];
+ progress_t progress;
+ int px;
+
+ if (!Context->quiet) {
+ snprintf(msgbuf, sizeof (msgbuf), _("Update labels..."));
+ mutt_progress_init(&progress, msgbuf, M_PROGRESS_MSG,
+ 1, Context->tagged);
+ }
+ nm_longrun_init(Context, TRUE);
+ for (px = 0, j = 0; j < Context->vcount; j++) {
+ if (Context->hdrs[Context->v2r[j]]->tagged) {
+ if (!Context->quiet)
+ mutt_progress_update(&progress, ++px, -1);
+ nm_modify_message_tags(Context, Context->hdrs[Context->v2r[j]], buf, sizeof (buf));
+ }
+ }
+ nm_longrun_done(Context);
+ menu->redraw = REDRAW_STATUS | REDRAW_INDEX;
+ }
+ else
+ {
+ if (nm_modify_message_tags(Context, CURHDR, buf, sizeof (buf))) {
+ mutt_message _("Failed to modify labels, aborting.");
+ break;
+ }
+ if (option (OPTRESOLVE))
+ {
+ if ((menu->current = ci_next_undeleted (menu->current)) == -1)
+ {
+ menu->current = menu->oldcurrent;
+ menu->redraw = REDRAW_CURRENT;
+ }
+ else
+ menu->redraw = REDRAW_MOTION_RESYNCH;
+ }
+ else
+ menu->redraw = REDRAW_CURRENT;
+ }
+ menu->redraw |= REDRAW_STATUS;
+ break;
+ case OP_MAIN_VFOLDER_FROM_QUERY:
buf[0] = '\0';
if (mutt_get_field ("Query: ", buf, sizeof (buf), 0) != 0 || !buf[0])
{
struct nm_hdrdata {
char *folder;
char *tags;
+ char *id; /* notmuch message ID */
int magic;
};
char *db_filename;
char *db_query;
int db_limit;
+ int longrun;
struct uri_tag *query_items;
};
if (data) {
FREE(&data->folder);
FREE(&data->tags);
+ FREE(&data->id);
FREE(&data);
}
h->data = NULL;
return h && h->data ? ((struct nm_hdrdata *) h->data)->magic : 0;
}
+static const char *nm_header_get_id(HEADER *h)
+{
+ return h && h->data ? ((struct nm_hdrdata *) h->data)->id : NULL;
+}
+
+
char *nm_header_get_fullpath(HEADER *h, char *buf, size_t bufsz)
{
snprintf(buf, bufsz, "%s/%s", nm_header_get_folder(h), h->path);
static struct nm_data *get_data(CONTEXT *ctx)
{
+ if (ctx->magic != M_NOTMUCH)
+ return NULL;
return ctx->data;
}
}
}
-static struct nm_hdrdata *create_hdrdata(HEADER *h, const char *path,
- notmuch_message_t *msg)
+void nm_longrun_init(CONTEXT *ctx, int writable)
{
- struct nm_hdrdata *data =
- safe_calloc(1, sizeof(struct nm_hdrdata));
- notmuch_tags_t *tags;
- char *tstr = NULL;
- size_t sz = 0;
- char *p;
+ struct nm_data *data = get_data(ctx);
- p = strrchr(path, '/');
- if (p && p - path > 3 &&
- (strncmp(p - 3, "cur", 3) == 0 ||
- strncmp(p - 3, "new", 3) == 0 ||
- strncmp(p - 3, "tmp", 3) == 0)) {
- data->magic = M_MAILDIR;
- p -= 3;
- h->path = safe_strdup(p);
- data->folder = strndup(path, p - path - 1);
+ if (data) {
+ get_db(ctx, writable);
+ data->longrun = TRUE;
}
+}
+
+void nm_longrun_done(CONTEXT *ctx)
+{
+ struct nm_data *data = get_data(ctx);
+
+ if (data) {
+ release_db(ctx);
+ data->longrun = FALSE;
+ }
+}
+
+static int is_longrun(CONTEXT *ctx)
+{
+ struct nm_data *data = get_data(ctx);
+
+ return data && data->longrun;
+}
+
+static int init_message_tags(struct nm_hdrdata *data, notmuch_message_t *msg)
+{
+ notmuch_tags_t *tags;
+ char *tstr = NULL, *p;
+ size_t sz = 0;
for (tags = notmuch_message_get_tags(msg);
tags && notmuch_tags_valid(tags);
sz += xsz;
}
+ FREE(&data->tags);
data->tags = tstr;
+ return 0;
+}
+
+static struct nm_hdrdata *create_hdrdata(HEADER *h, const char *path,
+ notmuch_message_t *msg)
+{
+ struct nm_hdrdata *data =
+ safe_calloc(1, sizeof(struct nm_hdrdata));
+ const char *id;
+ char *p;
+
+ p = strrchr(path, '/');
+ if (p && p - path > 3 &&
+ (strncmp(p - 3, "cur", 3) == 0 ||
+ strncmp(p - 3, "new", 3) == 0 ||
+ strncmp(p - 3, "tmp", 3) == 0)) {
+ data->magic = M_MAILDIR;
+ p -= 3;
+ h->path = safe_strdup(p);
+ data->folder = strndup(path, p - path - 1);
+ }
+
+ id = notmuch_message_get_message_id(msg);
+ if (id)
+ data->id = safe_strdup(id);
+
h->data = data;
+ init_message_tags(data, msg);
+
return data;
}
ctx->size += h->content->length;
ctx->hdrs[ctx->msgcount] = h;
ctx->msgcount++;
+
+ notmuch_message_destroy(m);
}
notmuch_query_destroy(q);
return buf;
}
+static notmuch_message_t *get_message(notmuch_database_t *db, HEADER *hdr)
+{
+ const char *id = nm_header_get_id(hdr);
+ return id && db ? notmuch_database_find_message(db, id) : NULL;
+}
+
+int nm_modify_message_tags(CONTEXT *ctx, HEADER *hdr, char *buf, size_t bufsz)
+{
+ notmuch_database_t *db = NULL;
+ notmuch_message_t *msg = NULL;
+ int rc = -1;
+ char *tag = NULL, *end = NULL, *p;
+
+ if (!buf || !*buf || !ctx
+ || ctx->magic != M_NOTMUCH
+ || !(db = get_db(ctx, TRUE))
+ || !(msg = get_message(db, hdr)))
+ goto done;
+
+ buf = safe_strdup(buf);
+
+ notmuch_message_freeze(msg);
+
+ for (p = buf; p && *p; p++) {
+ if (!tag && isspace(*p))
+ continue;
+ if (!tag)
+ tag = p; /* begin of the tag */
+ if (*p == ',' || *p == ' ')
+ end = p; /* terminate the tag */
+ else if (*(p + 1) == '\0')
+ end = p + 1; /* end of optstr */
+ if (!tag || !end)
+ continue;
+ if (tag >= end)
+ break;
+
+ *end = '\0';
+
+ if (*tag == '-')
+ notmuch_message_remove_tag(msg, tag + 1);
+ else
+ notmuch_message_add_tag(msg, *tag == '+' ? tag + 1 : tag);
+ end = tag = NULL;
+ }
+
+ notmuch_message_thaw(msg);
+
+ init_message_tags(hdr->data, msg);
+
+ rc = 0;
+done:
+ FREE(&buf);
+ if (msg)
+ notmuch_message_destroy(msg);
+ if (!is_longrun(ctx) && db)
+ release_db(ctx);
+ return rc;
+}
+
static int _nm_update_filename(notmuch_database_t *db,
const char *old, const char *new)
{
if (h->deleted)
notmuch_database_remove_message(db, old);
- else if (new && old)
+ else if (*new && *old)
_nm_update_filename(db, old, new);
}
}