Coverage Report

Created: 2024-05-04 12:45

/proc/self/cwd/external/curl/lib/mime.c
Line
Count
Source (jump to first uncovered line)
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9
 *
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.
13
 *
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.
17
 *
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
 * KIND, either express or implied.
20
 *
21
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
25
#include "curl_setup.h"
26
27
#include <curl/curl.h>
28
29
#include "mime.h"
30
#include "warnless.h"
31
#include "urldata.h"
32
#include "sendf.h"
33
34
#if !defined(CURL_DISABLE_MIME) && (!defined(CURL_DISABLE_HTTP) ||      \
35
                                    !defined(CURL_DISABLE_SMTP) ||      \
36
                                    !defined(CURL_DISABLE_IMAP))
37
38
#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
39
#include <libgen.h>
40
#endif
41
42
#include "rand.h"
43
#include "slist.h"
44
#include "strcase.h"
45
#include "dynbuf.h"
46
/* The last 3 #include files should be in this order */
47
#include "curl_printf.h"
48
#include "curl_memory.h"
49
#include "memdebug.h"
50
51
#ifdef WIN32
52
# ifndef R_OK
53
#  define R_OK 4
54
# endif
55
#endif
56
57
58
0
#define READ_ERROR                      ((size_t) -1)
59
0
#define STOP_FILLING                    ((size_t) -2)
60
61
static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
62
                                 void *instream, bool *hasread);
63
64
/* Encoders. */
65
static size_t encoder_nop_read(char *buffer, size_t size, bool ateof,
66
                                curl_mimepart *part);
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,
69
                                curl_mimepart *part);
70
static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
71
                                curl_mimepart *part);
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,
74
                              curl_mimepart *part);
75
static curl_off_t encoder_qp_size(curl_mimepart *part);
76
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}
84
};
85
86
/* Base64 encoding table */
87
static const char base64enc[] =
88
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
89
90
/* Quoted-printable character class table.
91
 *
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
0
#define QP_OK           1       /* Can be represented by itself. */
95
0
#define QP_SP           2       /* Space or tab. */
96
0
#define QP_CR           3       /* Carriage return. */
97
0
#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 */
123
};
124
125
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";
129
130
131
132
#ifndef __VMS
133
0
#define filesize(name, stat_data) (stat_data.st_size)
134
0
#define fopen_read fopen
135
136
#else
137
138
#include <fabdef.h>
139
/*
140
 * get_vms_file_size does what it takes to get the real size of the file
141
 *
142
 * For fixed files, find out the size of the EOF block and adjust.
143
 *
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.
147
 *
148
 */
149
curl_off_t VmsRealFileSize(const char *name,
150
                           const struct_stat *stat_buf)
151
{
152
  char buffer[8192];
153
  curl_off_t count;
154
  int ret_stat;
155
  FILE * file;
156
157
  file = fopen(name, FOPEN_READTEXT); /* VMS */
158
  if(!file)
159
    return 0;
160
161
  count = 0;
162
  ret_stat = 1;
163
  while(ret_stat > 0) {
164
    ret_stat = fread(buffer, 1, sizeof(buffer), file);
165
    if(ret_stat)
166
      count += ret_stat;
167
  }
168
  fclose(file);
169
170
  return count;
171
}
172
173
/*
174
 *
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.
177
 *
178
 */
179
static curl_off_t VmsSpecialSize(const char *name,
180
                                 const struct_stat *stat_buf)
181
{
182
  switch(stat_buf->st_fab_rfm) {
183
  case FAB$C_VAR:
184
  case FAB$C_VFC:
185
    return VmsRealFileSize(name, stat_buf);
186
    break;
187
  default:
188
    return stat_buf->st_size;
189
  }
190
}
191
192
#define filesize(name, stat_data) VmsSpecialSize(name, &stat_data)
193
194
/*
195
 * vmsfopenread
196
 *
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.
200
 *
201
 */
202
static FILE * vmsfopenread(const char *file, const char *mode)
203
{
204
  struct_stat statbuf;
205
  int result;
206
207
  result = stat(file, &statbuf);
208
209
  switch(statbuf.st_fab_rfm) {
210
  case FAB$C_VAR:
211
  case FAB$C_VFC:
212
  case FAB$C_STMCR:
213
    return fopen(file, FOPEN_READTEXT); /* VMS */
214
    break;
215
  default:
216
    return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm");
217
  }
218
}
219
220
#define fopen_read vmsfopenread
221
#endif
222
223
224
#ifndef HAVE_BASENAME
225
/*
226
  (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
227
  Edition)
228
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.
232
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 "//"
236
  is returned.
237
238
  If path is a null pointer or points to an empty string, basename() shall
239
  return a pointer to the string ".".
240
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().
244
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.
247
248
*/
249
static char *Curl_basename(char *path)
250
{
251
  /* Ignore all the details above for now and make a quick and simple
252
     implementation here */
253
  char *s1;
254
  char *s2;
255
256
  s1 = strrchr(path, '/');
257
  s2 = strrchr(path, '\\');
258
259
  if(s1 && s2) {
260
    path = (s1 > s2? s1 : s2) + 1;
261
  }
262
  else if(s1)
263
    path = s1 + 1;
264
  else if(s2)
265
    path = s2 + 1;
266
267
  return path;
268
}
269
270
#define basename(x)  Curl_basename((x))
271
#endif
272
273
274
/* Set readback state. */
275
static void mimesetstate(struct mime_state *state,
276
                         enum mimestate tok, void *ptr)
277
0
{
278
0
  state->state = tok;
279
0
  state->ptr = ptr;
280
0
  state->offset = 0;
281
0
}
282
283
284
/* Escape header string into allocated memory. */
285
static char *escape_string(struct Curl_easy *data,
286
                           const char *src, enum mimestrategy strategy)
287
0
{
288
0
  CURLcode result;
289
0
  struct dynbuf db;
290
0
  const char * const *table;
291
0
  const char * const *p;
292
  /* replace first character by rest of string. */
293
0
  static const char * const mimetable[] = {
294
0
    "\\\\\\",
295
0
    "\"\\\"",
296
0
    NULL
297
0
  };
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
0
  static const char * const formtable[] = {
305
0
    "\"%22",
306
0
    "\r%0D",
307
0
    "\n%0A",
308
0
    NULL
309
0
  };
310
311
0
  table = formtable;
312
  /* data can be NULL when this function is called indirectly from
313
     curl_formget(). */
314
0
  if(strategy == MIMESTRATEGY_MAIL ||
315
0
     (data && (data->set.mime_options & CURLMIMEOPT_FORMESCAPE)))
316
0
    table = mimetable;
317
318
0
  Curl_dyn_init(&db, CURL_MAX_INPUT_LENGTH);
319
320
0
  for(result = Curl_dyn_addn(&db, STRCONST("")); !result && *src; src++) {
321
0
    for(p = table; *p && **p != *src; p++)
322
0
      ;
323
324
0
    if(*p)
325
0
      result = Curl_dyn_add(&db, *p + 1);
326
0
    else
327
0
      result = Curl_dyn_addn(&db, src, 1);
328
0
  }
329
330
0
  return Curl_dyn_ptr(&db);
331
0
}
332
333
/* Check if header matches. */
334
static char *match_header(struct curl_slist *hdr, const char *lbl, size_t len)
335
0
{
336
0
  char *value = NULL;
337
338
0
  if(strncasecompare(hdr->data, lbl, len) && hdr->data[len] == ':')
339
0
    for(value = hdr->data + len + 1; *value == ' '; value++)
340
0
      ;
341
0
  return value;
342
0
}
343
344
/* Get a header from an slist. */
345
static char *search_header(struct curl_slist *hdrlist,
346
                           const char *hdr, size_t len)
347
0
{
348
0
  char *value = NULL;
349
350
0
  for(; !value && hdrlist; hdrlist = hdrlist->next)
351
0
    value = match_header(hdrlist, hdr, len);
352
353
0
  return value;
354
0
}
355
356
static char *strippath(const char *fullfile)
357
0
{
358
0
  char *filename;
359
0
  char *base;
360
0
  filename = strdup(fullfile); /* duplicate since basename() may ruin the
361
                                  buffer it works on */
362
0
  if(!filename)
363
0
    return NULL;
364
0
  base = strdup(basename(filename));
365
366
0
  free(filename); /* free temporary buffer */
367
368
0
  return base; /* returns an allocated string or NULL ! */
369
0
}
370
371
/* Initialize data encoder state. */
372
static void cleanup_encoder_state(struct mime_encoder_state *p)
373
0
{
374
0
  p->pos = 0;
375
0
  p->bufbeg = 0;
376
0
  p->bufend = 0;
377
0
}
378
379
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)
383
0
{
384
0
  struct mime_encoder_state *st = &part->encstate;
385
0
  size_t insize = st->bufend - st->bufbeg;
386
387
0
  (void) ateof;
388
389
0
  if(!size)
390
0
    return STOP_FILLING;
391
392
0
  if(size > insize)
393
0
    size = insize;
394
395
0
  if(size)
396
0
    memcpy(buffer, st->buf + st->bufbeg, size);
397
398
0
  st->bufbeg += size;
399
0
  return size;
400
0
}
401
402
static curl_off_t encoder_nop_size(curl_mimepart *part)
403
0
{
404
0
  return part->datasize;
405
0
}
406
407
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,
410
                                curl_mimepart *part)
