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