1 /**
2  * @file
3  * Manipulate multipart Emails
4  *
5  * @authors
6  * Copyright (C) 1996-2002,2009-2012 Michael R. Elkins <me@mutt.org>
7  * Copyright (C) 2019 Pietro Cerutti <gahr@gahr.ch>
8  *
9  * @copyright
10  * This program is free software: you can redistribute it and/or modify it under
11  * the terms of the GNU General Public License as published by the Free Software
12  * Foundation, either version 2 of the License, or (at your option) any later
13  * version.
14  *
15  * This program is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License along with
21  * this program.  If not, see <http://www.gnu.org/licenses/>.
22  */
23 
24 /**
25  * @page send_multipart Manipulate multipart Emails
26  *
27  * Manipulate multipart Emails
28  */
29 
30 #include "config.h"
31 #include <stddef.h>
32 #include <stdbool.h>
33 #include "mutt/lib.h"
34 #include "email/lib.h"
35 #include "multipart.h"
36 #include "sendlib.h"
37 
38 /**
39  * get_toplevel_encoding - Find the most restrictive encoding type
40  * @param a Body to examine
41  * @retval num Encoding type, e.g. #ENC_7BIT
42  */
get_toplevel_encoding(struct Body * a)43 static int get_toplevel_encoding(struct Body *a)
44 {
45   int e = ENC_7BIT;
46 
47   for (; a; a = a->next)
48   {
49     if (a->encoding == ENC_BINARY)
50       return ENC_BINARY;
51     if (a->encoding == ENC_8BIT)
52       e = ENC_8BIT;
53   }
54 
55   return e;
56 }
57 
58 /**
59  * check_boundary - Check for duplicate boundary
60  * @param boundary Boundary to look for
61  * @param b        Body parts to check
62  * @retval true Duplicate found
63  */
check_boundary(const char * boundary,struct Body * b)64 static bool check_boundary(const char *boundary, struct Body *b)
65 {
66   char *p = NULL;
67 
68   if (b->parts && check_boundary(boundary, b->parts))
69     return true;
70 
71   if (b->next && check_boundary(boundary, b->next))
72     return true;
73 
74   p = mutt_param_get(&b->parameter, "boundary");
75   if (p && mutt_str_equal(p, boundary))
76   {
77     return true;
78   }
79   return false;
80 }
81 
82 /**
83  * mutt_generate_boundary - Create a unique boundary id for a MIME part
84  * @param pl MIME part
85  */
mutt_generate_boundary(struct ParameterList * pl)86 void mutt_generate_boundary(struct ParameterList *pl)
87 {
88   char rs[MUTT_RANDTAG_LEN + 1];
89 
90   mutt_rand_base32(rs, sizeof(rs) - 1);
91   rs[MUTT_RANDTAG_LEN] = 0;
92   mutt_param_set(pl, "boundary", rs);
93 }
94 
95 /**
96  * mutt_make_multipart - Create a multipart email
97  * @param b Body of email to start
98  * @retval ptr Newly allocated Body
99  */
mutt_make_multipart(struct Body * b)100 struct Body *mutt_make_multipart(struct Body *b)
101 {
102   struct Body *new_body = mutt_body_new();
103   new_body->type = TYPE_MULTIPART;
104   new_body->subtype = mutt_str_dup("mixed");
105   new_body->encoding = get_toplevel_encoding(b);
106   do
107   {
108     mutt_generate_boundary(&new_body->parameter);
109     if (check_boundary(mutt_param_get(&new_body->parameter, "boundary"), b))
110       mutt_param_delete(&new_body->parameter, "boundary");
111   } while (!mutt_param_get(&new_body->parameter, "boundary"));
112   new_body->use_disp = false;
113   new_body->disposition = DISP_INLINE;
114   new_body->parts = b;
115 
116   return new_body;
117 }
118 
119 /**
120  * mutt_remove_multipart - Extract the multipart body if it exists
121  * @param b Body to alter
122  * @retval ptr The parts of the Body
123  *
124  * @note The original Body is freed
125  */
mutt_remove_multipart(struct Body * b)126 struct Body *mutt_remove_multipart(struct Body *b)
127 {
128   struct Body *t = NULL;
129 
130   if (b->parts)
131   {
132     t = b;
133     b = b->parts;
134     t->parts = NULL;
135     mutt_body_free(&t);
136   }
137   return b;
138 }
139