Coverage Report

Created: 2024-02-25 06:14

/src/PROJ/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
#include "strdup.h"
34
35
#if !defined(CURL_DISABLE_MIME) && (!defined(CURL_DISABLE_HTTP) ||      \
36
                                    !defined(CURL_DISABLE_SMTP) ||      \
37
                                    !defined(CURL_DISABLE_IMAP))
38
39
#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
40
#include <libgen.h>
41
#endif
42
43
#include "rand.h"
44
#include "slist.h"
45
#include "strcase.h"
46
#include "dynbuf.h"
47
/* The last 3 #include files should be in this order */
48
#include "curl_printf.h"
49
#include "curl_memory.h"
50
#include "memdebug.h"
51
52
#ifdef _WIN32
53
# ifndef R_OK
54
#  define R_OK 4
55
# endif
56
#endif
57
58
59
0
#define READ_ERROR                      ((size_t) -1)
60
0
#define STOP_FILLING                    ((size_t) -2)
61
62
static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
63
                                 void *instream, bool *hasread);
64
65
/* Encoders. */
66
static size_t encoder_nop_read(char *buffer, size_t size, bool ateof,
67
                                curl_mimepart *part);
68
static curl_off_t encoder_nop_size(curl_mimepart *part);
69
static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof,
70
                                curl_mimepart *part);
71
static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
72
                                curl_mimepart *part);
73
static curl_off_t encoder_base64_size(curl_mimepart *part);
74
static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
75
                              curl_mimepart *part);
76
static curl_off_t encoder_qp_size(curl_mimepart *part);
77
78
static const struct mime_encoder encoders[] = {
79
  {"binary", encoder_nop_read, encoder_nop_size},
80
  {"8bit", encoder_nop_read, encoder_nop_size},
81
  {"7bit", encoder_7bit_read, encoder_nop_size},
82
  {"base64", encoder_base64_read, encoder_base64_size},
83
  {"quoted-printable", encoder_qp_read, encoder_qp_size},
84
  {ZERO_NULL, ZERO_NULL, ZERO_NULL}
85
};
86
87
/* Base64 encoding table */
88
static const char base64enc[] =
89
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
90
91
/* Quoted-printable character class table.
92
 *
93
 * We cannot rely on ctype functions since quoted-printable input data
94
 * is assumed to be ascii-compatible, even on non-ascii platforms. */
95
0
#define QP_OK           1       /* Can be represented by itself. */
96
0
#define QP_SP           2       /* Space or tab. */
97
0
#define QP_CR           3       /* Carriage return. */
98
0
#define QP_LF           4       /* Line-feed. */
99
static const unsigned char qp_class[] = {
100
 0,     0,     0,     0,     0,     0,     0,     0,            /* 00 - 07 */
101
 0,     QP_SP, QP_LF, 0,     0,     QP_CR, 0,     0,            /* 08 - 0F */
102
 0,     0,     0,     0,     0,     0,     0,     0,            /* 10 - 17 */
103
 0,     0,     0,     0,     0,     0,     0,     0,            /* 18 - 1F */
104
 QP_SP, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 20 - 27 */
105
 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 28 - 2F */
106
 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 30 - 37 */
107
 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0    , QP_OK, QP_OK,        /* 38 - 3F */
108
 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 40 - 47 */
109
 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 48 - 4F */
110
 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 50 - 57 */
111
 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 58 - 5F */
112
 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 60 - 67 */
113
 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 68 - 6F */
114
 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK,        /* 70 - 77 */
115
 QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0,            /* 78 - 7F */
116
 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* 80 - 8F */
117
 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* 90 - 9F */
118
 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* A0 - AF */
119
 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* B0 - BF */
120
 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* C0 - CF */
121
 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* D0 - DF */
122
 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                /* E0 - EF */
123
 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0                 /* F0 - FF */
124
};
125
126
127
/* Binary --> hexadecimal ASCII table. */
128
static const char aschex[] =
129
  "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x41\x42\x43\x44\x45\x46";
130
131
132
133
#ifndef __VMS
134
0
#define filesize(name, stat_data) (stat_data.st_size)
135
0
#define fopen_read fopen
136
137
#else
138
139
#include <fabdef.h>
140
/*
141
 * get_vms_file_size does what it takes to get the real size of the file
142
 *
143
 * For fixed files, find out the size of the EOF block and adjust.
144
 *
145
 * For all others, have to read the entire file in, discarding the contents.
146
 * Most posted text files will be small, and binary files like zlib archives
147
 * and CD/DVD images should be either a STREAM_LF format or a fixed format.
148
 *
149
 */
150
curl_off_t VmsRealFileSize(const char *name,
151
                           const struct_stat *stat_buf)