411
0
{
412
0
  struct mime_encoder_state *st = &part->encstate;
413
0
  size_t cursize = st->bufend - st->bufbeg;
414
415
0
  (void) ateof;
416
417
0
  if(!size)
418
0
    return STOP_FILLING;
419
420
0
  if(size > cursize)
421
0
    size = cursize;
422
423
0
  for(cursize = 0; cursize < size; cursize++) {
424
0
    *buffer = st->buf[st->bufbeg];
425
0
    if(*buffer++ & 0x80)
426
0
      return cursize? cursize: READ_ERROR;
427
0
    st->bufbeg++;
428
0
  }
429
430
0
  return cursize;
431
0
}
432
433
434
/* Base64 content encoder. */
435
static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
436
                                curl_mimepart *part)
437
0
{
438
0
  struct mime_encoder_state *st = &part->encstate;
439
0
  size_t cursize = 0;
440
0
  int i;
441
0
  char *ptr = buffer;
442
443
0
  while(st->bufbeg < st->bufend) {
444
    /* Line full ? */
445
0
    if(st->pos > MAX_ENCODED_LINE_LENGTH - 4) {
446
      /* Yes, we need 2 characters for CRLF. */
447
0
      if(size < 2) {
448
0
        if(!cursize)
449
0
          return STOP_FILLING;
450
0
        break;
451
0
      }
452
0
      *ptr++ = '\r';
453
0
      *ptr++ = '\n';
454
0
      st->pos = 0;
455
0
      cursize += 2;
456
0
      size -= 2;
457
0
    }
458
459
    /* Be sure there is enough space and input data for a base64 group. */
460
0
    if(size < 4) {
461
0
      if(!cursize)
462
0
        return STOP_FILLING;
463
0
      break;
464
0
    }
465
0
    if(st->bufend - st->bufbeg < 3)
466
0
      break;
467
468
    /* Encode three bytes as four characters. */
469
0
    i = st->buf[st->bufbeg++] & 0xFF;
470
0
    i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
471
0
    i = (i << 8) | (st->buf[st->bufbeg++] & 0xFF);
472
0
    *ptr++ = base64enc[(i >> 18) & 0x3F];
473
0
    *ptr++ = base64enc[(i >> 12) & 0x3F];
474
0
    *ptr++ = base64enc[(i >> 6) & 0x3F];
475
0
    *ptr++ = base64enc[i & 0x3F];
476
0
    cursize += 4;
477
0
    st->pos += 4;
478
0
    size -= 4;
479
0
  }
480
481
  /* If at eof, we have to flush the buffered data. */
482
0
  if(ateof) {
483
0
    if(size < 4) {
484
0
      if(!cursize)
485
0
        return STOP_FILLING;
486
0
    }
487
0
    else {
488
      /* Buffered data size can only be 0, 1 or 2. */
489
0
      ptr[2] = ptr[3] = '=';
490
0
      i = 0;
491
492
      /* If there is buffered data */
493
0
      if(st->bufend != st->bufbeg) {
494
495
0
        if(st->bufend - st->bufbeg == 2)
496
0
          i = (st->buf[st->bufbeg + 1] & 0xFF) << 8;
497
498
0
        i |= (st->buf[st->bufbeg] & 0xFF) << 16;
499
0
        ptr[0] = base64enc[(i >> 18) & 0x3F];
500
0
        ptr[1] = base64enc[(i >> 12) & 0x3F];
501
0
        if(++st->bufbeg != st->bufend) {
502
0
          ptr[2] = base64enc[(i >> 6) & 0x3F];
503
0
          st->bufbeg++;
504
0
        }
505
0
        cursize += 4;
506
0
        st->pos += 4;
507
0
      }
508
0
    }
509
0
  }
510
511
0
  return cursize;
512
0
}
513
514
static curl_off_t encoder_base64_size(curl_mimepart *part)
515
0
{
516
0
  curl_off_t size = part->datasize;
517
518
0
  if(size <= 0)
519
0
    return size;    /* Unknown size or no data. */
520
521
  /* Compute base64 character count. */
522
0
  size = 4 * (1 + (size - 1) / 3);
523
524
  /* Effective character count must include CRLFs. */
525
0
  return size + 2 * ((size - 1) / MAX_ENCODED_LINE_LENGTH);
526
0
}
527
528
529
/* Quoted-printable lookahead.
530
 *
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.
533
 */
534
static int qp_lookahead_eol(struct mime_encoder_state *st, int ateof, size_t n)
535
0
{
536
0
  n += st->bufbeg;
537
0
  if(n >= st->bufend && ateof)
538
0
    return 1;
539
0
  if(n + 2 > st->bufend)
540
0
    return ateof? 0: -1;
541
0
  if(qp_class[st->buf[n] & 0xFF] == QP_CR &&
542
0
     qp_class[st->buf[n + 1] & 0xFF] == QP_LF)
543
0
    return 1;
544
0
  return 0;
545
0
}
546
547
/* Quoted-printable encoder. */
548
static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
549
                              curl_mimepart *part)
550
0
{
551
0
  struct mime_encoder_state *st = &part->encstate;
552
0
  char *ptr = buffer;
553
0
  size_t cursize = 0;
554
0
  int softlinebreak;
555
0
  char buf[4];
556
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
0
  while(st->bufbeg < st->bufend) {
562
0
    size_t len = 1;
563
0
    size_t consumed = 1;
564
0
    int i = st->buf[st->bufbeg];
565
0
    buf[0] = (char) i;
566
0
    buf[1] = aschex[(i >> 4) & 0xF];
567
0
    buf[2] = aschex[i & 0xF];
568
569
0
    switch(qp_class[st->buf[st->bufbeg] & 0xFF]) {
570
0
    case QP_OK:          /* Not a special character. */
571
0
      break;
572
0
    case QP_SP:          /* Space or tab. */
573
      /* Spacing must be escaped if followed by CRLF. */
574
0
      switch(qp_lookahead_eol(st, ateof, 1)) {
575
0
      case -1:          /* More input data needed. */
576
0
        return cursize;
577
0
      case 0:           /* No encoding needed. */
578
0
        break;
579
0
      default:          /* CRLF after space or tab. */
580
0
        buf[0] = '\x3D';    /* '=' */
581
0
        len = 3;
582
0
        break;
583
0
      }
584
0
      break;
585
0
    case QP_CR:         /* Carriage return. */
586
      /* If followed by a line-feed, output the CRLF pair.
587
         Else escape it. */
588
0
      switch(qp_lookahead_eol(st, ateof, 0)) {
589
0
      case -1:          /* Need more data. */
590
0
        return cursize;
591
0
      case 1:           /* CRLF found. */
592
0
        buf[len++] = '\x0A';    /* Append '\n'. */
593
0
        consumed = 2;
594
0
        break;
595
0
      default:          /* Not followed by LF: escape. */
596
0
        buf[0] = '\x3D';    /* '=' */
597
0
        len = 3;
598
0
        break;
599
0
      }
600
0
      break;
601
0
    default:            /* Character must be escaped. */
602
0
      buf[0] = '\x3D';    /* '=' */
603
0
      len = 3;
604
0
      break;
605
0
    }
606
607
    /* Be sure the encoded character fits within maximum line length. */
608
0
    if(buf[len - 1] != '\x0A') {    /* '\n' */
609
0
      softlinebreak = st->pos + len > MAX_ENCODED_LINE_LENGTH;
610
0
      if(!softlinebreak && st->pos + len == MAX_ENCODED_LINE_LENGTH) {
611
        /* We may use the current line only if end of data or followed by
612
           a CRLF. */
613
0
        switch(qp_lookahead_eol(st, ateof, consumed)) {
614
0
        case -1:        /* Need more data. */
615
0
          return cursize;
616
0
        case 0:         /* Not followed by a CRLF. */
617
0
          softlinebreak = 1;
618
0
          break;
619
0
        }
620
0
      }
621
0
      if(softlinebreak) {
622
0
        strcpy(buf, "\x3D\x0D\x0A");    /* "=\r\n" */
623
0
        len = 3;
624
0
        consumed = 0;
625
0
      }
626
0
    }
627
628
    /* If the output buffer would overflow, do not store. */
629
0
    if(len > size) {
630
0
      if(!cursize)
631
0
        return STOP_FILLING;
632
0
      break;
633
0
    }
634
635
    /* Append to output buffer. */
636
0
    memcpy(ptr, buf, len);
637
0
    cursize += len;
638
0
    ptr += len;
639
0
    size -= len;
640
0
    st->pos += len;
641
0
    if(buf[len - 1] == '\x0A')    /* '\n' */
642
0
      st->pos = 0;
643
0
    st->bufbeg += consumed;
644
0
  }
645
646
0
  return cursize;
647
0
}
648
649
static curl_off_t encoder_qp_size(curl_mimepart *part)
650
0
{
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
0
  return part->datasize? -1: 0;
654
0
}
655
656
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,
660
                            void *instream)
