This commit is contained in:
tiymat 2025-03-01 01:40:16 +08:00 committed by GitHub
commit fe69f98c58
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 386 additions and 15 deletions

View File

@ -92,7 +92,6 @@
9. IMAP
9.1 Enhanced capability support
9.2 upload unread
10. LDAP
10.1 SASL based authentication mechanisms
@ -721,12 +720,6 @@
Add the ability, for an application that uses libcurl, to obtain the list of
capabilities returned from the CAPABILITY command.
9.2 upload unread
Uploads over IMAP currently always set the email as "read" (or "seen"). It
would be good to offer a way for users to select for uploads to remain
unread.
10. LDAP
10.1 SASL based authentication mechanisms

View File

@ -301,6 +301,7 @@ DPAGES = \
trace.md \
unix-socket.md \
upload-file.md \
upload-flags.md \
url.md \
url-query.md \
use-ascii.md \

View File

@ -31,7 +31,7 @@ filename or curl thinks that your last directory name is the remote filename
to use.
When putting the local filename at the end of the URL, curl ignores what is on
the left side of any slash (/) or backslash (\) used in the filename and only
the left side of any slash (/) or backslash (\\) used in the filename and only
appends what is on the right side of the rightmost such character.
Use the filename `-` (a single dash) to use stdin instead of a given file.

View File

@ -0,0 +1,23 @@
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Long: upload-flags
Arg: <flags>
Help: Specify additional upload behavior
Category: curl output
Added: 8.13.0
Multi: single
See-also:
- upload-file
Example:
- --upload-flags Flagged,!Seen --upload-file local/dir/file $URL
---
# `--upload-flags`
Specify additional behavior to apply to uploaded files. Flags are
specified as either a single flag value or a comma-separated list
of flag values. Flag values may be negated by prepending them with
a '!' character. Currently the following case-sensitive flag values
are accepted: Answered, Deleted, Draft, Flagged, and Seen. The
currently-accepted flag values are used to set flags on IMAP uploads.

View File

@ -81,7 +81,7 @@ int Curl_str_quotedword(char **linep, struct Curl_str *out, const size_t max);
~~~
Get a "quoted" word. This means everything that is provided within a leading
and an ending double character. No escaping possible.
and an ending double quote character. No escaping possible.
`max` is the longest accepted word, or it returns error.

View File

@ -1273,6 +1273,10 @@ Upload data. See CURLOPT_UPLOAD(3)
Set upload buffer size. See CURLOPT_UPLOAD_BUFFERSIZE(3)
## CURLOPT_UPLOAD_FLAGS
Set upload flags. See CURLOPT_UPLOAD_FLAGS(3)
## CURLOPT_URL
URL to work on. See CURLOPT_URL(3)

View File

@ -0,0 +1,100 @@
---
c: Copyright (C) Daniel Stenberg, <daniel.se>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_UPLOAD_FLAGS
Section: 3
Source: libcurl
See-also:
- CURLOPT_UPLOAD (3)
Protocol:
- IMAP
- IMAPS
Added-in: 8.13.0
---
# NAME
CURLOPT_UPLOAD_FLAGS - configure upload flags
# SYNOPSIS
~~~c
#include <curl/curl.h>
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_UPLOAD_FLAGS, long bitmask);
~~~
# DESCRIPTION
Pass a long as parameter, which is set to a bitmask, to tell libcurl which
flags to send the server relating to uploaded files. The current supported
flags are **CURLULFLAG_ANSWERED**, which sets the **Answered** flag for IMAP
uploads, **CURLULFLAG_DELETED**, which sets the **Deleted** flag for IMAP
uploads, **CURLULFLAG_DRAFT**, which sets the **Draft** flag for IMAP uploads,
**CURLULFLAG_FLAGGED**, which sets the **Flagged** flag for IMAP uploads, and
**CURLULFLAG_SEEN**, which sets the **Seen** flag for IMAP uploads.
# DEFAULT
A bitmask with only the **CURLULFLAG_SEEN** flag set.
# %PROTOCOLS%
# EXAMPLE
~~~c
static size_t read_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
{
FILE *src = userdata;
/* copy as much data as possible into the 'ptr' buffer, but no more than
'size' * 'nmemb' bytes */
size_t retcode = fread(ptr, size, nmemb, src);
return retcode;
}
int main(void)
{
CURL *curl = curl_easy_init();
if(curl) {
FILE *src = fopen("local-file", "r");
curl_off_t fsize; /* set this to the size of the input file */
/* we want to use our own read function */
curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_cb);
/* enable uploading */
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
/* specify target */
curl_easy_setopt(curl, CURLOPT_URL, "imap://example.com:993/mailbox");
/* provide username */
curl_easy_setopt(curl, CURLOPT_USERNAME, "user@example.com");
/* provide password */
curl_easy_setopt(curl, CURLOPT_PASSWORD, "password");
/* specify that uploaded mail should be considered flagged */
curl_easy_setopt(curl, CURLOPT_UPLOAD_FLAGS, CURLULFLAG_FLAGGED);
/* now specify which pointer to pass to our callback */
curl_easy_setopt(curl, CURLOPT_READDATA, src);
/* Set the size of the file to upload */
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fsize);
/* perform the upload */
curl_easy_perform(curl);
}
}
~~~
# %AVAILABILITY%
# RETURN VALUE
curl_easy_setopt(3) returns a CURLcode indicating success or error.
CURLE_OK (0) means everything was OK, non-zero means an error occurred, see
libcurl-errors(3).