152
{
153
  char buffer[8192];
154
  curl_off_t count;
155
  int ret_stat;
156
  FILE * file;
157
158
  file = fopen(name, FOPEN_READTEXT); /* VMS */
159
  if(!file)
160
    return 0;
161
162
  count = 0;
163
  ret_stat = 1;
164
  while(ret_stat > 0) {
165
    ret_stat = fread(buffer, 1, sizeof(buffer), file);
166
    if(ret_stat)
167
      count += ret_stat;
168
  }
169
  fclose(file);
170
171
  return count;
172
}
173
174
/*
175
 *
176
 *  VmsSpecialSize checks to see if the stat st_size can be trusted and
177
 *  if not to call a routine to get the correct size.
178
 *
179
 */
180
static curl_off_t VmsSpecialSize(const char *name,
181
                                 const struct_stat *stat_buf)
182
{
183
  switch(stat_buf->st_fab_rfm) {
184
  case FAB$C_VAR:
185
  case FAB$C_VFC:
186
    return VmsRealFileSize(name, stat_buf);
187
    break;
188
  default:
189
    return stat_buf->st_size;
190
  }
191
}
192
193
#define filesize(name, stat_data) VmsSpecialSize(name, &stat_data)
194
195
/*
196
 * vmsfopenread
197
 *
198
 * For upload to work as expected on VMS, different optional
199
 * parameters must be added to the fopen command based on
200
 * record format of the file.
201
 *
202
 */
203
static FILE * vmsfopenread(const char *file, const char *mode)
204
{
205
  struct_stat statbuf;
206
  int result;
207
208
  result = stat(file, &statbuf);
209
210
  switch(statbuf.st_fab_rfm) {
211
  case FAB$C_VAR:
212
  case FAB$C_VFC:
213
  case FAB$C_STMCR:
214
    return fopen(file, FOPEN_READTEXT); /* VMS */
215
    break;
216
  default:
217
    return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm");
218
  }
219
}
220
221
#define fopen_read vmsfopenread
222
#endif
223
224
225
#ifndef HAVE_BASENAME
226
/*
227
  (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
228
  Edition)
229
230
  The basename() function shall take the pathname pointed to by path and
231
  return a pointer to the final component of the pathname, deleting any
232
  trailing '/' characters.
233
234
  If the string pointed to by path consists entirely of the '/' character,
235
  basename() shall return a pointer to the string "/". If the string pointed
236
  to by path is exactly "//", it is implementation-defined whether '/' or "//"
237
  is returned.
238
239
  If path is a null pointer or points to an empty string, basename() shall
240
  return a pointer to the string ".".
241
242
  The basename() function may modify the string pointed to by path, and may
243
  return a pointer to static storage that may then be overwritten by a
244
  subsequent call to basename().
245
246
  The basename() function need not be reentrant. A function that is not
247
  required to be reentrant is not required to be thread-safe.
248
249
*/
250
static char *Curl_basename(char *path)
251
{
252
  /* Ignore all the details above for now and make a quick and simple
253
     implementation here */
254
  char *s1;
255
  char *s2;
256
257
  s1 = strrchr(path, '/');
258
  s2 = strrchr(path, '\\');
259
260
  if(s1 && s2) {
261
    path = (s1 > s2? s1 : s2) + 1;
262
  }
263
  else if(s1)
264
    path = s1 + 1;
265
  else if(s2)
266
    path = s2 + 1;
267
268
  return path;
269
}
270
271
#define basename(x)  Curl_basename((x))
272
#endif
273
274
275
/* Set readback state. */
276
static void mimesetstate(struct mime_state *state,
277
                         enum mimestate tok, void *ptr)
278
0
{
279
0
  state->state = tok;
280
0
  state->ptr = ptr;
281
0
  state->offset = 0;
282
0
}
283
284
285
/* Escape header string into allocated memory. */
286
static char *escape_string(struct Curl_easy *data,
287
                           const char *src, enum mimestrategy strategy)
