From: Karel Zak Date: Thu, 15 Dec 2011 00:14:03 +0000 (+0100) Subject: add modify-label X-Git-Tag: neomutt-20160317~5^2~96 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2cda772e8e9335dff48761b7b334874ba1e157f2;p=neomutt add modify-label Signed-off-by: Karel Zak --- diff --git a/OPS.NOTMUCH b/OPS.NOTMUCH index eca66ac25..21b611dfa 100644 --- a/OPS.NOTMUCH +++ b/OPS.NOTMUCH @@ -1,2 +1,3 @@ OP_MAIN_CHANGE_VFOLDER "open a different virtual folder" OP_MAIN_VFOLDER_FROM_QUERY "generate virtual folder from query" +OP_MAIN_MODIFY_LABELS "modify (notmuch) tags" diff --git a/curs_main.c b/curs_main.c index 510e360b4..8e1835596 100644 --- a/curs_main.c +++ b/curs_main.c @@ -1381,8 +1381,64 @@ int mutt_index_menu (void) 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]) { diff --git a/functions.h b/functions.h index 28cc93edc..be524c23e 100644 --- a/functions.h +++ b/functions.h @@ -183,6 +183,7 @@ const struct binding_t OpMain[] = { /* map: index */ #ifdef USE_NOTMUCH { "change-vfolder", OP_MAIN_CHANGE_VFOLDER, "X" }, { "vfolder-from-query", OP_MAIN_VFOLDER_FROM_QUERY, "\033X" }, + { "modify-labels", OP_MAIN_MODIFY_LABELS, "`" }, #endif { NULL, 0, NULL } }; @@ -302,6 +303,7 @@ const struct binding_t OpPager[] = { /* map: pager */ #ifdef USE_NOTMUCH { "change-vfolder", OP_MAIN_CHANGE_VFOLDER, "X" }, { "vfolder-from-query", OP_MAIN_VFOLDER_FROM_QUERY, "\033X" }, + { "modify-labels", OP_MAIN_MODIFY_LABELS, "`" }, #endif { NULL, 0, NULL } diff --git a/mutt_notmuch.c b/mutt_notmuch.c index a0198b7ee..3e8c5cdab 100644 --- a/mutt_notmuch.c +++ b/mutt_notmuch.c @@ -48,6 +48,7 @@ struct uri_tag { struct nm_hdrdata { char *folder; char *tags; + char *id; /* notmuch message ID */ int magic; }; @@ -60,6 +61,7 @@ struct nm_data { char *db_filename; char *db_query; int db_limit; + int longrun; struct uri_tag *query_items; }; @@ -157,6 +159,7 @@ static void free_hdrdata(HEADER *h) if (data) { FREE(&data->folder); FREE(&data->tags); + FREE(&data->id); FREE(&data); } h->data = NULL; @@ -202,6 +205,12 @@ int nm_header_get_magic(HEADER *h) 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); @@ -231,6 +240,8 @@ static int init_data(CONTEXT *ctx) static struct nm_data *get_data(CONTEXT *ctx) { + if (ctx->magic != M_NOTMUCH) + return NULL; return ctx->data; } @@ -293,26 +304,38 @@ static void release_db(CONTEXT *ctx) } } -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); @@ -346,8 +369,37 @@ static struct nm_hdrdata *create_hdrdata(HEADER *h, const char *path, 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; } @@ -396,6 +448,8 @@ int nm_read_query(CONTEXT *ctx) ctx->size += h->content->length; ctx->hdrs[ctx->msgcount] = h; ctx->msgcount++; + + notmuch_message_destroy(m); } notmuch_query_destroy(q); @@ -421,6 +475,66 @@ char *nm_uri_from_query(CONTEXT *ctx, char *buf, size_t bufsz) 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) { @@ -496,7 +610,7 @@ int nm_sync(CONTEXT *ctx, int *index_hint) if (h->deleted) notmuch_database_remove_message(db, old); - else if (new && old) + else if (*new && *old) _nm_update_filename(db, old, new); } } diff --git a/mutt_notmuch.h b/mutt_notmuch.h index d25f6a29d..c2080d622 100644 --- a/mutt_notmuch.h +++ b/mutt_notmuch.h @@ -14,5 +14,9 @@ char *nm_header_get_tags(HEADER *h); int nm_get_count(char *path, unsigned *all, unsigned *new); int nm_update_filename(CONTEXT *ctx, const char *old, const char *new); char *nm_uri_from_query(CONTEXT *ctx, char *buf, size_t bufsz); +int nm_modify_message_tags(CONTEXT *ctx, HEADER *hdr, char *buf, size_t bufsz); + +void nm_longrun_init(CONTEXT *cxt, int writable); +void nm_longrun_done(CONTEXT *cxt); #endif /* _MUTT_NOTMUCH_H_ */