View File

@ -411,6 +411,7 @@ man_MANS = \
CURLOPT_UPKEEP_INTERVAL_MS.3 \
CURLOPT_UPLOAD.3 \
CURLOPT_UPLOAD_BUFFERSIZE.3 \
CURLOPT_UPLOAD_FLAGS.3 \
CURLOPT_URL.3 \
CURLOPT_USE_SSL.3 \
CURLOPT_USERAGENT.3 \

View File

@ -892,6 +892,7 @@ CURLOPT_UNRESTRICTED_AUTH 7.10.4
CURLOPT_UPKEEP_INTERVAL_MS 7.62.0
CURLOPT_UPLOAD 7.1
CURLOPT_UPLOAD_BUFFERSIZE 7.62.0
CURLOPT_UPLOAD_FLAGS 8.13.0
CURLOPT_URL 7.1
CURLOPT_USE_SSL 7.17.0
CURLOPT_USERAGENT 7.1
@ -1125,6 +1126,11 @@ CURLUPART_SCHEME 7.62.0
CURLUPART_URL 7.62.0
CURLUPART_USER 7.62.0
CURLUPART_ZONEID 7.65.0
CURLULFLAG_ANSWERED 8.13.0
CURLULFLAG_DELETED 8.13.0
CURLULFLAG_DRAFT 8.13.0
CURLULFLAG_FLAGGED 8.13.0
CURLULFLAG_SEEN 8.13.0
CURLUSESSL_ALL 7.17.0
CURLUSESSL_CONTROL 7.17.0
CURLUSESSL_NONE 7.17.0

View File

@ -266,6 +266,7 @@
--trace-time 7.14.0
--unix-socket 7.40.0
--upload-file (-T) 4.0
--upload-flags 8.13.0
--url 7.5
--url-query 7.87.0
--use-ascii (-B) 5.0

View File