288
0
{
289
0
  CURLcode result;
290
0
  struct dynbuf db;
291
0
  const char * const *table;
292
0
  const char * const *p;
293
  /* replace first character by rest of string. */
294
0
  static const char * const mimetable[] = {
295
0
    "\\\\\\",
296
0
    "\"\\\"",
297
0
    NULL
298
0
  };
299
  /* WHATWG HTML living standard 4.10.21.8 2 specifies:
300
     For field names and filenames for file fields, the result of the
301
     encoding in the previous bullet point must be escaped by replacing
302
     any 0x0A (LF) bytes with the byte sequence `%0A`, 0x0D (CR) with `%0D`
303
     and 0x22 (") with `%22`.
304
     The user agent must not perform any other escapes. */
305
0
  static const char * const formtable[] = {
306
0
    "\"%22",
307
0
    "\r%0D",
308
0
    "\n%0A",
309
0
    NULL
310
0
  };
311
312
0
  table = formtable;
313
  /* data can be NULL when this function is called indirectly from
314
     curl_formget(). */
315
0
  if(strategy == MIMESTRATEGY_MAIL || (data && (data->set.mime_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
0
      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
0
      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
0
        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
    DEBUGF(infof(data, "invalid MIMEKIND* attempt"));
1240
0
    res = CURLE_BAD_FUNCTION_ARGUMENT;  /* Internal error? */
1241
0
    break;
1242
0
  }
1243
1244
  /* Duplicate headers. */
1245
0
  if(!res && src->userheaders) {
1246
0
    struct curl_slist *hdrs = Curl_slist_duplicate(src->userheaders);
1247
1248
0
    if(!hdrs)
1249
0
      res = CURLE_OUT_OF_MEMORY;
1250
0
    else {
1251
      /* No one but this procedure knows about the new header list,
1252
         so always take ownership. */
1253
0
      res = curl_mime_headers(dst, hdrs, TRUE);
1254
0
      if(res)
1255
0
        curl_slist_free_all(hdrs);
1256
0
    }
1257
0
  }
1258
1259
0
  if(!res) {
1260
    /* Duplicate other fields. */
1261
0
    dst->encoder = src->encoder;
1262
0
    res = curl_mime_type(dst, src->mimetype);
1263
0
  }
1264
0
  if(!res)
1265
0
    res = curl_mime_name(dst, src->name);
1266
0
  if(!res)
1267
0
    res = curl_mime_filename(dst, src->filename);
1268
1269
  /* If an error occurred, rollback. */
1270
0
  if(res)
1271
0
    Curl_mime_cleanpart(dst);
1272
1273
0
  return res;
1274
0
}
1275
1276
/*
1277
 * Mime build functions.
1278
 */
1279
1280
/* Create a mime handle. */
1281
curl_mime *curl_mime_init(struct Curl_easy *easy)
1282
0
{
1283
0
  curl_mime *mime;
1284
1285
0
  mime = (curl_mime *) malloc(sizeof(*mime));
1286
1287
0
  if(mime) {
1288
0
    mime->parent = NULL;
1289
0
    mime->firstpart = NULL;
1290
0
    mime->lastpart = NULL;
1291
1292
0
    memset(mime->boundary, '-', MIME_BOUNDARY_DASHES);
1293
0
    if(Curl_rand_alnum(easy,
1294
0
                       (unsigned char *) &mime->boundary[MIME_BOUNDARY_DASHES],
1295
0
                       MIME_RAND_BOUNDARY_CHARS + 1)) {
1296
      /* failed to get random separator, bail out */
1297
0
      free(mime);
1298
0
      return NULL;
1299
0
    }
1300
0
    mimesetstate(&mime->state, MIMESTATE_BEGIN, NULL);
1301
0
  }
1302
1303
0
  return mime;
1304
0
}
1305
1306
/* Initialize a mime part. */
1307
void Curl_mime_initpart(curl_mimepart *part)
1308
0
{
1309
0
  memset((char *) part, 0, sizeof(*part));
1310
0
  part->lastreadstatus = 1; /* Successful read status. */
1311
0
  mimesetstate(&part->state, MIMESTATE_BEGIN, NULL);
1312
0
}
1313
1314
/* Create a mime part and append it to a mime handle's part list. */
1315
curl_mimepart *curl_mime_addpart(curl_mime *mime)
1316
0
{
1317
0
  curl_mimepart *part;
1318
1319
0
  if(!mime)
1320
0
    return NULL;
1321
1322
0
  part = (curl_mimepart *) malloc(sizeof(*part));
1323
1324
0
  if(part) {
1325
0
    Curl_mime_initpart(part);
1326
0
    part->parent = mime;
1327
1328
0
    if(mime->lastpart)
1329
0
      mime->lastpart->nextpart = part;
1330
0
    else
1331
0
      mime->firstpart = part;
1332
1333
0
    mime->lastpart = part;
1334
0
  }
1335
1336
0
  return part;
1337
0
}
1338
1339
/* Set mime part name. */
1340
CURLcode curl_mime_name(curl_mimepart *part, const char *name)
1341
0
{
1342
0
  if(!part)
1343
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1344
1345
0
  Curl_safefree(part->name);
1346
1347
0
  if(name) {
1348
0
    part->name = strdup(name);
1349
0
    if(!part->name)
1350
0
      return CURLE_OUT_OF_MEMORY;
1351
0
  }
1352
1353
0
  return CURLE_OK;
1354
0
}
1355
1356
/* Set mime part remote file name. */
1357
CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
1358
0
{
1359
0
  if(!part)
1360
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1361
1362
0
  Curl_safefree(part->filename);
1363
1364
0
  if(filename) {
1365
0
    part->filename = strdup(filename);
1366
0
    if(!part->filename)
1367
0
      return CURLE_OUT_OF_MEMORY;
1368
0
  }
1369
1370
0
  return CURLE_OK;
1371
0
}
1372
1373
/* Set mime part content from memory data. */
1374
CURLcode curl_mime_data(curl_mimepart *part,
1375
                        const char *ptr, size_t datasize)
1376
0
{
1377
0
  if(!part)
1378
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1379
1380
0
  cleanup_part_content(part);
1381
1382
0
  if(ptr) {
1383
0
    if(datasize == CURL_ZERO_TERMINATED)
1384
0
      datasize = strlen(ptr);
1385
1386
0
    part->data = Curl_memdup0(ptr, datasize);
1387
0
    if(!part->data)
1388
0
      return CURLE_OUT_OF_MEMORY;
1389
1390
0
    part->datasize = datasize;
1391
0
    part->readfunc = mime_mem_read;
1392
0
    part->seekfunc = mime_mem_seek;
1393
0
    part->freefunc = mime_mem_free;
1394
0
    part->flags |= MIME_FAST_READ;
1395
0
    part->kind = MIMEKIND_DATA;
1396
0
  }
1397
1398
0
  return CURLE_OK;
1399
0
}
1400
1401
/* Set mime part content from named local file. */
1402
CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
1403
0
{
1404
0
  CURLcode result = CURLE_OK;
1405
1406
0
  if(!part)
1407
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1408
1409
0
  cleanup_part_content(part);
1410
1411
0
  if(filename) {
1412
0
    char *base;
1413
0
    struct_stat sbuf;
1414
1415
0
    if(stat(filename, &sbuf) || access(filename, R_OK))
1416
0
      result = CURLE_READ_ERROR;
1417
1418
0
    part->data = strdup(filename);
1419
0
    if(!part->data)
1420
0
      result = CURLE_OUT_OF_MEMORY;
1421
1422
0
    part->datasize = -1;
1423
0
    if(!result && S_ISREG(sbuf.st_mode)) {
1424
0
      part->datasize = filesize(filename, sbuf);
1425
0
      part->seekfunc = mime_file_seek;
1426
0
    }
1427
1428
0
    part->readfunc = mime_file_read;
1429
0
    part->freefunc = mime_file_free;
1430
0
    part->kind = MIMEKIND_FILE;
1431
1432
    /* As a side effect, set the filename to the current file's base name.
1433
       It is possible to withdraw this by explicitly calling
1434
       curl_mime_filename() with a NULL filename argument after the current
1435
       call. */
1436
0
    base = strippath(filename);
1437
0
    if(!base)
1438
0
      result = CURLE_OUT_OF_MEMORY;
1439
0
    else {
1440
0
      CURLcode res = curl_mime_filename(part, base);
1441
1442
0
      if(res)
1443
0
        result = res;
1444
0
      free(base);
1445
0
    }
1446
0
  }
1447
0
  return result;
1448
0
}
1449
1450
/* Set mime part type. */
1451
CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
1452
0
{
1453
0
  if(!part)
1454
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1455
1456
0
  Curl_safefree(part->mimetype);
1457
1458
0
  if(mimetype) {
1459
0
    part->mimetype = strdup(mimetype);
1460
0
    if(!part->mimetype)
1461
0
      return CURLE_OUT_OF_MEMORY;
1462
0
  }
1463
1464
0
  return CURLE_OK;
1465
0
}
1466
1467
/* Set mime data transfer encoder. */
1468
CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
1469
0
{
1470
0
  CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
1471
0
  const struct mime_encoder *mep;
1472
1473
0
  if(!part)
1474
0
    return result;
1475
1476
0
  part->encoder = NULL;
1477
1478
0
  if(!encoding)
1479
0
    return CURLE_OK;    /* Removing current encoder. */
1480
1481
0
  for(mep = encoders; mep->name; mep++)
1482
0
    if(strcasecompare(encoding, mep->name)) {
1483
0
      part->encoder = mep;
1484
0
      result = CURLE_OK;
1485
0
    }
1486
1487
0
  return result;
1488
0
}
1489
1490
/* Set mime part headers. */
1491
CURLcode curl_mime_headers(curl_mimepart *part,
1492
                           struct curl_slist *headers, int take_ownership)
1493
0
{
1494
0
  if(!part)
1495
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1496
1497
0
  if(part->flags & MIME_USERHEADERS_OWNER) {
1498
0
    if(part->userheaders != headers)  /* Allow setting twice the same list. */
1499
0
      curl_slist_free_all(part->userheaders);
1500
0
    part->flags &= ~MIME_USERHEADERS_OWNER;
1501
0
  }
1502
0
  part->userheaders = headers;
1503
0
  if(headers && take_ownership)
1504
0
    part->flags |= MIME_USERHEADERS_OWNER;
1505
0
  return CURLE_OK;
1506
0
}
1507
1508
/* Set mime part content from callback. */
1509
CURLcode curl_mime_data_cb(curl_mimepart *part, curl_off_t datasize,
1510
                           curl_read_callback readfunc,
1511
                           curl_seek_callback seekfunc,
1512
                           curl_free_callback freefunc, void *arg)
1513
0
{
1514
0
  if(!part)
1515
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1516
1517
0
  cleanup_part_content(part);
1518
1519
0
  if(readfunc) {
1520
0
    part->readfunc = readfunc;
1521
0
    part->seekfunc = seekfunc;
1522
0
    part->freefunc = freefunc;
1523
0
    part->arg = arg;
1524
0
    part->datasize = datasize;
1525
0
    part->kind = MIMEKIND_CALLBACK;
1526
0
  }
1527
1528
0
  return CURLE_OK;
1529
0
}
1530
1531
/* Set mime part content from subparts. */
1532
CURLcode Curl_mime_set_subparts(curl_mimepart *part,
1533
                                curl_mime *subparts, int take_ownership)
1534
0
{
1535
0
  curl_mime *root;
1536
1537
0
  if(!part)
1538
0
    return CURLE_BAD_FUNCTION_ARGUMENT;
1539
1540
  /* Accept setting twice the same subparts. */
1541
0
  if(part->kind == MIMEKIND_MULTIPART && part->arg == subparts)
1542
0
    return CURLE_OK;
1543
1544
0
  cleanup_part_content(part);
1545
1546
0
  if(subparts) {
1547
    /* Should not have been attached already. */
1548
0
    if(subparts->parent)
1549
0
      return CURLE_BAD_FUNCTION_ARGUMENT;
1550
1551
    /* Should not be the part's root. */
1552
0
    root = part->parent;
1553
0
    if(root) {
1554
0
      while(root->parent && root->parent->parent)
1555
0
        root = root->parent->parent;
1556
0
      if(subparts == root) {
1557
        /* Can't add as a subpart of itself. */
1558
0
        return CURLE_BAD_FUNCTION_ARGUMENT;
1559
0
      }
1560
0
    }
1561
1562
0
    subparts->parent = part;
1563
    /* Subparts are processed internally: no read callback. */
1564
0
    part->seekfunc = mime_subparts_seek;
1565
0
    part->freefunc = take_ownership? mime_subparts_free: mime_subparts_unbind;
1566
0
    part->arg = subparts;
1567
0
    part->datasize = -1;
1568
0
    part->kind = MIMEKIND_MULTIPART;
1569
0
  }
1570
1571
0
  return CURLE_OK;
1572
0
}
1573
1574
CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
1575
0
{
1576
0
  return Curl_mime_set_subparts(part, subparts, TRUE);
1577
0
}
1578
1579
1580
/* Readback from top mime. */
1581
/* Argument is the dummy top part. */
1582
size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream)
1583
0
{
1584
0
  curl_mimepart *part = (curl_mimepart *) instream;
1585
0
  size_t ret;
1586
0
  bool hasread;
1587
1588
0
  (void) size;   /* Always 1. */
1589
1590
0
  do {
1591
0
    hasread = FALSE;
1592
0
    ret = readback_part(part, buffer, nitems, &hasread);
1593
    /*
1594
     * If this is not possible to get some data without calling more than
1595
     * one read callback (probably because a content encoder is not able to
1596
     * deliver a new bunch for the few data accumulated so far), force another
1597
     * read until we get enough data or a special exit code.
1598
     */
1599
0
  } while(ret == STOP_FILLING);
1600
1601
0
  return ret;
1602
0
}
1603
1604
/* Rewind mime stream. */
1605
CURLcode Curl_mime_rewind(curl_mimepart *part)
1606
0
{
1607
0
  return mime_part_rewind(part) == CURL_SEEKFUNC_OK?
1608
0
         CURLE_OK: CURLE_SEND_FAIL_REWIND;
1609
0
}
1610
1611
/* Compute header list size. */
1612
static size_t slist_size(struct curl_slist *s,
1613
                         size_t overhead, const char *skip, size_t skiplen)
1614
0
{
1615
0
  size_t size = 0;
1616
1617
0
  for(; s; s = s->next)
1618
0
    if(!skip || !match_header(s, skip, skiplen))
1619
0
      size += strlen(s->data) + overhead;
1620
0
  return size;
1621
0
}
1622
1623
/* Get/compute multipart size. */
1624
static curl_off_t multipart_size(curl_mime *mime)
1625
0
{
1626
0
  curl_off_t size;
1627
0
  curl_off_t boundarysize;
1628
0
  curl_mimepart *part;
1629
1630
0
  if(!mime)
1631
0
    return 0;           /* Not present -> empty. */
1632
1633
0
  boundarysize = 4 + MIME_BOUNDARY_LEN + 2;
1634
0
  size = boundarysize;  /* Final boundary - CRLF after headers. */
1635
1636
0
  for(part = mime->firstpart; part; part = part->nextpart) {
1637
0
    curl_off_t sz = Curl_mime_size(part);
1638
1639
0
    if(sz < 0)
1640
0
      size = sz;
1641
1642
0
    if(size >= 0)
1643
0
      size += boundarysize + sz;
1644
0
  }
1645
1646
0
  return size;
1647
0
}
1648
1649
/* Get/compute mime size. */
1650
curl_off_t Curl_mime_size(curl_mimepart *part)
1651
0
{
1652
0
  curl_off_t size;
1653
1654
0
  if(part->kind == MIMEKIND_MULTIPART)
1655
0
    part->datasize = multipart_size(part->arg);
1656
1657
0
  size = part->datasize;
1658
1659
0
  if(part->encoder)
1660
0
    size = part->encoder->sizefunc(part);
1661
1662
0
  if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) {
1663
    /* Compute total part size. */
1664
0
    size += slist_size(part->curlheaders, 2, NULL, 0);
1665
0
    size += slist_size(part->userheaders, 2, STRCONST("Content-Type"));
1666
0
    size += 2;    /* CRLF after headers. */
1667
0
  }
1668
0
  return size;
1669
0
}
1670
1671
/* Add a header. */
1672
/* VARARGS2 */
1673
CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
1674
0
{
1675
0
  struct curl_slist *hdr = NULL;
1676
0
  char *s = NULL;
1677
0
  va_list ap;
1678
1679
0
  va_start(ap, fmt);
1680
0
  s = curl_mvaprintf(fmt, ap);
1681
0
  va_end(ap);
1682
1683
0
  if(s) {
1684
0
    hdr = Curl_slist_append_nodup(*slp, s);
1685
0
    if(hdr)
1686
0
      *slp = hdr;
1687
0
    else
1688
0
      free(s);
1689
0
  }
1690
1691
0
  return hdr? CURLE_OK: CURLE_OUT_OF_MEMORY;
1692
0
}
1693
1694
/* Add a content type header. */
1695
static CURLcode add_content_type(struct curl_slist **slp,
1696
                                 const char *type, const char *boundary)