661
0
{
662
0
  curl_mimepart *part = (curl_mimepart *) instream;
663
0
  size_t sz = curlx_sotouz(part->datasize - part->state.offset);
664
0
  (void) size;   /* Always 1.*/
665
666
0
  if(!nitems)
667
0
    return STOP_FILLING;
668
669
0
  if(sz > nitems)
670
0
    sz = nitems;
671
672
0
  if(sz)
673
0
    memcpy(buffer, part->data + curlx_sotouz(part->state.offset), sz);
674
675
0
  return sz;
676
0
}
677
678
static int mime_mem_seek(void *instream, curl_off_t offset, int whence)
679
0
{
680
0
  curl_mimepart *part = (curl_mimepart *) instream;
681
682
0
  switch(whence) {
683
0
  case SEEK_CUR:
684
0
    offset += part->state.offset;
685
0
    break;
686
0
  case SEEK_END:
687
0
    offset += part->datasize;
688
0
    break;
689
0
  }
690
691
0
  if(offset < 0 || offset > part->datasize)
692
0
    return CURL_SEEKFUNC_FAIL;
693
694
0
  part->state.offset = offset;
695
0
  return CURL_SEEKFUNC_OK;
696
0
}
697
698
static void mime_mem_free(void *ptr)
699
0
{
700
0
  Curl_safefree(((curl_mimepart *) ptr)->data);
701
0
}
702
703
704
/* Named file callbacks. */
705
/* Argument is a pointer to the mime part. */
706
static int mime_open_file(curl_mimepart *part)
707
0
{
708
  /* Open a MIMEKIND_FILE part. */
709
710
0
  if(part->fp)
711
0
    return 0;
712
0
  part->fp = fopen_read(part->data, "rb");
713
0
  return part->fp? 0: -1;
714
0
}
715
716
static size_t mime_file_read(char *buffer, size_t size, size_t nitems,
717
                             void *instream)
718
0
{
719
0
  curl_mimepart *part = (curl_mimepart *) instream;
720
721
0
  if(!nitems)
722
0
    return STOP_FILLING;
723
724
0
  if(mime_open_file(part))
725
0
    return READ_ERROR;
726
727
0
  return fread(buffer, size, nitems, part->fp);
728
0
}
729
730
static int mime_file_seek(void *instream, curl_off_t offset, int whence)
731
0
{
732
0
  curl_mimepart *part = (curl_mimepart *) instream;
733
734
0
  if(whence == SEEK_SET && !offset && !part->fp)
735
0
    return CURL_SEEKFUNC_OK;   /* Not open: implicitly already at BOF. */
736
737
0
  if(mime_open_file(part))
738
0
    return CURL_SEEKFUNC_FAIL;
739
740
0
  return fseek(part->fp, (long) offset, whence)?
741
0
               CURL_SEEKFUNC_CANTSEEK: CURL_SEEKFUNC_OK;
742
0
}
743
744
static void mime_file_free(void *ptr)
745
0
{
746
0
  curl_mimepart *part = (curl_mimepart *) ptr;
747
748
0
  if(part->fp) {
749
0
    fclose(part->fp);
750
0
    part->fp = NULL;
751
0
  }
752
0
  Curl_safefree(part->data);
753
0
}
754
755
756
/* Subparts callbacks. */
757
/* Argument is a pointer to the mime structure. */
758
759
/* Readback a byte string segment. */
760
static size_t readback_bytes(struct mime_state *state,
761
                             char *buffer, size_t bufsize,
762
                             const char *bytes, size_t numbytes,
763
                             const char *trail, size_t traillen)
764
0
{
765
0
  size_t sz;
766
0
  size_t offset = curlx_sotouz(state->offset);
767
768
0
  if(numbytes > offset) {
769
0
    sz = numbytes - offset;
770
0
    bytes += offset;
771
0
  }
772
0
  else {
773
0
    sz = offset - numbytes;
774
0
    if(sz >= traillen)
775
0
      return 0;
776
0
    bytes = trail + sz;
777
0
    sz = traillen - sz;
778
0
  }
779
780
0
  if(sz > bufsize)
781
0
    sz = bufsize;
782
783
0
  memcpy(buffer, bytes, sz);
784
0
  state->offset += sz;
785
0
  return sz;
786
0
}
787
788
/* Read a non-encoded part content. */
789
static size_t read_part_content(curl_mimepart *part,
790
                                char *buffer, size_t bufsize, bool *hasread)
791
0
{
792
0
  size_t sz = 0;
793
794
0
  switch(part->lastreadstatus) {
795
0
  case 0:
796
0
  case CURL_READFUNC_ABORT:
797
0
  case CURL_READFUNC_PAUSE:
798
0
  case READ_ERROR:
799
0
    return part->lastreadstatus;
800
0
  default:
801
0
    break;
802
0
  }
803
804
  /* If we can determine we are at end of part data, spare a read. */
805
0
  if(part->datasize != (curl_off_t) -1 &&
806
0
     part->state.offset >= part->datasize) {
807
    /* sz is already zero. */
808
0
  }
809
0
  else {
810
0
    switch(part->kind) {
811
0
    case MIMEKIND_MULTIPART:
812
      /*
813
       * Cannot be processed as other kinds since read function requires
814
       * an additional parameter and is highly recursive.
815
       */
816
0
       sz = mime_subparts_read(buffer, 1, bufsize, part->arg, hasread);
817
0
       break;
818
0
    case MIMEKIND_FILE:
819
0
      if(part->fp && feof(part->fp))
820
0
        break;  /* At EOF. */
821
      /* FALLTHROUGH */
822
0
    default:
823
0
      if(part->readfunc) {
824
0
        if(!(part->flags & MIME_FAST_READ)) {
825
0
          if(*hasread)
826
0
            return STOP_FILLING;
827
0
          *hasread = TRUE;
828
0
        }
829
0
        sz = part->readfunc(buffer, 1, bufsize, part->arg);
830
0
      }
831
0
      break;
832
0
    }
833
0
  }
834
835
0
  switch(sz) {
836
0
  case STOP_FILLING:
837
0
    break;
838
0
  case 0:
839
0
  case CURL_READFUNC_ABORT:
840
0
  case CURL_READFUNC_PAUSE:
841
0
  case READ_ERROR:
842
0
    part->lastreadstatus = sz;
843
0
    break;
844
0
  default:
845
0
    part->state.offset += sz;
846
0
    part->lastreadstatus = sz;
847
0
    break;
848
0
  }
849
850
0
  return sz;
851
0
}
852
853
/* Read and encode part content. */
854
static size_t read_encoded_part_content(curl_mimepart *part, char *buffer,
855
                                        size_t bufsize, bool *hasread)
