bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "lib.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "array.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "str.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "strfuncs.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "str-sanitize.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "hex-binary.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "net.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "iso8601-date.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "uri-util.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "imap-url.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include <ctype.h>
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch/*
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * IMAP URL parsing
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch/*
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan BoschIMAP URL Grammar overview
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan BoschRFC5092 Section 11:
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschimapurl = "imap://" iserver ipath-query
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; Defines an absolute IMAP URL
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschiserver = [iuserinfo "@"] host [ ":" port ]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; This is the same as "authority" defined in [URI-GEN].
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschiuserinfo = enc-user [iauth] / [enc-user] iauth
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; conforms to the generic syntax of "userinfo" as
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; defined in [URI-GEN].
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschenc-user = 1*achar
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; %-encoded version of [IMAP4] authorization identity or
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; "userid".
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschiauth = ";AUTH=" ( "*" / enc-auth-type )
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschenc-auth-type = 1*achar
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; %-encoded version of [IMAP4] "auth-type"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschipath-query = ["/" [ icommand ]]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; Corresponds to "path-abempty [ "?" query ]" in
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; [URI-GEN]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschicommand = imessagelist /
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch imessagepart [iurlauth]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschimessagelist = imailbox-ref [ "?" enc-search ]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; "enc-search" is [URI-GEN] "query".
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschimessagepart = imailbox-ref iuid [isection] [ipartial]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschimailbox-ref = enc-mailbox [uidvalidity]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschuidvalidity = ";UIDVALIDITY=" nz-number
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; See [IMAP4] for "nz-number" definition
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschiuid = "/" iuid-only
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschiuid-only = ";UID=" nz-number
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; See [IMAP4] for "nz-number" definition
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschisection = "/" isection-only
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschisection-only = ";SECTION=" enc-section
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschipartial = "/" ipartial-only
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschipartial-only = ";PARTIAL=" partial-range
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschenc-search = 1*bchar
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; %-encoded version of [IMAPABNF]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; "search-program". Note that IMAP4
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; literals may not be used in
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; a "search-program", i.e., only
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; quoted or non-synchronizing
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; literals (if the server supports
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; LITERAL+ [LITERAL+]) are allowed.
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschenc-mailbox = 1*bchar
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; %-encoded version of [IMAP4] "mailbox"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschenc-section = 1*bchar
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; %-encoded version of [IMAP4] "section-spec"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschpartial-range = number ["." nz-number]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; partial FETCH. The first number is
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; the offset of the first byte,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; the second number is the length of
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; the fragment.
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschbchar = achar / ":" / "@" / "/"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschachar = uchar / "&" / "="
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ;; Same as [URI-GEN] 'unreserved / sub-delims /
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ;; pct-encoded', but ";" is disallowed.
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschuchar = unreserved / sub-delims-sh / pct-encoded
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschsub-delims-sh = "!" / "$" / "'" / "(" / ")" /
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch "*" / "+" / ","
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ;; Same as [URI-GEN] sub-delims,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ;; but without ";", "&" and "=".
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan BoschThe following rules are only used in the presence of the IMAP
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch[URLAUTH] extension:
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschauthimapurl = "imap://" iserver "/" imessagepart
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; Same as "imapurl" when "[icommand]" is
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; "imessagepart"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschauthimapurlfull = authimapurl iurlauth
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; Same as "imapurl" when "[icommand]" is
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; "imessagepart iurlauth"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschauthimapurlrump = authimapurl iurlauth-rump
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschiurlauth = iurlauth-rump iua-verifier
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschenc-urlauth = 32*HEXDIG
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschiua-verifier = ":" uauth-mechanism ":" enc-urlauth
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschiurlauth-rump = [expire] ";URLAUTH=" access
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschaccess = ("submit+" enc-user) / ("user+" enc-user) /
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch "authuser" / "anonymous"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschexpire = ";EXPIRE=" date-time
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; date-time is defined in [DATETIME]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschuauth-mechanism = "INTERNAL" / 1*(ALPHA / DIGIT / "-" / ".")
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ; Case-insensitive.
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch[URI-GEN] RFC3986 Appendix A:
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan BoschImplemented in src/lib/uri-util.c
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch*/
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch/*
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * Imap URL parser
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstruct imap_url_parser {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct uri_parser parser;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch enum imap_url_parse_flags flags;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct imap_url *url;
dc78180b54a05d5736d0e0e444cba0332265eb62Phil Carmody const struct imap_url *base;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool relative:1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch};
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic int
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschimap_url_parse_number(struct uri_parser *parser, const char *data,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uint32_t *number_r)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* [IMAP4] RFC3501, Section 9
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch *
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * number = 1*DIGIT
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; Unsigned 32-bit integer
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; (0 <= n < 4,294,967,296)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
662b2a7ec4b9f28b8e7ebac95c229db7babfe86aPhil Carmody if (i_isdigit(*data)) {
662b2a7ec4b9f28b8e7ebac95c229db7babfe86aPhil Carmody if (str_to_uint32(data, number_r) == 0)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return 1;
662b2a7ec4b9f28b8e7ebac95c229db7babfe86aPhil Carmody parser->error = "IMAP number is too high";
662b2a7ec4b9f28b8e7ebac95c229db7babfe86aPhil Carmody return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = t_strdup_printf(
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch "Value '%s' is not a valid IMAP number", data);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic int
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschimap_url_parse_offset(struct uri_parser *parser, const char *data,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uoff_t *number_r)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* Syntax for big (uoff_t) numbers. Not strictly IMAP syntax, but this
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch is handled similarly for Dovecot IMAP FETCH BODY partial <.>
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch implementation. */
662b2a7ec4b9f28b8e7ebac95c229db7babfe86aPhil Carmody if (i_isdigit(*data)) {
662b2a7ec4b9f28b8e7ebac95c229db7babfe86aPhil Carmody if (str_to_uoff(data, number_r) == 0)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return 1;
662b2a7ec4b9f28b8e7ebac95c229db7babfe86aPhil Carmody parser->error = "IMAP number is too high";
662b2a7ec4b9f28b8e7ebac95c229db7babfe86aPhil Carmody return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = t_strdup_printf(
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch "Value '%s' is not a valid IMAP number", data);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic int imap_url_parse_iserver(struct imap_url_parser *url_parser)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct uri_parser *parser = &url_parser->parser;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct uri_authority auth;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct imap_url *url = url_parser->url;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const char *data;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch int ret = 0;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* imapurl = "imap://" iserver {...}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * inetwork-path = "//" iserver {...}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * iserver = [iuserinfo "@"] host [":" port]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; This is the same as "authority" defined
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; in [URI-GEN].
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * iuserinfo = enc-user [iauth] / [enc-user] iauth
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; conforms to the generic syntax of "userinfo" as
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; defined in [URI-GEN].
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * enc-user = 1*achar
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; %-encoded version of [IMAP4] authorization identity or
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; "userid".
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * iauth = ";AUTH=" ( "*" / enc-auth-type )
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * enc-auth-type = 1*achar
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; %-encoded version of [IMAP4] "auth-type"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* "//" iserver */
d3b0b5d2389acc43c75b63d2960daf82cf1f8aa7Stephan Bosch if ((ret = uri_parse_slashslash_host_authority
d3b0b5d2389acc43c75b63d2960daf82cf1f8aa7Stephan Bosch (parser, &auth)) <= 0)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return ret;
8d2d2780c9e71581ff9c3e8bce527b492c295ec1Stephan Bosch if (auth.host.name == NULL || *auth.host.name == '\0') {
f3cf2f02155c4bac23fd50f0de96c0cae9c46478Stephan Bosch /* This situation is not documented anywhere, but it is not
f3cf2f02155c4bac23fd50f0de96c0cae9c46478Stephan Bosch currently useful either and potentially problematic if not
f3cf2f02155c4bac23fd50f0de96c0cae9c46478Stephan Bosch handled explicitly everywhere. So, it is denied hier for now.
f3cf2f02155c4bac23fd50f0de96c0cae9c46478Stephan Bosch */
f3cf2f02155c4bac23fd50f0de96c0cae9c46478Stephan Bosch parser->error = "IMAP URL does not allow empty host identifier";
f3cf2f02155c4bac23fd50f0de96c0cae9c46478Stephan Bosch return -1;
f3cf2f02155c4bac23fd50f0de96c0cae9c46478Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* iuserinfo = enc-user [iauth] / [enc-user] iauth */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (auth.enc_userinfo != NULL) {
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch const char *p, *uend;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* Scan for ";AUTH=" */
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch for (p = auth.enc_userinfo; *p != '\0'; p++) {
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch if (*p == ';')
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch break;
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch /* check for unallowed userinfo characters */
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch if (*p == ':') {
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch parser->error = t_strdup_printf(
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch "Stray ':' in userinfo `%s'", auth.enc_userinfo);
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch return -1;
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch }
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch }
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch uend = p;
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch if (*p == ';') {
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch if (strncasecmp(p, ";AUTH=", 6) != 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = t_strdup_printf(
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch "Stray ';' in userinfo `%s'",
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch auth.enc_userinfo);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch for (p += 6; *p != '\0'; p++) {
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch if (*p == ';' || *p == ':') {
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch parser->error = t_strdup_printf(
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch "Stray '%c' in userinfo `%s'", *p, auth.enc_userinfo);
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch return -1;
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* enc-user */
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch if (url != NULL && uend > auth.enc_userinfo) {
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch if (!uri_data_decode(parser, auth.enc_userinfo, uend, &data))
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url->userid = p_strdup(parser->pool, data);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* ( "*" / enc-auth-type ) */
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch if (*uend == ';') {
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch p = uend + 6;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (*p == '\0') {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = "Empty auth-type value after ';AUTH='";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (url != NULL) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (!uri_data_decode(parser, p, NULL, &data))
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url->auth_type = p_strdup(parser->pool, data);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (url != NULL) {
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch url->host = auth.host;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url->port = auth.port;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return 1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic int
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschimap_url_parse_urlauth(struct imap_url_parser *url_parser, const char *urlext)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct uri_parser *parser = &url_parser->parser;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct imap_url *url = url_parser->url;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const char *p, *q, *data;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch buffer_t *uauth_token;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch time_t expire = (time_t)-1;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen int tz;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* iurlauth = iurlauth-rump iua-verifier
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * enc-urlauth = 32*HEXDIG
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * iua-verifier = ":" uauth-mechanism ":" enc-urlauth
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * iurlauth-rump = [expire] ";URLAUTH=" access
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * access = ("submit+" enc-user) / ("user+" enc-user) /
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * "authuser" / "anonymous"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * expire = ";EXPIRE=" date-time
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; date-time is defined in [DATETIME]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * uauth-mechanism = "INTERNAL" / 1*(ALPHA / DIGIT / "-" / ".")
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; Case-insensitive.
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* ";EXPIRE=" date-time */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (strncasecmp(urlext, ";EXPIRE=", 8) == 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if ((url_parser->flags & IMAP_URL_PARSE_ALLOW_URLAUTH) == 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = "`;EXPIRE=' is not allowed in this context";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if ((p = strchr(urlext+8, ';')) != NULL) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (!iso8601_date_parse((const unsigned char *)urlext+8,
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen p-urlext-8, &expire, &tz)) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = "invalid date-time for `;EXPIRE='";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch urlext = p;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* ";URLAUTH=" access */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (strncasecmp(urlext, ";URLAUTH=", 9) != 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (expire != (time_t)-1) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = "`;EXPIRE=' without `;URLAUTH='";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return 0;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch urlext += 9;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (url != NULL)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url->uauth_expire = expire;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if ((url_parser->flags & IMAP_URL_PARSE_ALLOW_URLAUTH) == 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = "`;URLAUTH=' is not allowed in this context";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (url_parser->relative) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = "IMAP URLAUTH requires absolute URL";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if ((p = strchr(urlext, ':')) == NULL) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch size_t len = strlen(urlext);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (len == 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = "Missing URLAUTH access specifier";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch p = urlext+len;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch } else if (p == urlext) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = "Empty URLAUTH access specifier";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* parse access */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if ((q = strchr(urlext, '+')) == NULL) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* application */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (url != NULL) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url->uauth_access_application =
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch p_strdup_until(parser->pool, urlext, p);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch } else {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* application "+" enc-user */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (urlext == q) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = "Empty URLAUTH access application";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (q+1 == p) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = t_strdup_printf(
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch "Empty URLAUTH access user for `%s' application",
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch t_strdup_until(urlext, q));
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (!uri_data_decode(parser, q+1, p, &data))
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (url != NULL) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url->uauth_access_application =
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch p_strdup_until(parser->pool, urlext, q);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url->uauth_access_user = p_strdup(parser->pool, data);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (url != NULL) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* get rump url */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if ((url_parser->flags & IMAP_URL_PARSE_SCHEME_EXTERNAL) == 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url->uauth_rumpurl = p_strdup_until(parser->pool,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->begin, parser->end-strlen(p));
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch } else {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url->uauth_rumpurl = p_strconcat(parser->pool, "imap:",
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch t_strdup_until(parser->begin, parser->end-strlen(p)),
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch NULL);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (*p == '\0') {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* rump url; caller should check whether this is appropriate */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return 1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* iua-verifier = ":" uauth-mechanism ":" enc-urlauth */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch q = p + 1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (*q == '\0') {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = "Missing URLAUTH verifier";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if ((p = strchr(q, ':')) == NULL || p[1] == '\0') {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = "Missing URLAUTH token";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (p == q) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = "Missing URLAUTH mechanism";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (url != NULL) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* get mechanism */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url->uauth_mechanism = p_strdup_until(parser->pool, q, p);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* enc-urlauth = 32*HEXDIG */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch q = p+1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (strlen(q) < 32) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = "Too short URLAUTH token";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
c147bff818798a979d93537f72f5c1f68f5d5ba8Aki Tuomi uauth_token = t_buffer_create(64);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (hex_to_binary(q, uauth_token) < 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = "Invalid URLAUTH token";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (url != NULL) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url->uauth_token = uauth_token->data;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url->uauth_token_size = uauth_token->used;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return 1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic int
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschimap_url_parse_path(struct imap_url_parser *url_parser,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const char *const *path, int relative,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch bool *is_messagelist_r)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct uri_parser *parser = &url_parser->parser;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct imap_url *url = url_parser->url;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const char *const *segment;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch string_t *mailbox, *section = NULL;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uint32_t uid = 0, uidvalidity = 0;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uoff_t partial_offset = 0, partial_size = 0;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch bool have_partial = FALSE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const char *p, *value, *urlext = NULL;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch bool mailbox_endslash = FALSE, section_endslash = FALSE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch int ret;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* icommand = imessagelist /
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * imessagepart [iurlauth]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * imessagelist = imailbox-ref [ "?" enc-search ]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; "enc-search" is [URI-GEN] "query".
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * imessagepart = imailbox-ref iuid [isection] [ipartial]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * imailbox-ref = enc-mailbox [uidvalidity]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * uidvalidity = ";UIDVALIDITY=" nz-number
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * iuid = "/" iuid-only
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * iuid-only = ";UID=" nz-number
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; See [IMAP4] for "nz-number" definition
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * isection = "/" isection-only
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * isection-only = ";SECTION=" enc-section
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ipartial = "/" ipartial-only
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ipartial-only = ";PARTIAL=" partial-range
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * enc-mailbox = 1*bchar
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; %-encoded version of [IMAP4] "mailbox"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * enc-section = 1*bchar
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; %-encoded version of [IMAP4] "section-spec"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * partial-range = number ["." nz-number]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; partial FETCH. The first number is
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; the offset of the first byte,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; the second number is the length of
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; the fragment.
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* IMAP URL syntax is quite horrible to parse. It relies upon the
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch generic URI path resolution, but the icommand syntax also relies on
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ';' separators. We use the generic URI path parse functions to
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch adhere to the URI path resolution rules and glue back together path
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch segments when these are part of the same (mailbox or section) value.
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mailbox = t_str_new(256);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch segment = path;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* Resolve relative URI path; determine what to copy from the base URI */
8d35582f2577c64517b2341c5d6477c7010e0a0cPhil Carmody if (url != NULL && url_parser->base != NULL && relative > 0) {
dc78180b54a05d5736d0e0e444cba0332265eb62Phil Carmody const struct imap_url *base = url_parser->base;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch int rel = relative;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* /;PARTIAL= */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (base->have_partial && --rel <= 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch have_partial = base->have_partial;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch partial_offset = base->partial_offset;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch partial_size = base->partial_size;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* /;SECTION= */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (base->section != NULL) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch p = base->section + strlen(base->section);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* determine what to retain from base section path */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch for (; p > base->section && rel > 0; p--) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (*p =='/' && --rel <= 0) break;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (--rel <= 0 && p > base->section) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (p[-1] == '/') section_endslash = TRUE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (section == NULL)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch section = t_str_new(256);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch str_append_n(section, base->section, p-base->section);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* /;UID= */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (base->uid > 0 && --rel <= 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uid = base->uid;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* /mail/box;UIDVALIDITY= */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (base->mailbox != NULL) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uidvalidity = base->uidvalidity;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch p = base->mailbox + strlen(base->mailbox);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* mailbox has implicit trailing '/' */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (p[-1] != '/' && base->uid == 0 && rel > 0)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch rel--;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* determine what to retain from base mailbox path */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch for (; p > base->mailbox && rel > 0; p--) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (*p =='/') {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uidvalidity = 0;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (--rel <= 0)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch break;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (--rel <= 0 && p > base->mailbox) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (p[-1] == '/')
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mailbox_endslash = TRUE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch str_append_n(mailbox, base->mailbox,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch p - base->mailbox);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* Scan for last mailbox-ref segment */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (segment != NULL) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (relative == 0 || (!have_partial && section == NULL)) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch p = NULL;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch while (*segment != NULL) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch /* ';' must be pct-encoded; if it is not, this is
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch either the last mailbox-ref path segment containing
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch ';UIDVALIDITY=' or the subsequent iuid ';UID=' path
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch segment */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if ((p = strchr(*segment, ';')) != NULL)
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch break;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (**segment != '\0') {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (segment > path ||
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch (!mailbox_endslash && str_len(mailbox) > 0))
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch str_append_c(mailbox, '/');
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (!uri_data_decode(parser, *segment, NULL, &value))
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch str_append(mailbox, value);
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch mailbox_endslash = FALSE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch segment++;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch }
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch /* Handle ';' */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (p != NULL) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch /* [uidvalidity] */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (strncasecmp(p, ";UIDVALIDITY=", 13) == 0) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch /* append last bit of mailbox */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (*segment != p) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (segment > path ||
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch (!mailbox_endslash && str_len(mailbox) > 0))
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch str_append_c(mailbox, '/');
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (!uri_data_decode(parser, *segment, p, &value))
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch return -1;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch str_append(mailbox, value);
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch }
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch /* ";UIDVALIDITY=" nz-number */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (strchr(p+13, ';') != NULL) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch parser->error = "Encountered stray ';' after UIDVALIDITY";
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch return -1;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch /* nz-number */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (p[13] == '\0') {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch parser->error = "Empty UIDVALIDITY value";
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch return -1;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch }
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (imap_url_parse_number(parser, p+13, &uidvalidity) <= 0)
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch return -1;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (uidvalidity == 0) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch parser->error = "UIDVALIDITY cannot be zero";
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch return -1;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch }
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch segment++;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch } else if (p != *segment) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch parser->error = "Encountered stray ';' in mailbox reference";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch /* iuid */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (*segment != NULL && strncasecmp(*segment, ";UID=", 5) == 0) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch /* ";UID=" nz-number */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch value = (*segment)+5;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if ((p = strchr(value,';')) != NULL) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (segment[1] != NULL ) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch /* not the last segment, so it cannot be extension like iurlauth */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch parser->error = "Encountered stray ';' in UID path segment";
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch return -1;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch }
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch urlext = p;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch value = t_strdup_until(value, p);
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* nz-number */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (*value == '\0') {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch parser->error = "Empty UID value";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (imap_url_parse_number(parser, value, &uid) <= 0)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (uid == 0) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch parser->error = "UID cannot be zero";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch segment++;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch /* [isection] [ipartial] */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (*segment != NULL && uid > 0) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch /* [isection] */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (section != NULL ||
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch strncasecmp(*segment, ";SECTION=", 9) == 0) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch /* ";SECTION=" enc-section */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (section == NULL) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch section = t_str_new(256);
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch value = (*segment) + 9;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch } else {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch value = *segment;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch /* enc-section can contain slashes, so we merge path segments until one
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch contains ';' */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch while ((p = strchr(value,';')) == NULL) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (!section_endslash && str_len(section) > 0)
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch str_append_c(section, '/');
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (*value != '\0') {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (!uri_data_decode(parser, value, NULL, &value))
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch return -1;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch str_append(section, value);
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch section_endslash = FALSE;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch segment++;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (*segment == NULL)
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch break;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch value = *segment;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (p != NULL) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch /* found ';' */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (p != value) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch /* it is not at the beginning of the path segment */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (segment[1] != NULL) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch /* not the last segment, so it cannot be extension like iurlauth */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch parser->error = "Encountered stray ';' in SECTION path segment";
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch return -1;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch }
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch urlext = p;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch value = t_strdup_until(value, p);
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (!section_endslash && str_len(section) > 0)
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch str_append_c(section, '/');
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (!uri_data_decode(parser, value, NULL, &value))
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch return -1;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch str_append(section, value);
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch segment++;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (str_len(section) == 0) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch parser->error = "Empty SECTION value";
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch return -1;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch /* [ipartial] */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (*segment != NULL &&
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch strncasecmp(*segment, ";PARTIAL=", 9) == 0) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch have_partial = TRUE;
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch /* ";PARTIAL=" partial-range */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch value = (*segment) + 9;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if ((p = strchr(value,';')) != NULL) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch urlext = p;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch value = t_strdup_until(value, p);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (*value == '\0') {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch parser->error = "Empty PARTIAL value";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch /* partial-range = number ["." nz-number] */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if ((p = strchr(value,'.')) != NULL) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (p[1] == '\0') {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch parser->error = "Empty PARTIAL size";
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch return -1;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch }
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (imap_url_parse_offset(parser, p+1, &partial_size) <= 0)
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch return -1;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (partial_size == 0) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch parser->error = "PARTIAL size cannot be zero";
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch return -1;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch }
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch value = t_strdup_until(value, p);
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (*value == '\0') {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch parser->error = "Empty PARTIAL offset";
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch return -1;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch }
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch }
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (imap_url_parse_offset(parser,value, &partial_offset) <= 0)
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch return -1;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch segment++;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (*segment != NULL) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (urlext != NULL || **segment != '\0' || *(segment+1) != NULL ) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch parser->error = t_strdup_printf(
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch "Unexpected IMAP URL path segment: `%s'",
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch str_sanitize(*segment, 80));
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch return -1;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch }
17c29e3e2246972c3d988e05d91b9286398a624fStephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* ";" {...} at end of URL */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (urlext != NULL) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* [iurlauth] */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if ((ret = imap_url_parse_urlauth(url_parser, urlext)) < 0)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return ret;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch else if (ret == 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* something else */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = t_strdup_printf(
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch "Unrecognized IMAP URL extension: %s",
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch str_sanitize(urlext, 80));
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (is_messagelist_r != NULL)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch *is_messagelist_r = (uid == 0);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (url != NULL) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (str_len(mailbox) > 0)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url->mailbox = p_strdup(parser->pool, str_c(mailbox));
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url->uidvalidity = uidvalidity;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url->uid = uid;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (section != NULL)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url->section = p_strdup(parser->pool, str_c(section));
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch url->have_partial = have_partial;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url->partial_offset = partial_offset;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url->partial_size = partial_size;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return 1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic bool imap_url_do_parse(struct imap_url_parser *url_parser)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct uri_parser *parser = &url_parser->parser;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const char *const *path;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch bool is_messagelist = FALSE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch bool have_scheme = FALSE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch int relative;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const char *query;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch int ret, sret;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /*
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * imapurl = "imap://" iserver ipath-query
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; Defines an absolute IMAP URL
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * iserver = [iuserinfo "@"] host [":" port]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; This is the same as "authority" defined
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; in [URI-GEN].
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ipath-query = ["/" [ icommand ]]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; Corresponds to "path-abempty [ "?" query ]" in
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; [URI-GEN]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * icommand = imessagelist /
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * imessagepart [iurlauth]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * imessagelist = imailbox-ref [ "?" enc-search ]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; "enc-search" is [URI-GEN] "query".
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * imessagepart = imailbox-ref iuid [isection] [ipartial]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * enc-search = 1*bchar
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; %-encoded version of [IMAPABNF]
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; "search-program". Note that IMAP4
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; literals may not be used in
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; a "search-program", i.e., only
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; quoted or non-synchronizing
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; literals (if the server supports
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * ; LITERAL+ [LITERAL+]) are allowed.
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* "imap:" */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if ((url_parser->flags & IMAP_URL_PARSE_SCHEME_EXTERNAL) == 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const char *scheme;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
b4167b174b4eeebceaf80e240635e601f0a9860cStephan Bosch if (uri_parse_scheme(parser, &scheme) <= 0) {
b4167b174b4eeebceaf80e240635e601f0a9860cStephan Bosch parser->cur = parser->begin;
b4167b174b4eeebceaf80e240635e601f0a9860cStephan Bosch } else {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (strcasecmp(scheme, "imap") != 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = "Not an IMAP URL";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return FALSE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch have_scheme = TRUE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch } else {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch have_scheme = TRUE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* "//" iserver */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if ((sret = imap_url_parse_iserver(url_parser)) < 0)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return FALSE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (have_scheme && sret == 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = "Absolute IMAP URL requires `//' after `imap:'";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return FALSE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (sret > 0 &&
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch (url_parser->flags & IMAP_URL_PARSE_REQUIRE_RELATIVE) != 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = "Relative URL required";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return FALSE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* ipath-query = ["/" [ icommand ]] ; excludes `[ "?" enc-search ]` */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if ((ret = uri_parse_path(parser, &relative, &path)) < 0)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return FALSE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* Relative urls are only valid when we have a base url */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (sret == 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (url_parser->base == NULL) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = "Relative URL not allowed";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return FALSE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch } else if (url_parser->url != NULL) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct imap_url *url = url_parser->url;
dc78180b54a05d5736d0e0e444cba0332265eb62Phil Carmody const struct imap_url *base = url_parser->base;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch uri_host_copy(parser->pool, &url->host, &base->host);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url->port = base->port;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url->userid = p_strdup_empty(parser->pool, base->userid);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url->auth_type = p_strdup_empty(parser->pool, base->auth_type);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url_parser->relative = TRUE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* Parse path, i.e. `[ icommand ]` from `*( "/" segment )` */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (ret > 0 || url_parser->relative) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if ((ret = imap_url_parse_path(url_parser, path, relative,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch &is_messagelist)) < 0)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return FALSE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* [ "?" enc-search ] */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if ((ret = uri_parse_query(parser, &query)) != 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (ret < 0)
54fa2c9c1fe183d29edb8dec03ba883764d7f7b4Timo Sirainen return FALSE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (!is_messagelist) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error =
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch "Search query part only valid for messagelist-type IMAP URL";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return FALSE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch } else if (*query == '\0') {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = "Empty IMAP URL search query not allowed";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return FALSE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (url_parser->url != NULL) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (!uri_data_decode(parser, query, NULL, &query))
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return FALSE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url_parser->url->search_program =
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch p_strdup(parser->pool, query);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
bcd6c13936df11167350ac86598a781dce9038c3Stephan Bosch /* IMAP URL has no fragment */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if ((ret = uri_parse_fragment(parser, &query)) != 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (ret == 1)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch parser->error = "Fragment component not allowed in IMAP URL";
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return FALSE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
bcd6c13936df11167350ac86598a781dce9038c3Stephan Bosch
bcd6c13936df11167350ac86598a781dce9038c3Stephan Bosch /* must be at end of URL now */
bcd6c13936df11167350ac86598a781dce9038c3Stephan Bosch i_assert(parser->cur == parser->end);
bcd6c13936df11167350ac86598a781dce9038c3Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return TRUE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch/* Public API */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
dc78180b54a05d5736d0e0e444cba0332265eb62Phil Carmodyint imap_url_parse(const char *url, const struct imap_url *base,
639bb36b12b9f9bb54c8bb1be50eac623622f8a0Timo Sirainen enum imap_url_parse_flags flags,
639bb36b12b9f9bb54c8bb1be50eac623622f8a0Timo Sirainen struct imap_url **url_r, const char **error_r)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct imap_url_parser url_parser;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* base != NULL indicates whether relative URLs are allowed. However, certain
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch flags may also dictate whether relative URLs are allowed/required. */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i_assert((flags & IMAP_URL_PARSE_REQUIRE_RELATIVE) == 0 || base != NULL);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i_assert((flags & IMAP_URL_PARSE_SCHEME_EXTERNAL) == 0 || base == NULL);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&url_parser);
639bb36b12b9f9bb54c8bb1be50eac623622f8a0Timo Sirainen uri_parser_init(&url_parser.parser, pool_datastack_create(), url);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
639bb36b12b9f9bb54c8bb1be50eac623622f8a0Timo Sirainen url_parser.url = t_new(struct imap_url, 1);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url_parser.url->uauth_expire = (time_t)-1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url_parser.base = base;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch url_parser.flags = flags;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (!imap_url_do_parse(&url_parser)) {
639bb36b12b9f9bb54c8bb1be50eac623622f8a0Timo Sirainen *error_r = url_parser.parser.error;
639bb36b12b9f9bb54c8bb1be50eac623622f8a0Timo Sirainen return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
639bb36b12b9f9bb54c8bb1be50eac623622f8a0Timo Sirainen *url_r = url_parser.url;
639bb36b12b9f9bb54c8bb1be50eac623622f8a0Timo Sirainen return 0;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch/*
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch * IMAP URL construction
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Boschstatic void
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Boschimap_url_append_mailbox(const struct imap_url *url, string_t *urlstr)
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch{
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch uri_append_path_data(urlstr, ";", url->mailbox);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch if (url->uidvalidity != 0)
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch str_printfa(urlstr, ";UIDVALIDITY=%u", url->uidvalidity);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch if (url->uid == 0) {
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch /* message list */
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch if (url->search_program != NULL) {
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch str_append_c(urlstr, '?');
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch uri_append_query_data(urlstr, ";", url->search_program);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch }
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch } else {
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch /* message part */
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch str_printfa(urlstr, "/;UID=%u", url->uid);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch if (url->section != NULL) {
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch str_append(urlstr, "/;SECTION=");
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch uri_append_path_data(urlstr, ";", url->section);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch }
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch if (url->have_partial) {
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch str_append(urlstr, "/;PARTIAL=");
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch if (url->partial_size == 0) {
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch str_printfa(urlstr, "%"PRIuUOFF_T,
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch url->partial_offset);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch } else {
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch str_printfa(urlstr, "%"PRIuUOFF_T".%"PRIuUOFF_T,
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch url->partial_offset,
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch url->partial_size);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch }
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch }
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch /* urlauth */
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch if (url->uauth_access_application != NULL) {
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch if (url->uauth_expire != (time_t)-1) {
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch str_append(urlstr, ";EXPIRE=");
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch str_append(urlstr, iso8601_date_create(url->uauth_expire));
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch }
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch str_append(urlstr, ";URLAUTH=");
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch str_append(urlstr, url->uauth_access_application);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch if (url->uauth_access_user != NULL) {
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch str_append_c(urlstr, '+');
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch uri_append_user_data(urlstr, ";",
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch url->uauth_access_user);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch }
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch }
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch }
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch}
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Boschconst char *imap_url_create(const struct imap_url *url)
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch{
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch string_t *urlstr = t_str_new(512);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch /* scheme */
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch uri_append_scheme(urlstr, "imap");
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch str_append(urlstr, "//");
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch /* user */
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch if (url->userid != NULL || url->auth_type != NULL) {
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch if (url->userid != NULL)
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch uri_append_user_data(urlstr, ";:", url->userid);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch if (url->auth_type != NULL) {
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch str_append(urlstr, ";AUTH=");
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch uri_append_user_data(urlstr, ";:", url->auth_type);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch }
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch str_append_c(urlstr, '@');
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch }
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch /* server */
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch uri_append_host(urlstr, &url->host);
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch uri_append_port(urlstr, url->port);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch /* Older syntax (RFC 2192) requires this slash at all times */
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch str_append_c(urlstr, '/');
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch /* mailbox */
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch if (url->mailbox != NULL)
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch imap_url_append_mailbox(url, urlstr);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch return str_c(urlstr);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch}
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschconst char *
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschimap_url_add_urlauth(const char *rumpurl, const char *mechanism,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const unsigned char *token, size_t token_len)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return t_strconcat(rumpurl, ":", t_str_lcase(mechanism), ":",
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch binary_to_hex(token, token_len), NULL);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}