1697
0
{
1698
0
  return Curl_mime_add_header(slp, "Content-Type: %s%s%s", type,
1699
0
                              boundary? "; boundary=": "",
1700
0
                              boundary? boundary: "");
1701
0
}
1702
1703
const char *Curl_mime_contenttype(const char *filename)
1704
0
{
1705
  /*
1706
   * If no content type was specified, we scan through a few well-known
1707
   * extensions and pick the first we match!
1708
   */
1709
0
  struct ContentType {
1710
0
    const char *extension;
1711
0
    const char *type;
1712
0
  };
1713
0
  static const struct ContentType ctts[] = {
1714
0
    {".gif",  "image/gif"},
1715
0
    {".jpg",  "image/jpeg"},
1716
0
    {".jpeg", "image/jpeg"},
1717
0
    {".png",  "image/png"},
1718
0
    {".svg",  "image/svg+xml"},
1719
0
    {".txt",  "text/plain"},
1720
0
    {".htm",  "text/html"},
1721
0
    {".html", "text/html"},
1722
0
    {".pdf",  "application/pdf"},
1723
0
    {".xml",  "application/xml"}
1724
0
  };
1725
1726
0
  if(filename) {
1727
0
    size_t len1 = strlen(filename);
1728
0
    const char *nameend = filename + len1;
1729
0
    unsigned int i;
1730
1731
0
    for(i = 0; i < sizeof(ctts) / sizeof(ctts[0]); i++) {
1732
0
      size_t len2 = strlen(ctts[i].extension);
1733
1734
0
      if(len1 >= len2 && strcasecompare(nameend - len2, ctts[i].extension))
1735
0
        return ctts[i].type;
1736
0
    }
1737
0
  }
1738
0
  return NULL;
1739
0
}
1740
1741
static bool content_type_match(const char *contenttype,
1742
                               const char *target, size_t len)