856
0
{
857
0
  struct mime_encoder_state *st = &part->encstate;
858
0
  size_t cursize = 0;
859
0
  size_t sz;
860
0
  bool ateof = FALSE;
861
862
0
  for(;;) {
863
0
    if(st->bufbeg < st->bufend || ateof) {
864
      /* Encode buffered data. */
865
0
      sz = part->encoder->encodefunc(buffer, bufsize, ateof, part);
866
0
      switch(sz) {
867
0
      case 0:
868
0
        if(ateof)
869
0
          return cursize;
870
0
        break;
871
0
      case READ_ERROR:
872
0
      case STOP_FILLING:
873
0
        return cursize? cursize: sz;
874
0
      default:
875
0
        cursize += sz;
876
0
        buffer += sz;
877
0
        bufsize -= sz;
878
0
        continue;
879
0
      }
880
0
    }
881
882
    /* We need more data in input buffer. */
883
0
    if(st->bufbeg) {
884
0
      size_t len = st->bufend - st->bufbeg;
885
886
0
      if(len)
887
0
        memmove(st->buf, st->buf + st->bufbeg, len);
888
0
      st->bufbeg = 0;
889
0
      st->bufend = len;
890
0
    }
891
0
    if(st->bufend >= sizeof(st->buf))
892
0
      return cursize? cursize: READ_ERROR;    /* Buffer full. */
893
0
    sz = read_part_content(part, st->buf + st->bufend,
894
0
                           sizeof(st->buf) - st->bufend, hasread);
895
0
    switch(sz) {
896
0
    case 0:
897
0
      ateof = TRUE;
898
0
      break;
899
0
    case CURL_READFUNC_ABORT:
900
0
    case CURL_READFUNC_PAUSE:
901
0
    case READ_ERROR:
902
0
    case STOP_FILLING:
903
0
      return cursize? cursize: sz;
904
0
    default:
905
0
      st->bufend += sz;
906
0
      break;
907
0
    }
908
0
  }
909
910
  /* NOTREACHED */
911
0
}
912
913
/* Readback a mime part. */
914
static size_t readback_part(curl_mimepart *part,
915
                            char *buffer, size_t bufsize, bool *hasread)
916
0
{
917
0
  size_t cursize = 0;
918
919
  /* Readback from part. */
920
921
0
  while(bufsize) {
922
0
    size_t sz = 0;
923
0
    struct curl_slist *hdr = (struct curl_slist *) part->state.ptr;
924
0
    switch(part->state.state) {
925
0
    case MIMESTATE_BEGIN:
926
0
      mimesetstate(&part->state,
927
0
                   (part->flags & MIME_BODY_ONLY)?
928
0
                     MIMESTATE_BODY: MIMESTATE_CURLHEADERS,
929
0
                   part->curlheaders);
930
0
      break;
931
0
    case MIMESTATE_USERHEADERS:
932
0
      if(!hdr) {
933
0
        mimesetstate(&part->state, MIMESTATE_EOH, NULL);
934
0
        break;
935
0
      }
936
0
      if(match_header(hdr, "Content-Type", 12)) {
937
0
        mimesetstate(&part->state, MIMESTATE_USERHEADERS, hdr->next);
938
0
        break;
939
0
      }
940
      /* FALLTHROUGH */
941
0
    case MIMESTATE_CURLHEADERS:
942
0
      if(!hdr)
943
0
        mimesetstate(&part->state, MIMESTATE_USERHEADERS, part->userheaders);
944
0
      else {
945
0
        sz = readback_bytes(&part->state, buffer, bufsize,
946
0
                            hdr->data, strlen(hdr->data), STRCONST("\r\n"));
947
0
        if(!sz)
948
0
          mimesetstate(&part->state, part->state.state, hdr->next);
949
0
      }
950
0
      break;
951
0
    case MIMESTATE_EOH:
952
0
      sz = readback_bytes(&part->state, buffer, bufsize, STRCONST("\r\n"),
953
0
                          STRCONST(""));
954
0
      if(!sz)
955
0
        mimesetstate(&part->state, MIMESTATE_BODY, NULL);
956
0
      break;
957
0
    case MIMESTATE_BODY:
958
0
      cleanup_encoder_state(&part->encstate);
959
0
      mimesetstate(&part->state, MIMESTATE_CONTENT, NULL);
960
0
      break;
961
0
    case MIMESTATE_CONTENT:
962
0
      if(part->encoder)
963
0
        sz = read_encoded_part_content(part, buffer, bufsize, hasread);
964
0
      else
965
0
        sz = read_part_content(part, buffer, bufsize, hasread);
966
0
      switch(sz) {
967
0
      case 0:
968
0
        mimesetstate(&part->state, MIMESTATE_END, NULL);
969
        /* Try sparing open file descriptors. */
970
0
        if(part->kind == MIMEKIND_FILE && part->fp) {
971
0
          fclose(part->fp);
972
0
          part->fp = NULL;
973
0
        }
974
        /* FALLTHROUGH */
975
0
      case CURL_READFUNC_ABORT:
976
0
      case CURL_READFUNC_PAUSE:
977
0
      case READ_ERROR:
978
0
      case STOP_FILLING:
979
0
        return cursize? cursize: sz;
980
0
      }
981
0
      break;
982
0
    case MIMESTATE_END:
983
0
      return cursize;
984
0
    default:
985
0
      break;    /* Other values not in part state. */
986
0
    }
987
988
    /* Bump buffer and counters according to read size. */
989
0
    cursize += sz;
990
0
    buffer += sz;
991
0
    bufsize -= sz;
992
0
  }
993
994
0
  return cursize;
995
0
}
996
997
/* Readback from mime. Warning: not a read callback function. */
998
static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
999
                                 void *instream, bool *hasread)
1000
0
{
1001
0
  curl_mime *mime = (curl_mime *) instream;
1002
0
  size_t cursize = 0;
1003
0
  (void) size;   /* Always 1. */
1004
1005
0
  while(nitems) {
1006
0
    size_t sz = 0;
1007
0
    curl_mimepart *part = mime->state.ptr;
1008
0
    switch(mime->state.state) {
1009
0
    case MIMESTATE_BEGIN:
1010
0
    case MIMESTATE_BODY:
1011
0
      mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, mime->firstpart);
1012
      /* The first boundary always follows the header termination empty line,
1013
         so is always preceded by a CRLF. We can then spare 2 characters
1014
         by skipping the leading CRLF in boundary. */
1015
0
      mime->state.offset += 2;
1016
0
      break;
1017
0
    case MIMESTATE_BOUNDARY1:
1018
0
      sz = readback_bytes(&mime->state, buffer, nitems, STRCONST("\r\n--"),
1019
0
                          STRCONST(""));
1020
0
      if(!sz)
1021
0
        mimesetstate(&mime->state, MIMESTATE_BOUNDARY2, part);
1022
0
      break;
1023
0
    case MIMESTATE_BOUNDARY2:
1024
0
      if(part)
1025
0
        sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary,
1026
0
                            MIME_BOUNDARY_LEN, STRCONST("\r\n"));
1027
0
      else
1028
0
        sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary,
1029
0
                            MIME_BOUNDARY_LEN, STRCONST("--\r\n"));
1030
0
      if(!sz) {
1031
0
        mimesetstate(&mime->state, MIMESTATE_CONTENT, part);
1032
0
      }
1033
0
      break;
1034
0
    case MIMESTATE_CONTENT:
1035
0
      if(!part) {
1036
0
        mimesetstate(&mime->state, MIMESTATE_END, NULL);
1037
0
        break;
1038
0
      }
1039
0
      sz = readback_part(part, buffer, nitems, hasread);
1040
0
      switch(sz) {
1041
0
      case CURL_READFUNC_ABORT:
1042
0
      case CURL_READFUNC_PAUSE:
1043
0
      case READ_ERROR:
1044
0
      case STOP_FILLING:
1045
0
        return cursize? cursize: sz;
1046
0
      case 0:
1047
0
        mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, part->nextpart);
1048
0
        break;
1049
0
      }
1050
0
      break;
1051
0
    case MIMESTATE_END:
1052
0
      return cursize;
1053
0
    default:
1054
0
      break;    /* other values not used in mime state. */
1055
0
    }
1056
1057
    /* Bump buffer and counters according to read size. */
1058
0
    cursize += sz;
1059
0
    buffer += sz;
1060
0
    nitems -= sz;
1061
0
  }
1062
1063
0
  return cursize;
