static notmuch_query_t *get_query(struct nm_ctxdata *data, int writable) { notmuch_database_t *db = NULL; notmuch_query_t *q = NULL; const char *str; if (!data) return NULL; db = get_db(data, writable); str = get_query_string(data); if (!db || !str) goto err; q = notmuch_query_create(db, str); if (!q) goto err; apply_exclude_tags(q); notmuch_query_set_sort(q, NOTMUCH_SORT_NEWEST_FIRST); dprint(2, (debugfile, "nm: query successfully initialized\n")); return q; err: if (!is_longrun(data)) release_db(data); return NULL; }
int nm_read_entire_thread(CONTEXT *ctx, HEADER *h) { struct nm_ctxdata *data = get_ctxdata(ctx); const char *id; char *qstr = NULL; notmuch_query_t *q = NULL; notmuch_database_t *db = NULL; notmuch_message_t *msg = NULL; int rc = -1; if (!data) return -1; if (!(db = get_db(data, FALSE)) || !(msg = get_nm_message(db, h))) goto done; dprint(1, (debugfile, "nm: reading entire-thread messages...[current count=%d]\n", ctx->msgcount)); nm_progress_reset(ctx); id = notmuch_message_get_thread_id(msg); if (!id) goto done; append_str_item(&qstr, "thread:", 0); append_str_item(&qstr, id, 0); q = notmuch_query_create(db, qstr); FREE(&qstr); if (!q) goto done; apply_exclude_tags(q); notmuch_query_set_sort(q, NOTMUCH_SORT_NEWEST_FIRST); read_threads_query(ctx, q, 1, 0); ctx->mtime = time(NULL); rc = 0; if (ctx->msgcount > data->oldmsgcount) mx_update_context(ctx, ctx->msgcount - data->oldmsgcount); done: if (q) notmuch_query_destroy(q); if (!is_longrun(data)) release_db(data); if (ctx->msgcount == data->oldmsgcount) mutt_message _("No more messages in the thread."); data->oldmsgcount = 0; dprint(1, (debugfile, "nm: reading entire-thread messages... done [rc=%d, count=%d]\n", rc, ctx->msgcount)); return rc; }
/* * call-seq: QUERY.sort=(fixnum) => nil * * Set sort type of the +QUERY+ */ VALUE notmuch_rb_query_set_sort(VALUE self, VALUE sortv) { notmuch_query_t *query; Data_Get_Notmuch_Query(self, query); if (!FIXNUM_P(sortv)) rb_raise(rb_eTypeError, "Not a Fixnum"); notmuch_query_set_sort(query, FIX2UINT(sortv)); return Qnil; }
/* Tag messages matching 'query_string' according to 'tag_ops' */ static int tag_query (void *ctx, notmuch_database_t *notmuch, const char *query_string, tag_op_list_t *tag_ops, tag_op_flag_t flags) { notmuch_query_t *query; notmuch_messages_t *messages; notmuch_message_t *message; int ret = NOTMUCH_STATUS_SUCCESS; if (! (flags & TAG_FLAG_REMOVE_ALL)) { /* Optimize the query so it excludes messages that already * have the specified set of tags. */ query_string = _optimize_tag_query (ctx, query_string, tag_ops); if (query_string == NULL) { fprintf (stderr, "Out of memory.\n"); return 1; } flags |= TAG_FLAG_PRE_OPTIMIZED; } query = notmuch_query_create (notmuch, query_string); if (query == NULL) { fprintf (stderr, "Out of memory.\n"); return 1; } /* tagging is not interested in any special sort order */ notmuch_query_set_sort (query, NOTMUCH_SORT_UNSORTED); for (messages = notmuch_query_search_messages (query); notmuch_messages_valid (messages) && ! interrupted; notmuch_messages_move_to_next (messages)) { message = notmuch_messages_get (messages); ret = tag_op_list_apply (message, tag_ops, flags); notmuch_message_destroy (message); if (ret != NOTMUCH_STATUS_SUCCESS) break; } notmuch_query_destroy (query); return ret || interrupted; }
int notmuch_search_command (void *ctx, int argc, char *argv[]) { notmuch_config_t *config; notmuch_database_t *notmuch; notmuch_query_t *query; char *query_str; char *opt; notmuch_sort_t sort = NOTMUCH_SORT_NEWEST_FIRST; const search_format_t *format = &format_text; int i, ret; output_t output = OUTPUT_SUMMARY; for (i = 0; i < argc && argv[i][0] == '-'; i++) { if (strcmp (argv[i], "--") == 0) { i++; break; } if (STRNCMP_LITERAL (argv[i], "--sort=") == 0) { opt = argv[i] + sizeof ("--sort=") - 1; if (strcmp (opt, "oldest-first") == 0) { sort = NOTMUCH_SORT_OLDEST_FIRST; } else if (strcmp (opt, "newest-first") == 0) { sort = NOTMUCH_SORT_NEWEST_FIRST; } else { fprintf (stderr, "Invalid value for --sort: %s\n", opt); return 1; } } else if (STRNCMP_LITERAL (argv[i], "--format=") == 0) { opt = argv[i] + sizeof ("--format=") - 1; if (strcmp (opt, "text") == 0) { format = &format_text; } else if (strcmp (opt, "json") == 0) { format = &format_json; } else { fprintf (stderr, "Invalid value for --format: %s\n", opt); return 1; } } else if (STRNCMP_LITERAL (argv[i], "--output=") == 0) { opt = argv[i] + sizeof ("--output=") - 1; if (strcmp (opt, "summary") == 0) { output = OUTPUT_SUMMARY; } else if (strcmp (opt, "threads") == 0) { output = OUTPUT_THREADS; } else if (strcmp (opt, "messages") == 0) { output = OUTPUT_MESSAGES; } else if (strcmp (opt, "files") == 0) { output = OUTPUT_FILES; } else if (strcmp (opt, "tags") == 0) { output = OUTPUT_TAGS; } else { fprintf (stderr, "Invalid value for --output: %s\n", opt); return 1; } } else { fprintf (stderr, "Unrecognized option: %s\n", argv[i]); return 1; } } argc -= i; argv += i; config = notmuch_config_open (ctx, NULL, NULL); if (config == NULL) return 1; notmuch = notmuch_database_open (notmuch_config_get_database_path (config), NOTMUCH_DATABASE_MODE_READ_ONLY); if (notmuch == NULL) return 1; query_str = query_string_from_args (notmuch, argc, argv); if (query_str == NULL) { fprintf (stderr, "Out of memory.\n"); return 1; } if (*query_str == '\0') { fprintf (stderr, "Error: notmuch search requires at least one search term.\n"); return 1; } query = notmuch_query_create (notmuch, query_str); if (query == NULL) { fprintf (stderr, "Out of memory\n"); return 1; } notmuch_query_set_sort (query, sort); switch (output) { default: case OUTPUT_SUMMARY: case OUTPUT_THREADS: ret = do_search_threads (format, query, sort, output); break; case OUTPUT_MESSAGES: case OUTPUT_FILES: ret = do_search_messages (format, query, output); break; case OUTPUT_TAGS: ret = do_search_tags (notmuch, format, query); break; } notmuch_query_destroy (query); notmuch_database_close (notmuch); return ret; }
int notmuch_tag_command (void *ctx, unused (int argc), unused (char *argv[])) { int *add_tags, *remove_tags; int add_tags_count = 0; int remove_tags_count = 0; char *query_string; notmuch_config_t *config; notmuch_database_t *notmuch; notmuch_query_t *query; notmuch_messages_t *messages; notmuch_message_t *message; struct sigaction action; int i; /* Setup our handler for SIGINT */ memset (&action, 0, sizeof (struct sigaction)); action.sa_handler = handle_sigint; sigemptyset (&action.sa_mask); action.sa_flags = SA_RESTART; sigaction (SIGINT, &action, NULL); add_tags = talloc_size (ctx, argc * sizeof (int)); if (add_tags == NULL) { fprintf (stderr, "Out of memory.\n"); return 1; } remove_tags = talloc_size (ctx, argc * sizeof (int)); if (remove_tags == NULL) { fprintf (stderr, "Out of memory.\n"); return 1; } for (i = 0; i < argc; i++) { if (strcmp (argv[i], "--") == 0) { i++; break; } if (argv[i][0] == '+') { add_tags[add_tags_count++] = i; } else if (argv[i][0] == '-') { remove_tags[remove_tags_count++] = i; } else { break; } } if (add_tags_count == 0 && remove_tags_count == 0) { fprintf (stderr, "Error: 'notmuch tag' requires at least one tag to add or remove.\n"); return 1; } query_string = query_string_from_args (ctx, argc - i, &argv[i]); if (*query_string == '\0') { fprintf (stderr, "Error: notmuch tag requires at least one search term.\n"); return 1; } config = notmuch_config_open (ctx, NULL, NULL); if (config == NULL) return 1; notmuch = notmuch_database_open (notmuch_config_get_database_path (config), NOTMUCH_DATABASE_MODE_READ_WRITE); if (notmuch == NULL) return 1; query = notmuch_query_create (notmuch, query_string); if (query == NULL) { fprintf (stderr, "Out of memory.\n"); return 1; } /* tagging is not interested in any special sort order */ notmuch_query_set_sort (query, NOTMUCH_SORT_UNSORTED); for (messages = notmuch_query_search_messages (query); notmuch_messages_valid (messages) && !interrupted; notmuch_messages_move_to_next (messages)) { message = notmuch_messages_get (messages); notmuch_message_freeze (message); for (i = 0; i < remove_tags_count; i++) notmuch_message_remove_tag (message, argv[remove_tags[i]] + 1); for (i = 0; i < add_tags_count; i++) notmuch_message_add_tag (message, argv[add_tags[i]] + 1); notmuch_message_thaw (message); notmuch_message_destroy (message); } notmuch_query_destroy (query); notmuch_database_close (notmuch); return interrupted; }
static int database_dump_file (notmuch_database_t *notmuch, gzFile output, const char *query_str, int output_format) { notmuch_query_t *query; notmuch_messages_t *messages; notmuch_message_t *message; notmuch_tags_t *tags; if (! query_str) query_str = ""; query = notmuch_query_create (notmuch, query_str); if (query == NULL) { fprintf (stderr, "Out of memory\n"); return EXIT_FAILURE; } /* Don't ask xapian to sort by Message-ID. Xapian optimizes returning the * first results quickly at the expense of total time. */ notmuch_query_set_sort (query, NOTMUCH_SORT_UNSORTED); char *buffer = NULL; size_t buffer_size = 0; for (messages = notmuch_query_search_messages (query); notmuch_messages_valid (messages); notmuch_messages_move_to_next (messages)) { int first = 1; const char *message_id; message = notmuch_messages_get (messages); message_id = notmuch_message_get_message_id (message); if (output_format == DUMP_FORMAT_BATCH_TAG && strchr (message_id, '\n')) { /* This will produce a line break in the output, which * would be difficult to handle in tools. However, it's * also impossible to produce an email containing a line * break in a message ID because of unfolding, so we can * safely disallow it. */ fprintf (stderr, "Warning: skipping message id containing line break: \"%s\"\n", message_id); notmuch_message_destroy (message); continue; } if (output_format == DUMP_FORMAT_SUP) { gzprintf (output, "%s (", message_id); } for (tags = notmuch_message_get_tags (message); notmuch_tags_valid (tags); notmuch_tags_move_to_next (tags)) { const char *tag_str = notmuch_tags_get (tags); if (! first) gzputs (output, " "); first = 0; if (output_format == DUMP_FORMAT_SUP) { gzputs (output, tag_str); } else { if (hex_encode (notmuch, tag_str, &buffer, &buffer_size) != HEX_SUCCESS) { fprintf (stderr, "Error: failed to hex-encode tag %s\n", tag_str); return EXIT_FAILURE; } gzprintf (output, "+%s", buffer); } } if (output_format == DUMP_FORMAT_SUP) { gzputs (output, ")\n"); } else { if (make_boolean_term (notmuch, "id", message_id, &buffer, &buffer_size)) { fprintf (stderr, "Error quoting message id %s: %s\n", message_id, strerror (errno)); return EXIT_FAILURE; } gzprintf (output, " -- %s\n", buffer); } notmuch_message_destroy (message); } notmuch_query_destroy (query); return EXIT_SUCCESS; }
static int _notmuch_search_prepare (search_context_t *ctx, notmuch_config_t *config, int argc, char *argv[]) { char *query_str; unsigned int i; char *status_string = NULL; switch (ctx->format_sel) { case NOTMUCH_FORMAT_TEXT: ctx->format = sprinter_text_create (config, stdout); break; case NOTMUCH_FORMAT_TEXT0: if (ctx->output == OUTPUT_SUMMARY) { fprintf (stderr, "Error: --format=text0 is not compatible with --output=summary.\n"); return EXIT_FAILURE; } ctx->format = sprinter_text0_create (config, stdout); break; case NOTMUCH_FORMAT_JSON: ctx->format = sprinter_json_create (config, stdout); break; case NOTMUCH_FORMAT_SEXP: ctx->format = sprinter_sexp_create (config, stdout); break; default: /* this should never happen */ INTERNAL_ERROR("no output format selected"); } notmuch_exit_if_unsupported_format (); if (notmuch_database_open_verbose ( notmuch_config_get_database_path (config), NOTMUCH_DATABASE_MODE_READ_ONLY, &ctx->notmuch, &status_string)) { if (status_string) { fputs (status_string, stderr); free (status_string); } return EXIT_FAILURE; } notmuch_exit_if_unmatched_db_uuid (ctx->notmuch); query_str = query_string_from_args (ctx->notmuch, argc, argv); if (query_str == NULL) { fprintf (stderr, "Out of memory.\n"); return EXIT_FAILURE; } if (*query_str == '\0') { fprintf (stderr, "Error: notmuch search requires at least one search term.\n"); return EXIT_FAILURE; } ctx->query = notmuch_query_create (ctx->notmuch, query_str); if (ctx->query == NULL) { fprintf (stderr, "Out of memory\n"); return EXIT_FAILURE; } notmuch_query_set_sort (ctx->query, ctx->sort); if (ctx->exclude == NOTMUCH_EXCLUDE_FLAG && ctx->output != OUTPUT_SUMMARY) { /* If we are not doing summary output there is nowhere to * print the excluded flag so fall back on including the * excluded messages. */ fprintf (stderr, "Warning: this output format cannot flag excluded messages.\n"); ctx->exclude = NOTMUCH_EXCLUDE_FALSE; } if (ctx->exclude != NOTMUCH_EXCLUDE_FALSE) { const char **search_exclude_tags; size_t search_exclude_tags_length; search_exclude_tags = notmuch_config_get_search_exclude_tags (config, &search_exclude_tags_length); for (i = 0; i < search_exclude_tags_length; i++) notmuch_query_add_tag_exclude (ctx->query, search_exclude_tags[i]); notmuch_query_set_omit_excluded (ctx->query, ctx->exclude); } return 0; }