diff --git a/docs/TODO b/docs/TODO index 62affea011..d4890f95d0 100644 --- a/docs/TODO +++ b/docs/TODO @@ -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 diff --git a/docs/cmdline-opts/Makefile.inc b/docs/cmdline-opts/Makefile.inc index be6fadd26b..3cc44c9896 100644 --- a/docs/cmdline-opts/Makefile.inc +++ b/docs/cmdline-opts/Makefile.inc @@ -301,6 +301,7 @@ DPAGES = \ trace.md \ unix-socket.md \ upload-file.md \ + upload-flags.md \ url.md \ url-query.md \ use-ascii.md \ diff --git a/docs/cmdline-opts/upload-file.md b/docs/cmdline-opts/upload-file.md index 7e9ffbf1e6..5a2842e58a 100644 --- a/docs/cmdline-opts/upload-file.md +++ b/docs/cmdline-opts/upload-file.md @@ -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. diff --git a/docs/cmdline-opts/upload-flags.md b/docs/cmdline-opts/upload-flags.md new file mode 100644 index 0000000000..b935f3f261 --- /dev/null +++ b/docs/cmdline-opts/upload-flags.md @@ -0,0 +1,23 @@ +--- +c: Copyright (C) Daniel Stenberg, , et al. +SPDX-License-Identifier: curl +Long: upload-flags +Arg: +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. diff --git a/docs/internals/STRPARSE.md b/docs/internals/STRPARSE.md index b6117df9ac..82fae94bda 100644 --- a/docs/internals/STRPARSE.md +++ b/docs/internals/STRPARSE.md @@ -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. diff --git a/docs/libcurl/curl_easy_setopt.md b/docs/libcurl/curl_easy_setopt.md index b6e08912ee..bf5f90e25f 100644 --- a/docs/libcurl/curl_easy_setopt.md +++ b/docs/libcurl/curl_easy_setopt.md @@ -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) diff --git a/docs/libcurl/opts/CURLOPT_UPLOAD_FLAGS.md b/docs/libcurl/opts/CURLOPT_UPLOAD_FLAGS.md new file mode 100644 index 0000000000..10327eeb2f --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_UPLOAD_FLAGS.md @@ -0,0 +1,100 @@ +--- +c: Copyright (C) Daniel Stenberg, , 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 + +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). diff --git a/docs/libcurl/opts/Makefile.inc b/docs/libcurl/opts/Makefile.inc index 9d8606dd06..24f668cb07 100644 --- a/docs/libcurl/opts/Makefile.inc +++ b/docs/libcurl/opts/Makefile.inc @@ -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 \ diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index 0b566edbc3..86fd0c0b7d 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -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 diff --git a/docs/options-in-versions b/docs/options-in-versions index 057cbafccd..fceff631bf 100644 --- a/docs/options-in-versions +++ b/docs/options-in-versions @@ -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 diff --git a/include/curl/curl.h b/include/curl/curl.h index 346872b39d..313fbee4f5 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -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; diff --git a/lib/easyoptions.c b/lib/easyoptions.c index f2ced2cb50..be617b5d2a 100644 --- a/lib/easyoptions.c +++ b/lib/easyoptions.c @@ -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 diff --git a/lib/imap.c b/lib/imap.c index 778530ea95..713dd02c65 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -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) diff --git a/lib/setopt.c b/lib/setopt.c index ef05cfb6ef..83cc5798e0 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -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; diff --git a/lib/urldata.h b/lib/urldata.h index 0f6278e201..c3f20a981b 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -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 */ diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c index d7ee7b1b22..3de7cbd921 100644 --- a/src/tool_cfgable.c +++ b/src/tool_cfgable.c @@ -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); } diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index 950ef3862f..d91629e1f2 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -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 */ diff --git a/src/tool_getparam.c b/src/tool_getparam.c index 5364098d2f..04cf9ee133 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -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; diff --git a/src/tool_getparam.h b/src/tool_getparam.h index bcfb35f065..f058020ea7 100644 --- a/src/tool_getparam.h +++ b/src/tool_getparam.h @@ -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, diff --git a/src/tool_listhelp.c b/src/tool_listhelp.c index c79859d2d2..c2a15fba1f 100644 --- a/src/tool_listhelp.c +++ b/src/tool_listhelp.c @@ -808,6 +808,9 @@ const struct helptxt helptext[] = { {"-T, --upload-file ", "Transfer local FILE to destination", CURLHELP_IMPORTANT | CURLHELP_UPLOAD}, + {" --upload-flags ", + "Specify additional upload behavior", + CURLHELP_CURL | CURLHELP_OUTPUT}, {" --url ", "URL(s) to work with", CURLHELP_CURL}, diff --git a/src/tool_operate.c b/src/tool_operate.c index 1c8f787f64..c229735ac8 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -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; } diff --git a/src/tool_setopt.c b/src/tool_setopt.c index 3770c9e495..02bb47fcd4 100644 --- a/src/tool_setopt.c +++ b/src/tool_setopt.c @@ -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 }; diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 015d568c53..2ceea914a9 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -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 diff --git a/tests/data/test3209 b/tests/data/test3209 new file mode 100644 index 0000000000..9ca4313f9f --- /dev/null +++ b/tests/data/test3209 @@ -0,0 +1,62 @@ + + + +IMAP +Clear Text +APPEND +UPLOAD + + + +# +# Server-side + + + +# +# Client-side + + +imap + + +Upload message via IMAP with upload flags + + +imap://%HOSTIP:%IMAPPORT/%TESTNUMBER -T %LOGDIR/upload%TESTNUMBER -u user:secret --upload-flags Answered,Deleted,Draft,Flagged,Seen + + +Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST) +From: Fred Foobar +Subject: afternoon meeting +To: joe@example.com +Message-Id: +MIME-Version: 1.0 +Content-Type: TEXT/PLAIN; CHARSET=US-ASCII + +Hello Joe, do you think we can meet at 3:30 tomorrow? + + + +# +# Verify data after the test has been "shot" + + +A001 CAPABILITY +A002 LOGIN user secret +A003 APPEND %TESTNUMBER (\Answered \Deleted \Draft \Flagged \Seen) {286} +A004 LOGOUT + + +Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST) +From: Fred Foobar +Subject: afternoon meeting +To: joe@example.com +Message-Id: +MIME-Version: 1.0 +Content-Type: TEXT/PLAIN; CHARSET=US-ASCII + +Hello Joe, do you think we can meet at 3:30 tomorrow? + + + diff --git a/tests/data/test3210 b/tests/data/test3210 new file mode 100644 index 0000000000..9bdc3323b7 --- /dev/null +++ b/tests/data/test3210 @@ -0,0 +1,62 @@ + + + +IMAP +Clear Text +APPEND +UPLOAD + + + +# +# Server-side + + + +# +# Client-side + + +imap + + +Upload message unread via IMAP + + +imap://%HOSTIP:%IMAPPORT/%TESTNUMBER -T %LOGDIR/upload%TESTNUMBER -u user:secret --upload-flags !Seen + + +Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST) +From: Fred Foobar +Subject: afternoon meeting +To: joe@example.com +Message-Id: +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. + + + +# +# Verify data after the test has been "shot" + + +A001 CAPABILITY +A002 LOGIN user secret +A003 APPEND %TESTNUMBER {356} +A004 LOGOUT + + +Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST) +From: Fred Foobar +Subject: afternoon meeting +To: joe@example.com +Message-Id: +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. + + +