1064
0
}
1065
1066
static int mime_part_rewind(curl_mimepart *part)
1067
0
{
1068
0
  int res = CURL_SEEKFUNC_OK;
1069
0
  enum mimestate targetstate = MIMESTATE_BEGIN;
1070
1071
0
  if(part->flags & MIME_BODY_ONLY)
1072
0
    targetstate = MIMESTATE_BODY;
1073
0
  cleanup_encoder_state(&part->encstate);
1074
0
  if(part->state.state > targetstate) {
1075
0
    res = CURL_SEEKFUNC_CANTSEEK;
1076
0
    if(part->seekfunc) {
1077
0
      res = part->seekfunc(part->arg, (curl_off_t) 0, SEEK_SET);
1078
0
      switch(res) {
1079
0
      case CURL_SEEKFUNC_OK:
1080
0
      case CURL_SEEKFUNC_FAIL:
1081
0
      case CURL_SEEKFUNC_CANTSEEK:
1082
0
        break;
1083
0
      case -1:    /* For fseek() error. */
1084
0
        res = CURL_SEEKFUNC_CANTSEEK;
1085
0
        break;
1086
0
      default:
1087
0
        res = CURL_SEEKFUNC_FAIL;
1088
0
        break;
1089
0
      }
1090
0
    }
1091
0
  }
1092
1093
0
  if(res == CURL_SEEKFUNC_OK)
1094
0
    mimesetstate(&part->state, targetstate, NULL);
1095
1096
0
  part->lastreadstatus = 1; /* Successful read status. */
1097
0
  return res;
1098
0
}
1099
1100
static int mime_subparts_seek(void *instream, curl_off_t offset, int whence)
1101
0
{
1102
0
  curl_mime *mime = (curl_mime *) instream;
1103
0
  curl_mimepart *part;
1104
0
  int result = CURL_SEEKFUNC_OK;
1105
1106
0
  if(whence != SEEK_SET || offset)
1107
0
    return CURL_SEEKFUNC_CANTSEEK;    /* Only support full rewind. */
1108
1109
0
  if(mime->state.state == MIMESTATE_BEGIN)
1110
0
    return CURL_SEEKFUNC_OK;           /* Already rewound. */
1111
1112
0
  for(part = mime->firstpart; part; part = part->nextpart) {
1113
0
    int res = mime_part_rewind(part);
1114
0
    if(res != CURL_SEEKFUNC_OK)
1115
0
      result = res;
1116
0
  }
1117
1118
0
  if(result == CURL_SEEKFUNC_OK)
1119
0
    mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
1120
1121
0
  return result;
1122
0
}
1123
1124
/* Release part content. */
1125
static void cleanup_part_content(curl_mimepart *part)
1126
0
{
1127
0
  if(part->freefunc)
1128
0
    part->freefunc(part->arg);
1129
1130
0
  part->readfunc = NULL;
1131
0
  part->seekfunc = NULL;
1132
0
  part->freefunc = NULL;
1133
0
  part->arg = (void *) part;          /* Defaults to part itself. */
1134
0
  part->data = NULL;
1135
0
  part->fp = NULL;
1136
0
  part->datasize = (curl_off_t) 0;    /* No size yet. */
1137
0
  cleanup_encoder_state(&part->encstate);
1138
0
  part->kind = MIMEKIND_NONE;
1139
0
  part->flags &= ~MIME_FAST_READ;
1140
0
  part->lastreadstatus = 1; /* Successful read status. */
1141
0
  part->state.state = MIMESTATE_BEGIN;
1142
0
}
1143
1144
static void mime_subparts_free(void *ptr)
1145
0
{
1146
0
  curl_mime *mime = (curl_mime *) ptr;
1147
1148
0
  if(mime && mime->parent) {
1149
0
    mime->parent->freefunc = NULL;  /* Be sure we won't be called again. */
1150
0
    cleanup_part_content(mime->parent);  /* Avoid dangling pointer in part. */
1151
0
  }
1152
0
  curl_mime_free(mime);
1153
0
}
1154
1155
/* Do not free subparts: unbind them. This is used for the top level only. */
1156
static void mime_subparts_unbind(void *ptr)
1157
0
{
1158
0
  curl_mime *mime = (curl_mime *) ptr;
1159
1160
0
  if(mime && mime->parent) {
1161
0
    mime->parent->freefunc = NULL;  /* Be sure we won't be called again. */
1162
0
    cleanup_part_content(mime->parent);  /* Avoid dangling pointer in part. */
1163
0
    mime->parent = NULL;
1164
0
  }
1165
0
}
1166
1167
1168
void Curl_mime_cleanpart(curl_mimepart *part)
1169
0
{
1170
0
  if(part) {
1171
0
    cleanup_part_content(part);
1172
0
    curl_slist_free_all(part->curlheaders);
1173
0
    if(part->flags & MIME_USERHEADERS_OWNER)
1174
0
      curl_slist_free_all(part->userheaders);
1175
0
    Curl_safefree(part->mimetype);
1176
0
    Curl_safefree(part->name);
1177
0
    Curl_safefree(part->filename);
1178
0
    Curl_mime_initpart(part);
1179
0
  }
1180
0
}
1181
1182
/* Recursively delete a mime handle and its parts. */
1183
void curl_mime_free(curl_mime *mime)
1184
0
{
1185
0
  curl_mimepart *part;
1186
1187
0
  if(mime) {
1188
0
    mime_subparts_unbind(mime);  /* Be sure it's not referenced anymore. */
1189
0
    while(mime->firstpart) {
1190
0
      part = mime->firstpart;
1191
0
      mime->firstpart = part->nextpart;
1192
0
      Curl_mime_cleanpart(part);
1193
0
      free(part);
1194
0
    }
1195
0
    free(mime);
1196
0
  }
1197
0
}
1198
1199
CURLcode Curl_mime_duppart(struct Curl_easy *data,
1200
                           curl_mimepart *dst, const curl_mimepart *src)
1201
0
{
1202
0
  curl_mime *mime;
1203
0
  curl_mimepart *d;
1204
0
  const curl_mimepart *s;
1205
0
  CURLcode res = CURLE_OK;
1206
1207
0
  DEBUGASSERT(dst);
1208
1209
  /* Duplicate content. */
1210
0
  switch(src->kind) {
1211
0
  case MIMEKIND_NONE:
1212
0
    break;
1213
0
  case MIMEKIND_DATA:
1214
0
    res = curl_mime_data(dst, src->data, (size_t) src->datasize);
1215
0
    break;
1216
0
  case MIMEKIND_FILE:
1217
0
    res = curl_mime_filedata(dst, src->data);
1218
    /* Do not abort duplication if file is not readable. */
1219
0
    if(res == CURLE_READ_ERROR)
1220
0
      res = CURLE_OK;
1221
0
    break;
1222
0
  case MIMEKIND_CALLBACK:
1223
0
    res = curl_mime_data_cb(dst, src->datasize, src->readfunc,
1224
0
                            src->seekfunc, src->freefunc, src->arg);
1225
0
    break;
1226
0
  case MIMEKIND_MULTIPART:
1227
    /* No one knows about the cloned subparts, thus always attach ownership
1228
       to the part. */
1229
0
    mime = curl_mime_init(data);
1230
0
    res = mime? curl_mime_subparts(dst, mime): CURLE_OUT_OF_MEMORY;
1231
1232
    /* Duplicate subparts. */
1233
0
    for(s = ((curl_mime *) src->arg)->firstpart; !res && s; s = s->nextpart) {
1234
0
      d = curl_mime_addpart(mime);
1235
0
      res = d? Curl_mime_duppart(data, d, s): CURLE_OUT_OF_MEMORY;
1236
0
    }
1237
0
    break;
1238
0
  default:  /* Invalid kind: should not occur. */
1239
0
    res = CURLE_BAD_FUNCTION_ARGUMENT;  /* Internal error? */
1240
0
    break;
1241
0
  }
1242
1243
  /* Duplicate headers. */
1244
0
  if(!res && src->userheaders) {
1245
0
    struct curl_slist *hdrs = Curl_slist_duplicate(src->userheaders);
1246
1247
0
    if(!hdrs)
1248
0
      res = CURLE_OUT_OF_MEMORY;
1249
0
    else {
1250
      /* No one but this procedure knows about the new header list,
1251
         so always take ownership. */
1252
0
      res = curl_mime_headers(dst, hdrs, TRUE);
1253
0
      if(res)
1254
0
        curl_slist_free_all(hdrs);
1255
0
    }
1256
0
  }
1257
1258
0
  if(!res) {
1259
    /* Duplicate other fields. */
1260
0
    dst->encoder = src->encoder;
1261
0
    res = curl_mime_type(dst, src->mimetype);
1262
0
  }
1263
0
  if(!res)
1264
0
    res = curl_mime_name(dst, src->name);
1265
0
  if(!res)
1266
0
    res = curl_mime_filename(dst, src->filename);
1267
1268
  /* If an error occurred, rollback. */
1269
0
  if(res)
1270
0
    Curl_mime_cleanpart(dst);
1271
1272
0
  return res;
1273
0
}
1274
1275
/*
1276
 * Mime build functions.
1277
 */
