1 #include "database-private.h"
4 #include "regexp-fields.h"
5 #include "parse-time-vrp.h"
11 notmuch_field_flag_t flags;
14 /* With these prefix values we follow the conventions published here:
16 * https://xapian.org/docs/omega/termprefixes.html
18 * as much as makes sense. Note that I took some liberty in matching
19 * the reserved prefix values to notmuch concepts, (for example, 'G'
20 * is documented as "newsGroup (or similar entity - e.g. a web forum
21 * name)", for which I think the thread is the closest analogue in
22 * notmuch. This in spite of the fact that we will eventually be
23 * storing mailing-list messages where 'G' for "mailing list name"
24 * might be even a closer analogue. I'm treating the single-character
25 * prefixes preferentially for core notmuch concepts (which will be
26 * nearly universal to all mail messages).
30 prefix_t prefix_table[] = {
31 /* name term prefix flags */
32 { "type", "T", NOTMUCH_FIELD_NO_FLAGS },
33 { "reference", "XREFERENCE", NOTMUCH_FIELD_NO_FLAGS },
34 { "replyto", "XREPLYTO", NOTMUCH_FIELD_NO_FLAGS },
35 { "directory", "XDIRECTORY", NOTMUCH_FIELD_NO_FLAGS },
36 { "file-direntry", "XFDIRENTRY", NOTMUCH_FIELD_NO_FLAGS },
37 { "directory-direntry", "XDDIRENTRY", NOTMUCH_FIELD_NO_FLAGS },
38 { "body", "", NOTMUCH_FIELD_EXTERNAL |
39 NOTMUCH_FIELD_PROBABILISTIC },
40 { "thread", "G", NOTMUCH_FIELD_EXTERNAL |
41 NOTMUCH_FIELD_PROCESSOR },
42 { "tag", "K", NOTMUCH_FIELD_EXTERNAL |
43 NOTMUCH_FIELD_PROCESSOR },
44 { "is", "K", NOTMUCH_FIELD_EXTERNAL |
45 NOTMUCH_FIELD_PROCESSOR },
46 { "id", "Q", NOTMUCH_FIELD_EXTERNAL },
47 { "mid", "Q", NOTMUCH_FIELD_EXTERNAL |
48 NOTMUCH_FIELD_PROCESSOR },
49 { "path", "P", NOTMUCH_FIELD_EXTERNAL |
50 NOTMUCH_FIELD_PROCESSOR | NOTMUCH_FIELD_STRIP_TRAILING_SLASH },
51 { "property", "XPROPERTY", NOTMUCH_FIELD_EXTERNAL },
53 * Unconditionally add ':' to reduce potential ambiguity with
54 * overlapping prefixes and/or terms that start with capital
55 * letters. See Xapian document termprefixes.html for related
58 { "folder", "XFOLDER:", NOTMUCH_FIELD_EXTERNAL |
59 NOTMUCH_FIELD_PROCESSOR | NOTMUCH_FIELD_STRIP_TRAILING_SLASH },
60 { "date", NULL, NOTMUCH_FIELD_EXTERNAL |
61 NOTMUCH_FIELD_PROCESSOR },
62 { "query", NULL, NOTMUCH_FIELD_EXTERNAL |
63 NOTMUCH_FIELD_PROCESSOR },
64 { "sexp", NULL, NOTMUCH_FIELD_EXTERNAL |
65 NOTMUCH_FIELD_PROCESSOR },
66 { "from", "XFROM", NOTMUCH_FIELD_EXTERNAL |
67 NOTMUCH_FIELD_PROBABILISTIC |
68 NOTMUCH_FIELD_PROCESSOR },
69 { "to", "XTO", NOTMUCH_FIELD_EXTERNAL |
70 NOTMUCH_FIELD_PROBABILISTIC },
71 { "attachment", "XATTACHMENT", NOTMUCH_FIELD_EXTERNAL |
72 NOTMUCH_FIELD_PROBABILISTIC },
73 { "mimetype", "XMIMETYPE", NOTMUCH_FIELD_EXTERNAL |
74 NOTMUCH_FIELD_PROBABILISTIC },
75 { "subject", "XSUBJECT", NOTMUCH_FIELD_EXTERNAL |
76 NOTMUCH_FIELD_PROBABILISTIC |
77 NOTMUCH_FIELD_PROCESSOR },
81 _user_prefix (void *ctx, const char *name)
83 return talloc_asprintf (ctx, "XU%s:", name);
87 _find_prefix (const char *name)
91 for (i = 0; i < ARRAY_SIZE (prefix_table); i++) {
92 if (strcmp (name, prefix_table[i].name) == 0)
93 return prefix_table[i].prefix;
96 INTERNAL_ERROR ("No prefix exists for '%s'\n", name);
101 /* Like find prefix, but include the possibility of user defined
102 * prefixes specific to this database */
105 _notmuch_database_prefix (notmuch_database_t *notmuch, const char *name)
109 /*XXX TODO: reduce code duplication */
110 for (i = 0; i < ARRAY_SIZE (prefix_table); i++) {
111 if (strcmp (name, prefix_table[i].name) == 0)
112 return prefix_table[i].prefix;
115 if (notmuch->user_prefix)
116 return _notmuch_string_map_get (notmuch->user_prefix, name);
122 _setup_query_field_default (const prefix_t *prefix, notmuch_database_t *notmuch)
125 notmuch->query_parser->add_prefix ("", prefix->prefix);
126 if (prefix->flags & NOTMUCH_FIELD_PROBABILISTIC)
127 notmuch->query_parser->add_prefix (prefix->name, prefix->prefix);
129 notmuch->query_parser->add_boolean_prefix (prefix->name, prefix->prefix);
133 _setup_query_field (const prefix_t *prefix, notmuch_database_t *notmuch)
135 if (prefix->flags & NOTMUCH_FIELD_PROCESSOR) {
136 Xapian::FieldProcessor *fp;
138 if (STRNCMP_LITERAL (prefix->name, "date") == 0)
139 fp = (new DateFieldProcessor (NOTMUCH_VALUE_TIMESTAMP))->release ();
140 else if (STRNCMP_LITERAL (prefix->name, "query") == 0)
141 fp = (new QueryFieldProcessor (*notmuch->query_parser, notmuch))->release ();
142 else if (STRNCMP_LITERAL (prefix->name, "thread") == 0)
143 fp = (new ThreadFieldProcessor (*notmuch->query_parser, notmuch))->release ();
144 else if (STRNCMP_LITERAL (prefix->name, "sexp") == 0)
145 fp = (new SexpFieldProcessor (notmuch))->release ();
147 fp = (new RegexpFieldProcessor (prefix->name, prefix->flags,
148 *notmuch->query_parser, notmuch))->release ();
150 /* we treat all field-processor fields as boolean in order to get the raw input */
152 notmuch->query_parser->add_prefix ("", prefix->prefix);
153 notmuch->query_parser->add_boolean_prefix (prefix->name, fp);
155 _setup_query_field_default (prefix, notmuch);
160 _notmuch_database_setup_standard_query_fields (notmuch_database_t *notmuch)
162 for (unsigned int i = 0; i < ARRAY_SIZE (prefix_table); i++) {
163 const prefix_t *prefix = &prefix_table[i];
164 if (prefix->flags & NOTMUCH_FIELD_EXTERNAL) {
165 _setup_query_field (prefix, notmuch);
168 return NOTMUCH_STATUS_SUCCESS;
172 _notmuch_database_setup_user_query_fields (notmuch_database_t *notmuch)
174 notmuch_string_map_iterator_t *list;
176 notmuch->user_prefix = _notmuch_string_map_create (notmuch);
177 if (notmuch->user_prefix == NULL)
178 return NOTMUCH_STATUS_OUT_OF_MEMORY;
180 notmuch->user_header = _notmuch_string_map_create (notmuch);
181 if (notmuch->user_header == NULL)
182 return NOTMUCH_STATUS_OUT_OF_MEMORY;
184 list = _notmuch_string_map_iterator_create (notmuch->config, CONFIG_HEADER_PREFIX, FALSE);
186 INTERNAL_ERROR ("unable to read headers from configuration");
188 for (; _notmuch_string_map_iterator_valid (list);
189 _notmuch_string_map_iterator_move_to_next (list)) {
191 prefix_t query_field;
193 const char *key = _notmuch_string_map_iterator_key (list)
194 + sizeof (CONFIG_HEADER_PREFIX) - 1;
196 _notmuch_string_map_append (notmuch->user_prefix,
198 _user_prefix (notmuch, key));
200 _notmuch_string_map_append (notmuch->user_header,
202 _notmuch_string_map_iterator_value (list));
204 query_field.name = talloc_strdup (notmuch, key);
205 query_field.prefix = _user_prefix (notmuch, key);
206 query_field.flags = NOTMUCH_FIELD_PROBABILISTIC
207 | NOTMUCH_FIELD_EXTERNAL;
209 _setup_query_field_default (&query_field, notmuch);
212 _notmuch_string_map_iterator_destroy (list);
214 return NOTMUCH_STATUS_SUCCESS;