1 
2 /*
3  * The "sndparts" routines manage chunks of outgoing messages.
4  * In the simplest case, there will be a single part that corresponds
5  * to the outbound mail message.  These routines provide support to
6  * add attachments and inclusions, as well as complex parts such
7  * as the MIME "multipart/mixed" type.
8  */
9 
10 /*
11  * RFC-1521 (sec 4.5.3) says 7bit/8bit parts cannot exceed this length
12  * Actually, the max is 1000, but we've accounted for CRNL termination here.
13  */
14 #define RFC821_MAXLEN	998
15 
16 /* generate maximally random/minimally ugly multipart separator */
17 #define MIME_MAKE_BOUNDARY(buf, type, seq) \
18 	    sprintf(buf, "%%--%s-boundary-%d.%d.%lu--%%", \
19 			(type), (seq), getpid(), \
20 			(unsigned long)time((time_t *)NULL));
21 
22 /* commands that handle various content encodings */
23 # define MIME_ENCODE_CMD_QUOTED(buf, infile, outfile) \
24 	    sprintf((buf), "mmencode -q %s >%s", (infile), (outfile))
25 # define MIME_ENCODE_CMD_BASE64(buf, infile, outfile) \
26 	    sprintf((buf), "mmencode -b %s >%s", (infile), (outfile))
27 # define MIME_ENCODE_CMD_UUENCODE(buf, infile, outfile) \
28 	    sprintf((buf), "uuencode %s <%s >%s", \
29 	    basename(infile), (infile), (outfile))	/* SIDE EFFECTS */
30 
31 /* command that provides information on the content of a part */
32 # define MIME_FILE_CMD(buf, infile, outfile) \
33 	    sprintf((buf), "file %s >%s", (infile), (outfile))
34 
35 
36 /*
37  * A (SEND_BODYPART) describes a chunk of data being sent.  In the
38  * simplest case (a plain old mail message) there is just a single
39  * part representing the message.  Additional parts will be used
40  * as attachments and inclusions are created.
41  */
42 
43 /* part_type settings for a (SEND_BODYPART) */
44 #define BP_IS_DUMMY	0	/* not a real part			*/
45 #define BP_IS_MSSGTEXT	1	/* text/plain subject to [...] interp	*/
46 #define BP_IS_MIMEPART	2	/* a regular MIME body part		*/
47 #define BP_IS_MULTIPART	3	/* head of a multipart			*/
48 
49 /* content_header[] selectors */
50 #define BP_CONT_TYPE		0	/* Content-Type			*/
51 #define BP_CONT_ENCODING	1	/* Content-Transfer-Encoding	*/
52 #define BP_CONT_DESCRIPTION	2	/* Content-Description		*/
53 #define BP_CONT_DISPOSITION	3	/* Content-Disposition		*/
54 #define BP_CONT_MD5		4	/* Content-MD5			*/
55 #define BP_NUM_CONT_HEADERS	5
56 
57 /* the header names associated with the above */
58 extern char *Mime_header_names[BP_NUM_CONT_HEADERS];
59 
60 #ifdef ANSI_C
61 struct send_multipart;
62 #endif
63 
64 /*
65  * The (SEND_BODYPART) describes a chunk of the message body.
66  */
67 typedef struct send_bodypart {
68 
69 	/*
70 	 * The "part_type" indicate what this part contains.  The remaining
71 	 * members of the structure are interpreted according to the type.
72 	 *
73 	 * BP_IS_DUMMY - Not a real part.  This is used in the attachments
74 	 * menu to create labels.  The only member of the structure that
75 	 * is valid for one of these is "fname", which contains a label.
76 	 * Never ever try to output one of these!
77 	 *
78 	 * BP_IS_MIMEPART - This part is a single entity, such as a
79 	 * file attachment.  The MIME header information and the content
80 	 * statistics members will be valid.  The multipart information,
81 	 * however, does not contain meaningful information.  Except
82 	 * for the main message (which will be a BP_IS_MSSGTEXT), every
83 	 * chunk of data is represented by one of these.
84 	 *
85 	 * BP_IS_MULTIPART - This part does not contain any data, but
86 	 * instead represents a chunk of parts, a "multipart/mixed".  In
87 	 * this case, the multipart members are valid, and will lead
88 	 * to the parts that comprise this multipart.  The MIME header
89 	 * and content statistics members should be ignored.
90 	 * ("multipart/mixed" is the only form of multipart supported at
91 	 * this time.)
92 	 *
93 	 * BP_IS_MSSGTEXT - This part represents the message entered by
94 	 * the user.  The MIME header and content statistics members
95 	 * describe the message text.  The multipart information will
96 	 * indicate whether the user has provided any attachments or
97 	 * inclusions.  If the multipart list is empty, this message
98 	 * is sent as a simple "text/plain".  If there is multipart
99 	 * information, then the message is a "multipart/mixed", with
100 	 * this text appearing with one (or more) subparts.
101 	 */
102 	int part_type;
103 
104 	/*
105 	 * The (SEND_MULTIPART) structure is just a list of these
106 	 * (SEND_BODYPART) pieces.  It is possible to have a body part
107 	 * appear in multiple lists.  (For instance, it could appear
108 	 * in the list of attachments for a BP_IS_MSSGTEXT part, as well
109 	 * as a separate list that tracks the attachments that were
110 	 * created by the attachments menu.)  The "link_count" indicates
111 	 * how many (SEND_MULTIPART) lists reference this part.  When
112 	 * the link count reaches zero, this part no longer is in use
113 	 * and may be destroyed.
114 	 */
115 	int link_count;
116 
117 	/*
118 	 * The file that contains the data for this part.
119 	 * BP_IS_DUMMY - a text label.
120 	 * BP_IS_MIMEPART - filename containing part data.
121 	 * BP_IS_MULTIPART - undefined value, do not use.
122 	 * BP_IS_MSSGTEXT - filename containing message text.
123 	 */
124 	char *fname;
125 
126 	/*
127 	 * Procedures that emit the part header and body.
128 	 * BP_IS_DUMMY - undefined values, do not use.
129 	 * BP_IS_MIMEPART - procedures to emit part header and body.
130 	 * BP_IS_MULTIPART - procedures to emit the multipart hdr and body.
131 	 * BP_IS_MSSGTEXT - procedures to emit message (and attachments and
132 	 *	inclusions) header and body.
133 	 */
134 	int (*emit_hdr_proc) P_((FILE *, struct send_bodypart *));
135 	int (*emit_body_proc) P_((FILE *, struct send_bodypart *));
136 
137 	/*
138 	 * Values of the MIME "Content-" headers.
139 	 * BP_IS_DUMMY - undefined values, do not use.
140 	 * BP_IS_MIMEPART - valid header values.
141 	 * BP_IS_MULTIPART - undefined values, do not use.
142 	 * BP_IS_MSSGTEXT - header values associated with the message text.
143 	 *	If the message will be transmitted as "text/plain" then
144 	 *	these appear in the main message headers.  If the message
145 	 *	is "multipart/mixed" then these appear in the part
146 	 *	that contains the message text.
147 	 */
148 	char *content_header[BP_NUM_CONT_HEADERS];
149 
150 	/*
151 	 * Statistics on the data.
152 	 * BP_IS_DUMMY - undefined values, do not use.
153 	 * BP_IS_MIMEPART - valid statistics on the part data.
154 	 * BP_IS_MULTIPART - undefined values, do not use.
155 	 * BP_IS_MSSGTEXT - valid statistics on the message text.
156 	 */
157 	long total_chars;	/* size of the part			*/
158 	long ascii_chars;	/* chars 0x20 thru 0x7F plus whitespace	*/
159 	long binlo_chars;	/* non-space chars < 0x20 (incl 0x0!)	*/
160 	long binhi_chars;	/* chars >= 0x80			*/
161 	int max_linelen;	/* length of longest line, excluding NL	*/
162 
163 	/*
164 	 * Multipart information.
165 	 * BP_IS_DUMMY - undefined values, do not use.
166 	 * BP_IS_MIMEPART - undefined values, do not use.
167 	 * BP_IS_MULTIPART - lists the parts that comprise this multipart.
168 	 * BP_IS_MSSGTEXT - the attachments and inclusions for the
169 	 *	message.  If the list is empty then there are none
170 	 *	and the message will be sent as "text/plain".
171 	 */
172 	struct send_multipart *subparts;
173 	char *boundary;		/* multipart boundary seperator		*/
174 
175 } SEND_BODYPART;
176 
177 
178 /*
179  * A multipart list is constructed with (SEND_MULTIPART).  For a list
180  * with N parts, there will be N+1 (SEND_MULTIPART) entries.  One serves
181  * as the list head, and the remainder encapsulate a (SEND_BODYPART)
182  * that contains the data for the corresponding part.
183  */
184 typedef struct send_multipart {
185 
186     /*
187      * A part may be keyed with an ID number.  This is optional, and is
188      * required only if a lookup-by-ID will be performed.  This is
189      * used, for instance, by the [include] feature.  When initially
190      * scanning the user's message, the included parts are keyed by
191      * fseek position in the file.  This means that when the final
192      * output is produced, the part can be located easily without
193      * reparsing the input.  On the other hand, the [attach] parts
194      * are not keyed, since no lookup is performed (they merely are
195      * dumped out when the message text is complete).
196      */
197     long id;
198 
199     /*
200      * The "part" is the (SEND_BODYPART) that contains the data for
201      * this part.  The list head will have a NULL value here.
202      */
203     struct send_bodypart *part;
204 
205     /*
206      * Forward and back pointers for double-linked list.
207      */
208     struct send_multipart *prev, *next;
209 
210 } SEND_MULTIPART;
211 
212 
213 /* operations that may be performed on the head element of a (SEND_MULTIPART) */
214 #define MULTIPART_HEAD(mp)	((mp)->next)
215 #define MULTIPART_TAIL(mp)	((mp)->prev)
216 #define MULTIPART_IS_EMPTY(mp)	((mp)->next == (mp))
217 
218 /* operations that may be performed on any element of a (SEND_MULTIPART) */
219 #define MULTIPART_PART(mp)	((mp)->part)
220 #define MULTIPART_ID(mp)	((mp)->id)
221 
222 /* ID used for attachment parts */
223 #define MP_ID_ATTACHMENT	(-1L)
224 
225 
226 /* sndpart_lib.c */
227 
228 int encoding_is_reasonable P_((const char *));
229 
230 SEND_BODYPART *bodypart_new P_((const char *, int));
231 void bodypart_destroy P_((SEND_BODYPART *));
232 void bodypart_set_content P_((SEND_BODYPART *, int, const char *));
233 const char *bodypart_get_content P_((SEND_BODYPART *, int));
234 void bodypart_guess_content P_((SEND_BODYPART *, int));
235 
236 #define bodypart_get_filename(part)	((part)->fname)
237 
238 SEND_MULTIPART *multipart_new P_((SEND_BODYPART *, long));
239 void multipart_destroy P_((SEND_MULTIPART *));
240 SEND_MULTIPART *multipart_insertpart P_((SEND_MULTIPART *, SEND_MULTIPART *, SEND_BODYPART *, long));
241 SEND_MULTIPART *multipart_appendpart P_((SEND_MULTIPART *, SEND_MULTIPART *, SEND_BODYPART *, long));
242 SEND_BODYPART *multipart_deletepart P_((SEND_MULTIPART *, SEND_MULTIPART *));
243 SEND_MULTIPART *multipart_next P_((SEND_MULTIPART *, SEND_MULTIPART *));
244 SEND_MULTIPART *multipart_find P_((SEND_MULTIPART *, long));
245 
246 #ifdef NDEBUG
247 # define bodypart_integrity_check(part)
248 # define multipart_integrity_check(part)
249 #else
250   void bodypart_integrity_check P_((const SEND_BODYPART *));
251   void multipart_integrity_check P_((const SEND_MULTIPART *));
252 #endif
253 
254 
255 /* sndpart_io.c */
256 
257 SEND_BODYPART *newpart_mssgtext P_((const char *));
258 SEND_BODYPART *newpart_mimepart P_((const char *));
259 
260 int emitpart P_((FILE *, SEND_BODYPART *));
261 int emitpart_mssghdr P_((FILE *, SEND_BODYPART *));
262 int emitpart_mssgbody P_((FILE *, SEND_BODYPART *));
263 
264