1278
1279
/* Create a mime handle. */
1280
curl_mime *curl_mime_init(struct Curl_easy *easy)
1281
0
{
1282
0
  curl_mime *mime;
1283
1284
0
  mime = (curl_mime *) malloc(sizeof(*mime));
1285
1286
0
  if(mime) {
1287
0
    mime->parent = NULL;
1288
0
    mime->firstpart = NULL;
1289
0
    mime->lastpart = NULL;
1290
1291
0
    memset(mime->boundary, '-', MIME_BOUNDARY_DASHES);
1292
0
    if(Curl_rand_alnum(easy,
1293
0
                       (unsigned char *) &mime->boundary[MIME_BOUNDARY_DASHES],
1294
0
                       MIME_RAND_BOUNDARY_CHARS + 1)) {
1295
      /* failed to get random separator, bail out */
1296
0
      free(mime);
1297
0
      return NULL;
1298
0
    }
1299
0
    mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
1300
0
  }
1301
1302
0
  return mime;
1303
0
}
1304
1305
/* Initialize a mime part. */
1306
void Curl_mime_initpart(curl_mimepart *part)
1307
0
{
1308
0
  memset((char *) part, 0, sizeof(*part));
1309
0
  part->lastreadstatus = 1; /* Successful read status. */
1310
0
  mimesetstate(&part->state, MIMESTATE_BEGIN, NULL);
1311
0
}
1312
1313
/* Create a mime part and append it to a mime handle's part list. */
1314
curl_mimepart *curl_mime_addpart(curl_mime *mime)
1315
0
{
1316
0
  curl_mimepart *part;
1317
1318
0
  if(!mime)
1319
0
    return NULL;
1320
1321
0
  part = (curl_mimepart *) malloc(sizeof(*part));
1322
1323
0
  if(part) {
1324
0
    Curl_mime_initpart(part);
1325
0
    part->parent = mime;
1326
1327
0
    if(mime->lastpart)
1328
0
      mime->lastpart->nextpart = part;
1329
0
    else
1330
0
      mime->firstpart = part;
1331
1332
0
    mime->lastpart = part;
1333
0
  }
1334
1335
0
  return part;
1336
0
}
1337
1338
/* Set mime part name. */
1339
CURLcode curl_mime_name(curl_mimepart *part, const char *name)
1340
0
{
1341
0
  if(!part)
1342
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1343
1344
0
  Curl_safefree(part->name);
1345
1346
0
  if(name) {
1347
0
    part->name = strdup(name);
1348
0
    if(!part->name)
1349
0
      return CURLE_OUT_OF_MEMORY;
1350
0
  }
1351
1352
0
  return CURLE_OK;
1353
0
}
1354
1355
/* Set mime part remote file name. */
1356
CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
1357
0
{
1358
0
  if(!part)
1359
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1360
1361
0
  Curl_safefree(part->filename);
1362
1363
0
  if(filename) {
1364
0
    part->filename = strdup(filename);
1365
0
    if(!part->filename)
1366
0
      return CURLE_OUT_OF_MEMORY;
1367
0
  }
1368
1369
0
  return CURLE_OK;
1370
0
}
1371
1372
/* Set mime part content from memory data. */
1373
CURLcode curl_mime_data(curl_mimepart *part,
1374
                        const char *data, size_t datasize)
1375
0
{
1376
0
  if(!part)
1377
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1378
1379
0
  cleanup_part_content(part);
1380
1381
0
  if(data) {
1382
0
    if(datasize == CURL_ZERO_TERMINATED)
1383
0
      datasize = strlen(data);
1384
1385
0
    part->data = malloc(datasize + 1);
1386
0
    if(!part->data)
1387
0
      return CURLE_OUT_OF_MEMORY;
1388
1389
0
    part->datasize = datasize;
1390
1391
0
    if(datasize)
1392
0
      memcpy(part->data, data, datasize);
1393
0
    part->data[datasize] = '\0';    /* Set a null terminator as sentinel. */
1394
1395
0
    part->readfunc = mime_mem_read;
1396
0
    part->seekfunc = mime_mem_seek;
1397
0
    part->freefunc = mime_mem_free;
1398
0
    part->flags |= MIME_FAST_READ;
1399
0
    part->kind = MIMEKIND_DATA;
1400
0
  }
1401
1402
0
  return CURLE_OK;
1403
0
}
1404
1405
/* Set mime part content from named local file. */
1406
CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
1407
0
{
1408
0
  CURLcode result = CURLE_OK;
1409
1410
0
  if(!part)
1411
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1412
1413
0
  cleanup_part_content(part);
1414
1415
0
  if(filename) {
1416
0
    char *base;
1417
0
    struct_stat sbuf;
1418
1419
0
    if(stat(filename, &sbuf) || access(filename, R_OK))
1420
0
      result = CURLE_READ_ERROR;
1421
1422
0
    part->data = strdup(filename);
1423
0
    if(!part->data)
1424
0
      result = CURLE_OUT_OF_MEMORY;
1425
1426
0
    part->datasize = -1;
1427
0
    if(!result && S_ISREG(sbuf.st_mode)) {
1428
0
      part->datasize = filesize(filename, sbuf);
1429
0
      part->seekfunc = mime_file_seek;
1430
0
    }
1431
1432
0
    part->readfunc = mime_file_read;
1433
0
    part->freefunc = mime_file_free;
1434
0
    part->kind = MIMEKIND_FILE;
1435
1436
    /* As a side effect, set the filename to the current file's base name.
1437
       It is possible to withdraw this by explicitly calling
1438
       curl_mime_filename() with a NULL filename argument after the current
1439
       call. */
1440
0
    base = strippath(filename);
1441
0
    if(!base)
1442
0
      result = CURLE_OUT_OF_MEMORY;
1443
0
    else {
1444
0
      CURLcode res = curl_mime_filename(part, base);
1445
1446
0
      if(res)
1447
0
        result = res;
1448
0
      free(base);
1449
0
    }
1450
0
  }
1451
0
  return result;
1452
0
}
1453
1454
/* Set mime part type. */
1455
CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
1456
0
{
1457
0
  if(!part)
1458
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1459
1460
0
  Curl_safefree(part->mimetype);
1461
1462
0
  if(mimetype) {
1463
0
    part->mimetype = strdup(mimetype);
1464
0
    if(!part->mimetype)
1465
0
      return CURLE_OUT_OF_MEMORY;
1466
0
  }
1467
1468
0
  return CURLE_OK;
1469
0
}
1470
1471
/* Set mime data transfer encoder. */
1472
CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
1473
0
{
1474
0
  CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
1475
0
  const struct mime_encoder *mep;
1476
1477
0
  if(!part)
1478
0
    return result;
1479
1480
0
  part->encoder = NULL;
1481
1482
0
  if(!encoding)
1483
0
    return CURLE_OK;    /* Removing current encoder. */
1484
1485
0
  for(mep = encoders; mep->name; mep++)
1486
0
    if(strcasecompare(encoding, mep->name)) {
1487
0
      part->encoder = mep;
1488
0
      result = CURLE_OK;
1489
0
    }
1490
1491
0
  return result;
1492
0
}
1493
1494
/* Set mime part headers. */
1495
CURLcode curl_mime_headers(curl_mimepart *part,
1496
                           struct curl_slist *headers, int take_ownership)
1497
0
{
1498
0
  if(!part)
1499
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1500
1501
0
  if(part->flags & MIME_USERHEADERS_OWNER) {
1502
0
    if(part->userheaders != headers)  /* Allow setting twice the same list. */
1503
0
      curl_slist_free_all(part->userheaders);
1504
0
    part->flags &= ~MIME_USERHEADERS_OWNER;
1505
0
  }
1506
0
  part->userheaders = headers;
1507
0
  if(headers && take_ownership)
1508
0
    part->flags |= MIME_USERHEADERS_OWNER;
1509
0
  return CURLE_OK;
1510
0
}
1511
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)
1517
0
{
1518
0
  if(!part)
1519
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1520
1521
0
  cleanup_part_content(part);
1522
1523
0
  if(readfunc) {
1524
0
    part->readfunc = readfunc;
1525
0
    part->seekfunc = seekfunc;
1526
0
    part->freefunc = freefunc;
1527
0
    part->arg = arg;
1528
0
    part->datasize = datasize;
1529
0
    part->kind = MIMEKIND_CALLBACK;
1530
0
  }
1531
1532
0
  return CURLE_OK;
1533
0
}
1534
1535
/* Set mime part content from subparts. */
1536
CURLcode Curl_mime_set_subparts(curl_mimepart *part,
1537
                                curl_mime *subparts, int take_ownership)