1743
0
{
1744
0
  if(contenttype && strncasecompare(contenttype, target, len))
1745
0
    switch(contenttype[len]) {
1746
0
    case '\0':
1747
0
    case '\t':
1748
0
    case '\r':
1749
0
    case '\n':
1750
0
    case ' ':
1751
0
    case ';':
1752
0
      return TRUE;
1753
0
    }
1754
0
  return FALSE;
1755
0
}
1756
1757
CURLcode Curl_mime_prepare_headers(struct Curl_easy *data,
1758
                                   curl_mimepart *part,
1759
                                   const char *contenttype,
1760
                                   const char *disposition,
1761
                                   enum mimestrategy strategy)
1762
0
{
1763
0
  curl_mime *mime = NULL;
1764
0
  const char *boundary = NULL;
1765
0
  char *customct;
1766
0
  const char *cte = NULL;
1767
0
  CURLcode ret = CURLE_OK;
1768
1769
  /* Get rid of previously prepared headers. */
1770
0
  curl_slist_free_all(part->curlheaders);
1771
0
  part->curlheaders = NULL;
1772
1773
  /* Be sure we won't access old headers later. */
1774
0
  if(part->state.state == MIMESTATE_CURLHEADERS)
1775
0
    mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL);
1776
1777
  /* Check if content type is specified. */
1778
0
  customct = part->mimetype;
1779
0
  if(!customct)
1780
0
    customct = search_header(part->userheaders, STRCONST("Content-Type"));
1781
0
  if(customct)
1782
0
    contenttype = customct;
1783
1784
  /* If content type is not specified, try to determine it. */
1785
0
  if(!contenttype) {
1786
0
    switch(part->kind) {
1787
0
    case MIMEKIND_MULTIPART:
1788
0
      contenttype = MULTIPART_CONTENTTYPE_DEFAULT;
1789
0
      break;
1790
0
    case MIMEKIND_FILE:
1791
0
      contenttype = Curl_mime_contenttype(part->filename);
1792
0
      if(!contenttype)
1793
0
        contenttype = Curl_mime_contenttype(part->data);
1794
0
      if(!contenttype && part->filename)
1795
0
        contenttype = FILE_CONTENTTYPE_DEFAULT;
1796
0
      break;
1797
0
    default:
1798
0
      contenttype = Curl_mime_contenttype(part->filename);
1799
0
      break;
1800
0
    }
1801
0
  }
1802
1803
0
  if(part->kind == MIMEKIND_MULTIPART) {
1804
0
    mime = (curl_mime *) part->arg;
1805
0
    if(mime)
1806
0
      boundary = mime->boundary;
1807
0
  }
1808
0
  else if(contenttype && !customct &&
1809
0
          content_type_match(contenttype, STRCONST("text/plain")))
1810
0
    if(strategy == MIMESTRATEGY_MAIL || !part->filename)
1811
0
      contenttype = NULL;
1812
1813
  /* Issue content-disposition header only if not already set by caller. */
1814
0
  if(!search_header(part->userheaders, STRCONST("Content-Disposition"))) {
1815
0
    if(!disposition)
1816
0
      if(part->filename || part->name ||
1817
0
        (contenttype && !strncasecompare(contenttype, "multipart/", 10)))
1818
0
          disposition = DISPOSITION_DEFAULT;
1819
0
    if(disposition && curl_strequal(disposition, "attachment") &&
1820
0
     !part->name && !part->filename)
1821
0
      disposition = NULL;
1822
0
    if(disposition) {
1823
0
      char *name = NULL;
1824
0
      char *filename = NULL;
1825
1826
0
      if(part->name) {
1827
0
        name = escape_string(data, part->name, strategy);
1828
0
        if(!name)
1829
0
          ret = CURLE_OUT_OF_MEMORY;
1830
0
      }
1831
0
      if(!ret && part->filename) {
1832
0
        filename = escape_string(data, part->filename, strategy);
1833
0
        if(!filename)
1834
0
          ret = CURLE_OUT_OF_MEMORY;
1835
0
      }
1836
0
      if(!ret)
1837
0
        ret = Curl_mime_add_header(&part->curlheaders,
1838
0
                                   "Content-Disposition: %s%s%s%s%s%s%s",
1839
0
                                   disposition,
1840
0
                                   name? "; name=\"": "",
1841
0
                                   name? name: "",
1842
0
                                   name? "\"": "",
1843
0
                                   filename? "; filename=\"": "",
1844
0
                                   filename? filename: "",
1845
0
                                   filename? "\"": "");
1846
0
      Curl_safefree(name);
1847
0
      Curl_safefree(filename);
1848
0
      if(ret)
1849
0
        return ret;
1850
0
      }
1851
0
    }
1852
1853
  /* Issue Content-Type header. */
1854
0
  if(contenttype) {
1855
0
    ret = add_content_type(&part->curlheaders, contenttype, boundary);
1856
0
    if(ret)
1857
0
      return ret;
1858
0
  }
1859
1860
  /* Content-Transfer-Encoding header. */
1861
0
  if(!search_header(part->userheaders,
1862
0
                    STRCONST("Content-Transfer-Encoding"))) {
1863
0
    if(part->encoder)
1864
0
      cte = part->encoder->name;
1865
0
    else if(contenttype && strategy == MIMESTRATEGY_MAIL &&
1866
0
     part->kind != MIMEKIND_MULTIPART)
1867
0
      cte = "8bit";
1868
0
    if(cte) {
1869
0
      ret = Curl_mime_add_header(&part->curlheaders,
1870
0
                                 "Content-Transfer-Encoding: %s", cte);
1871
0
      if(ret)
1872
0
        return ret;
1873
0
    }
1874
0
  }
