NM_QUERY_TYPE_THREADS /**< Whole threads */
};
-/**
- * struct UriTag - Parsed Notmuch-URI arguments
- *
- * The arguments in a URI are saved in a linked list.
- *
- * @sa NmCtxData#query_items
- */
-struct UriTag
-{
- char *name;
- char *value;
- struct UriTag *next;
-};
-
/**
* struct NmHdrData - Notmuch data attached to an email
*
{
notmuch_database_t *db;
- char *db_filename; /**< Filename of the Notmuch database */
+ struct Url db_url; /**< Parsed view url of the Notmuch database */
+ char *db_url_holder; /**< The storage string used by db_url, we keep it
+ * to be able to free db_url */
char *db_query; /**< Previous query */
int db_limit; /**< Maximum number of results to return */
enum NmQueryType query_type; /**< Messages or Threads */
- struct UriTag *query_items;
-
struct Progress progress; /**< A progress bar */
int oldmsgcount;
int ignmsgcount; /**< Ignored messages */
#endif
/**
- * url_free_tags - Free a list of tags
- * @param tags List of tags
- *
- * Tags are stored as a singly-linked list.
- * Free all the strings and the list, itself.
- */
-static void url_free_tags(struct UriTag *tags)
-{
- while (tags)
- {
- struct UriTag *next = tags->next;
- FREE(&tags->name);
- FREE(&tags->value);
- FREE(&tags);
- tags = next;
- }
-}
-
-/**
- * url_parse_query - Extract the tokens from a query URI
- * @param[in] url URI to parse
- * @param[out] filename Save the filename
- * @param[out] tags Save the list of tags
- * @retval true Success
- * @retval false Error Bad format
- *
- * Parse a Notmuch URI, such as:
- * * notmuch:///path/to/db?query=tag:lkml&limit=1000
- * * notmuch://?query=neomutt
+ * free_hdrdata - Free header data attached to an email
+ * @param data Header data
*
- * Extract the database filename (optional) and any search parameters (tags).
- * The tags will be saved in a linked list (#UriTag).
+ * Each email can have an attached nm_hdrdata struct, which contains things
+ * like the tags (labels). This function frees all the resources and the
+ * nm_hdrdata struct itself.
*/
-static bool url_parse_query(const char *url, char **filename, struct UriTag **tags)
-{
- char *p = strstr(url, "://"); /* remote unsupported */
- char *e = NULL;
- struct UriTag *tag, *last = NULL;
-
- *filename = NULL;
- *tags = NULL;
-
- if (!p || !*(p + 3))
- return false;
-
- p += 3;
- *filename = p;
-
- e = strchr(p, '?');
-
- *filename = e ? (e == p) ? NULL : mutt_substrdup(p, e) : safe_strdup(p);
- if (!e)
- return true; /* only filename */
-
- if (*filename && (url_pct_decode(*filename) < 0))
- goto err;
-
- e++; /* skip '?' */
- p = e;
-
- while (p && *p)
- {
- tag = safe_calloc(1, sizeof(struct UriTag));
-
- if (!*tags)
- last = *tags = tag;
- else
- {
- last->next = tag;
- last = tag;
- }
-
- e = strchr(p, '=');
- if (!e)
- e = strchr(p, '&');
- tag->name = e ? mutt_substrdup(p, e) : safe_strdup(p);
- if (!tag->name || (url_pct_decode(tag->name) < 0))
- goto err;
- if (!e)
- break;
-
- p = e + 1;
-
- if (*e == '&')
- continue;
-
- e = strchr(p, '&');
- tag->value = e ? mutt_substrdup(p, e) : safe_strdup(p);
- if (!tag->value || (url_pct_decode(tag->value) < 0))
- goto err;
- if (!e)
- break;
- p = e + 1;
- }
-
- return true;
-err:
- FREE(&(*filename));
- url_free_tags(*tags);
- return false;
-}
-
static void free_hdrdata(struct NmHdrData *data)
{
if (!data)
#endif
data->db = NULL;
- FREE(&data->db_filename);
+ url_free(&data->db_url);
+ FREE(&data->db_url_holder);
FREE(&data->db_query);
- url_free_tags(data->query_items);
FREE(&data);
}
mutt_debug(1, "nm: initialize context data %p\n", (void *) data);
data->db_limit = NmDbLimit;
+ data->db_url_holder = safe_strdup(uri);
- if (!url_parse_query(uri, &data->db_filename, &data->query_items))
+ if (url_parse(&data->db_url, data->db_url_holder) < 0)
{
mutt_error(_("failed to parse notmuch uri: %s"), uri);
FREE(&data);
return NULL;
}
-
return data;
}
{
mutt_debug(2, "nm: get_query_string(%s)\n", window ? "true" : "false");
- struct UriTag *item = NULL;
+ struct UrlQueryString *item = NULL;
if (!data)
return NULL;
data->query_type = string_to_query_type(NmQueryType); /* user's default */
- for (item = data->query_items; item; item = item->next)
+ STAILQ_FOREACH(item, &data->db_url.query_strings, entries)
{
if (!item->value || !item->name)
continue;
if (!data)
return NULL;
- db_filename = data->db_filename ? data->db_filename : NmDefaultUri;
+ db_filename = data->db_url.path ? data->db_url.path : NmDefaultUri;
if (!db_filename)
db_filename = Folder;
if (!db_filename)
{
mutt_debug(2, "nm_normalize_uri (%s)\n", orig_uri);
char buf[LONG_STRING];
+ int rc = -1;
struct Context tmp_ctx;
memset(&tmp_ctx, 0, sizeof(tmp_ctx));
mutt_debug(2, "nm_normalize_uri #1 () -> db_query: %s\n", tmp_ctxdata->db_query);
if (get_query_string(tmp_ctxdata, false) == NULL)
- {
- mutt_error(_("failed to parse notmuch uri: %s"), orig_uri);
- mutt_debug(2, "nm_normalize_uri () -> error #1\n");
- FREE(&tmp_ctxdata);
- return false;
- }
+ goto gone;
mutt_debug(2, "nm_normalize_uri #2 () -> db_query: %s\n", tmp_ctxdata->db_query);
strfcpy(buf, tmp_ctxdata->db_query, sizeof(buf));
if (nm_uri_from_query(&tmp_ctx, buf, sizeof(buf)) == NULL)
- {
- mutt_error(_("failed to parse notmuch uri: %s"), orig_uri);
- mutt_debug(2, "nm_normalize_uri () -> error #2\n");
- FREE(&tmp_ctxdata);
- return true;
- }
-
- FREE(&tmp_ctxdata);
+ goto gone;
strncpy(new_uri, buf, new_uri_sz);
mutt_debug(2, "nm_normalize_uri #3 (%s) -> %s\n", orig_uri, new_uri);
+
+ rc = 0;
+gone:
+ url_free(&tmp_ctxdata->db_url);
+ FREE(&tmp_ctxdata->db_url_holder);
+ FREE(&tmp_ctxdata);
+ if (rc < 0)
+ {
+ mutt_error(_("failed to parse notmuch uri: %s"), orig_uri);
+ mutt_debug(2, "nm_normalize_uri () -> error\n");
+ return false;
+ }
return true;
}
int nm_nonctx_get_count(char *path, int *all, int *new)
{
- struct UriTag *query_items = NULL, *item = NULL;
+ struct UrlQueryString *item = NULL;
+ struct Url url;
+ char *url_holder = safe_strdup(path);
char *db_filename = NULL, *db_query = NULL;
notmuch_database_t *db = NULL;
int rc = -1;
- bool dflt = false;
-
mutt_debug(1, "nm: count\n");
- if (!url_parse_query(path, &db_filename, &query_items))
+ memset(&url, 0, sizeof(struct Url));
+
+ if (url_parse(&url, url_holder) < 0)
{
mutt_error(_("failed to parse notmuch uri: %s"), path);
goto done;
}
- if (!query_items)
- goto done;
- for (item = query_items; item; item = item->next)
+ STAILQ_FOREACH(item, &url.query_strings, entries)
{
if (item->value && (strcmp(item->name, "query") == 0))
{
if (!db_query)
goto done;
+ db_filename = url.path;
if (!db_filename)
{
if (NmDefaultUri)
}
else if (Folder)
db_filename = Folder;
- dflt = true;
}
/* don't be verbose about connection, as we're called from
#endif
mutt_debug(1, "nm: count close DB\n");
}
- if (!dflt)
- FREE(&db_filename);
- url_free_tags(query_items);
+ url_free(&url);
+ FREE(&url_holder);
mutt_debug(1, "nm: count done [rc=%d]\n", rc);
return rc;
return (enum UrlScheme) i;
}
+
+static int parse_query_string(struct Url *u, char *src)
+{
+ struct UrlQueryString *qs = NULL;
+ char *k = NULL, *v = NULL;
+
+ while (src && *src)
+ {
+ qs = safe_calloc(1, sizeof(struct UrlQueryString));
+ if ((k = strchr(src, '&')))
+ *k = '\0';
+
+ if ((v = strchr(src, '=')))
+ {
+ *v = '\0';
+ qs->value = v + 1;
+ if (url_pct_decode(qs->value) < 0)
+ {
+ FREE(&qs);
+ return -1;
+ }
+ }
+ qs->name = src;
+ if (url_pct_decode(qs->name) < 0)
+ {
+ FREE(&qs);
+ return -1;
+ }
+ STAILQ_INSERT_TAIL(&u->query_strings, qs, entries);
+
+ if (!k)
+ break;
+ src = k + 1;
+ }
+ return 0;
+}
+
+
/**
- * parse_userhost - fill in components of Url with info from src
+ * url_parse - Fill in Url
+ * @param u Url where the result is stored
+ * @param src String to parse
+ * @retval 0 String is valid
+ * @retval -1 String is invalid
+ *
+ * char* elements are pointers into src, which is modified by this call
+ * (duplicate it first if you need to).
+ *
+ * This method doesn't allocated any additional char* of the Url and
+ * UrlQueryString structs.
*
- * Note: These are pointers into src, which is altered with '\0's.
- * Port of 0 means no port given.
+ * To free Url, caller must free "src" and call url_free()
*/
-static int parse_userhost(struct Url *u, char *src)
+int url_parse(struct Url *u, char *src)
{
char *t = NULL, *p = NULL;
+ u->scheme = url_check_scheme(src);
+ if (u->scheme == U_UNKNOWN)
+ return -1;
+
+ src = strchr(src, ':') + 1;
+
u->user = NULL;
u->pass = NULL;
u->host = NULL;
u->port = 0;
+ u->path = NULL;
+ STAILQ_INIT(&u->query_strings);
if (strncmp(src, "//", 2) != 0)
{
src += 2;
+ if ((t = strchr(src, '?')))
+ {
+ *t++ = '\0';
+ if (parse_query_string(u, t) < 0)
+ goto err;
+ }
+
if ((u->path = strchr(src, '/')))
*u->path++ = '\0';
+ if (u->path && url_pct_decode(u->path) < 0)
+ goto err;
+
if ((t = strrchr(src, '@')))
{
*t = '\0';
*p = '\0';
u->pass = p + 1;
if (url_pct_decode(u->pass) < 0)
- return -1;
+ goto err;
}
u->user = src;
if (url_pct_decode(u->user) < 0)
- return -1;
+ goto err;
src = t + 1;
}
int num;
*p++ = '\0';
if (mutt_atoi(p, &num) < 0 || num < 0 || num > 0xffff)
- return -1;
+ goto err;
u->port = (unsigned short) num;
}
else
u->port = 0;
- u->host = src;
- return url_pct_decode(u->host) >= 0 && (!u->path || url_pct_decode(u->path) >= 0) ? 0 : -1;
-}
-/**
- * url_parse - Fill in Url
- *
- * char* elements are pointers into src, which is modified by this call
- * (duplicate it first if you need to).
- */
-int url_parse(struct Url *u, char *src)
-{
- char *tmp = NULL;
+ if (mutt_strlen(src) != 0)
+ {
+ u->host = src;
+ if (url_pct_decode(u->host) < 0)
+ goto err;
+ }
+ else if (u->path)
+ {
+ /* No host are provided, we restore the / because this is absolute path */
+ u->path = src;
+ *src++ = '/';
+ }
- u->scheme = url_check_scheme(src);
- if (u->scheme == U_UNKNOWN)
- return -1;
+ return 0;
- tmp = strchr(src, ':') + 1;
+err:
+ url_free(u);
+ return -1;
+}
- return parse_userhost(u, tmp);
+void url_free(struct Url *u)
+{
+ struct UrlQueryString *np = STAILQ_FIRST(&u->query_strings), *next = NULL;
+ while (np)
+ {
+ next = STAILQ_NEXT(np, entries);
+ /* NOTE(sileht): We don't free members, they will be freed when
+ * the src char* passed to url_parse() is freed */
+ FREE(&np);
+ np = next;
+ }
+ STAILQ_INIT(&u->query_strings);
}
void url_pct_encode(char *dst, size_t l, const char *src)