Skip to content

Commit

Permalink
imap: change from "FETCH" to "UID FETCH"
Browse files Browse the repository at this point in the history
... and add "MAILINDEX".

As described in curl#2789, this is a suggested solution.  Changing UID=xx to
actually get mail with UID xx and add "MAILINDEX" to get a mail with a
special index in the mail box (old behavior).  So MAILINDEX=1 gives the
first non deleted mail in the mail box.

Fixes curl#2789
Closes curl#2815
  • Loading branch information
nicklasaven authored and falconindy committed Sep 10, 2018
1 parent 7318056 commit 4d8bbe4
Show file tree
Hide file tree
Showing 40 changed files with 140 additions and 60 deletions.
5 changes: 4 additions & 1 deletion docs/libcurl/opts/CURLOPT_URL.3
Expand Up @@ -187,7 +187,10 @@ imap://user:password@mail.example.com/INBOX - Performs a folder list on the
user's inbox

imap://user:password@mail.example.com/INBOX/;UID=1 - Selects the user's inbox
and fetches message 1
and fetches message with uid = 1

imap://user:password@mail.example.com/INBOX/;MAILINDEX=1 - Selects the user's inbox
and fetches the first message in the mail box

imap://user:password@mail.example.com/INBOX;UIDVALIDITY=50/;UID=2 - Selects
the user's inbox, checks the UIDVALIDITY of the mailbox is 50 and fetches
Expand Down
63 changes: 42 additions & 21 deletions lib/imap.c
Expand Up @@ -421,7 +421,6 @@ static CURLcode imap_perform_capability(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
struct imap_conn *imapc = &conn->proto.imapc;

imapc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */
imapc->sasl.authused = SASL_AUTH_NONE; /* Clear the auth. mechanism used */
imapc->tls_supported = FALSE; /* Clear the TLS capability */
Expand Down Expand Up @@ -683,24 +682,37 @@ static CURLcode imap_perform_fetch(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
struct IMAP *imap = conn->data->req.protop;

/* Check we have a UID */
if(!imap->uid) {
failf(conn->data, "Cannot FETCH without a UID.");
return CURLE_URL_MALFORMAT;
if(imap->uid) {

/* Send the FETCH command */
if(imap->partial)
result = imap_sendf(conn, "UID FETCH %s BODY[%s]<%s>",
imap->uid,
imap->section ? imap->section : "",
imap->partial);
else
result = imap_sendf(conn, "UID FETCH %s BODY[%s]",
imap->uid,
imap->section ? imap->section : "");
}
else if(imap->mindex) {

/* Send the FETCH command */
if(imap->partial)
result = imap_sendf(conn, "FETCH %s BODY[%s]<%s>",
imap->mindex,
imap->section ? imap->section : "",
imap->partial);
else
result = imap_sendf(conn, "FETCH %s BODY[%s]",
imap->mindex,
imap->section ? imap->section : "");
}
else {
failf(conn->data, "Cannot FETCH without a UID.");
return CURLE_URL_MALFORMAT;
}

/* Send the FETCH command */
if(imap->partial)
result = imap_sendf(conn, "FETCH %s BODY[%s]<%s>",
imap->uid,
imap->section ? imap->section : "",
imap->partial);
else
result = imap_sendf(conn, "FETCH %s BODY[%s]",
imap->uid,
imap->section ? imap->section : "");

if(!result)
state(conn, IMAP_FETCH);

Expand Down Expand Up @@ -1464,9 +1476,10 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status,
result = status; /* use the already set error code */
}
else if(!data->set.connect_only && !imap->custom &&
(imap->uid || data->set.upload ||
(imap->uid || imap->mindex || data->set.upload ||
data->set.mimepost.kind != MIMEKIND_NONE)) {
/* Handle responses after FETCH or APPEND transfer has finished */

if(!data->set.upload && data->set.mimepost.kind == MIMEKIND_NONE)
state(conn, IMAP_FETCH_FINAL);
else {
Expand All @@ -1490,6 +1503,7 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status,
Curl_safefree(imap->mailbox);
Curl_safefree(imap->uidvalidity);
Curl_safefree(imap->uid);
Curl_safefree(imap->mindex);
Curl_safefree(imap->section);
Curl_safefree(imap->partial);
Curl_safefree(imap->query);
Expand Down Expand Up @@ -1543,14 +1557,14 @@ static CURLcode imap_perform(struct connectdata *conn, bool *connected,
else if(imap->custom && (selected || !imap->mailbox))
/* Custom command using the same mailbox or no mailbox */
result = imap_perform_list(conn);
else if(!imap->custom && selected && imap->uid)
else if(!imap->custom && selected && (imap->uid || imap->mindex))
/* FETCH from the same mailbox */
result = imap_perform_fetch(conn);
else if(!imap->custom && selected && imap->query)
/* SEARCH the current mailbox */
result = imap_perform_search(conn);
else if(imap->mailbox && !selected &&
(imap->custom || imap->uid || imap->query))
(imap->custom || imap->uid || imap->mindex || imap->query))
/* SELECT the mailbox */
result = imap_perform_select(conn);
else
Expand Down Expand Up @@ -2016,6 +2030,13 @@ static CURLcode imap_parse_url_path(struct connectdata *conn)
imap->uid = value;
value = NULL;
}
else if(strcasecompare(name, "MAILINDEX") && !imap->mindex) {
if(valuelen > 0 && value[valuelen - 1] == '/')
value[valuelen - 1] = '\0';

imap->mindex = value;
value = NULL;
}
else if(strcasecompare(name, "SECTION") && !imap->section) {
if(valuelen > 0 && value[valuelen - 1] == '/')
value[valuelen - 1] = '\0';
Expand Down Expand Up @@ -2043,7 +2064,7 @@ static CURLcode imap_parse_url_path(struct connectdata *conn)

/* Does the URL contain a query parameter? Only valid when we have a mailbox
and no UID as per RFC-5092 */
if(imap->mailbox && !imap->uid && *ptr == '?') {
if(imap->mailbox && !imap->uid && !imap->mindex && *ptr == '?') {
/* Find the length of the query parameter */
begin = ++ptr;
while(imap_is_bchar(*ptr))
Expand Down
1 change: 1 addition & 0 deletions lib/imap.h
Expand Up @@ -58,6 +58,7 @@ struct IMAP {
char *mailbox; /* Mailbox to select */
char *uidvalidity; /* UIDVALIDITY to check in select */
char *uid; /* Message UID to fetch */
char *mindex; /* Index in mail box of mail to fetch */
char *section; /* Message SECTION to fetch */
char *partial; /* Message PARTIAL to fetch */
char *query; /* Query to search for */
Expand Down
2 changes: 1 addition & 1 deletion tests/data/Makefile.inc
Expand Up @@ -93,7 +93,7 @@ test809 test810 test811 test812 test813 test814 test815 test816 test817 \
test818 test819 test820 test821 test822 test823 test824 test825 test826 \
test827 test828 test829 test830 test831 test832 test833 test834 test835 \
test836 test837 test838 test839 test840 test841 test842 test843 test844 \
test845 test846 \
test845 test846 test847 \
\
test850 test851 test852 test853 test854 test855 test856 test857 test858 \
test859 test860 test861 test862 test863 test864 test865 test866 test867 \
Expand Down
2 changes: 1 addition & 1 deletion tests/data/test1321
Expand Up @@ -51,7 +51,7 @@ http
IMAP FETCH tunneled through HTTP proxy
</name>
<command>
'imap://imap.1321:%IMAPPORT/1321/;UID=1' -u user:secret -p -x %HOSTIP:%PROXYPORT
'imap://imap.1321:%IMAPPORT/1321/;MAILINDEX=1' -u user:secret -p -x %HOSTIP:%PROXYPORT
</command>
</client>

Expand Down
4 changes: 2 additions & 2 deletions tests/data/test1420
Expand Up @@ -36,7 +36,7 @@ imap
SSL_CERT_FILE=
</setenv>
<command>
'imap://%HOSTIP:%IMAPPORT/1420/;UID=1' -u user:secret --libcurl log/test1420.c
'imap://%HOSTIP:%IMAPPORT/1420/;MAILINDEX=1' -u user:secret --libcurl log/test1420.c
</command>
</client>

Expand Down Expand Up @@ -64,7 +64,7 @@ int main(int argc, char *argv[])

hnd = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
curl_easy_setopt(hnd, CURLOPT_URL, "imap://%HOSTIP:%IMAPPORT/1420/;UID=1");
curl_easy_setopt(hnd, CURLOPT_URL, "imap://%HOSTIP:%IMAPPORT/1420/;MAILINDEX=1");
curl_easy_setopt(hnd, CURLOPT_USERPWD, "user:secret");
curl_easy_setopt(hnd, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
Expand Down
2 changes: 1 addition & 1 deletion tests/data/test1552
Expand Up @@ -39,7 +39,7 @@ IMAP multi transfer error without curl_multi_remove_handle
lib1552
</tool>
<command>
'imap://%HOSTIP:%IMAPPORT/1552/;UID=1'
'imap://%HOSTIP:%IMAPPORT/1552/;MAILINDEX=1'
</command>
</client>

Expand Down
2 changes: 1 addition & 1 deletion tests/data/test800
Expand Up @@ -31,7 +31,7 @@ imap
IMAP FETCH message
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/800/;UID=1' -u '"user:sec"ret{'
'imap://%HOSTIP:%IMAPPORT/800/;MAILINDEX=1' -u '"user:sec"ret{'
</command>
</client>

Expand Down
4 changes: 2 additions & 2 deletions tests/data/test801
Expand Up @@ -25,10 +25,10 @@ body
imap
</server>
<name>
IMAP FETCH message by UID and SECTION
IMAP FETCH message by MAILINDEX and SECTION
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/801/;UID=123/;SECTION=1' -u user:secret
'imap://%HOSTIP:%IMAPPORT/801/;MAILINDEX=123/;SECTION=1' -u user:secret
</command>
</client>

Expand Down
2 changes: 1 addition & 1 deletion tests/data/test802
Expand Up @@ -29,7 +29,7 @@ imap
IMAP SELECT UIDVALIDITY Success
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/802;UIDVALIDITY=3857529045/;UID=123/;SECTION=TEXT' -u user:secret
'imap://%HOSTIP:%IMAPPORT/802;UIDVALIDITY=3857529045/;MAILINDEX=123/;SECTION=TEXT' -u user:secret
</command>
</client>

Expand Down
2 changes: 1 addition & 1 deletion tests/data/test803
Expand Up @@ -24,7 +24,7 @@ imap
IMAP SELECT UIDVALIDITY Failure
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/803;UIDVALIDITY=12345/;UID=123' -u user:secret
'imap://%HOSTIP:%IMAPPORT/803;UIDVALIDITY=12345/;MAILINDEX=123' -u user:secret
</command>
</client>

Expand Down
2 changes: 1 addition & 1 deletion tests/data/test804
Expand Up @@ -28,7 +28,7 @@ imap
IMAP doesn't perform SELECT if re-using the same mailbox
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/804/;UID=123/;SECTION=1' 'imap://%HOSTIP:%IMAPPORT/804/;UID=456/;SECTION=2.3' -u user:secret
'imap://%HOSTIP:%IMAPPORT/804/;MAILINDEX=123/;SECTION=1' 'imap://%HOSTIP:%IMAPPORT/804/;MAILINDEX=456/;SECTION=2.3' -u user:secret
</command>
</client>

Expand Down
2 changes: 1 addition & 1 deletion tests/data/test819
Expand Up @@ -37,7 +37,7 @@ imap
IMAP plain authentication
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/819/;UID=1' -u user:secret
'imap://%HOSTIP:%IMAPPORT/819/;MAILINDEX=1' -u user:secret
</command>
</client>

Expand Down
2 changes: 1 addition & 1 deletion tests/data/test820
Expand Up @@ -37,7 +37,7 @@ imap
IMAP login authentication
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/820/;UID=1' -u user:secret
'imap://%HOSTIP:%IMAPPORT/820/;MAILINDEX=1' -u user:secret
</command>
</client>

Expand Down
2 changes: 1 addition & 1 deletion tests/data/test821
Expand Up @@ -40,7 +40,7 @@ crypto
IMAP CRAM-MD5 authentication
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/821/;UID=1' -u user:secret
'imap://%HOSTIP:%IMAPPORT/821/;MAILINDEX=1' -u user:secret
</command>
</client>

Expand Down
2 changes: 1 addition & 1 deletion tests/data/test822
Expand Up @@ -48,7 +48,7 @@ CURL_GETHOSTNAME=curlhost
LD_PRELOAD=%PWD/libtest/.libs/libhostname.so
</setenv>
<command>
'imap://%HOSTIP:%IMAPPORT/822/;UID=1' -u testuser:testpass
'imap://%HOSTIP:%IMAPPORT/822/;MAILINDEX=1' -u testuser:testpass
</command>
<precheck>
chkhostname curlhost
Expand Down
2 changes: 1 addition & 1 deletion tests/data/test823
Expand Up @@ -43,7 +43,7 @@ crypto
IMAP DIGEST-MD5 authentication
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/823/;UID=1' -u user:secret
'imap://%HOSTIP:%IMAPPORT/823/;MAILINDEX=1' -u user:secret
</command>
</client>

Expand Down
2 changes: 1 addition & 1 deletion tests/data/test824
Expand Up @@ -37,7 +37,7 @@ imap
IMAP OAuth 2.0 (XOAUTH2) authentication
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/824/;UID=1' -u user --oauth2-bearer mF_9.B5f-4.1JqM
'imap://%HOSTIP:%IMAPPORT/824/;MAILINDEX=1' -u user --oauth2-bearer mF_9.B5f-4.1JqM
</command>
</client>

Expand Down
2 changes: 1 addition & 1 deletion tests/data/test825
Expand Up @@ -38,7 +38,7 @@ imap
IMAP plain authentication with initial response
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/825/;UID=1' -u user:secret
'imap://%HOSTIP:%IMAPPORT/825/;MAILINDEX=1' -u user:secret
</command>
</client>

Expand Down
2 changes: 1 addition & 1 deletion tests/data/test826
Expand Up @@ -38,7 +38,7 @@ imap
IMAP login authentication with initial response
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/826/;UID=1' -u user:secret
'imap://%HOSTIP:%IMAPPORT/826/;MAILINDEX=1' -u user:secret
</command>
</client>

Expand Down
2 changes: 1 addition & 1 deletion tests/data/test827
Expand Up @@ -49,7 +49,7 @@ CURL_GETHOSTNAME=curlhost
LD_PRELOAD=%PWD/libtest/.libs/libhostname.so
</setenv>
<command>
'imap://%HOSTIP:%IMAPPORT/827/;UID=1' -u testuser:testpass
'imap://%HOSTIP:%IMAPPORT/827/;MAILINDEX=1' -u testuser:testpass
</command>
<precheck>
chkhostname curlhost
Expand Down
2 changes: 1 addition & 1 deletion tests/data/test828
Expand Up @@ -38,7 +38,7 @@ imap
IMAP OAuth 2.0 (XOAUTH2) authentication with initial response
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/828/;UID=1' -u user --oauth2-bearer mF_9.B5f-4.1JqM
'imap://%HOSTIP:%IMAPPORT/828/;MAILINDEX=1' -u user --oauth2-bearer mF_9.B5f-4.1JqM
</command>
</client>

Expand Down
2 changes: 1 addition & 1 deletion tests/data/test830
Expand Up @@ -33,7 +33,7 @@ crypto
IMAP CRAM-MD5 graceful cancellation
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/830/;UID=1' -u user:secret
'imap://%HOSTIP:%IMAPPORT/830/;MAILINDEX=1' -u user:secret
</command>
</client>

Expand Down
2 changes: 1 addition & 1 deletion tests/data/test831
Expand Up @@ -40,7 +40,7 @@ CURL_GETHOSTNAME=curlhost
LD_PRELOAD=%PWD/libtest/.libs/libhostname.so
</setenv>
<command>
'imap://%HOSTIP:%IMAPPORT/831/;UID=1' -u testuser:testpass
'imap://%HOSTIP:%IMAPPORT/831/;MAILINDEX=1' -u testuser:testpass
</command>
<precheck>
chkhostname curlhost
Expand Down
2 changes: 1 addition & 1 deletion tests/data/test832
Expand Up @@ -35,7 +35,7 @@ crypto
IMAP DIGEST-MD5 graceful cancellation
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/832/;UID=1' -u user:secret
'imap://%HOSTIP:%IMAPPORT/832/;MAILINDEX=1' -u user:secret
</command>
</client>

Expand Down
2 changes: 1 addition & 1 deletion tests/data/test833
Expand Up @@ -44,7 +44,7 @@ crypto
IMAP CRAM-MD5 authentication with SASL downgrade
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/833/;UID=1' -u user:secret
'imap://%HOSTIP:%IMAPPORT/833/;MAILINDEX=1' -u user:secret
</command>
</client>

Expand Down
2 changes: 1 addition & 1 deletion tests/data/test834
Expand Up @@ -51,7 +51,7 @@ CURL_GETHOSTNAME=curlhost
LD_PRELOAD=%PWD/libtest/.libs/libhostname.so
</setenv>
<command>
'imap://%HOSTIP:%IMAPPORT/834/;UID=1' -u user:secret
'imap://%HOSTIP:%IMAPPORT/834/;MAILINDEX=1' -u user:secret
</command>
<precheck>
chkhostname curlhost
Expand Down
2 changes: 1 addition & 1 deletion tests/data/test835
Expand Up @@ -46,7 +46,7 @@ crypto
IMAP DIGEST-MD5 authentication with SASL downgrade
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/835/;UID=1' -u user:secret
'imap://%HOSTIP:%IMAPPORT/835/;MAILINDEX=1' -u user:secret
</command>
</client>

Expand Down
2 changes: 1 addition & 1 deletion tests/data/test836
Expand Up @@ -36,7 +36,7 @@ imap
IMAP multiple connection authentication
</name>
<command>
'imap://%HOSTIP:%IMAPPORT/836/;UID=1' -u user.one:secret -: 'imap://%HOSTIP:%IMAPPORT/836/;UID=2' -u user.two:secret
'imap://%HOSTIP:%IMAPPORT/836/;MAILINDEX=1' -u user.one:secret -: 'imap://%HOSTIP:%IMAPPORT/836/;UID=2' -u user.two:secret
</command>
</client>

Expand Down
2 changes: 1 addition & 1 deletion tests/data/test837
Expand Up @@ -37,7 +37,7 @@ imap
IMAP external authentication
</name>
<command>
'imap://user;AUTH=EXTERNAL@%HOSTIP:%IMAPPORT/837/;UID=1'
'imap://user;AUTH=EXTERNAL@%HOSTIP:%IMAPPORT/837/;MAILINDEX=1'
</command>
</client>

Expand Down

0 comments on commit 4d8bbe4

Please sign in to comment.