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 ***************************************************************************/
23 #include "curl_setup.h"
25 #include <curl/curl.h>
32 #if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)) || \
33 !defined(CURL_DISABLE_SMTP) || !defined(CURL_DISABLE_IMAP)
35 #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
43 /* The last 3 #include files should be in this order */
44 #include "curl_printf.h"
45 #include "curl_memory.h"
55 #define READ_ERROR ((size_t) -1)
56 #define STOP_FILLING ((size_t) -2)
58 static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
59 void *instream, bool *hasread);
62 static size_t encoder_nop_read(char *buffer, size_t size, bool ateof,
64 static curl_off_t encoder_nop_size(curl_mimepart *part);
65 static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof,
67 static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
69 static curl_off_t encoder_base64_size(curl_mimepart *part);
70 static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
72 static curl_off_t encoder_qp_size(curl_mimepart *part);
74 static const struct mime_encoder encoders[] = {
75 {"binary", encoder_nop_read, encoder_nop_size},
76 {"8bit", encoder_nop_read, encoder_nop_size},
77 {"7bit", encoder_7bit_read, encoder_nop_size},
78 {"base64", encoder_base64_read, encoder_base64_size},
79 {"quoted-printable", encoder_qp_read, encoder_qp_size},
80 {ZERO_NULL, ZERO_NULL, ZERO_NULL}
83 /* Base64 encoding table */
84 static const char base64[] =
85 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
87 /* Quoted-printable character class table.
89 * We cannot rely on ctype functions since quoted-printable input data
90 * is assumed to be ascii-compatible, even on non-ascii platforms. */
91 #define QP_OK 1 /* Can be represented by itself. */
92 #define QP_SP 2 /* Space or tab. */
93 #define QP_CR 3 /* Carriage return. */
94 #define QP_LF 4 /* Line-feed. */
95 static const unsigned char qp_class[] = {
96 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 07 */
97 0, QP_SP, QP_LF, 0, 0, QP_CR, 0, 0, /* 08 - 0F */
98 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 17 */
99 0, 0, 0, 0, 0, 0, 0, 0, /* 18 - 1F */
100 QP_SP, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 20 - 27 */
101 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 28 - 2F */
102 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 30 - 37 */
103 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0 , QP_OK, QP_OK, /* 38 - 3F */
104 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 40 - 47 */
105 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 48 - 4F */
106 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 50 - 57 */
107 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 58 - 5F */
108 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 60 - 67 */
109 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 68 - 6F */
110 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 70 - 77 */
111 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0, /* 78 - 7F */
112 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
113 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
114 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
116 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
118 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
119 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */
123 /* Binary --> hexadecimal ASCII table. */
124 static const char aschex[] =
125 "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x41\x42\x43\x44\x45\x46";
130 #define filesize(name, stat_data) (stat_data.st_size)
131 #define fopen_read fopen
137 * get_vms_file_size does what it takes to get the real size of the file
139 * For fixed files, find out the size of the EOF block and adjust.
141 * For all others, have to read the entire file in, discarding the contents.
142 * Most posted text files will be small, and binary files like zlib archives
143 * and CD/DVD images should be either a STREAM_LF format or a fixed format.
146 curl_off_t VmsRealFileSize(const char *name,
147 const struct_stat *stat_buf)
154 file = fopen(name, FOPEN_READTEXT); /* VMS */
160 while(ret_stat > 0) {
161 ret_stat = fread(buffer, 1, sizeof(buffer), file);
172 * VmsSpecialSize checks to see if the stat st_size can be trusted and
173 * if not to call a routine to get the correct size.
176 static curl_off_t VmsSpecialSize(const char *name,
177 const struct_stat *stat_buf)
179 switch(stat_buf->st_fab_rfm) {
182 return VmsRealFileSize(name, stat_buf);
185 return stat_buf->st_size;
189 #define filesize(name, stat_data) VmsSpecialSize(name, &stat_data)
194 * For upload to work as expected on VMS, different optional
195 * parameters must be added to the fopen command based on
196 * record format of the file.
199 static FILE * vmsfopenread(const char *file, const char *mode)
204 result = stat(file, &statbuf);
206 switch(statbuf.st_fab_rfm) {
210 return fopen(file, FOPEN_READTEXT); /* VMS */
213 return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm");
217 #define fopen_read vmsfopenread
221 #ifndef HAVE_BASENAME
223 (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
226 The basename() function shall take the pathname pointed to by path and
227 return a pointer to the final component of the pathname, deleting any
228 trailing '/' characters.
230 If the string pointed to by path consists entirely of the '/' character,
231 basename() shall return a pointer to the string "/". If the string pointed
232 to by path is exactly "//", it is implementation-defined whether '/' or "//"
235 If path is a null pointer or points to an empty string, basename() shall
236 return a pointer to the string ".".
238 The basename() function may modify the string pointed to by path, and may
239 return a pointer to static storage that may then be overwritten by a
240 subsequent call to basename().
242 The basename() function need not be reentrant. A function that is not
243 required to be reentrant is not required to be thread-safe.
246 static char *Curl_basename(char *path)
248 /* Ignore all the details above for now and make a quick and simple
249 implementation here */
253 s1 = strrchr(path, '/');
254 s2 = strrchr(path, '\\');
257 path = (s1 > s2? s1 : s2) + 1;
267 #define basename(x) Curl_basename((x))
271 /* Set readback state. */
272 static void mimesetstate(struct mime_state *state,
273 enum mimestate tok, void *ptr)
281 /* Escape header string into allocated memory. */
282 static char *escape_string(struct Curl_easy *data,
283 const char *src, enum mimestrategy strategy)
287 const char * const *table;
288 const char * const *p;
289 /* replace first character by rest of string. */
290 static const char * const mimetable[] = {
295 /* WHATWG HTML living standard 4.10.21.8 2 specifies:
296 For field names and filenames for file fields, the result of the
297 encoding in the previous bullet point must be escaped by replacing
298 any 0x0A (LF) bytes with the byte sequence `%0A`, 0x0D (CR) with `%0D`
299 and 0x22 (") with `%22`.
300 The user agent must not perform any other escapes. */
301 static const char * const formtable[] = {
309 /* data can be NULL when this function is called indirectly from
311 if(strategy == MIMESTRATEGY_MAIL ||
312 (data && (data->set.mime_options & CURLMIMEOPT_FORMESCAPE)))
315 Curl_dyn_init(&db, CURL_MAX_INPUT_LENGTH);
317 for(result = Curl_dyn_addn(&db, STRCONST("")); !result && *src; src++) {
318 for(p = table; *p && **p != *src; p++)
322 result = Curl_dyn_add(&db, *p + 1);
324 result = Curl_dyn_addn(&db, src, 1);
327 return Curl_dyn_ptr(&db);
330 /* Check if header matches. */
331 static char *match_header(struct curl_slist *hdr, const char *lbl, size_t len)
335 if(strncasecompare(hdr->data, lbl, len) && hdr->data[len] == ':')
336 for(value = hdr->data + len + 1; *value == ' '; value++)
341 /* Get a header from an slist. */
342 static char *search_header(struct curl_slist *hdrlist,
343 const char *hdr, size_t len)
347 for(; !value && hdrlist; hdrlist = hdrlist->next)
348 value = match_header(hdrlist, hdr, len);
353 static char *strippath(const char *fullfile)
357 filename = strdup(fullfile); /* duplicate since basename() may ruin the
358 buffer it works on */
361 base = strdup(basename(filename));
363 free(filename); /* free temporary buffer */
365 return base; /* returns an allocated string or NULL ! */
368 /* Initialize data encoder state. */
369 static void cleanup_encoder_state(struct mime_encoder_state *p)
377 /* Dummy encoder. This is used for 8bit and binary content encodings. */
378 static size_t encoder_nop_read(char *buffer, size_t size, bool ateof,
379 struct curl_mimepart *part)
381 struct mime_encoder_state *st = &part->encstate;
382 size_t insize = st->bufend - st->bufbeg;
393 memcpy(buffer, st->buf + st->bufbeg, size);
399 static curl_off_t encoder_nop_size(curl_mimepart *part)
401 return part->datasize;
405 /* 7bit encoder: the encoder is just a data validity check. */
406 static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof,
409 struct mime_encoder_state *st = &part->encstate;
410 size_t cursize = st->bufend - st->bufbeg;
420 for(cursize = 0; cursize < size; cursize++) {
421 *buffer = st->buf[st->bufbeg];
423 return cursize? cursize: READ_ERROR;
431 /* Base64 content encoder. */
432 static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
435 struct mime_encoder_state *st = &part->encstate;
440 while(st->bufbeg < st->bufend) {
442 if(st->pos > MAX_ENCODED_LINE_LENGTH - 4) {
443 /* Yes, we need 2 characters for CRLF. */
456 /* Be sure there is enough space and input data for a base64 group. */
462 if(st->bufend - st->bufbeg < 3)
465 /* Encode three bytes as four characters. */
466 i = st->buf[st->bufbeg++] & 0xFF;
467 i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
468 i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
469 *ptr++ = base64[(i >> 18) & 0x3F];
470 *ptr++ = base64[(i >> 12) & 0x3F];
471 *ptr++ = base64[(i >> 6) & 0x3F];
472 *ptr++ = base64[i & 0x3F];
478 /* If at eof, we have to flush the buffered data. */
485 /* Buffered data size can only be 0, 1 or 2. */
486 ptr[2] = ptr[3] = '=';
489 /* If there is buffered data */
490 if(st->bufend != st->bufbeg) {
492 if(st->bufend - st->bufbeg == 2)
493 i = (st->buf[st->bufbeg + 1] & 0xFF) << 8;
495 i |= (st->buf[st->bufbeg] & 0xFF) << 16;
496 ptr[0] = base64[(i >> 18) & 0x3F];
497 ptr[1] = base64[(i >> 12) & 0x3F];
498 if(++st->bufbeg != st->bufend) {
499 ptr[2] = base64[(i >> 6) & 0x3F];
511 static curl_off_t encoder_base64_size(curl_mimepart *part)
513 curl_off_t size = part->datasize;
516 return size; /* Unknown size or no data. */
518 /* Compute base64 character count. */
519 size = 4 * (1 + (size - 1) / 3);
521 /* Effective character count must include CRLFs. */
522 return size + 2 * ((size - 1) / MAX_ENCODED_LINE_LENGTH);
526 /* Quoted-printable lookahead.
528 * Check if a CRLF or end of data is in input buffer at current position + n.
529 * Return -1 if more data needed, 1 if CRLF or end of data, else 0.
531 static int qp_lookahead_eol(struct mime_encoder_state *st, int ateof, size_t n)
534 if(n >= st->bufend && ateof)
536 if(n + 2 > st->bufend)
538 if(qp_class[st->buf[n] & 0xFF] == QP_CR &&
539 qp_class[st->buf[n + 1] & 0xFF] == QP_LF)
544 /* Quoted-printable encoder. */
545 static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
548 struct mime_encoder_state *st = &part->encstate;
554 /* On all platforms, input is supposed to be ASCII compatible: for this
555 reason, we use hexadecimal ASCII codes in this function rather than
556 character constants that can be interpreted as non-ascii on some
557 platforms. Preserve ASCII encoding on output too. */
558 while(st->bufbeg < st->bufend) {
561 int i = st->buf[st->bufbeg];
563 buf[1] = aschex[(i >> 4) & 0xF];
564 buf[2] = aschex[i & 0xF];
566 switch(qp_class[st->buf[st->bufbeg] & 0xFF]) {
567 case QP_OK: /* Not a special character. */
569 case QP_SP: /* Space or tab. */
570 /* Spacing must be escaped if followed by CRLF. */
571 switch(qp_lookahead_eol(st, ateof, 1)) {
572 case -1: /* More input data needed. */
574 case 0: /* No encoding needed. */
576 default: /* CRLF after space or tab. */
577 buf[0] = '\x3D'; /* '=' */
582 case QP_CR: /* Carriage return. */
583 /* If followed by a line-feed, output the CRLF pair.
585 switch(qp_lookahead_eol(st, ateof, 0)) {
586 case -1: /* Need more data. */
588 case 1: /* CRLF found. */
589 buf[len++] = '\x0A'; /* Append '\n'. */
592 default: /* Not followed by LF: escape. */
593 buf[0] = '\x3D'; /* '=' */
598 default: /* Character must be escaped. */
599 buf[0] = '\x3D'; /* '=' */
604 /* Be sure the encoded character fits within maximum line length. */
605 if(buf[len - 1] != '\x0A') { /* '\n' */
606 softlinebreak = st->pos + len > MAX_ENCODED_LINE_LENGTH;
607 if(!softlinebreak && st->pos + len == MAX_ENCODED_LINE_LENGTH) {
608 /* We may use the current line only if end of data or followed by
610 switch(qp_lookahead_eol(st, ateof, consumed)) {
611 case -1: /* Need more data. */
613 case 0: /* Not followed by a CRLF. */
619 strcpy(buf, "\x3D\x0D\x0A"); /* "=\r\n" */
625 /* If the output buffer would overflow, do not store. */
632 /* Append to output buffer. */
633 memcpy(ptr, buf, len);
638 if(buf[len - 1] == '\x0A') /* '\n' */
640 st->bufbeg += consumed;
646 static curl_off_t encoder_qp_size(curl_mimepart *part)
648 /* Determining the size can only be done by reading the data: unless the
649 data size is 0, we return it as unknown (-1). */
650 return part->datasize? -1: 0;
654 /* In-memory data callbacks. */
655 /* Argument is a pointer to the mime part. */
656 static size_t mime_mem_read(char *buffer, size_t size, size_t nitems,
659 curl_mimepart *part = (curl_mimepart *) instream;
660 size_t sz = curlx_sotouz(part->datasize - part->state.offset);
661 (void) size; /* Always 1.*/
670 memcpy(buffer, part->data + curlx_sotouz(part->state.offset), sz);
675 static int mime_mem_seek(void *instream, curl_off_t offset, int whence)
677 curl_mimepart *part = (curl_mimepart *) instream;
681 offset += part->state.offset;
684 offset += part->datasize;
688 if(offset < 0 || offset > part->datasize)
689 return CURL_SEEKFUNC_FAIL;
691 part->state.offset = offset;
692 return CURL_SEEKFUNC_OK;
695 static void mime_mem_free(void *ptr)
697 Curl_safefree(((curl_mimepart *) ptr)->data);
701 /* Named file callbacks. */
702 /* Argument is a pointer to the mime part. */
703 static int mime_open_file(curl_mimepart *part)
705 /* Open a MIMEKIND_FILE part. */
709 part->fp = fopen_read(part->data, "rb");
710 return part->fp? 0: -1;
713 static size_t mime_file_read(char *buffer, size_t size, size_t nitems,
716 curl_mimepart *part = (curl_mimepart *) instream;
721 if(mime_open_file(part))
724 return fread(buffer, size, nitems, part->fp);
727 static int mime_file_seek(void *instream, curl_off_t offset, int whence)
729 curl_mimepart *part = (curl_mimepart *) instream;
731 if(whence == SEEK_SET && !offset && !part->fp)
732 return CURL_SEEKFUNC_OK; /* Not open: implicitly already at BOF. */
734 if(mime_open_file(part))
735 return CURL_SEEKFUNC_FAIL;
737 return fseek(part->fp, (long) offset, whence)?
738 CURL_SEEKFUNC_CANTSEEK: CURL_SEEKFUNC_OK;
741 static void mime_file_free(void *ptr)
743 curl_mimepart *part = (curl_mimepart *) ptr;
749 Curl_safefree(part->data);
754 /* Subparts callbacks. */
755 /* Argument is a pointer to the mime structure. */
757 /* Readback a byte string segment. */
758 static size_t readback_bytes(struct mime_state *state,
759 char *buffer, size_t bufsize,
760 const char *bytes, size_t numbytes,
761 const char *trail, size_t traillen)
764 size_t offset = curlx_sotouz(state->offset);
766 if(numbytes > offset) {
767 sz = numbytes - offset;
771 sz = offset - numbytes;
781 memcpy(buffer, bytes, sz);
786 /* Read a non-encoded part content. */
787 static size_t read_part_content(curl_mimepart *part,
788 char *buffer, size_t bufsize, bool *hasread)
792 switch(part->lastreadstatus) {
794 case CURL_READFUNC_ABORT:
795 case CURL_READFUNC_PAUSE:
797 return part->lastreadstatus;
802 /* If we can determine we are at end of part data, spare a read. */
803 if(part->datasize != (curl_off_t) -1 &&
804 part->state.offset >= part->datasize) {
805 /* sz is already zero. */
809 case MIMEKIND_MULTIPART:
811 * Cannot be processed as other kinds since read function requires
812 * an additional parameter and is highly recursive.
814 sz = mime_subparts_read(buffer, 1, bufsize, part->arg, hasread);
817 if(part->fp && feof(part->fp))
822 if(!(part->flags & MIME_FAST_READ)) {
827 sz = part->readfunc(buffer, 1, bufsize, part->arg);
837 case CURL_READFUNC_ABORT:
838 case CURL_READFUNC_PAUSE:
840 part->lastreadstatus = sz;
843 part->state.offset += sz;
844 part->lastreadstatus = sz;
851 /* Read and encode part content. */
852 static size_t read_encoded_part_content(curl_mimepart *part, char *buffer,
853 size_t bufsize, bool *hasread)
855 struct mime_encoder_state *st = &part->encstate;
861 if(st->bufbeg < st->bufend || ateof) {
862 /* Encode buffered data. */
863 sz = part->encoder->encodefunc(buffer, bufsize, ateof, part);
871 return cursize? cursize: sz;
880 /* We need more data in input buffer. */
882 size_t len = st->bufend - st->bufbeg;
885 memmove(st->buf, st->buf + st->bufbeg, len);
889 if(st->bufend >= sizeof(st->buf))
890 return cursize? cursize: READ_ERROR; /* Buffer full. */
891 sz = read_part_content(part, st->buf + st->bufend,
892 sizeof(st->buf) - st->bufend, hasread);
897 case CURL_READFUNC_ABORT:
898 case CURL_READFUNC_PAUSE:
901 return cursize? cursize: sz;
911 /* Readback a mime part. */
912 static size_t readback_part(curl_mimepart *part,
913 char *buffer, size_t bufsize, bool *hasread)
917 /* Readback from part. */
921 struct curl_slist *hdr = (struct curl_slist *) part->state.ptr;
922 switch(part->state.state) {
923 case MIMESTATE_BEGIN:
924 mimesetstate(&part->state,
925 (part->flags & MIME_BODY_ONLY)?
926 MIMESTATE_BODY: MIMESTATE_CURLHEADERS,
929 case MIMESTATE_USERHEADERS:
931 mimesetstate(&part->state, MIMESTATE_EOH, NULL);
934 if(match_header(hdr, "Content-Type", 12)) {
935 mimesetstate(&part->state, MIMESTATE_USERHEADERS, hdr->next);
939 case MIMESTATE_CURLHEADERS:
941 mimesetstate(&part->state, MIMESTATE_USERHEADERS, part->userheaders);
943 sz = readback_bytes(&part->state, buffer, bufsize,
944 hdr->data, strlen(hdr->data), STRCONST("\r\n"));
946 mimesetstate(&part->state, part->state.state, hdr->next);
950 sz = readback_bytes(&part->state, buffer, bufsize, STRCONST("\r\n"),
953 mimesetstate(&part->state, MIMESTATE_BODY, NULL);
956 cleanup_encoder_state(&part->encstate);
957 mimesetstate(&part->state, MIMESTATE_CONTENT, NULL);
959 case MIMESTATE_CONTENT:
961 sz = read_encoded_part_content(part, buffer, bufsize, hasread);
963 sz = read_part_content(part, buffer, bufsize, hasread);
966 mimesetstate(&part->state, MIMESTATE_END, NULL);
967 /* Try sparing open file descriptors. */
968 if(part->kind == MIMEKIND_FILE && part->fp) {
973 case CURL_READFUNC_ABORT:
974 case CURL_READFUNC_PAUSE:
977 return cursize? cursize: sz;
983 break; /* Other values not in part state. */
986 /* Bump buffer and counters according to read size. */
995 /* Readback from mime. Warning: not a read callback function. */
996 static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
997 void *instream, bool *hasread)
999 curl_mime *mime = (curl_mime *) instream;
1001 (void) size; /* Always 1. */
1005 curl_mimepart *part = mime->state.ptr;
1006 switch(mime->state.state) {
1007 case MIMESTATE_BEGIN:
1008 case MIMESTATE_BODY:
1009 mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, mime->firstpart);
1010 /* The first boundary always follows the header termination empty line,
1011 so is always preceded by a CRLF. We can then spare 2 characters
1012 by skipping the leading CRLF in boundary. */
1013 mime->state.offset += 2;
1015 case MIMESTATE_BOUNDARY1:
1016 sz = readback_bytes(&mime->state, buffer, nitems, STRCONST("\r\n--"),
1019 mimesetstate(&mime->state, MIMESTATE_BOUNDARY2, part);
1021 case MIMESTATE_BOUNDARY2:
1023 sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary,
1024 MIME_BOUNDARY_LEN, STRCONST("\r\n"));
1026 sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary,
1027 MIME_BOUNDARY_LEN, STRCONST("--\r\n"));
1029 mimesetstate(&mime->state, MIMESTATE_CONTENT, part);
1032 case MIMESTATE_CONTENT:
1034 mimesetstate(&mime->state, MIMESTATE_END, NULL);
1037 sz = readback_part(part, buffer, nitems, hasread);
1039 case CURL_READFUNC_ABORT:
1040 case CURL_READFUNC_PAUSE:
1043 return cursize? cursize: sz;
1045 mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, part->nextpart);
1052 break; /* other values not used in mime state. */
1055 /* Bump buffer and counters according to read size. */
1064 static int mime_part_rewind(curl_mimepart *part)
1066 int res = CURL_SEEKFUNC_OK;
1067 enum mimestate targetstate = MIMESTATE_BEGIN;
1069 if(part->flags & MIME_BODY_ONLY)
1070 targetstate = MIMESTATE_BODY;
1071 cleanup_encoder_state(&part->encstate);
1072 if(part->state.state > targetstate) {
1073 res = CURL_SEEKFUNC_CANTSEEK;
1074 if(part->seekfunc) {
1075 res = part->seekfunc(part->arg, (curl_off_t) 0, SEEK_SET);
1077 case CURL_SEEKFUNC_OK:
1078 case CURL_SEEKFUNC_FAIL:
1079 case CURL_SEEKFUNC_CANTSEEK:
1081 case -1: /* For fseek() error. */
1082 res = CURL_SEEKFUNC_CANTSEEK;
1085 res = CURL_SEEKFUNC_FAIL;
1091 if(res == CURL_SEEKFUNC_OK)
1092 mimesetstate(&part->state, targetstate, NULL);
1094 part->lastreadstatus = 1; /* Successful read status. */
1098 static int mime_subparts_seek(void *instream, curl_off_t offset, int whence)
1100 curl_mime *mime = (curl_mime *) instream;
1101 curl_mimepart *part;
1102 int result = CURL_SEEKFUNC_OK;
1104 if(whence != SEEK_SET || offset)
1105 return CURL_SEEKFUNC_CANTSEEK; /* Only support full rewind. */
1107 if(mime->state.state == MIMESTATE_BEGIN)
1108 return CURL_SEEKFUNC_OK; /* Already rewound. */
1110 for(part = mime->firstpart; part; part = part->nextpart) {
1111 int res = mime_part_rewind(part);
1112 if(res != CURL_SEEKFUNC_OK)
1116 if(result == CURL_SEEKFUNC_OK)
1117 mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
1122 /* Release part content. */
1123 static void cleanup_part_content(curl_mimepart *part)
1126 part->freefunc(part->arg);
1128 part->readfunc = NULL;
1129 part->seekfunc = NULL;
1130 part->freefunc = NULL;
1131 part->arg = (void *) part; /* Defaults to part itself. */
1134 part->datasize = (curl_off_t) 0; /* No size yet. */
1135 cleanup_encoder_state(&part->encstate);
1136 part->kind = MIMEKIND_NONE;
1137 part->flags &= ~MIME_FAST_READ;
1138 part->lastreadstatus = 1; /* Successful read status. */
1139 part->state.state = MIMESTATE_BEGIN;
1142 static void mime_subparts_free(void *ptr)
1144 curl_mime *mime = (curl_mime *) ptr;
1146 if(mime && mime->parent) {
1147 mime->parent->freefunc = NULL; /* Be sure we won't be called again. */
1148 cleanup_part_content(mime->parent); /* Avoid dangling pointer in part. */
1150 curl_mime_free(mime);
1153 /* Do not free subparts: unbind them. This is used for the top level only. */
1154 static void mime_subparts_unbind(void *ptr)
1156 curl_mime *mime = (curl_mime *) ptr;
1158 if(mime && mime->parent) {
1159 mime->parent->freefunc = NULL; /* Be sure we won't be called again. */
1160 cleanup_part_content(mime->parent); /* Avoid dangling pointer in part. */
1161 mime->parent = NULL;
1166 void Curl_mime_cleanpart(curl_mimepart *part)
1168 cleanup_part_content(part);
1169 curl_slist_free_all(part->curlheaders);
1170 if(part->flags & MIME_USERHEADERS_OWNER)
1171 curl_slist_free_all(part->userheaders);
1172 Curl_safefree(part->mimetype);
1173 Curl_safefree(part->name);
1174 Curl_safefree(part->filename);
1175 Curl_mime_initpart(part, part->easy);
1178 /* Recursively delete a mime handle and its parts. */
1179 void curl_mime_free(curl_mime *mime)
1181 curl_mimepart *part;
1184 mime_subparts_unbind(mime); /* Be sure it's not referenced anymore. */
1185 while(mime->firstpart) {
1186 part = mime->firstpart;
1187 mime->firstpart = part->nextpart;
1188 Curl_mime_cleanpart(part);
1195 CURLcode Curl_mime_duppart(curl_mimepart *dst, const curl_mimepart *src)
1199 const curl_mimepart *s;
1200 CURLcode res = CURLE_OK;
1204 /* Duplicate content. */
1209 res = curl_mime_data(dst, src->data, (size_t) src->datasize);
1212 res = curl_mime_filedata(dst, src->data);
1213 /* Do not abort duplication if file is not readable. */
1214 if(res == CURLE_READ_ERROR)
1217 case MIMEKIND_CALLBACK:
1218 res = curl_mime_data_cb(dst, src->datasize, src->readfunc,
1219 src->seekfunc, src->freefunc, src->arg);
1221 case MIMEKIND_MULTIPART:
1222 /* No one knows about the cloned subparts, thus always attach ownership
1224 mime = curl_mime_init(dst->easy);
1225 res = mime? curl_mime_subparts(dst, mime): CURLE_OUT_OF_MEMORY;
1227 /* Duplicate subparts. */
1228 for(s = ((curl_mime *) src->arg)->firstpart; !res && s; s = s->nextpart) {
1229 d = curl_mime_addpart(mime);
1230 res = d? Curl_mime_duppart(d, s): CURLE_OUT_OF_MEMORY;
1233 default: /* Invalid kind: should not occur. */
1234 res = CURLE_BAD_FUNCTION_ARGUMENT; /* Internal error? */
1238 /* Duplicate headers. */
1239 if(!res && src->userheaders) {
1240 struct curl_slist *hdrs = Curl_slist_duplicate(src->userheaders);
1243 res = CURLE_OUT_OF_MEMORY;
1245 /* No one but this procedure knows about the new header list,
1246 so always take ownership. */
1247 res = curl_mime_headers(dst, hdrs, TRUE);
1249 curl_slist_free_all(hdrs);
1254 /* Duplicate other fields. */
1255 dst->encoder = src->encoder;
1256 res = curl_mime_type(dst, src->mimetype);
1259 res = curl_mime_name(dst, src->name);
1261 res = curl_mime_filename(dst, src->filename);
1263 /* If an error occurred, rollback. */
1265 Curl_mime_cleanpart(dst);
1271 * Mime build functions.
1274 /* Create a mime handle. */
1275 curl_mime *curl_mime_init(struct Curl_easy *easy)
1279 mime = (curl_mime *) malloc(sizeof(*mime));
1283 mime->parent = NULL;
1284 mime->firstpart = NULL;
1285 mime->lastpart = NULL;
1287 memset(mime->boundary, '-', MIME_BOUNDARY_DASHES);
1288 if(Curl_rand_hex(easy,
1289 (unsigned char *) &mime->boundary[MIME_BOUNDARY_DASHES],
1290 MIME_RAND_BOUNDARY_CHARS + 1)) {
1291 /* failed to get random separator, bail out */
1295 mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
1301 /* Initialize a mime part. */
1302 void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy)
1304 memset((char *) part, 0, sizeof(*part));
1306 part->lastreadstatus = 1; /* Successful read status. */
1307 mimesetstate(&part->state, MIMESTATE_BEGIN, NULL);
1310 /* Create a mime part and append it to a mime handle's part list. */
1311 curl_mimepart *curl_mime_addpart(curl_mime *mime)
1313 curl_mimepart *part;
1318 part = (curl_mimepart *) malloc(sizeof(*part));
1321 Curl_mime_initpart(part, mime->easy);
1322 part->parent = mime;
1325 mime->lastpart->nextpart = part;
1327 mime->firstpart = part;
1329 mime->lastpart = part;
1335 /* Set mime part name. */
1336 CURLcode curl_mime_name(curl_mimepart *part, const char *name)
1339 return CURLE_BAD_FUNCTION_ARGUMENT;
1341 Curl_safefree(part->name);
1345 part->name = strdup(name);
1347 return CURLE_OUT_OF_MEMORY;
1353 /* Set mime part remote file name. */
1354 CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
1357 return CURLE_BAD_FUNCTION_ARGUMENT;
1359 Curl_safefree(part->filename);
1360 part->filename = NULL;
1363 part->filename = strdup(filename);
1365 return CURLE_OUT_OF_MEMORY;
1371 /* Set mime part content from memory data. */
1372 CURLcode curl_mime_data(curl_mimepart *part,
1373 const char *data, size_t datasize)
1376 return CURLE_BAD_FUNCTION_ARGUMENT;
1378 cleanup_part_content(part);
1381 if(datasize == CURL_ZERO_TERMINATED)
1382 datasize = strlen(data);
1384 part->data = malloc(datasize + 1);
1386 return CURLE_OUT_OF_MEMORY;
1388 part->datasize = datasize;
1391 memcpy(part->data, data, datasize);
1392 part->data[datasize] = '\0'; /* Set a null terminator as sentinel. */
1394 part->readfunc = mime_mem_read;
1395 part->seekfunc = mime_mem_seek;
1396 part->freefunc = mime_mem_free;
1397 part->flags |= MIME_FAST_READ;
1398 part->kind = MIMEKIND_DATA;
1404 /* Set mime part content from named local file. */
1405 CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
1407 CURLcode result = CURLE_OK;
1410 return CURLE_BAD_FUNCTION_ARGUMENT;
1412 cleanup_part_content(part);
1418 if(stat(filename, &sbuf) || access(filename, R_OK))
1419 result = CURLE_READ_ERROR;
1421 part->data = strdup(filename);
1423 result = CURLE_OUT_OF_MEMORY;
1425 part->datasize = -1;
1426 if(!result && S_ISREG(sbuf.st_mode)) {
1427 part->datasize = filesize(filename, sbuf);
1428 part->seekfunc = mime_file_seek;
1431 part->readfunc = mime_file_read;
1432 part->freefunc = mime_file_free;
1433 part->kind = MIMEKIND_FILE;
1435 /* As a side effect, set the filename to the current file's base name.
1436 It is possible to withdraw this by explicitly calling
1437 curl_mime_filename() with a NULL filename argument after the current
1439 base = strippath(filename);
1441 result = CURLE_OUT_OF_MEMORY;
1443 CURLcode res = curl_mime_filename(part, base);
1453 /* Set mime part type. */
1454 CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
1457 return CURLE_BAD_FUNCTION_ARGUMENT;
1459 Curl_safefree(part->mimetype);
1460 part->mimetype = NULL;
1463 part->mimetype = strdup(mimetype);
1465 return CURLE_OUT_OF_MEMORY;
1471 /* Set mime data transfer encoder. */
1472 CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
1474 CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
1475 const struct mime_encoder *mep;
1480 part->encoder = NULL;
1483 return CURLE_OK; /* Removing current encoder. */
1485 for(mep = encoders; mep->name; mep++)
1486 if(strcasecompare(encoding, mep->name)) {
1487 part->encoder = mep;
1494 /* Set mime part headers. */
1495 CURLcode curl_mime_headers(curl_mimepart *part,
1496 struct curl_slist *headers, int take_ownership)
1499 return CURLE_BAD_FUNCTION_ARGUMENT;
1501 if(part->flags & MIME_USERHEADERS_OWNER) {
1502 if(part->userheaders != headers) /* Allow setting twice the same list. */
1503 curl_slist_free_all(part->userheaders);
1504 part->flags &= ~MIME_USERHEADERS_OWNER;
1506 part->userheaders = headers;
1507 if(headers && take_ownership)
1508 part->flags |= MIME_USERHEADERS_OWNER;
1512 /* Set mime part content from callback. */
1513 CURLcode curl_mime_data_cb(curl_mimepart *part, curl_off_t datasize,
1514 curl_read_callback readfunc,
1515 curl_seek_callback seekfunc,
1516 curl_free_callback freefunc, void *arg)
1519 return CURLE_BAD_FUNCTION_ARGUMENT;
1521 cleanup_part_content(part);
1524 part->readfunc = readfunc;
1525 part->seekfunc = seekfunc;
1526 part->freefunc = freefunc;
1528 part->datasize = datasize;
1529 part->kind = MIMEKIND_CALLBACK;
1535 /* Set mime part content from subparts. */
1536 CURLcode Curl_mime_set_subparts(curl_mimepart *part,
1537 curl_mime *subparts, int take_ownership)
1542 return CURLE_BAD_FUNCTION_ARGUMENT;
1544 /* Accept setting twice the same subparts. */
1545 if(part->kind == MIMEKIND_MULTIPART && part->arg == subparts)
1548 cleanup_part_content(part);
1551 /* Must belong to the same data handle. */
1552 if(part->easy && subparts->easy && part->easy != subparts->easy)
1553 return CURLE_BAD_FUNCTION_ARGUMENT;
1555 /* Should not have been attached already. */
1556 if(subparts->parent)
1557 return CURLE_BAD_FUNCTION_ARGUMENT;
1559 /* Should not be the part's root. */
1560 root = part->parent;
1562 while(root->parent && root->parent->parent)
1563 root = root->parent->parent;
1564 if(subparts == root) {
1566 failf(part->easy, "Can't add itself as a subpart");
1567 return CURLE_BAD_FUNCTION_ARGUMENT;
1571 subparts->parent = part;
1572 /* Subparts are processed internally: no read callback. */
1573 part->seekfunc = mime_subparts_seek;
1574 part->freefunc = take_ownership? mime_subparts_free: mime_subparts_unbind;
1575 part->arg = subparts;
1576 part->datasize = -1;
1577 part->kind = MIMEKIND_MULTIPART;
1583 CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
1585 return Curl_mime_set_subparts(part, subparts, TRUE);
1589 /* Readback from top mime. */
1590 /* Argument is the dummy top part. */
1591 size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream)
1593 curl_mimepart *part = (curl_mimepart *) instream;
1597 (void) size; /* Always 1. */
1601 ret = readback_part(part, buffer, nitems, &hasread);
1603 * If this is not possible to get some data without calling more than
1604 * one read callback (probably because a content encoder is not able to
1605 * deliver a new bunch for the few data accumulated so far), force another
1606 * read until we get enough data or a special exit code.
1608 } while(ret == STOP_FILLING);
1613 /* Rewind mime stream. */
1614 CURLcode Curl_mime_rewind(curl_mimepart *part)
1616 return mime_part_rewind(part) == CURL_SEEKFUNC_OK?
1617 CURLE_OK: CURLE_SEND_FAIL_REWIND;
1620 /* Compute header list size. */
1621 static size_t slist_size(struct curl_slist *s,
1622 size_t overhead, const char *skip, size_t skiplen)
1626 for(; s; s = s->next)
1627 if(!skip || !match_header(s, skip, skiplen))
1628 size += strlen(s->data) + overhead;
1632 /* Get/compute multipart size. */
1633 static curl_off_t multipart_size(curl_mime *mime)
1636 size_t boundarysize;
1637 curl_mimepart *part;
1640 return 0; /* Not present -> empty. */
1642 boundarysize = 4 + MIME_BOUNDARY_LEN + 2;
1643 size = boundarysize; /* Final boundary - CRLF after headers. */
1645 for(part = mime->firstpart; part; part = part->nextpart) {
1646 curl_off_t sz = Curl_mime_size(part);
1652 size += boundarysize + sz;
1658 /* Get/compute mime size. */
1659 curl_off_t Curl_mime_size(curl_mimepart *part)
1663 if(part->kind == MIMEKIND_MULTIPART)
1664 part->datasize = multipart_size(part->arg);
1666 size = part->datasize;
1669 size = part->encoder->sizefunc(part);
1671 if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) {
1672 /* Compute total part size. */
1673 size += slist_size(part->curlheaders, 2, NULL, 0);
1674 size += slist_size(part->userheaders, 2, STRCONST("Content-Type"));
1675 size += 2; /* CRLF after headers. */
1682 CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
1684 struct curl_slist *hdr = NULL;
1689 s = curl_mvaprintf(fmt, ap);
1693 hdr = Curl_slist_append_nodup(*slp, s);
1700 return hdr? CURLE_OK: CURLE_OUT_OF_MEMORY;
1703 /* Add a content type header. */
1704 static CURLcode add_content_type(struct curl_slist **slp,
1705 const char *type, const char *boundary)
1707 return Curl_mime_add_header(slp, "Content-Type: %s%s%s", type,
1708 boundary? "; boundary=": "",
1709 boundary? boundary: "");
1712 const char *Curl_mime_contenttype(const char *filename)
1715 * If no content type was specified, we scan through a few well-known
1716 * extensions and pick the first we match!
1718 struct ContentType {
1719 const char *extension;
1722 static const struct ContentType ctts[] = {
1723 {".gif", "image/gif"},
1724 {".jpg", "image/jpeg"},
1725 {".jpeg", "image/jpeg"},
1726 {".png", "image/png"},
1727 {".svg", "image/svg+xml"},
1728 {".txt", "text/plain"},
1729 {".htm", "text/html"},
1730 {".html", "text/html"},
1731 {".pdf", "application/pdf"},
1732 {".xml", "application/xml"}
1736 size_t len1 = strlen(filename);
1737 const char *nameend = filename + len1;
1740 for(i = 0; i < sizeof(ctts) / sizeof(ctts[0]); i++) {
1741 size_t len2 = strlen(ctts[i].extension);
1743 if(len1 >= len2 && strcasecompare(nameend - len2, ctts[i].extension))
1744 return ctts[i].type;
1750 static bool content_type_match(const char *contenttype,
1751 const char *target, size_t len)
1753 if(contenttype && strncasecompare(contenttype, target, len))
1754 switch(contenttype[len]) {
1766 CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
1767 const char *contenttype,
1768 const char *disposition,
1769 enum mimestrategy strategy)
1771 curl_mime *mime = NULL;
1772 const char *boundary = NULL;
1774 const char *cte = NULL;
1775 CURLcode ret = CURLE_OK;
1777 /* Get rid of previously prepared headers. */
1778 curl_slist_free_all(part->curlheaders);
1779 part->curlheaders = NULL;
1781 /* Be sure we won't access old headers later. */
1782 if(part->state.state == MIMESTATE_CURLHEADERS)
1783 mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL);
1785 /* Check if content type is specified. */
1786 customct = part->mimetype;
1788 customct = search_header(part->userheaders, STRCONST("Content-Type"));
1790 contenttype = customct;
1792 /* If content type is not specified, try to determine it. */
1794 switch(part->kind) {
1795 case MIMEKIND_MULTIPART:
1796 contenttype = MULTIPART_CONTENTTYPE_DEFAULT;
1799 contenttype = Curl_mime_contenttype(part->filename);
1801 contenttype = Curl_mime_contenttype(part->data);
1802 if(!contenttype && part->filename)
1803 contenttype = FILE_CONTENTTYPE_DEFAULT;
1806 contenttype = Curl_mime_contenttype(part->filename);
1811 if(part->kind == MIMEKIND_MULTIPART) {
1812 mime = (curl_mime *) part->arg;
1814 boundary = mime->boundary;
1816 else if(contenttype && !customct &&
1817 content_type_match(contenttype, STRCONST("text/plain")))
1818 if(strategy == MIMESTRATEGY_MAIL || !part->filename)
1821 /* Issue content-disposition header only if not already set by caller. */
1822 if(!search_header(part->userheaders, STRCONST("Content-Disposition"))) {
1824 if(part->filename || part->name ||
1825 (contenttype && !strncasecompare(contenttype, "multipart/", 10)))
1826 disposition = DISPOSITION_DEFAULT;
1827 if(disposition && curl_strequal(disposition, "attachment") &&
1828 !part->name && !part->filename)
1832 char *filename = NULL;
1835 name = escape_string(part->easy, part->name, strategy);
1837 ret = CURLE_OUT_OF_MEMORY;
1839 if(!ret && part->filename) {
1840 filename = escape_string(part->easy, part->filename, strategy);
1842 ret = CURLE_OUT_OF_MEMORY;
1845 ret = Curl_mime_add_header(&part->curlheaders,
1846 "Content-Disposition: %s%s%s%s%s%s%s",
1848 name? "; name=\"": "",
1851 filename? "; filename=\"": "",
1852 filename? filename: "",
1853 filename? "\"": "");
1854 Curl_safefree(name);
1855 Curl_safefree(filename);
1861 /* Issue Content-Type header. */
1863 ret = add_content_type(&part->curlheaders, contenttype, boundary);
1868 /* Content-Transfer-Encoding header. */
1869 if(!search_header(part->userheaders,
1870 STRCONST("Content-Transfer-Encoding"))) {
1872 cte = part->encoder->name;
1873 else if(contenttype && strategy == MIMESTRATEGY_MAIL &&
1874 part->kind != MIMEKIND_MULTIPART)
1877 ret = Curl_mime_add_header(&part->curlheaders,
1878 "Content-Transfer-Encoding: %s", cte);
1884 /* If we were reading curl-generated headers, restart with new ones (this
1885 should not occur). */
1886 if(part->state.state == MIMESTATE_CURLHEADERS)
1887 mimesetstate(&part->state, MIMESTATE_CURLHEADERS, part->curlheaders);
1889 /* Process subparts. */
1890 if(part->kind == MIMEKIND_MULTIPART && mime) {
1891 curl_mimepart *subpart;
1894 if(content_type_match(contenttype, STRCONST("multipart/form-data")))
1895 disposition = "form-data";
1896 for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) {
1897 ret = Curl_mime_prepare_headers(subpart, NULL, disposition, strategy);
1905 /* Recursively reset paused status in the given part. */
1906 void Curl_mime_unpause(curl_mimepart *part)
1909 if(part->lastreadstatus == CURL_READFUNC_PAUSE)
1910 part->lastreadstatus = 1; /* Successful read status. */
1911 if(part->kind == MIMEKIND_MULTIPART) {
1912 curl_mime *mime = (curl_mime *) part->arg;
1915 curl_mimepart *subpart;
1917 for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart)
1918 Curl_mime_unpause(subpart);
1925 #else /* !CURL_DISABLE_HTTP && !CURL_DISABLE_MIME ||
1926 !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP */
1928 /* Mime not compiled in: define stubs for externally-referenced functions. */
1929 curl_mime *curl_mime_init(CURL *easy)
1935 void curl_mime_free(curl_mime *mime)
1940 curl_mimepart *curl_mime_addpart(curl_mime *mime)
1946 CURLcode curl_mime_name(curl_mimepart *part, const char *name)
1950 return CURLE_NOT_BUILT_IN;
1953 CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
1957 return CURLE_NOT_BUILT_IN;
1960 CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
1964 return CURLE_NOT_BUILT_IN;
1967 CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
1971 return CURLE_NOT_BUILT_IN;
1974 CURLcode curl_mime_data(curl_mimepart *part,
1975 const char *data, size_t datasize)
1980 return CURLE_NOT_BUILT_IN;
1983 CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
1987 return CURLE_NOT_BUILT_IN;
1990 CURLcode curl_mime_data_cb(curl_mimepart *part,
1991 curl_off_t datasize,
1992 curl_read_callback readfunc,
1993 curl_seek_callback seekfunc,
1994 curl_free_callback freefunc,
2003 return CURLE_NOT_BUILT_IN;
2006 CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
2010 return CURLE_NOT_BUILT_IN;
2013 CURLcode curl_mime_headers(curl_mimepart *part,
2014 struct curl_slist *headers, int take_ownership)
2018 (void) take_ownership;
2019 return CURLE_NOT_BUILT_IN;
2022 CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
2026 return CURLE_NOT_BUILT_IN;
2029 #endif /* if disabled */