Skip to content

Instantly share code, notes, and snippets.

@robn
Last active May 22, 2022 09:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robn/a56420062127238f57541eb47bc962f5 to your computer and use it in GitHub Desktop.
Save robn/a56420062127238f57541eb47bc962f5 to your computer and use it in GitHub Desktop.

Here is a notmuch-using program that adds two messages to the index, rewrites their maildir filenames with the right flags, showing the filename list from the message object and from a query at each step:

#include <stdio.h>
#include <stdlib.h>
#include <notmuch.h>

void check_error(const char *func, notmuch_status_t st) {
  if (st != NOTMUCH_STATUS_SUCCESS && st != NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID) {
    printf("%s: %s\n", func, notmuch_status_to_string(st));
    abort();
  }
}

void _dump_message_filenames(notmuch_message_t *msg) {
  notmuch_filenames_t *filenames = notmuch_message_get_filenames(msg);
  while(notmuch_filenames_valid(filenames)) {
    printf("    %s\n", notmuch_filenames_get(filenames));
    notmuch_filenames_move_to_next(filenames);
  }
  notmuch_filenames_destroy(filenames);
}

void dump_message_filenames(notmuch_message_t *msg) {
  printf("filename from message:\n");
  _dump_message_filenames(msg);
}

void dump_query_filenames(notmuch_database_t *db) {
  notmuch_status_t st;
  notmuch_messages_t *msgs;

  printf("filename from query:\n");

  notmuch_query_t *query = notmuch_query_create(db, "id:aaa@bbb");

  st = notmuch_query_search_messages(query, &msgs);
  check_error("notmuch_query_search_messages", st);

  while (notmuch_messages_valid(msgs)) {
    _dump_message_filenames(notmuch_messages_get(msgs));
    notmuch_messages_move_to_next(msgs);
  }

  notmuch_query_destroy(query);
}

int main (int argc, char **argv) {
  notmuch_status_t st;
  notmuch_database_t *db = NULL;
  notmuch_message_t *m1 = NULL, *m2 = NULL;
  char *err = NULL;

  st = notmuch_database_open_with_config(NULL, NOTMUCH_DATABASE_MODE_READ_WRITE, NULL, NULL, &db, &err);
  if (st != NOTMUCH_STATUS_SUCCESS) {
    printf("notmuch_database_open_with_config: %s\n", err);
    return 1;
  }

  printf("\nadding message #1\n");
  st = notmuch_database_index_file(db, "test/cur/one", NULL, &m1);
  check_error("notmuch_database_index_file", st);
  dump_message_filenames(m1);
  dump_query_filenames(db);

  printf("\nadding message #2\n");
  st = notmuch_database_index_file(db, "test/cur/two", NULL, &m2);
  check_error("notmuch_database_index_file", st);
  dump_message_filenames(m2);
  dump_query_filenames(db);

  printf("\nrewriting message #1\n");
  st = notmuch_message_tags_to_maildir_flags(m1);
  check_error("notmuch_message_tags_to_maildir_flags", st);
  dump_message_filenames(m1);
  dump_query_filenames(db);

  printf("\nrewriting message #2\n");
  st = notmuch_message_tags_to_maildir_flags(m2);
  check_error("notmuch_message_tags_to_maildir_flags", st);
  dump_message_filenames(m2);
  dump_query_filenames(db);

  printf("\ndestroying messages\n");
  notmuch_message_destroy(m1);
  notmuch_message_destroy(m2);
  dump_query_filenames(db);

  st = notmuch_database_close(db);
  check_error("notmuch_database_close", st);

  return 0;
}

Compile the program:

$ gcc -ggdb -Wall -o notmuch-filename-check notmuch-filename-check.c -lnotmuch

Set up an empty notmuch index and drop two identical mail files into it (adjust paths to taste).

$ rm -rf ~/mail/.notmuch/xapian ~/mail/test/cur/* && notmuch new && cat <<EOF > ~/mail/test/cur/one && cp ~/mail/test/cur/one ~/mail/test/cur/two
From: nobody@example.com
To: nobody@example.com
Subject: test message
Message-Id: <aaa@bbb>

oh no
EOF
Found 0 total files (that's not much mail).
Processed 0 total files in almost no time.
No new mail.

Run the program:

$ ./notmuch-filename-check
adding message #1
filename from message:
    /home/robn/mail/test/cur/one
filename from query:
    /home/robn/mail/test/cur/one

adding message #2
filename from message:
    /home/robn/mail/test/cur/one
    /home/robn/mail/test/cur/two
filename from query:
    /home/robn/mail/test/cur/one
    /home/robn/mail/test/cur/two

rewriting message #1
filename from message:
    /home/robn/mail/test/cur/one:2,S
filename from query:
    /home/robn/mail/test/cur/one:2,S

rewriting message #2
filename from message:
    /home/robn/mail/test/cur/one
    /home/robn/mail/test/cur/two:2,S
filename from query:
    /home/robn/mail/test/cur/one
    /home/robn/mail/test/cur/two:2,S

destroying messages
filename from query:
    /home/robn/mail/test/cur/one
    /home/robn/mail/test/cur/two:2,S

Observation #1: the filename list is cached inside the message object

Observation #2: when rewriting the filename, the cached filename list is pushed back into the index

The second observation is more noticeable if the "rewriting message #2" block is commented out and the program recompiled:

$ ./notmuch-filename-check
adding message #1
filename from message:
    /home/robn/mail/test/cur/one
filename from query:
    /home/robn/mail/test/cur/one

adding message #2
filename from message:
    /home/robn/mail/test/cur/one
    /home/robn/mail/test/cur/two
filename from query:
    /home/robn/mail/test/cur/one
    /home/robn/mail/test/cur/two

rewriting message #1
filename from message:
    /home/robn/mail/test/cur/one:2,S
filename from query:
    /home/robn/mail/test/cur/one:2,S

destroying messages
filename from query:
    /home/robn/mail/test/cur/one:2,S

Notice that after the first rewrite, the second message is now entirely gone from the index.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment