From: Daniel Stenberg Date: Wed, 22 Oct 2025 09:25:42 +0000 (+0200) Subject: imap: parse and use UIDVALIDITY as a number X-Git-Tag: rc-8_17_0-3~62 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=fb6a4802d7a76d8e36652bedbf6c03270b541974;p=thirdparty%2Fcurl.git imap: parse and use UIDVALIDITY as a number Instead of a string. Saves a malloc, adds earlier format check. RFC 3501 section 2.3.1.1 documents the value as a 32-bit value. Closes #19188 --- diff --git a/lib/imap.c b/lib/imap.c index 0feaedf5ac..8cbda96a05 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -115,8 +115,8 @@ struct imap_conn { struct SASL sasl; /* SASL-related parameters */ struct dynbuf dyn; /* for the IMAP commands */ char *mailbox; /* The last selected mailbox */ - char *mailbox_uidvalidity; /* UIDVALIDITY parsed from select response */ imapstate state; /* Always use imap.c:state() to change state! */ + unsigned int mb_uidvalidity; /* UIDVALIDITY parsed from select response */ char resptag[5]; /* Response tag to wait for */ unsigned char preftype; /* Preferred authentication type */ unsigned char cmdid; /* Last used command ID */ @@ -125,6 +125,7 @@ struct imap_conn { BIT(tls_supported); /* StartTLS capability supported by server */ BIT(login_disabled); /* LOGIN command disabled by server */ BIT(ir_supported); /* Initial response supported by server */ + BIT(mb_uidvalidity_set); }; /* This IMAP struct is used in the Curl_easy. All IMAP data that is @@ -134,7 +135,6 @@ struct imap_conn { struct IMAP { curl_pp_transfer transfer; 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 */ @@ -142,6 +142,8 @@ struct IMAP { char *query; /* Query to search for */ char *custom; /* Custom request */ char *custom_params; /* Parameters for the custom request */ + unsigned int uidvalidity; /* UIDVALIDITY to check in select */ + BIT(uidvalidity_set); }; @@ -780,7 +782,6 @@ static CURLcode imap_perform_select(struct Curl_easy *data, /* Invalidate old information as we are switching mailboxes */ Curl_safefree(imapc->mailbox); - Curl_safefree(imapc->mailbox_uidvalidity); /* Check we have a mailbox */ if(!imap->mailbox) { @@ -1222,24 +1223,19 @@ static CURLcode imap_state_select_resp(struct Curl_easy *data, if(imapcode == '*') { /* See if this is an UIDVALIDITY response */ if(checkprefix("OK [UIDVALIDITY ", line + 2)) { - size_t len = 0; + curl_off_t value; const char *p = &line[2] + strlen("OK [UIDVALIDITY "); - while((len < 20) && p[len] && ISDIGIT(p[len])) - len++; - if(len && (p[len] == ']')) { - struct dynbuf uid; - curlx_dyn_init(&uid, 20); - if(curlx_dyn_addn(&uid, p, len)) - return CURLE_OUT_OF_MEMORY; - free(imapc->mailbox_uidvalidity); - imapc->mailbox_uidvalidity = curlx_dyn_ptr(&uid); + if(!curlx_str_number(&p, &value, UINT_MAX)) { + imapc->mb_uidvalidity = (unsigned int)value; + imapc->mb_uidvalidity_set = TRUE; } + } } else if(imapcode == IMAP_RESP_OK) { /* Check if the UIDVALIDITY has been specified and matches */ - if(imap->uidvalidity && imapc->mailbox_uidvalidity && - !curl_strequal(imap->uidvalidity, imapc->mailbox_uidvalidity)) { + if(imap->uidvalidity_set && imapc->mb_uidvalidity_set && + (imap->uidvalidity != imapc->mb_uidvalidity)) { failf(data, "Mailbox UIDVALIDITY has changed"); result = CURLE_REMOTE_FILE_NOT_FOUND; } @@ -1690,8 +1686,8 @@ static CURLcode imap_perform(struct Curl_easy *data, bool *connected, has already been selected on this connection */ if(imap->mailbox && imapc->mailbox && curl_strequal(imap->mailbox, imapc->mailbox) && - (!imap->uidvalidity || !imapc->mailbox_uidvalidity || - curl_strequal(imap->uidvalidity, imapc->mailbox_uidvalidity))) + (!imap->uidvalidity_set || !imapc->mb_uidvalidity_set || + (imap->uidvalidity == imapc->mb_uidvalidity))) selected = TRUE; /* Start the first command in the DO phase */ @@ -1861,7 +1857,6 @@ static CURLcode imap_regular_transfer(struct Curl_easy *data, static void imap_easy_reset(struct IMAP *imap) { Curl_safefree(imap->mailbox); - Curl_safefree(imap->uidvalidity); Curl_safefree(imap->uid); Curl_safefree(imap->mindex); Curl_safefree(imap->section); @@ -1890,7 +1885,6 @@ static void imap_conn_dtor(void *key, size_t klen, void *entry) Curl_pp_disconnect(&imapc->pp); curlx_dyn_free(&imapc->dyn); Curl_safefree(imapc->mailbox); - Curl_safefree(imapc->mailbox_uidvalidity); free(imapc); } @@ -2177,54 +2171,45 @@ static CURLcode imap_parse_url_path(struct Curl_easy *data, DEBUGF(infof(data, "IMAP URL parameter '%s' = '%s'", name, value)); - /* Process the known hierarchical parameters (UIDVALIDITY, UID, SECTION and - PARTIAL) stripping of the trailing slash character if it is present. + /* Process the known hierarchical parameters (UIDVALIDITY, UID, SECTION + and PARTIAL) stripping of the trailing slash character if it is + present. Note: Unknown parameters trigger a URL_MALFORMAT error. */ - if(curl_strequal(name, "UIDVALIDITY") && !imap->uidvalidity) { - if(valuelen > 0 && value[valuelen - 1] == '/') - value[valuelen - 1] = '\0'; - - imap->uidvalidity = value; - value = NULL; - } - else if(curl_strequal(name, "UID") && !imap->uid) { - if(valuelen > 0 && value[valuelen - 1] == '/') - value[valuelen - 1] = '\0'; - - imap->uid = value; - value = NULL; - } - else if(curl_strequal(name, "MAILINDEX") && !imap->mindex) { - if(valuelen > 0 && value[valuelen - 1] == '/') - value[valuelen - 1] = '\0'; - - imap->mindex = value; - value = NULL; - } - else if(curl_strequal(name, "SECTION") && !imap->section) { - if(valuelen > 0 && value[valuelen - 1] == '/') - value[valuelen - 1] = '\0'; - - imap->section = value; - value = NULL; - } - else if(curl_strequal(name, "PARTIAL") && !imap->partial) { - if(valuelen > 0 && value[valuelen - 1] == '/') - value[valuelen - 1] = '\0'; - - imap->partial = value; - value = NULL; + if(valuelen > 0 && value[valuelen - 1] == '/') + value[valuelen - 1] = '\0'; + if(valuelen) { + if(curl_strequal(name, "UIDVALIDITY") && !imap->uidvalidity_set) { + curl_off_t num; + const char *p = (const char *)value; + if(!curlx_str_number(&p, &num, UINT_MAX)) { + imap->uidvalidity = (unsigned int)num; + imap->uidvalidity_set = TRUE; + } + free(value); + } + else if(curl_strequal(name, "UID") && !imap->uid) { + imap->uid = value; + } + else if(curl_strequal(name, "MAILINDEX") && !imap->mindex) { + imap->mindex = value; + } + else if(curl_strequal(name, "SECTION") && !imap->section) { + imap->section = value; + } + else if(curl_strequal(name, "PARTIAL") && !imap->partial) { + imap->partial = value; + } + else { + free(name); + free(value); + return CURLE_URL_MALFORMAT; + } } - else { - free(name); + else + /* blank? */ free(value); - - return CURLE_URL_MALFORMAT; - } - free(name); - free(value); } /* Does the URL contain a query parameter? Only valid when we have a mailbox