1875
1876
  /* If we were reading curl-generated headers, restart with new ones (this
1877
     should not occur). */
1878
0
  if(part->state.state == MIMESTATE_CURLHEADERS)
1879
0
    mimesetstate(&part->state, MIMESTATE_CURLHEADERS, part->curlheaders);
1880
1881
  /* Process subparts. */
1882
0
  if(part->kind == MIMEKIND_MULTIPART && mime) {
1883
0
    curl_mimepart *subpart;
1884
1885
0
    disposition = NULL;
1886
0
    if(content_type_match(contenttype, STRCONST("multipart/form-data")))
1887
0
      disposition = "form-data";
1888
0
    for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) {
1889
0
      ret = Curl_mime_prepare_headers(data, subpart, NULL,
1890
0
                                      disposition, strategy);
1891
0
      if(ret)
1892
0
        return ret;
1893
0
    }
1894
0
  }
1895
0
  return ret;
1896
0
}
1897
1898
/* Recursively reset paused status in the given part. */
1899
void Curl_mime_unpause(curl_mimepart *part)
1900
0
{
1901
0
  if(part) {
1902
0
    if(part->lastreadstatus == CURL_READFUNC_PAUSE)
1903
0
      part->lastreadstatus = 1; /* Successful read status. */
1904
0
    if(part->kind == MIMEKIND_MULTIPART) {
1905
0
      curl_mime *mime = (curl_mime *) part->arg;
1906
1907
0
      if(mime) {
1908
0
        curl_mimepart *subpart;
1909
1910
0
        for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart)
1911
0
          Curl_mime_unpause(subpart);
1912
0
      }
1913
0
    }
1914
0
  }
1915
0
}
1916
1917
1918
#else /* !CURL_DISABLE_MIME && (!CURL_DISABLE_HTTP ||
1919
                                !CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP) */
1920
1921
/* Mime not compiled in: define stubs for externally-referenced functions. */
1922
curl_mime *curl_mime_init(CURL *easy)
1923
{
1924
  (void) easy;
1925
  return NULL;
1926
}
1927
1928
void curl_mime_free(curl_mime *mime)
1929
{
1930
  (void) mime;
1931
}
1932
1933
curl_mimepart *curl_mime_addpart(curl_mime *mime)
1934
{
1935
  (void) mime;
1936
  return NULL;
1937
}
1938
1939
CURLcode curl_mime_name(curl_mimepart *part, const char *name)
1940
{
1941
  (void) part;
1942
  (void) name;
1943
  return CURLE_NOT_BUILT_IN;
1944
}
1945
1946
CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
1947
{
1948
  (void) part;
1949
  (void) filename;
1950
  return CURLE_NOT_BUILT_IN;
1951
}
1952
1953
CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
1954
{
1955
  (void) part;
1956
  (void) mimetype;
1957
  return CURLE_NOT_BUILT_IN;
1958
}
1959
1960
CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
1961
{
1962
  (void) part;
1963
  (void) encoding;
1964
  return CURLE_NOT_BUILT_IN;
1965
}
1966
1967
CURLcode curl_mime_data(curl_mimepart *part,
1968
                        const char *data, size_t datasize)
1969
{
1970
  (void) part;
1971
  (void) data;
1972
  (void) datasize;
1973
  return CURLE_NOT_BUILT_IN;
1974
}
1975
1976
CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
1977
{
1978
  (void) part;
1979
  (void) filename;
1980
  return CURLE_NOT_BUILT_IN;
1981
}
1982
1983
CURLcode curl_mime_data_cb(curl_mimepart *part,
1984
                           curl_off_t datasize,
1985
                           curl_read_callback readfunc,
1986
                           curl_seek_callback seekfunc,
1987
                           curl_free_callback freefunc,
1988
                           void *arg)
1989
{
1990
  (void) part;
1991
  (void) datasize;
1992
  (void) readfunc;
1993
  (void) seekfunc;
1994
  (void) freefunc;
1995
  (void) arg;
1996
  return CURLE_NOT_BUILT_IN;
1997
}
1998
1999
CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts)
2000
{
2001
  (void) part;
2002
  (void) subparts;
2003
  return CURLE_NOT_BUILT_IN;
2004
}
2005
2006
CURLcode curl_mime_headers(curl_mimepart *part,
2007
                           struct curl_slist *headers, int take_ownership)
2008
{
2009
  (void) part;
2010
  (void) headers;
2011
  (void) take_ownership;
2012
  return CURLE_NOT_BUILT_IN;
2013
}
2014
2015
CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
2016
{
2017
  (void)slp;
2018
  (void)fmt;
2019
  return CURLE_NOT_BUILT_IN;
2020
}
2021
2022
#endif /* if disabled */