1538
0
{
1539
0
  curl_mime *root;
1540
1541
0
  if(!part)
1542
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1543
1544
  /* Accept setting twice the same subparts. */
1545
0
  if(part->kind == MIMEKIND_MULTIPART && part->arg == subparts)
1546
0
    return CURLE_OK;
1547
1548
0
  cleanup_part_content(part);
1549
1550
0
  if(subparts) {
1551
    /* Should not have been attached already. */
1552
0
    if(subparts->parent)
1553
0
      return CURLE_BAD_FUNCTION_ARGUMENT;
1554
1555
    /* Should not be the part's root. */
1556
0
    root = part->parent;
1557
0
    if(root) {
1558
0
      while(root->parent && root->parent->parent)
1559
0
        root = root->parent->parent;
1560
0
      if(subparts == root) {
1561
        /* Can't add as a subpart of itself. */
1562
0
        return CURLE_BAD_FUNCTION_ARGUMENT;
1563
0
      }
1564
0
    }
1565
1566
0
    subparts->parent = part;
1567
    /* Subparts are processed internally: no read callback. */
1568
0
    part->seekfunc = mime_subparts_seek;
1569
0
    part->freefunc = take_ownership? mime_subparts_free: mime_subparts_unbind;
1570
0
    part->arg = subparts;
1571
0
    part->datasize = -1;
1572
0
    part->kind = MIMEKIND_MULTIPART;
1573
0
  }
1574
1575
0
  return CURLE_OK;
1576
0
}
1577
1578
CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
1579
0
{
1580
0
  return Curl_mime_set_subparts(part, subparts, TRUE);
1581
0
}
1582
1583
1584
/* Readback from top mime. */
1585
/* Argument is the dummy top part. */
1586
size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream)
1587
0
{
1588
0
  curl_mimepart *part = (curl_mimepart *) instream;
1589
0
  size_t ret;
1590
0
  bool hasread;
1591
1592
0
  (void) size;   /* Always 1. */
1593
1594
0
  do {
1595
0
    hasread = FALSE;
1596
0
    ret = readback_part(part, buffer, nitems, &hasread);
1597
    /*
1598
     * If this is not possible to get some data without calling more than
1599
     * one read callback (probably because a content encoder is not able to
1600
     * deliver a new bunch for the few data accumulated so far), force another
1601
     * read until we get enough data or a special exit code.
1602
     */
1603
0
  } while(ret == STOP_FILLING);
1604
1605
0
  return ret;
1606
0
}
1607
1608
/* Rewind mime stream. */
1609
CURLcode Curl_mime_rewind(curl_mimepart *part)
1610
0
{
1611
0
  return mime_part_rewind(part) == CURL_SEEKFUNC_OK?
1612
0
         CURLE_OK: CURLE_SEND_FAIL_REWIND;
1613
0
}
1614
1615
/* Compute header list size. */
1616
static size_t slist_size(struct curl_slist *s,
1617
                         size_t overhead, const char *skip, size_t skiplen)
1618
0
{
1619
0
  size_t size = 0;
1620
1621
0
  for(; s; s = s->next)
1622
0
    if(!skip || !match_header(s, skip, skiplen))
1623
0
      size += strlen(s->data) + overhead;
1624
0
  return size;
1625
0
}
1626
1627
/* Get/compute multipart size. */
1628
static curl_off_t multipart_size(curl_mime *mime)
1629
0
{
1630
0
  curl_off_t size;
1631
0
  curl_off_t boundarysize;
1632
0
  curl_mimepart *part;
1633
1634
0
  if(!mime)
1635
0
    return 0;           /* Not present -> empty. */
1636
1637
0
  boundarysize = 4 + MIME_BOUNDARY_LEN + 2;
1638
0
  size = boundarysize;  /* Final boundary - CRLF after headers. */
1639
1640
0
  for(part = mime->firstpart; part; part = part->nextpart) {
1641
0
    curl_off_t sz = Curl_mime_size(part);
1642
1643
0
    if(sz < 0)
1644
0
      size = sz;
1645
1646
0
    if(size >= 0)
1647
0
      size += boundarysize + sz;
1648
0
  }
1649
1650
0
  return size;
1651
0
}
1652
1653
/* Get/compute mime size. */
1654
curl_off_t Curl_mime_size(curl_mimepart *part)
1655
0
{
1656
0
  curl_off_t size;
1657
1658
0
  if(part->kind == MIMEKIND_MULTIPART)
1659
0
    part->datasize = multipart_size(part->arg);
1660
1661
0
  size = part->datasize;
1662
1663
0
  if(part->encoder)
1664
0
    size = part->encoder->sizefunc(part);
1665
1666
0
  if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) {
1667
    /* Compute total part size. */
1668
0
    size += slist_size(part->curlheaders, 2, NULL, 0);
1669
0
    size += slist_size(part->userheaders, 2, STRCONST("Content-Type"));
1670
0
    size += 2;    /* CRLF after headers. */
1671
0
  }
1672
0
  return size;
1673
0
}
1674
1675
/* Add a header. */
1676
/* VARARGS2 */
1677
CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
1678
0
{
1679
0
  struct curl_slist *hdr = NULL;
1680
0
  char *s = NULL;
1681
0
  va_list ap;
1682
1683
0
  va_start(ap, fmt);
1684
0
  s = curl_mvaprintf(fmt, ap);
1685
0
  va_end(ap);
1686
1687
0
  if(s) {
1688
0
    hdr = Curl_slist_append_nodup(*slp, s);
1689
0
    if(hdr)
1690
0
      *slp = hdr;
1691
0
    else
1692
0
      free(s);
1693
0
  }
1694
1695
0
  return hdr? CURLE_OK: CURLE_OUT_OF_MEMORY;
1696
0
}
1697
1698
/* Add a content type header. */
1699
static CURLcode add_content_type(struct curl_slist **slp,
1700
                                 const char *type, const char *boundary)
1701
0
{
1702
0
  return Curl_mime_add_header(slp, "Content-Type: %s%s%s", type,
1703
0
                              boundary? "; boundary=": "",
1704
0
                              boundary? boundary: "");
1705
0
}
1706
1707
const char *Curl_mime_contenttype(const char *filename)
1708
0
{
1709
  /*
1710
   * If no content type was specified, we scan through a few well-known
1711
   * extensions and pick the first we match!
1712
   */
1713
0
  struct ContentType {
1714
0
    const char *extension;
1715
0
    const char *type;
1716
0
  };
1717
0
  static const struct ContentType ctts[] = {
1718
0
    {".gif",  "image/gif"},
1719
0
    {".jpg",  "image/jpeg"},
1720
0
    {".jpeg", "image/jpeg"},
1721
0
    {".png",  "image/png"},
1722
0
    {".svg",  "image/svg+xml"},
1723
0
    {".txt",  "text/plain"},
1724
0
    {".htm",  "text/html"},
1725
0
    {".html", "text/html"},
1726
0
    {".pdf",  "application/pdf"},
1727
0
    {".xml",  "application/xml"}
1728
0
  };
1729
1730
0
  if(filename) {
1731
0
    size_t len1 = strlen(filename);
1732
0
    const char *nameend = filename + len1;
1733
0
    unsigned int i;
1734
1735
0
    for(i = 0; i < sizeof(ctts) / sizeof(ctts[0]); i++) {
1736
0
      size_t len2 = strlen(ctts[i].extension);
1737
1738
0
      if(len1 >= len2 && strcasecompare(nameend - len2, ctts[i].extension))
1739
0
        return ctts[i].type;
1740
0
    }
1741
0
  }
1742
0
  return NULL;
1743
0
}
1744
1745
static bool content_type_match(const char *contenttype,
1746
                               const char *target, size_t len)
1747
0
{
1748
0
  if(contenttype && strncasecompare(contenttype, target, len))
1749
0
    switch(contenttype[len]) {
1750
0
    case '\0':
1751
0
    case '\t':
1752
0
    case '\r':
1753
0
    case '\n':
1754
0
    case ' ':
1755
0
    case ';':
1756
0
      return TRUE;
1757
0
    }
1758
0
  return FALSE;
1759
0
}
1760
1761
CURLcode Curl_mime_prepare_headers(struct Curl_easy *data,
1762
                                   curl_mimepart *part,
1763
                                   const char *contenttype,
1764
                                   const char *disposition,
1765
                                   enum mimestrategy strategy)
1766
0
{
1767
0
  curl_mime *mime = NULL;
1768
0
  const char *boundary = NULL;
1769
0
  char *customct;
1770
0
  const char *cte = NULL;
1771
0
  CURLcode ret = CURLE_OK;
1772
1773
  /* Get rid of previously prepared headers. */
1774
0
  curl_slist_free_all(part->curlheaders);
1775
0
  part->curlheaders = NULL;
1776
1777
  /* Be sure we won't access old headers later. */
1778
0
  if(part->state.state == MIMESTATE_CURLHEADERS)
1779
0
    mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL);
1780
1781
  /* Check if content type is specified. */
1782
0
  customct = part->mimetype;
1783
0
  if(!customct)
1784
0
    customct = search_header(part->userheaders, STRCONST("Content-Type"));
1785
0
  if(customct)
1786
0
    contenttype = customct;
1787
1788
  /* If content type is not specified, try to determine it. */
