1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * SPDX-License-Identifier: curl
23 ***************************************************************************/
25 #include "curl_setup.h"
27 #include <curl/curl.h>
34 #if !defined(CURL_DISABLE_MIME) && (!defined(CURL_DISABLE_HTTP) || \
35 !defined(CURL_DISABLE_SMTP) || \
36 !defined(CURL_DISABLE_IMAP))
38 #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
46 /* The last 3 #include files should be in this order */
47 #include "curl_printf.h"
48 #include "curl_memory.h"
58 #define READ_ERROR ((size_t) -1)
59 #define STOP_FILLING ((size_t) -2)
61 static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
62 void *instream, bool *hasread);
65 static size_t encoder_nop_read(char *buffer, size_t size, bool ateof,
67 static curl_off_t encoder_nop_size(curl_mimepart *part);
68 static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof,
70 static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
72 static curl_off_t encoder_base64_size(curl_mimepart *part);
73 static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
75 static curl_off_t encoder_qp_size(curl_mimepart *part);
77 static const struct mime_encoder encoders[] = {
78 {"binary", encoder_nop_read, encoder_nop_size},
79 {"8bit", encoder_nop_read, encoder_nop_size},
80 {"7bit", encoder_7bit_read, encoder_nop_size},
81 {"base64", encoder_base64_read, encoder_base64_size},
82 {"quoted-printable", encoder_qp_read, encoder_qp_size},
83 {ZERO_NULL, ZERO_NULL, ZERO_NULL}
86 /* Base64 encoding table */
87 static const char base64[] =
88 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
90 /* Quoted-printable character class table.
92 * We cannot rely on ctype functions since quoted-printable input data
93 * is assumed to be ascii-compatible, even on non-ascii platforms. */
94 #define QP_OK 1 /* Can be represented by itself. */
95 #define QP_SP 2 /* Space or tab. */
96 #define QP_CR 3 /* Carriage return. */
97 #define QP_LF 4 /* Line-feed. */
98 static const unsigned char qp_class[] = {
99 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 07 */
100 0, QP_SP, QP_LF, 0, 0, QP_CR, 0, 0, /* 08 - 0F */
101 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 17 */
102 0, 0, 0, 0, 0, 0, 0, 0, /* 18 - 1F */
103 QP_SP, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 20 - 27 */
104 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 28 - 2F */
105 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 30 - 37 */
106 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0 , QP_OK, QP_OK, /* 38 - 3F */
107 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 40 - 47 */
108 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 48 - 4F */
109 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 50 - 57 */
110 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 58 - 5F */
111 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 60 - 67 */
112 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 68 - 6F */
113 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 70 - 77 */
114 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0, /* 78 - 7F */
115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
116 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
118 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
119 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
120 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
121 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
122 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */
126 /* Binary --> hexadecimal ASCII table. */
127 static const char aschex[] =
128 "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x41\x42\x43\x44\x45\x46";
133 #define filesize(name, stat_data) (stat_data.st_size)
134 #define fopen_read fopen
140 * get_vms_file_size does what it takes to get the real size of the file
142 * For fixed files, find out the size of the EOF block and adjust.
144 * For all others, have to read the entire file in, discarding the contents.
145 * Most posted text files will be small, and binary files like zlib archives
146 * and CD/DVD images should be either a STREAM_LF format or a fixed format.
149 curl_off_t VmsRealFileSize(const char *name,
150 const struct_stat *stat_buf)
157 file = fopen(name, FOPEN_READTEXT); /* VMS */
163 while(ret_stat > 0) {
164 ret_stat = fread(buffer, 1, sizeof(buffer), file);
175 * VmsSpecialSize checks to see if the stat st_size can be trusted and
176 * if not to call a routine to get the correct size.
179 static curl_off_t VmsSpecialSize(const char *name,
180 const struct_stat *stat_buf)
182 switch(stat_buf->st_fab_rfm) {
185 return VmsRealFileSize(name, stat_buf);
188 return stat_buf->st_size;
192 #define filesize(name, stat_data) VmsSpecialSize(name, &stat_data)
197 * For upload to work as expected on VMS, different optional
198 * parameters must be added to the fopen command based on
199 * record format of the file.
202 static FILE * vmsfopenread(const char *file, const char *mode)
207 result = stat(file, &statbuf);
209 switch(statbuf.st_fab_rfm) {
213 return fopen(file, FOPEN_READTEXT); /* VMS */
216 return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm");
220 #define fopen_read vmsfopenread
224 #ifndef HAVE_BASENAME
226 (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
229 The basename() function shall take the pathname pointed to by path and
230 return a pointer to the final component of the pathname, deleting any
231 trailing '/' characters.
233 If the string pointed to by path consists entirely of the '/' character,
234 basename() shall return a pointer to the string "/". If the string pointed
235 to by path is exactly "//", it is implementation-defined whether '/' or "//"
238 If path is a null pointer or points to an empty string, basename() shall
239 return a pointer to the string ".".
241 The basename() function may modify the string pointed to by path, and may
242 return a pointer to static storage that may then be overwritten by a
243 subsequent call to basename().
245 The basename() function need not be reentrant. A function that is not
246 required to be reentrant is not required to be thread-safe.
249 static char *Curl_basename(char *path)
251 /* Ignore all the details above for now and make a quick and simple
252 implementation here */
256 s1 = strrchr(path, '/');
257 s2 = strrchr(path, '\\');
260 path = (s1 > s2? s1 : s2) + 1;
270 #define basename(x) Curl_basename((x))
274 /* Set readback state. */
275 static void mimesetstate(struct mime_state *state,
276 enum mimestate tok, void *ptr)
284 /* Escape header string into allocated memory. */
285 static char *escape_string(struct Curl_easy *data,
286 const char *src, enum mimestrategy strategy)
290 const char * const *table;
291 const char * const *p;
292 /* replace first character by rest of string. */
293 static const char * const mimetable[] = {
298 /* WHATWG HTML living standard 4.10.21.8 2 specifies:
299 For field names and filenames for file fields, the result of the
300 encoding in the previous bullet point must be escaped by replacing
301 any 0x0A (LF) bytes with the byte sequence `%0A`, 0x0D (CR) with `%0D`
302 and 0x22 (") with `%22`.
303 The user agent must not perform any other escapes. */
304 static const char * const formtable[] = {
312 /* data can be NULL when this function is called indirectly from
314 if(strategy == MIMESTRATEGY_MAIL ||
315 (data && (data->set.mime_options & CURLMIMEOPT_FORMESCAPE)))
318 Curl_dyn_init(&db, CURL_MAX_INPUT_LENGTH);
320 for(result = Curl_dyn_addn(&db, STRCONST("")); !result && *src; src++) {
321 for(p = table; *p && **p != *src; p++)
325 result = Curl_dyn_add(&db, *p + 1);
327 result = Curl_dyn_addn(&db, src, 1);
330 return Curl_dyn_ptr(&db);
333 /* Check if header matches. */
334 static char *match_header(struct curl_slist *hdr, const char *lbl, size_t len)
338 if(strncasecompare(hdr->data, lbl, len) && hdr->data[len] == ':')
339 for(value = hdr->data + len + 1; *value == ' '; value++)
344 /* Get a header from an slist. */
345 static char *search_header(struct curl_slist *hdrlist,
346 const char *hdr, size_t len)
350 for(; !value && hdrlist; hdrlist = hdrlist->next)
351 value = match_header(hdrlist, hdr, len);
356 static char *strippath(const char *fullfile)
360 filename = strdup(fullfile); /* duplicate since basename() may ruin the
361 buffer it works on */
364 base = strdup(basename(filename));
366 free(filename); /* free temporary buffer */
368 return base; /* returns an allocated string or NULL ! */
371 /* Initialize data encoder state. */
372 static void cleanup_encoder_state(struct mime_encoder_state *p)
380 /* Dummy encoder. This is used for 8bit and binary content encodings. */
381 static size_t encoder_nop_read(char *buffer, size_t size, bool ateof,
382 struct curl_mimepart *part)
384 struct mime_encoder_state *st = &part->encstate;
385 size_t insize = st->bufend - st->bufbeg;
396 memcpy(buffer, st->buf + st->bufbeg, size);
402 static curl_off_t encoder_nop_size(curl_mimepart *part)
404 return part->datasize;
408 /* 7bit encoder: the encoder is just a data validity check. */
409 static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof,
412 struct mime_encoder_state *st = &part->encstate;
413 size_t cursize = st->bufend - st->bufbeg;
423 for(cursize = 0; cursize < size; cursize++) {
424 *buffer = st->buf[st->bufbeg];
426 return cursize? cursize: READ_ERROR;
434 /* Base64 content encoder. */
435 static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
438 struct mime_encoder_state *st = &part->encstate;
443 while(st->bufbeg < st->bufend) {
445 if(st->pos > MAX_ENCODED_LINE_LENGTH - 4) {
446 /* Yes, we need 2 characters for CRLF. */
459 /* Be sure there is enough space and input data for a base64 group. */
465 if(st->bufend - st->bufbeg < 3)
468 /* Encode three bytes as four characters. */
469 i = st->buf[st->bufbeg++] & 0xFF;
470 i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
471 i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
472 *ptr++ = base64[(i >> 18) & 0x3F];
473 *ptr++ = base64[(i >> 12) & 0x3F];
474 *ptr++ = base64[(i >> 6) & 0x3F];
475 *ptr++ = base64[i & 0x3F];
481 /* If at eof, we have to flush the buffered data. */
488 /* Buffered data size can only be 0, 1 or 2. */
489 ptr[2] = ptr[3] = '=';
492 /* If there is buffered data */
493 if(st->bufend != st->bufbeg) {
495 if(st->bufend - st->bufbeg == 2)
496 i = (st->buf[st->bufbeg + 1] & 0xFF) << 8;
498 i |= (st->buf[st->bufbeg] & 0xFF) << 16;
499 ptr[0] = base64[(i >> 18) & 0x3F];
500 ptr[1] = base64[(i >> 12) & 0x3F];
501 if(++st->bufbeg != st->bufend) {
502 ptr[2] = base64[(i >> 6) & 0x3F];
514 static curl_off_t encoder_base64_size(curl_mimepart *part)
516 curl_off_t size = part->datasize;
519 return size; /* Unknown size or no data. */
521 /* Compute base64 character count. */
522 size = 4 * (1 + (size - 1) / 3);
524 /* Effective character count must include CRLFs. */
525 return size + 2 * ((size - 1) / MAX_ENCODED_LINE_LENGTH);
529 /* Quoted-printable lookahead.
531 * Check if a CRLF or end of data is in input buffer at current position + n.
532 * Return -1 if more data needed, 1 if CRLF or end of data, else 0.
534 static int qp_lookahead_eol(struct mime_encoder_state *st, int ateof, size_t n)
537 if(n >= st->bufend && ateof)
539 if(n + 2 > st->bufend)
541 if(qp_class[st->buf[n] & 0xFF] == QP_CR &&
542 qp_class[st->buf[n + 1] & 0xFF] == QP_LF)
547 /* Quoted-printable encoder. */
548 static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
551 struct mime_encoder_state *st = &part->encstate;
557 /* On all platforms, input is supposed to be ASCII compatible: for this
558 reason, we use hexadecimal ASCII codes in this function rather than
559 character constants that can be interpreted as non-ascii on some
560 platforms. Preserve ASCII encoding on output too. */
561 while(st->bufbeg < st->bufend) {
564 int i = st->buf[st->bufbeg];
566 buf[1] = aschex[(i >> 4) & 0xF];
567 buf[2] = aschex[i & 0xF];
569 switch(qp_class[st->buf[st->bufbeg] & 0xFF]) {
570 case QP_OK: /* Not a special character. */
572 case QP_SP: /* Space or tab. */
573 /* Spacing must be escaped if followed by CRLF. */
574 switch(qp_lookahead_eol(st, ateof, 1)) {
575 case -1: /* More input data needed. */
577 case 0: /* No encoding needed. */
579 default: /* CRLF after space or tab. */
580 buf[0] = '\x3D'; /* '=' */
585 case QP_CR: /* Carriage return. */
586 /* If followed by a line-feed, output the CRLF pair.
588 switch(qp_lookahead_eol(st, ateof, 0)) {
589 case -1: /* Need more data. */
591 case 1: /* CRLF found. */
592 buf[len++] = '\x0A'; /* Append '\n'. */
595 default: /* Not followed by LF: escape. */
596 buf[0] = '\x3D'; /* '=' */
601 default: /* Character must be escaped. */
602 buf[0] = '\x3D'; /* '=' */
607 /* Be sure the encoded character fits within maximum line length. */
608 if(buf[len - 1] != '\x0A') { /* '\n' */
609 softlinebreak = st->pos + len > MAX_ENCODED_LINE_LENGTH;
610 if(!softlinebreak && st->pos + len == MAX_ENCODED_LINE_LENGTH) {
611 /* We may use the current line only if end of data or followed by
613 switch(qp_lookahead_eol(st, ateof, consumed)) {
614 case -1: /* Need more data. */
616 case 0: /* Not followed by a CRLF. */
622 strcpy(buf, "\x3D\x0D\x0A"); /* "=\r\n" */
628 /* If the output buffer would overflow, do not store. */
635 /* Append to output buffer. */
636 memcpy(ptr, buf, len);
641 if(buf[len - 1] == '\x0A') /* '\n' */
643 st->bufbeg += consumed;
649 static curl_off_t encoder_qp_size(curl_mimepart *part)
651 /* Determining the size can only be done by reading the data: unless the
652 data size is 0, we return it as unknown (-1). */
653 return part->datasize? -1: 0;
657 /* In-memory data callbacks. */
658 /* Argument is a pointer to the mime part. */
659 static size_t mime_mem_read(char *buffer, size_t size, size_t nitems,
662 curl_mimepart *part = (curl_mimepart *) instream;
663 size_t sz = curlx_sotouz(part->datasize - part->state.offset);
664 (void) size; /* Always 1.*/
673 memcpy(buffer, part->data + curlx_sotouz(part->state.offset), sz);
678 static int mime_mem_seek(void *instream, curl_off_t offset, int whence)
680 curl_mimepart *part = (curl_mimepart *) instream;
684 offset += part->state.offset;
687 offset += part->datasize;
691 if(offset < 0 || offset > part->datasize)
692 return CURL_SEEKFUNC_FAIL;
694 part->state.offset = offset;
695 return CURL_SEEKFUNC_OK;
698 static void mime_mem_free(void *ptr)
700 Curl_safefree(((curl_mimepart *) ptr)->data);
704 /* Named file callbacks. */
705 /* Argument is a pointer to the mime part. */
706 static int mime_open_file(curl_mimepart *part)
708 /* Open a MIMEKIND_FILE part. */
712 part->fp = fopen_read(part->data, "rb");
713 return part->fp? 0: -1;
716 static size_t mime_file_read(char *buffer, size_t size, size_t nitems,
719 curl_mimepart *part = (curl_mimepart *) instream;
724 if(mime_open_file(part))
727 return fread(buffer, size, nitems, part->fp);
730 static int mime_file_seek(void *instream, curl_off_t offset, int whence)
732 curl_mimepart *part = (curl_mimepart *) instream;
734 if(whence == SEEK_SET && !offset && !part->fp)
735 return CURL_SEEKFUNC_OK; /* Not open: implicitly already at BOF. */
737 if(mime_open_file(part))
738 return CURL_SEEKFUNC_FAIL;
740 return fseek(part->fp, (long) offset, whence)?
741 CURL_SEEKFUNC_CANTSEEK: CURL_SEEKFUNC_OK;
744 static void mime_file_free(void *ptr)
746 curl_mimepart *part = (curl_mimepart *) ptr;
752 Curl_safefree(part->data);
757 /* Subparts callbacks. */
758 /* Argument is a pointer to the mime structure. */
760 /* Readback a byte string segment. */
761 static size_t readback_bytes(struct mime_state *state,
762 char *buffer, size_t bufsize,
763 const char *bytes, size_t numbytes,
764 const char *trail, size_t traillen)
767 size_t offset = curlx_sotouz(state->offset);
769 if(numbytes > offset) {
770 sz = numbytes - offset;
774 sz = offset - numbytes;
784 memcpy(buffer, bytes, sz);
789 /* Read a non-encoded part content. */
790 static size_t read_part_content(curl_mimepart *part,
791 char *buffer, size_t bufsize, bool *hasread)
795 switch(part->lastreadstatus) {
797 case CURL_READFUNC_ABORT:
798 case CURL_READFUNC_PAUSE:
800 return part->lastreadstatus;
805 /* If we can determine we are at end of part data, spare a read. */
806 if(part->datasize != (curl_off_t) -1 &&
807 part->state.offset >= part->datasize) {
808 /* sz is already zero. */
812 case MIMEKIND_MULTIPART:
814 * Cannot be processed as other kinds since read function requires
815 * an additional parameter and is highly recursive.
817 sz = mime_subparts_read(buffer, 1, bufsize, part->arg, hasread);
820 if(part->fp && feof(part->fp))
825 if(!(part->flags & MIME_FAST_READ)) {
830 sz = part->readfunc(buffer, 1, bufsize, part->arg);
840 case CURL_READFUNC_ABORT:
841 case CURL_READFUNC_PAUSE:
843 part->lastreadstatus = sz;
846 part->state.offset += sz;
847 part->lastreadstatus = sz;
854 /* Read and encode part content. */
855 static size_t read_encoded_part_content(curl_mimepart *part, char *buffer,
856 size_t bufsize, bool *hasread)
858 struct mime_encoder_state *st = &part->encstate;
864 if(st->bufbeg < st->bufend || ateof) {
865 /* Encode buffered data. */
866 sz = part->encoder->encodefunc(buffer, bufsize, ateof, part);
874 return cursize? cursize: sz;
883 /* We need more data in input buffer. */
885 size_t len = st->bufend - st->bufbeg;
888 memmove(st->buf, st->buf + st->bufbeg, len);
892 if(st->bufend >= sizeof(st->buf))
893 return cursize? cursize: READ_ERROR; /* Buffer full. */
894 sz = read_part_content(part, st->buf + st->bufend,
895 sizeof(st->buf) - st->bufend, hasread);
900 case CURL_READFUNC_ABORT:
901 case CURL_READFUNC_PAUSE:
904 return cursize? cursize: sz;
914 /* Readback a mime part. */
915 static size_t readback_part(curl_mimepart *part,
916 char *buffer, size_t bufsize, bool *hasread)
920 /* Readback from part. */
924 struct curl_slist *hdr = (struct curl_slist *) part->state.ptr;
925 switch(part->state.state) {
926 case MIMESTATE_BEGIN:
927 mimesetstate(&part->state,
928 (part->flags & MIME_BODY_ONLY)?
929 MIMESTATE_BODY: MIMESTATE_CURLHEADERS,
932 case MIMESTATE_USERHEADERS:
934 mimesetstate(&part->state, MIMESTATE_EOH, NULL);
937 if(match_header(hdr, "Content-Type", 12)) {
938 mimesetstate(&part->state, MIMESTATE_USERHEADERS, hdr->next);
942 case MIMESTATE_CURLHEADERS:
944 mimesetstate(&part->state, MIMESTATE_USERHEADERS, part->userheaders);
946 sz = readback_bytes(&part->state, buffer, bufsize,
947 hdr->data, strlen(hdr->data), STRCONST("\r\n"));
949 mimesetstate(&part->state, part->state.state, hdr->next);
953 sz = readback_bytes(&part->state, buffer, bufsize, STRCONST("\r\n"),
956 mimesetstate(&part->state, MIMESTATE_BODY, NULL);
959 cleanup_encoder_state(&part->encstate);
960 mimesetstate(&part->state, MIMESTATE_CONTENT, NULL);
962 case MIMESTATE_CONTENT:
964 sz = read_encoded_part_content(part, buffer, bufsize, hasread);
966 sz = read_part_content(part, buffer, bufsize, hasread);
969 mimesetstate(&part->state, MIMESTATE_END, NULL);
970 /* Try sparing open file descriptors. */
971 if(part->kind == MIMEKIND_FILE && part->fp) {
976 case CURL_READFUNC_ABORT:
977 case CURL_READFUNC_PAUSE:
980 return cursize? cursize: sz;
986 break; /* Other values not in part state. */
989 /* Bump buffer and counters according to read size. */
998 /* Readback from mime. Warning: not a read callback function. */
999 static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
1000 void *instream, bool *hasread)
1002 curl_mime *mime = (curl_mime *) instream;
1004 (void) size; /* Always 1. */
1008 curl_mimepart *part = mime->state.ptr;
1009 switch(mime->state.state) {
1010 case MIMESTATE_BEGIN:
1011 case MIMESTATE_BODY:
1012 mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, mime->firstpart);
1013 /* The first boundary always follows the header termination empty line,
1014 so is always preceded by a CRLF. We can then spare 2 characters
1015 by skipping the leading CRLF in boundary. */
1016 mime->state.offset += 2;
1018 case MIMESTATE_BOUNDARY1:
1019 sz = readback_bytes(&mime->state, buffer, nitems, STRCONST("\r\n--"),
1022 mimesetstate(&mime->state, MIMESTATE_BOUNDARY2, part);
1024 case MIMESTATE_BOUNDARY2:
1026 sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary,
1027 MIME_BOUNDARY_LEN, STRCONST("\r\n"));
1029 sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary,
1030 MIME_BOUNDARY_LEN, STRCONST("--\r\n"));
1032 mimesetstate(&mime->state, MIMESTATE_CONTENT, part);
1035 case MIMESTATE_CONTENT:
1037 mimesetstate(&mime->state, MIMESTATE_END, NULL);
1040 sz = readback_part(part, buffer, nitems, hasread);
1042 case CURL_READFUNC_ABORT:
1043 case CURL_READFUNC_PAUSE:
1046 return cursize? cursize: sz;
1048 mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, part->nextpart);
1055 break; /* other values not used in mime state. */
1058 /* Bump buffer and counters according to read size. */
1067 static int mime_part_rewind(curl_mimepart *part)
1069 int res = CURL_SEEKFUNC_OK;
1070 enum mimestate targetstate = MIMESTATE_BEGIN;
1072 if(part->flags & MIME_BODY_ONLY)
1073 targetstate = MIMESTATE_BODY;
1074 cleanup_encoder_state(&part->encstate);
1075 if(part->state.state > targetstate) {
1076 res = CURL_SEEKFUNC_CANTSEEK;
1077 if(part->seekfunc) {
1078 res = part->seekfunc(part->arg, (curl_off_t) 0, SEEK_SET);
1080 case CURL_SEEKFUNC_OK:
1081 case CURL_SEEKFUNC_FAIL:
1082 case CURL_SEEKFUNC_CANTSEEK:
1084 case -1: /* For fseek() error. */
1085 res = CURL_SEEKFUNC_CANTSEEK;
1088 res = CURL_SEEKFUNC_FAIL;
1094 if(res == CURL_SEEKFUNC_OK)
1095 mimesetstate(&part->state, targetstate, NULL);
1097 part->lastreadstatus = 1; /* Successful read status. */
1101 static int mime_subparts_seek(void *instream, curl_off_t offset, int whence)
1103 curl_mime *mime = (curl_mime *) instream;
1104 curl_mimepart *part;
1105 int result = CURL_SEEKFUNC_OK;
1107 if(whence != SEEK_SET || offset)
1108 return CURL_SEEKFUNC_CANTSEEK; /* Only support full rewind. */
1110 if(mime->state.state == MIMESTATE_BEGIN)
1111 return CURL_SEEKFUNC_OK; /* Already rewound. */
1113 for(part = mime->firstpart; part; part = part->nextpart) {
1114 int res = mime_part_rewind(part);
1115 if(res != CURL_SEEKFUNC_OK)
1119 if(result == CURL_SEEKFUNC_OK)
1120 mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
1125 /* Release part content. */
1126 static void cleanup_part_content(curl_mimepart *part)
1129 part->freefunc(part->arg);
1131 part->readfunc = NULL;
1132 part->seekfunc = NULL;
1133 part->freefunc = NULL;
1134 part->arg = (void *) part; /* Defaults to part itself. */
1137 part->datasize = (curl_off_t) 0; /* No size yet. */
1138 cleanup_encoder_state(&part->encstate);
1139 part->kind = MIMEKIND_NONE;
1140 part->flags &= ~MIME_FAST_READ;
1141 part->lastreadstatus = 1; /* Successful read status. */
1142 part->state.state = MIMESTATE_BEGIN;
1145 static void mime_subparts_free(void *ptr)
1147 curl_mime *mime = (curl_mime *) ptr;
1149 if(mime && mime->parent) {
1150 mime->parent->freefunc = NULL; /* Be sure we won't be called again. */
1151 cleanup_part_content(mime->parent); /* Avoid dangling pointer in part. */
1153 curl_mime_free(mime);
1156 /* Do not free subparts: unbind them. This is used for the top level only. */
1157 static void mime_subparts_unbind(void *ptr)
1159 curl_mime *mime = (curl_mime *) ptr;
1161 if(mime && mime->parent) {
1162 mime->parent->freefunc = NULL; /* Be sure we won't be called again. */
1163 cleanup_part_content(mime->parent); /* Avoid dangling pointer in part. */
1164 mime->parent = NULL;
1169 void Curl_mime_cleanpart(curl_mimepart *part)
1171 cleanup_part_content(part);
1172 curl_slist_free_all(part->curlheaders);
1173 if(part->flags & MIME_USERHEADERS_OWNER)
1174 curl_slist_free_all(part->userheaders);
1175 Curl_safefree(part->mimetype);
1176 Curl_safefree(part->name);
1177 Curl_safefree(part->filename);
1178 Curl_mime_initpart(part, part->easy);
1181 /* Recursively delete a mime handle and its parts. */
1182 void curl_mime_free(curl_mime *mime)
1184 curl_mimepart *part;
1187 mime_subparts_unbind(mime); /* Be sure it's not referenced anymore. */
1188 while(mime->firstpart) {
1189 part = mime->firstpart;
1190 mime->firstpart = part->nextpart;
1191 Curl_mime_cleanpart(part);
1198 CURLcode Curl_mime_duppart(curl_mimepart *dst, const curl_mimepart *src)
1202 const curl_mimepart *s;
1203 CURLcode res = CURLE_OK;
1207 /* Duplicate content. */
1212 res = curl_mime_data(dst, src->data, (size_t) src->datasize);
1215 res = curl_mime_filedata(dst, src->data);
1216 /* Do not abort duplication if file is not readable. */
1217 if(res == CURLE_READ_ERROR)
1220 case MIMEKIND_CALLBACK:
1221 res = curl_mime_data_cb(dst, src->datasize, src->readfunc,
1222 src->seekfunc, src->freefunc, src->arg);
1224 case MIMEKIND_MULTIPART:
1225 /* No one knows about the cloned subparts, thus always attach ownership
1227 mime = curl_mime_init(dst->easy);
1228 res = mime? curl_mime_subparts(dst, mime): CURLE_OUT_OF_MEMORY;
1230 /* Duplicate subparts. */
1231 for(s = ((curl_mime *) src->arg)->firstpart; !res && s; s = s->nextpart) {
1232 d = curl_mime_addpart(mime);
1233 res = d? Curl_mime_duppart(d, s): CURLE_OUT_OF_MEMORY;
1236 default: /* Invalid kind: should not occur. */
1237 res = CURLE_BAD_FUNCTION_ARGUMENT; /* Internal error? */
1241 /* Duplicate headers. */
1242 if(!res && src->userheaders) {
1243 struct curl_slist *hdrs = Curl_slist_duplicate(src->userheaders);
1246 res = CURLE_OUT_OF_MEMORY;
1248 /* No one but this procedure knows about the new header list,
1249 so always take ownership. */
1250 res = curl_mime_headers(dst, hdrs, TRUE);
1252 curl_slist_free_all(hdrs);
1257 /* Duplicate other fields. */
1258 dst->encoder = src->encoder;
1259 res = curl_mime_type(dst, src->mimetype);
1262 res = curl_mime_name(dst, src->name);
1264 res = curl_mime_filename(dst, src->filename);
1266 /* If an error occurred, rollback. */
1268 Curl_mime_cleanpart(dst);
1274 * Mime build functions.
1277 /* Create a mime handle. */
1278 curl_mime *curl_mime_init(struct Curl_easy *easy)
1282 mime = (curl_mime *) malloc(sizeof(*mime));
1286 mime->parent = NULL;
1287 mime->firstpart = NULL;
1288 mime->lastpart = NULL;
1290 memset(mime->boundary, '-', MIME_BOUNDARY_DASHES);
1291 if(Curl_rand_hex(easy,
1292 (unsigned char *) &mime->boundary[MIME_BOUNDARY_DASHES],
1293 MIME_RAND_BOUNDARY_CHARS + 1)) {
1294 /* failed to get random separator, bail out */
1298 mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
1304 /* Initialize a mime part. */
1305 void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy)
1307 memset((char *) part, 0, sizeof(*part));
1309 part->lastreadstatus = 1; /* Successful read status. */
1310 mimesetstate(&part->state, MIMESTATE_BEGIN, NULL);
1313 /* Create a mime part and append it to a mime handle's part list. */
1314 curl_mimepart *curl_mime_addpart(curl_mime *mime)
1316 curl_mimepart *part;
1321 part = (curl_mimepart *) malloc(sizeof(*part));
1324 Curl_mime_initpart(part, mime->easy);
1325 part->parent = mime;
1328 mime->lastpart->nextpart = part;
1330 mime->firstpart = part;
1332 mime->lastpart = part;
1338 /* Set mime part name. */
1339 CURLcode curl_mime_name(curl_mimepart *part, const char *name)
1342 return CURLE_BAD_FUNCTION_ARGUMENT;
1344 Curl_safefree(part->name);
1348 part->name = strdup(name);
1350 return CURLE_OUT_OF_MEMORY;
1356 /* Set mime part remote file name. */
1357 CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
1360 return CURLE_BAD_FUNCTION_ARGUMENT;
1362 Curl_safefree(part->filename);
1363 part->filename = NULL;
1366 part->filename = strdup(filename);
1368 return CURLE_OUT_OF_MEMORY;
1374 /* Set mime part content from memory data. */
1375 CURLcode curl_mime_data(curl_mimepart *part,
1376 const char *data, size_t datasize)
1379 return CURLE_BAD_FUNCTION_ARGUMENT;
1381 cleanup_part_content(part);
1384 if(datasize == CURL_ZERO_TERMINATED)
1385 datasize = strlen(data);
1387 part->data = malloc(datasize + 1);
1389 return CURLE_OUT_OF_MEMORY;
1391 part->datasize = datasize;
1394 memcpy(part->data, data, datasize);
1395 part->data[datasize] = '\0'; /* Set a null terminator as sentinel. */
1397 part->readfunc = mime_mem_read;
1398 part->seekfunc = mime_mem_seek;
1399 part->freefunc = mime_mem_free;
1400 part->flags |= MIME_FAST_READ;
1401 part->kind = MIMEKIND_DATA;
1407 /* Set mime part content from named local file. */
1408 CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
1410 CURLcode result = CURLE_OK;
1413 return CURLE_BAD_FUNCTION_ARGUMENT;
1415 cleanup_part_content(part);
1421 if(stat(filename, &sbuf) || access(filename, R_OK))
1422 result = CURLE_READ_ERROR;
1424 part->data = strdup(filename);
1426 result = CURLE_OUT_OF_MEMORY;
1428 part->datasize = -1;
1429 if(!result && S_ISREG(sbuf.st_mode)) {
1430 part->datasize = filesize(filename, sbuf);
1431 part->seekfunc = mime_file_seek;
1434 part->readfunc = mime_file_read;
1435 part->freefunc = mime_file_free;
1436 part->kind = MIMEKIND_FILE;
1438 /* As a side effect, set the filename to the current file's base name.
1439 It is possible to withdraw this by explicitly calling
1440 curl_mime_filename() with a NULL filename argument after the current
1442 base = strippath(filename);
1444 result = CURLE_OUT_OF_MEMORY;
1446 CURLcode res = curl_mime_filename(part, base);
1456 /* Set mime part type. */
1457 CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
1460 return CURLE_BAD_FUNCTION_ARGUMENT;
1462 Curl_safefree(part->mimetype);
1463 part->mimetype = NULL;
1466 part->mimetype = strdup(mimetype);
1468 return CURLE_OUT_OF_MEMORY;
1474 /* Set mime data transfer encoder. */
1475 CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
1477 CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
1478 const struct mime_encoder *mep;
1483 part->encoder = NULL;
1486 return CURLE_OK; /* Removing current encoder. */
1488 for(mep = encoders; mep->name; mep++)
1489 if(strcasecompare(encoding, mep->name)) {
1490 part->encoder = mep;
1497 /* Set mime part headers. */
1498 CURLcode curl_mime_headers(curl_mimepart *part,
1499 struct curl_slist *headers, int take_ownership)
1502 return CURLE_BAD_FUNCTION_ARGUMENT;
1504 if(part->flags & MIME_USERHEADERS_OWNER) {
1505 if(part->userheaders != headers) /* Allow setting twice the same list. */
1506 curl_slist_free_all(part->userheaders);
1507 part->flags &= ~MIME_USERHEADERS_OWNER;
1509 part->userheaders = headers;
1510 if(headers && take_ownership)
1511 part->flags |= MIME_USERHEADERS_OWNER;
1515 /* Set mime part content from callback. */
1516 CURLcode curl_mime_data_cb(curl_mimepart *part, curl_off_t datasize,
1517 curl_read_callback readfunc,
1518 curl_seek_callback seekfunc,
1519 curl_free_callback freefunc, void *arg)
1522 return CURLE_BAD_FUNCTION_ARGUMENT;
1524 cleanup_part_content(part);
1527 part->readfunc = readfunc;
1528 part->seekfunc = seekfunc;
1529 part->freefunc = freefunc;
1531 part->datasize = datasize;
1532 part->kind = MIMEKIND_CALLBACK;
1538 /* Set mime part content from subparts. */
1539 CURLcode Curl_mime_set_subparts(curl_mimepart *part,
1540 curl_mime *subparts, int take_ownership)
1545 return CURLE_BAD_FUNCTION_ARGUMENT;
1547 /* Accept setting twice the same subparts. */
1548 if(part->kind == MIMEKIND_MULTIPART && part->arg == subparts)
1551 cleanup_part_content(part);
1554 /* Must belong to the same data handle. */
1555 if(part->easy && subparts->easy && part->easy != subparts->easy)
1556 return CURLE_BAD_FUNCTION_ARGUMENT;
1558 /* Should not have been attached already. */
1559 if(subparts->parent)
1560 return CURLE_BAD_FUNCTION_ARGUMENT;
1562 /* Should not be the part's root. */
1563 root = part->parent;
1565 while(root->parent && root->parent->parent)
1566 root = root->parent->parent;
1567 if(subparts == root) {
1569 failf(part->easy, "Can't add itself as a subpart");
1570 return CURLE_BAD_FUNCTION_ARGUMENT;
1574 subparts->parent = part;
1575 /* Subparts are processed internally: no read callback. */
1576 part->seekfunc = mime_subparts_seek;
1577 part->freefunc = take_ownership? mime_subparts_free: mime_subparts_unbind;
1578 part->arg = subparts;
1579 part->datasize = -1;
1580 part->kind = MIMEKIND_MULTIPART;
1586 CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
1588 return Curl_mime_set_subparts(part, subparts, TRUE);
1592 /* Readback from top mime. */
1593 /* Argument is the dummy top part. */
1594 size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream)
1596 curl_mimepart *part = (curl_mimepart *) instream;
1600 (void) size; /* Always 1. */
1604 ret = readback_part(part, buffer, nitems, &hasread);
1606 * If this is not possible to get some data without calling more than
1607 * one read callback (probably because a content encoder is not able to
1608 * deliver a new bunch for the few data accumulated so far), force another
1609 * read until we get enough data or a special exit code.
1611 } while(ret == STOP_FILLING);
1616 /* Rewind mime stream. */
1617 CURLcode Curl_mime_rewind(curl_mimepart *part)
1619 return mime_part_rewind(part) == CURL_SEEKFUNC_OK?
1620 CURLE_OK: CURLE_SEND_FAIL_REWIND;
1623 /* Compute header list size. */
1624 static size_t slist_size(struct curl_slist *s,
1625 size_t overhead, const char *skip, size_t skiplen)
1629 for(; s; s = s->next)
1630 if(!skip || !match_header(s, skip, skiplen))
1631 size += strlen(s->data) + overhead;
1635 /* Get/compute multipart size. */
1636 static curl_off_t multipart_size(curl_mime *mime)
1639 size_t boundarysize;
1640 curl_mimepart *part;
1643 return 0; /* Not present -> empty. */
1645 boundarysize = 4 + MIME_BOUNDARY_LEN + 2;
1646 size = boundarysize; /* Final boundary - CRLF after headers. */
1648 for(part = mime->firstpart; part; part = part->nextpart) {
1649 curl_off_t sz = Curl_mime_size(part);
1655 size += boundarysize + sz;
1661 /* Get/compute mime size. */
1662 curl_off_t Curl_mime_size(curl_mimepart *part)
1666 if(part->kind == MIMEKIND_MULTIPART)
1667 part->datasize = multipart_size(part->arg);
1669 size = part->datasize;
1672 size = part->encoder->sizefunc(part);
1674 if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) {
1675 /* Compute total part size. */
1676 size += slist_size(part->curlheaders, 2, NULL, 0);
1677 size += slist_size(part->userheaders, 2, STRCONST("Content-Type"));
1678 size += 2; /* CRLF after headers. */
1685 CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
1687 struct curl_slist *hdr = NULL;
1692 s = curl_mvaprintf(fmt, ap);
1696 hdr = Curl_slist_append_nodup(*slp, s);
1703 return hdr? CURLE_OK: CURLE_OUT_OF_MEMORY;
1706 /* Add a content type header. */
1707 static CURLcode add_content_type(struct curl_slist **slp,
1708 const char *type, const char *boundary)
1710 return Curl_mime_add_header(slp, "Content-Type: %s%s%s", type,
1711 boundary? "; boundary=": "",
1712 boundary? boundary: "");
1715 const char *Curl_mime_contenttype(const char *filename)
1718 * If no content type was specified, we scan through a few well-known
1719 * extensions and pick the first we match!
1721 struct ContentType {
1722 const char *extension;
1725 static const struct ContentType ctts[] = {
1726 {".gif", "image/gif"},
1727 {".jpg", "image/jpeg"},
1728 {".jpeg", "image/jpeg"},
1729 {".png", "image/png"},
1730 {".svg", "image/svg+xml"},
1731 {".txt", "text/plain"},
1732 {".htm", "text/html"},
1733 {".html", "text/html"},
1734 {".pdf", "application/pdf"},
1735 {".xml", "application/xml"}
1739 size_t len1 = strlen(filename);
1740 const char *nameend = filename + len1;
1743 for(i = 0; i < sizeof(ctts) / sizeof(ctts[0]); i++) {
1744 size_t len2 = strlen(ctts[i].extension);
1746 if(len1 >= len2 && strcasecompare(nameend - len2, ctts[i].extension))
1747 return ctts[i].type;
1753 static bool content_type_match(const char *contenttype,
1754 const char *target, size_t len)
1756 if(contenttype && strncasecompare(contenttype, target, len))
1757 switch(contenttype[len]) {
1769 CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
1770 const char *contenttype,
1771 const char *disposition,
1772 enum mimestrategy strategy)
1774 curl_mime *mime = NULL;
1775 const char *boundary = NULL;
1777 const char *cte = NULL;
1778 CURLcode ret = CURLE_OK;
1780 /* Get rid of previously prepared headers. */
1781 curl_slist_free_all(part->curlheaders);
1782 part->curlheaders = NULL;
1784 /* Be sure we won't access old headers later. */
1785 if(part->state.state == MIMESTATE_CURLHEADERS)
1786 mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL);
1788 /* Check if content type is specified. */
1789 customct = part->mimetype;
1791 customct = search_header(part->userheaders, STRCONST("Content-Type"));
1793 contenttype = customct;
1795 /* If content type is not specified, try to determine it. */
1797 switch(part->kind) {
1798 case MIMEKIND_MULTIPART:
1799 contenttype = MULTIPART_CONTENTTYPE_DEFAULT;
1802 contenttype = Curl_mime_contenttype(part->filename);
1804 contenttype = Curl_mime_contenttype(part->data);
1805 if(!contenttype && part->filename)
1806 contenttype = FILE_CONTENTTYPE_DEFAULT;
1809 contenttype = Curl_mime_contenttype(part->filename);
1814 if(part->kind == MIMEKIND_MULTIPART) {
1815 mime = (curl_mime *) part->arg;
1817 boundary = mime->boundary;
1819 else if(contenttype && !customct &&
1820 content_type_match(contenttype, STRCONST("text/plain")))
1821 if(strategy == MIMESTRATEGY_MAIL || !part->filename)
1824 /* Issue content-disposition header only if not already set by caller. */
1825 if(!search_header(part->userheaders, STRCONST("Content-Disposition"))) {
1827 if(part->filename || part->name ||
1828 (contenttype && !strncasecompare(contenttype, "multipart/", 10)))
1829 disposition = DISPOSITION_DEFAULT;
1830 if(disposition && curl_strequal(disposition, "attachment") &&
1831 !part->name && !part->filename)
1835 char *filename = NULL;
1838 name = escape_string(part->easy, part->name, strategy);
1840 ret = CURLE_OUT_OF_MEMORY;
1842 if(!ret && part->filename) {
1843 filename = escape_string(part->easy, part->filename, strategy);
1845 ret = CURLE_OUT_OF_MEMORY;
1848 ret = Curl_mime_add_header(&part->curlheaders,
1849 "Content-Disposition: %s%s%s%s%s%s%s",
1851 name? "; name=\"": "",
1854 filename? "; filename=\"": "",
1855 filename? filename: "",
1856 filename? "\"": "");
1857 Curl_safefree(name);
1858 Curl_safefree(filename);
1864 /* Issue Content-Type header. */
1866 ret = add_content_type(&part->curlheaders, contenttype, boundary);
1871 /* Content-Transfer-Encoding header. */
1872 if(!search_header(part->userheaders,
1873 STRCONST("Content-Transfer-Encoding"))) {
1875 cte = part->encoder->name;
1876 else if(contenttype && strategy == MIMESTRATEGY_MAIL &&
1877 part->kind != MIMEKIND_MULTIPART)
1880 ret = Curl_mime_add_header(&part->curlheaders,
1881 "Content-Transfer-Encoding: %s", cte);
1887 /* If we were reading curl-generated headers, restart with new ones (this
1888 should not occur). */
1889 if(part->state.state == MIMESTATE_CURLHEADERS)
1890 mimesetstate(&part->state, MIMESTATE_CURLHEADERS, part->curlheaders);
1892 /* Process subparts. */
1893 if(part->kind == MIMEKIND_MULTIPART && mime) {
1894 curl_mimepart *subpart;
1897 if(content_type_match(contenttype, STRCONST("multipart/form-data")))
1898 disposition = "form-data";
1899 for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) {
1900 ret = Curl_mime_prepare_headers(subpart, NULL, disposition, strategy);
1908 /* Recursively reset paused status in the given part. */
1909 void Curl_mime_unpause(curl_mimepart *part)
1912 if(part->lastreadstatus == CURL_READFUNC_PAUSE)
1913 part->lastreadstatus = 1; /* Successful read status. */
1914 if(part->kind == MIMEKIND_MULTIPART) {
1915 curl_mime *mime = (curl_mime *) part->arg;
1918 curl_mimepart *subpart;
1920 for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart)
1921 Curl_mime_unpause(subpart);
1928 #else /* !CURL_DISABLE_MIME && (!CURL_DISABLE_HTTP ||
1929 !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP) */
1931 /* Mime not compiled in: define stubs for externally-referenced functions. */
1932 curl_mime *curl_mime_init(CURL *easy)
1938 void curl_mime_free(curl_mime *mime)
1943 curl_mimepart *curl_mime_addpart(curl_mime *mime)
1949 CURLcode curl_mime_name(curl_mimepart *part, const char *name)
1953 return CURLE_NOT_BUILT_IN;
1956 CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
1960 return CURLE_NOT_BUILT_IN;
1963 CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
1967 return CURLE_NOT_BUILT_IN;
1970 CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
1974 return CURLE_NOT_BUILT_IN;
1977 CURLcode curl_mime_data(curl_mimepart *part,
1978 const char *data, size_t datasize)
1983 return CURLE_NOT_BUILT_IN;
1986 CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
1990 return CURLE_NOT_BUILT_IN;
1993 CURLcode curl_mime_data_cb(curl_mimepart *part,
1994 curl_off_t datasize,
1995 curl_read_callback readfunc,
1996 curl_seek_callback seekfunc,
1997 curl_free_callback freefunc,
2006 return CURLE_NOT_BUILT_IN;
2009 CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
2013 return CURLE_NOT_BUILT_IN;
2016 CURLcode curl_mime_headers(curl_mimepart *part,
2017 struct curl_slist *headers, int take_ownership)
2021 (void) take_ownership;
2022 return CURLE_NOT_BUILT_IN;
2025 CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
2029 return CURLE_NOT_BUILT_IN;
2032 #endif /* if disabled */