@ -1013,6 +1013,12 @@ typedef enum {
#define CURLALTSVC_H2 (1<<4)
#define CURLALTSVC_H3 (1<<5)
/* bitmask values for CURLOPT_UPLOAD_FLAGS */
#define CURLULFLAG_ANSWERED (((unsigned char)1)<<0)
#define CURLULFLAG_DELETED (((unsigned char)1)<<1)
#define CURLULFLAG_DRAFT (((unsigned char)1)<<2)
#define CURLULFLAG_FLAGGED (((unsigned char)1)<<3)
#define CURLULFLAG_SEEN (((unsigned char)1)<<4)
struct curl_hstsentry {
char *name;
@ -2226,6 +2232,8 @@ typedef enum {
/* maximum number of keepalive probes (Linux, *BSD, macOS, etc.) */
CURLOPT(CURLOPT_TCP_KEEPCNT, CURLOPTTYPE_LONG, 326),
CURLOPT(CURLOPT_UPLOAD_FLAGS, CURLOPTTYPE_LONG, 327),
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;

View File

@ -353,6 +353,7 @@ struct curl_easyoption Curl_easyopts[] = {
{"UPKEEP_INTERVAL_MS", CURLOPT_UPKEEP_INTERVAL_MS, CURLOT_LONG, 0},
{"UPLOAD", CURLOPT_UPLOAD, CURLOT_LONG, 0},
{"UPLOAD_BUFFERSIZE", CURLOPT_UPLOAD_BUFFERSIZE, CURLOT_LONG, 0},
{"UPLOAD_FLAGS", CURLOPT_UPLOAD_FLAGS, CURLOT_LONG, 0},
{"URL", CURLOPT_URL, CURLOT_STRING, 0},
{"USERAGENT", CURLOPT_USERAGENT, CURLOT_STRING, 0},
{"USERNAME", CURLOPT_USERNAME, CURLOT_STRING, 0},
@ -377,6 +378,6 @@ struct curl_easyoption Curl_easyopts[] = {
*/
int Curl_easyopts_check(void)
{
return (CURLOPT_LASTENTRY % 10000) != (326 + 1);
return (CURLOPT_LASTENTRY % 10000) != (327 + 1);
}
#endif

View File

@ -36,6 +36,7 @@
***************************************************************************/
#include "curl_setup.h"
#include "dynbuf.h"
#ifndef CURL_DISABLE_IMAP
@ -192,6 +193,11 @@ static const struct SASLproto saslimap = {
SASL_FLAG_BASE64 /* Configuration flags */
};
struct ulbits {
int bit;
const char *flag;
};
/***********************************************************************
*
@ -760,6 +766,7 @@ static CURLcode imap_perform_append(struct Curl_easy *data)
CURLcode result = CURLE_OK;
struct IMAP *imap = data->req.p.imap;
char *mailbox;
struct dynbuf flags;
/* Check we have a mailbox */
if(!imap->mailbox) {
@ -808,10 +815,43 @@ static CURLcode imap_perform_append(struct Curl_easy *data)
if(!mailbox)
return CURLE_OUT_OF_MEMORY;
/* Send the APPEND command */
result = imap_sendf(data, "APPEND %s (\\Seen) {%" FMT_OFF_T "}",
mailbox, data->state.infilesize);
/* Generate flags string and send the APPEND command */
Curl_dyn_init(&flags, 100);
if(data->set.upload_flags) {
int i;
struct ulbits ulflag[] = {
{CURLULFLAG_ANSWERED, "Answered"},
{CURLULFLAG_DELETED, "Deleted"},
{CURLULFLAG_DRAFT, "Draft"},
{CURLULFLAG_FLAGGED, "Flagged"},
{CURLULFLAG_SEEN, "Seen"},
{0, NULL}
};
result = CURLE_OUT_OF_MEMORY;
if(Curl_dyn_add(&flags, " (")) {
goto cleanup;
}
for(i = 0; ulflag[i].bit; i++) {
if(data->set.upload_flags & ulflag[i].bit) {
if((Curl_dyn_len(&flags) > 2 && Curl_dyn_add(&flags, " ")) ||
Curl_dyn_add(&flags, "\\") || Curl_dyn_add(&flags, ulflag[i].flag))
goto cleanup;
}
}
if(Curl_dyn_add(&flags, ")"))
goto cleanup;
}
else if(Curl_dyn_add(&flags, ""))
goto cleanup;
result = imap_sendf(data, "APPEND %s%s {%" FMT_OFF_T "}",
mailbox, Curl_dyn_ptr(&flags), data->state.infilesize);
cleanup:
Curl_dyn_free(&flags);
free(mailbox);
if(!result)

View File

@ -1401,7 +1401,9 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option,
*/
Curl_safefree(data->set.str[STRING_SSL_ENGINE]);
return Curl_ssl_set_engine_default(data);
case CURLOPT_UPLOAD_FLAGS:
data->set.upload_flags = (unsigned char)arg;
break;
default:
/* unknown option */
return CURLE_UNKNOWN_OPTION;

View File

@ -1593,6 +1593,7 @@ struct UserDefined {
struct curl_slist *connect_to; /* list of host:port mappings to override
the hostname and port to connect to */
time_t timevalue; /* what time to compare with */
unsigned char upload_flags;
struct ssl_config_data ssl; /* user defined SSL stuff */
#ifndef CURL_DISABLE_PROXY
struct ssl_config_data proxy_ssl; /* user defined SSL stuff for proxy */

View File

@ -45,6 +45,7 @@ void config_init(struct OperationConfig *config)
config->http09_allowed = FALSE;
config->ftp_skip_ip = TRUE;
config->file_clobber_mode = CLOBBER_DEFAULT;
config->upload_flags = CURLULFLAG_SEEN;
curlx_dyn_init(&config->postdata, MAX_FILE2MEMORY);
}

View File

@ -163,6 +163,7 @@ struct OperationConfig {
char *ech; /* Config set by --ech keywords */
char *ech_config; /* Config set by "--ech esl:" option */
char *ech_public; /* Config set by "--ech pn:" option */
unsigned char upload_flags; /* Bitmask for --upload-flags */
struct GlobalConfig *global;
struct OperationConfig *prev;
struct OperationConfig *next; /* Always last in the struct */

View File

@ -339,6 +339,7 @@ static const struct LongShort aliases[]= {
{"trace-time", ARG_BOOL, ' ', C_TRACE_TIME},
{"unix-socket", ARG_FILE, ' ', C_UNIX_SOCKET},
{"upload-file", ARG_FILE, 'T', C_UPLOAD_FILE},
{"upload-flags", ARG_STRG, ' ', C_UPLOAD_FLAGS},
{"url", ARG_STRG, ' ', C_URL},
{"url-query", ARG_STRG, ' ', C_URL_QUERY},
{"use-ascii", ARG_BOOL, 'B', C_USE_ASCII},
@ -1622,6 +1623,57 @@ static ParameterError parse_time_cond(struct GlobalConfig *global,
return err;
}
static ParameterError parse_upload_flags(struct OperationConfig *config,
char *nextarg)
{
char *tmp, *upload_flag;
ParameterError err = PARAM_OK;
size_t flag_len;
tmp = strdup(nextarg);
if(!tmp)
return PARAM_NO_MEM;
/* Allow strtok() here since this is not used threaded */
/* !checksrc! disable BANNEDFUNC 2 */
upload_flag = strtok(tmp, ",");
while(upload_flag) {
flag_len = strlen(upload_flag);
if(flag_len == 8 && !strncmp(upload_flag, "Answered", 8))
config->upload_flags |= CURLULFLAG_ANSWERED;
else if(flag_len == 9 && !strncmp(upload_flag, "!Answered", 9))
config->upload_flags &= (unsigned char)~CURLULFLAG_ANSWERED;
else if(flag_len == 7 && !strncmp(upload_flag, "Deleted", 7))
config->upload_flags |= CURLULFLAG_DELETED;
else if(flag_len == 8 && !strncmp(upload_flag, "!Deleted", 8))
config->upload_flags &= (unsigned char)~CURLULFLAG_DELETED;
else if(flag_len == 5 && !strncmp(upload_flag, "Draft", 5))
config->upload_flags |= CURLULFLAG_DRAFT;
else if(flag_len == 6 && !strncmp(upload_flag, "!Draft", 6))
config->upload_flags &= (unsigned char)~CURLULFLAG_DRAFT;
else if(flag_len == 7 && !strncmp(upload_flag, "Flagged", 7))
config->upload_flags |= CURLULFLAG_FLAGGED;
else if(flag_len == 8 && !strncmp(upload_flag, "!Flagged", 8))
config->upload_flags &= (unsigned char)~CURLULFLAG_FLAGGED;
else if(flag_len == 4 && !strncmp(upload_flag, "Seen", 4))
config->upload_flags |= CURLULFLAG_SEEN;
else if(flag_len == 5 && !strncmp(upload_flag, "!Seen", 5))
config->upload_flags &= (unsigned char)~CURLULFLAG_SEEN;
else {
err = PARAM_OPTION_UNKNOWN;
break;
}
upload_flag = strtok(NULL, ",");
}
free(tmp);
return err;
}
ParameterError getparameter(const char *flag, /* f or -long-flag */
char *nextarg, /* NULL if unset */
argv_item_t cleararg1,
@ -2909,6 +2961,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
case C_MPTCP: /* --mptcp */
config->mptcp = TRUE;
break;
case C_UPLOAD_FLAGS: /* --upload-flags */
err = parse_upload_flags(config, nextarg);
break;
default: /* unknown flag */
err = PARAM_OPTION_UNKNOWN;
break;

View File

@ -293,6 +293,7 @@ typedef enum {
C_IP_TOS,
C_UNIX_SOCKET,
C_UPLOAD_FILE,
C_UPLOAD_FLAGS,
C_URL,
C_URL_QUERY,
C_USE_ASCII,

View File

@ -808,6 +808,9 @@ const struct helptxt helptext[] = {
{"-T, --upload-file <file>",
"Transfer local FILE to destination",
CURLHELP_IMPORTANT | CURLHELP_UPLOAD},
{" --upload-flags <flags>",
"Specify additional upload behavior",
CURLHELP_CURL | CURLHELP_OUTPUT},
{" --url <url/file>",
"URL(s) to work with",
CURLHELP_CURL},

View File

@ -1749,6 +1749,9 @@ static CURLcode config2setopts(struct GlobalConfig *global,
}
#endif
}
/* new in 8.13.0 */
if(config->upload_flags)
my_setopt(curl, CURLOPT_UPLOAD_FLAGS, (long)config->upload_flags);
return result;
}

View File

@ -164,6 +164,7 @@ static const struct NameValue setopt_nv_CURLNONZERODEFAULTS[] = {
NV1(CURLOPT_PROXY_SSL_VERIFYPEER, 1),
NV1(CURLOPT_PROXY_SSL_VERIFYHOST, 1),
NV1(CURLOPT_SOCKS5_AUTH, 1),
NV1(CURLOPT_UPLOAD_FLAGS, CURLULFLAG_SEEN),
NVEND
};

View File

@ -272,6 +272,7 @@ test3032 \
\
test3100 test3101 test3102 test3103 test3104 test3105 \
test3200 \
test3201 test3202 test3203 test3204 test3205 test3207 test3208
test3201 test3202 test3203 test3204 test3205 test3207 test3208 test3209 \
test3210
EXTRA_DIST = $(TESTCASES) DISABLED

62
tests/data/test3209 Normal file
View File

@ -0,0 +1,62 @@
<testcase>
<info>
<keywords>
IMAP
Clear Text
APPEND
UPLOAD
</keywords>
</info>
#
# Server-side
<reply>
</reply>
#
# Client-side
<client>
<server>
imap
</server>
<name>
Upload message via IMAP with upload flags
</name>
<command>
imap://%HOSTIP:%IMAPPORT/%TESTNUMBER -T %LOGDIR/upload%TESTNUMBER -u user:secret --upload-flags Answered,Deleted,Draft,Flagged,Seen
</command>
<file name="%LOGDIR/upload%TESTNUMBER">
Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
From: Fred Foobar <foobar@example.COM>
Subject: afternoon meeting
To: joe@example.com
Message-Id: <B27397-0100000@example.COM>
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
Hello Joe, do you think we can meet at 3:30 tomorrow?
</file>
</client>
#
# Verify data after the test has been "shot"
<verify>
<protocol crlf="yes">
A001 CAPABILITY
A002 LOGIN user secret
A003 APPEND %TESTNUMBER (\Answered \Deleted \Draft \Flagged \Seen) {286}
A004 LOGOUT
</protocol>
<upload>
Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
From: Fred Foobar <foobar@example.COM>
Subject: afternoon meeting
To: joe@example.com
Message-Id: <B27397-0100000@example.COM>
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
Hello Joe, do you think we can meet at 3:30 tomorrow?
</upload>
</verify>
</testcase>

62
tests/data/test3210 Normal file
View File

@ -0,0 +1,62 @@
<testcase>
<info>
<keywords>
IMAP
Clear Text
APPEND
UPLOAD
</keywords>
</info>
#
# Server-side
<reply>
</reply>
#
# Client-side
<client>
<server>
imap
</server>
<name>
Upload message unread via IMAP
</name>
<command>
imap://%HOSTIP:%IMAPPORT/%TESTNUMBER -T %LOGDIR/upload%TESTNUMBER -u user:secret --upload-flags !Seen
</command>
<file name="%LOGDIR/upload%TESTNUMBER">
Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
From: Fred Foobar <foobar@example.COM>
Subject: afternoon meeting
To: joe@example.com
Message-Id: <B27397-0100000@example.COM>
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</file>
</client>
#
# Verify data after the test has been "shot"
<verify>
<protocol crlf="yes">
A001 CAPABILITY
A002 LOGIN user secret
A003 APPEND %TESTNUMBER {356}
A004 LOGOUT
</protocol>
<upload>
Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
From: Fred Foobar <foobar@example.COM>
Subject: afternoon meeting
To: joe@example.com
Message-Id: <B27397-0100000@example.COM>
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</upload>
</verify>
</testcase>