1789
0
  if(!contenttype) {
1790
0
    switch(part->kind) {
1791
0
    case MIMEKIND_MULTIPART:
1792
0
      contenttype = MULTIPART_CONTENTTYPE_DEFAULT;
1793
0
      break;
1794
0
    case MIMEKIND_FILE:
1795
0
      contenttype = Curl_mime_contenttype(part->filename);
1796
0
      if(!contenttype)
1797
0
        contenttype = Curl_mime_contenttype(part->data);
1798
0
      if(!contenttype && part->filename)
1799
0
        contenttype = FILE_CONTENTTYPE_DEFAULT;
1800
0
      break;
1801
0
    default:
1802
0
      contenttype = Curl_mime_contenttype(part->filename);
1803
0
      break;
1804
0
    }
1805
0
  }
1806
1807
0
  if(part->kind == MIMEKIND_MULTIPART) {
1808
0
    mime = (curl_mime *) part->arg;
1809
0
    if(mime)
1810
0
      boundary = mime->boundary;
1811
0
  }
1812
0
  else if(contenttype && !customct &&
1813
0
          content_type_match(contenttype, STRCONST("text/plain")))
1814
0
    if(strategy == MIMESTRATEGY_MAIL || !part->filename)
1815
0
      contenttype = NULL;
1816
1817
  /* Issue content-disposition header only if not already set by caller. */
1818
0
  if(!search_header(part->userheaders, STRCONST("Content-Disposition"))) {
1819
0
    if(!disposition)
1820
0
      if(part->filename || part->name ||
1821
0
        (contenttype && !strncasecompare(contenttype, "multipart/", 10)))
1822
0
          disposition = DISPOSITION_DEFAULT;
1823
0
    if(disposition && curl_strequal(disposition, "attachment") &&
1824
0
     !part->name && !part->filename)
1825
0
      disposition = NULL;
1826
0
    if(disposition) {
1827
0
      char *name = NULL;
1828
0
      char *filename = NULL;
1829
1830
0
      if(part->name) {
1831
0
        name = escape_string(data, part->name, strategy);
1832
0
        if(!name)
1833
0
          ret = CURLE_OUT_OF_MEMORY;
1834
0
      }
1835
0
      if(!ret && part->filename) {
1836
0
        filename = escape_string(data, part->filename, strategy);
1837
0
        if(!filename)
1838
0
          ret = CURLE_OUT_OF_MEMORY;
1839
0
      }
1840
0
      if(!ret)
1841
0
        ret = Curl_mime_add_header(&part->curlheaders,
1842
0
                                   "Content-Disposition: %s%s%s%s%s%s%s",
1843
0
                                   disposition,
1844
0
                                   name? "; name=\"": "",
1845
0
                                   name? name: "",
1846
0
                                   name? "\"": "",
1847
0
                                   filename? "; filename=\"": "",
1848
0
                                   filename? filename: "",
1849
0
                                   filename? "\"": "");
1850
0
      Curl_safefree(name);
1851
0
      Curl_safefree(filename);
1852
0
      if(ret)
1853
0
        return ret;
1854
0
      }
1855
0
    }
1856
1857
  /* Issue Content-Type header. */
1858
0
  if(contenttype) {
1859
0
    ret = add_content_type(&part->curlheaders, contenttype, boundary);
1860
0
    if(ret)
1861
0
      return ret;
1862
0
  }
1863
1864
  /* Content-Transfer-Encoding header. */
1865
0
  if(!search_header(part->userheaders,
1866
0
                    STRCONST("Content-Transfer-Encoding"))) {
1867
0
    if(part->encoder)
1868
0
      cte = part->encoder->name;
1869
0
    else if(contenttype && strategy == MIMESTRATEGY_MAIL &&
1870
0
     part->kind != MIMEKIND_MULTIPART)
1871
0
      cte = "8bit";
1872
0
    if(cte) {
1873
0
      ret = Curl_mime_add_header(&part->curlheaders,
1874
0
                                 "Content-Transfer-Encoding: %s", cte);
1875
0
      if(ret)
1876
0
        return ret;
1877
0
    }
1878
0
  }
1879
1880
  /* If we were reading curl-generated headers, restart with new ones (this
1881
     should not occur). */
1882
0
  if(part->state.state == MIMESTATE_CURLHEADERS)
1883
0
    mimesetstate(&part->state, MIMESTATE_CURLHEADERS, part->curlheaders);
1884
1885
  /* Process subparts. */
1886
0
  if(part->kind == MIMEKIND_MULTIPART && mime) {
1887
0
    curl_mimepart *subpart;
1888
1889
0
    disposition = NULL;
1890
0
    if(content_type_match(contenttype, STRCONST("multipart/form-data")))
1891
0
      disposition = "form-data";
1892
0
    for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) {
1893
0
      ret = Curl_mime_prepare_headers(data, subpart, NULL,
1894
0
                                      disposition, strategy);
1895
0
      if(ret)
1896
0
        return ret;
1897
0
    }
1898
0
  }
1899
0
  return ret;
1900
0
}
1901
1902
/* Recursively reset paused status in the given part. */
1903
void Curl_mime_unpause(curl_mimepart *part)
1904
0
{
1905
0
  if(part) {
1906
0
    if(part->lastreadstatus == CURL_READFUNC_PAUSE)
1907
0
      part->lastreadstatus = 1; /* Successful read status. */
1908
0
    if(part->kind == MIMEKIND_MULTIPART) {
1909
0
      curl_mime *mime = (curl_mime *) part->arg;
1910
1911
0
      if(mime) {
1912
0
        curl_mimepart *subpart;
1913
1914
0
        for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart)
1915
0
          Curl_mime_unpause(subpart);
1916
0
      }
1917
0
    }
1918
0
  }
1919
0
}
1920
1921
1922
#else /* !CURL_DISABLE_MIME && (!CURL_DISABLE_HTTP ||
1923
                                !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP) */
1924
1925
/* Mime not compiled in: define stubs for externally-referenced functions. */
1926
curl_mime *curl_mime_init(CURL *easy)
1927
{
1928
  (void) easy;
1929
  return NULL;
1930
}
1931
1932
void curl_mime_free(curl_mime *mime)
1933
{
1934
  (void) mime;
1935
}
1936
1937
curl_mimepart *curl_mime_addpart(curl_mime *mime)
1938
{
1939
  (void) mime;
1940
  return NULL;
1941
}
1942
1943
CURLcode curl_mime_name(curl_mimepart *part, const char *name)
1944
{
1945
  (void) part;
1946
  (void) name;
1947
  return CURLE_NOT_BUILT_IN;
1948
}
1949
1950
CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
1951
{
1952
  (void) part;
1953
  (void) filename;
1954
  return CURLE_NOT_BUILT_IN;
1955
}
1956
1957
CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
1958
{
1959
  (void) part;
1960
  (void) mimetype;
1961
  return CURLE_NOT_BUILT_IN;
1962
}
1963
1964
CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
1965
{
1966
  (void) part;
1967
  (void) encoding;
1968
  return CURLE_NOT_BUILT_IN;
1969
}
1970
1971
CURLcode curl_mime_data(curl_mimepart *part,
1972
                        const char *data, size_t datasize)
1973
{
1974
  (void) part;
1975
  (void) data;
1976
  (void) datasize;
1977
  return CURLE_NOT_BUILT_IN;
1978
}
1979
1980
CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
1981
{
1982
  (void) part;
1983
  (void) filename;
1984
  return CURLE_NOT_BUILT_IN;
1985
}
1986
1987
CURLcode curl_mime_data_cb(curl_mimepart *part,
1988
                           curl_off_t datasize,
1989
                           curl_read_callback readfunc,
1990
                           curl_seek_callback seekfunc,
1991
                           curl_free_callback freefunc,
1992
                           void *arg)
1993
{
1994
  (void) part;
1995
  (void) datasize;
1996
  (void) readfunc;
1997
  (void) seekfunc;
1998
  (void) freefunc;
1999
  (void) arg;
2000
  return CURLE_NOT_BUILT_IN;
2001
}
2002
2003
CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
2004
{
2005
  (void) part;
2006
  (void) subparts;
2007
  return CURLE_NOT_BUILT_IN;
2008
}
2009
2010
CURLcode curl_mime_headers(curl_mimepart *part,
2011
                           struct curl_slist *headers, int take_ownership)
2012
{
2013
  (void) part;
2014
  (void) headers;
2015
  (void) take_ownership;
2016
  return CURLE_NOT_BUILT_IN;
2017
}
2018
2019
CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
2020
{
2021
  (void)slp;
2022
  (void)fmt;
2023
  return CURLE_NOT_BUILT_IN;
2024
}
2025
2026
#endif /* if disabled */