mime.c (302408) | mime.c (38032) |
---|---|
1/* | 1/* |
2 * Copyright (c) 1998-2003, 2006, 2013 Proofpoint, Inc. and its suppliers. 3 * All rights reserved. | 2 * Copyright (c) 1998 Sendmail, Inc. All rights reserved. |
4 * Copyright (c) 1994, 1996-1997 Eric P. Allman. All rights reserved. 5 * Copyright (c) 1994 6 * The Regents of the University of California. All rights reserved. 7 * 8 * By using this file, you agree to the terms and conditions set 9 * forth in the LICENSE file which can be found at the top level of 10 * the sendmail distribution. 11 * 12 */ 13 | 3 * Copyright (c) 1994, 1996-1997 Eric P. Allman. All rights reserved. 4 * Copyright (c) 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * By using this file, you agree to the terms and conditions set 8 * forth in the LICENSE file which can be found at the top level of 9 * the sendmail distribution. 10 * 11 */ 12 |
14#include <sendmail.h> 15#include | 13# include "sendmail.h" 14# include <string.h> |
16 | 15 |
17SM_RCSID("@(#)$Id: mime.c,v 8.149 2013-11-22 20:51:56 ca Exp $") | 16#ifndef lint 17static char sccsid[] = "@(#)mime.c 8.66 (Berkeley) 5/19/98"; 18#endif /* not lint */ |
18 19/* 20** MIME support. 21** 22** I am indebted to John Beck of Hewlett-Packard, who contributed 23** his code to me for inclusion. As it turns out, I did not use 24** his code since he used a "minimum change" approach that used 25** several temp files, and I wanted a "minimum impact" approach 26** that would avoid copying. However, looking over his code 27** helped me cement my understanding of the problem. 28** 29** I also looked at, but did not directly use, Nathaniel 30** Borenstein's "code.c" module. Again, it functioned as 31** a file-to-file translator, which did not fit within my 32** design bounds, but it was a useful base for understanding 33** the problem. 34*/ 35 | 19 20/* 21** MIME support. 22** 23** I am indebted to John Beck of Hewlett-Packard, who contributed 24** his code to me for inclusion. As it turns out, I did not use 25** his code since he used a "minimum change" approach that used 26** several temp files, and I wanted a "minimum impact" approach 27** that would avoid copying. However, looking over his code 28** helped me cement my understanding of the problem. 29** 30** I also looked at, but did not directly use, Nathaniel 31** Borenstein's "code.c" module. Again, it functioned as 32** a file-to-file translator, which did not fit within my 33** design bounds, but it was a useful base for understanding 34** the problem. 35*/ 36 |
36/* use "old" mime 7 to 8 algorithm by default */ 37#ifndef MIME7TO8_OLD 38# define MIME7TO8_OLD 1 39#endif /* ! MIME7TO8_OLD */ 40 | |
41#if MIME8TO7 | 37#if MIME8TO7 |
42static int isboundary __P((char *, char **)); 43static int mimeboundary __P((char *, char **)); 44static int mime_getchar __P((SM_FILE_T *, char **, int *)); 45static int mime_getchar_crlf __P((SM_FILE_T *, char **, int *)); | |
46 47/* character set for hex and base64 encoding */ | 38 39/* character set for hex and base64 encoding */ |
48static char Base16Code[] = "0123456789ABCDEF"; 49static char Base64Code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | 40char Base16Code[] = "0123456789ABCDEF"; 41char Base64Code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
50 51/* types of MIME boundaries */ | 42 43/* types of MIME boundaries */ |
52# define MBT_SYNTAX 0 /* syntax error */ 53# define MBT_NOTSEP 1 /* not a boundary */ 54# define MBT_INTERMED 2 /* intermediate boundary (no trailing --) */ 55# define MBT_FINAL 3 /* final boundary (trailing -- included) */ | 44#define MBT_SYNTAX 0 /* syntax error */ 45#define MBT_NOTSEP 1 /* not a boundary */ 46#define MBT_INTERMED 2 /* intermediate boundary (no trailing --) */ 47#define MBT_FINAL 3 /* final boundary (trailing -- included) */ |
56 57static char *MimeBoundaryNames[] = 58{ 59 "SYNTAX", "NOTSEP", "INTERMED", "FINAL" 60}; 61 | 48 49static char *MimeBoundaryNames[] = 50{ 51 "SYNTAX", "NOTSEP", "INTERMED", "FINAL" 52}; 53 |
62static bool MapNLtoCRLF; | 54bool MapNLtoCRLF; |
63 | 55 |
64/* | 56extern int mimeboundary __P((char *, char **)); 57/* |
65** MIME8TO7 -- output 8 bit body in 7 bit format 66** 67** The header has already been output -- this has to do the 68** 8 to 7 bit conversion. It would be easy if we didn't have 69** to deal with nested formats (multipart/xxx and message/rfc822). 70** 71** We won't be called if we don't have to do a conversion, and 72** appropriate MIME-Version: and Content-Type: fields have been 73** output. Any Content-Transfer-Encoding: field has not been 74** output, and we can add it here. 75** 76** Parameters: 77** mci -- mailer connection information. 78** header -- the header for this body part. 79** e -- envelope. 80** boundaries -- the currently pending message boundaries. 81** NULL if we are processing the outer portion. 82** flags -- to tweak processing. | 58** MIME8TO7 -- output 8 bit body in 7 bit format 59** 60** The header has already been output -- this has to do the 61** 8 to 7 bit conversion. It would be easy if we didn't have 62** to deal with nested formats (multipart/xxx and message/rfc822). 63** 64** We won't be called if we don't have to do a conversion, and 65** appropriate MIME-Version: and Content-Type: fields have been 66** output. Any Content-Transfer-Encoding: field has not been 67** output, and we can add it here. 68** 69** Parameters: 70** mci -- mailer connection information. 71** header -- the header for this body part. 72** e -- envelope. 73** boundaries -- the currently pending message boundaries. 74** NULL if we are processing the outer portion. 75** flags -- to tweak processing. |
83** level -- recursion level. | |
84** 85** Returns: 86** An indicator of what terminated the message part: 87** MBT_FINAL -- the final boundary 88** MBT_INTERMED -- an intermediate boundary 89** MBT_NOTSEP -- an end of file | 76** 77** Returns: 78** An indicator of what terminated the message part: 79** MBT_FINAL -- the final boundary 80** MBT_INTERMED -- an intermediate boundary 81** MBT_NOTSEP -- an end of file |
90** SM_IO_EOF -- I/O error occurred | |
91*/ 92 93struct args 94{ | 82*/ 83 84struct args 85{ |
95 char *a_field; /* name of field */ 96 char *a_value; /* value of that field */ | 86 char *field; /* name of field */ 87 char *value; /* value of that field */ |
97}; 98 99int | 88}; 89 90int |
100mime8to7(mci, header, e, boundaries, flags, level) | 91mime8to7(mci, header, e, boundaries, flags) |
101 register MCI *mci; 102 HDR *header; 103 register ENVELOPE *e; 104 char **boundaries; 105 int flags; | 92 register MCI *mci; 93 HDR *header; 94 register ENVELOPE *e; 95 char **boundaries; 96 int flags; |
106 int level; | |
107{ 108 register char *p; 109 int linelen; | 97{ 98 register char *p; 99 int linelen; |
110 int blen; | |
111 int bt; 112 off_t offset; 113 size_t sectionsize, sectionhighbits; 114 int i; 115 char *type; 116 char *subtype; 117 char *cte; 118 char **pvp; 119 int argc = 0; 120 char *bp; | 100 int bt; 101 off_t offset; 102 size_t sectionsize, sectionhighbits; 103 int i; 104 char *type; 105 char *subtype; 106 char *cte; 107 char **pvp; 108 int argc = 0; 109 char *bp; |
121 bool use_qp = false; | 110 bool use_qp = FALSE; |
122 struct args argv[MAXMIMEARGS]; 123 char bbuf[128]; 124 char buf[MAXLINE]; 125 char pvpbuf[MAXLINE]; | 111 struct args argv[MAXMIMEARGS]; 112 char bbuf[128]; 113 char buf[MAXLINE]; 114 char pvpbuf[MAXLINE]; |
126 extern unsigned char MimeTokenTab[256]; | 115 extern u_char MimeTokenTab[256]; 116 extern int mime_getchar __P((FILE *, char **, int *)); 117 extern int mime_getchar_crlf __P((FILE *, char **, int *)); |
127 | 118 |
128 if (level > MAXMIMENESTING) 129 { 130 if (!bitset(EF_TOODEEP, e->e_flags)) 131 { 132 if (tTd(43, 4)) 133 sm_dprintf("mime8to7: too deep, level=%d\n", 134 level); 135 usrerr("mime8to7: recursion level %d exceeded", 136 level); 137 e->e_flags |= EF_DONT_MIME|EF_TOODEEP; 138 } 139 } | |
140 if (tTd(43, 1)) 141 { | 119 if (tTd(43, 1)) 120 { |
142 sm_dprintf("mime8to7: flags = %x, boundaries =", flags); | 121 printf("mime8to7: flags = %x, boundaries =", flags); |
143 if (boundaries[0] == NULL) | 122 if (boundaries[0] == NULL) |
144 sm_dprintf(" <none>"); | 123 printf(" |
145 else 146 { 147 for (i = 0; boundaries[i] != NULL; i++) | 124 else 125 { 126 for (i = 0; boundaries[i] != NULL; i++) |
148 sm_dprintf(" %s", boundaries[i]); | 127 printf(" %s", boundaries[i]); |
149 } | 128 } |
150 sm_dprintf("\n"); | 129 printf("\n"); |
151 } | 130 } |
152 MapNLtoCRLF = true; | 131 MapNLtoCRLF = TRUE; |
153 p = hvalue("Content-Transfer-Encoding", header); 154 if (p == NULL || | 132 p = hvalue("Content-Transfer-Encoding", header); 133 if (p == NULL || |
155 (pvp = prescan(p, '\0', pvpbuf, sizeof(pvpbuf), NULL, 156 MimeTokenTab, false)) == NULL || | 134 (pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL, 135 MimeTokenTab)) == NULL || |
157 pvp[0] == NULL) 158 { 159 cte = NULL; 160 } 161 else 162 { | 136 pvp[0] == NULL) 137 { 138 cte = NULL; 139 } 140 else 141 { |
163 cataddr(pvp, NULL, buf, sizeof(buf), '\0', false); 164 cte = sm_rpool_strdup_x(e->e_rpool, buf); | 142 cataddr(pvp, NULL, buf, sizeof buf, '\0'); 143 cte = newstr(buf); |
165 } 166 167 type = subtype = NULL; 168 p = hvalue("Content-Type", header); 169 if (p == NULL) 170 { 171 if (bitset(M87F_DIGEST, flags)) 172 p = "message/rfc822"; 173 else 174 p = "text/plain"; 175 } 176 if (p != NULL && | 144 } 145 146 type = subtype = NULL; 147 p = hvalue("Content-Type", header); 148 if (p == NULL) 149 { 150 if (bitset(M87F_DIGEST, flags)) 151 p = "message/rfc822"; 152 else 153 p = "text/plain"; 154 } 155 if (p != NULL && |
177 (pvp = prescan(p, '\0', pvpbuf, sizeof(pvpbuf), NULL, 178 MimeTokenTab, false)) != NULL && | 156 (pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL, 157 MimeTokenTab)) != NULL && |
179 pvp[0] != NULL) 180 { 181 if (tTd(43, 40)) 182 { 183 for (i = 0; pvp[i] != NULL; i++) | 158 pvp[0] != NULL) 159 { 160 if (tTd(43, 40)) 161 { 162 for (i = 0; pvp[i] != NULL; i++) |
184 sm_dprintf("pvp[%d] = \"%s\"\n", i, pvp[i]); | 163 printf("pvp[%d] = \"%s\"\n", i, pvp[i]); |
185 } 186 type = *pvp++; 187 if (*pvp != NULL && strcmp(*pvp, "/") == 0 && 188 *++pvp != NULL) 189 { 190 subtype = *pvp++; 191 } 192 193 /* break out parameters */ 194 while (*pvp != NULL && argc < MAXMIMEARGS) 195 { 196 /* skip to semicolon separator */ 197 while (*pvp != NULL && strcmp(*pvp, ";") != 0) 198 pvp++; 199 if (*pvp++ == NULL || *pvp == NULL) 200 break; 201 | 164 } 165 type = *pvp++; 166 if (*pvp != NULL && strcmp(*pvp, "/") == 0 && 167 *++pvp != NULL) 168 { 169 subtype = *pvp++; 170 } 171 172 /* break out parameters */ 173 while (*pvp != NULL && argc < MAXMIMEARGS) 174 { 175 /* skip to semicolon separator */ 176 while (*pvp != NULL && strcmp(*pvp, ";") != 0) 177 pvp++; 178 if (*pvp++ == NULL || *pvp == NULL) 179 break; 180 |
202 /* complain about empty values */ 203 if (strcmp(*pvp, ";") == 0) 204 { 205 usrerr("mime8to7: Empty parameter in Content-Type header"); 206 207 /* avoid bounce loops */ 208 e->e_flags |= EF_DONT_MIME; 209 continue; 210 } 211 | |
212 /* extract field name */ | 181 /* extract field name */ |
213 argv[argc].a_field = *pvp++; | 182 argv[argc].field = *pvp++; |
214 215 /* see if there is a value */ 216 if (*pvp != NULL && strcmp(*pvp, "=") == 0 && 217 (*++pvp == NULL || strcmp(*pvp, ";") != 0)) 218 { | 183 184 /* see if there is a value */ 185 if (*pvp != NULL && strcmp(*pvp, "=") == 0 && 186 (*++pvp == NULL || strcmp(*pvp, ";") != 0)) 187 { |
219 argv[argc].a_value = *pvp; | 188 argv[argc].value = *pvp; |
220 argc++; 221 } 222 } 223 } 224 225 /* check for disaster cases */ 226 if (type == NULL) 227 type = "-none-"; 228 if (subtype == NULL) 229 subtype = "-none-"; 230 | 189 argc++; 190 } 191 } 192 } 193 194 /* check for disaster cases */ 195 if (type == NULL) 196 type = "-none-"; 197 if (subtype == NULL) 198 subtype = "-none-"; 199 |
231 /* don't propagate some flags more than one level into the message */ | 200 /* don't propogate some flags more than one level into the message */ |
232 flags &= ~M87F_DIGEST; 233 234 /* 235 ** Check for cases that can not be encoded. 236 ** 237 ** For example, you can't encode certain kinds of types 238 ** or already-encoded messages. If we find this case, 239 ** just copy it through. 240 */ 241 | 201 flags &= ~M87F_DIGEST; 202 203 /* 204 ** Check for cases that can not be encoded. 205 ** 206 ** For example, you can't encode certain kinds of types 207 ** or already-encoded messages. If we find this case, 208 ** just copy it through. 209 */ 210 |
242 (void) sm_snprintf(buf, sizeof(buf), "%.100s/%.100s", type, subtype); | 211 snprintf(buf, sizeof buf, "%.100s/%.100s", type, subtype); |
243 if (wordinclass(buf, 'n') || (cte != NULL && !wordinclass(cte, 'e'))) 244 flags |= M87F_NO8BIT; 245 | 212 if (wordinclass(buf, 'n') || (cte != NULL && !wordinclass(cte, 'e'))) 213 flags |= M87F_NO8BIT; 214 |
246# ifdef USE_B_CLASS | 215#ifdef USE_B_CLASS |
247 if (wordinclass(buf, 'b') || wordinclass(type, 'b')) | 216 if (wordinclass(buf, 'b') || wordinclass(type, 'b')) |
248 MapNLtoCRLF = false; 249# endif /* USE_B_CLASS */ | 217 MapNLtoCRLF = FALSE; 218#endif |
250 if (wordinclass(buf, 'q') || wordinclass(type, 'q')) | 219 if (wordinclass(buf, 'q') || wordinclass(type, 'q')) |
251 use_qp = true; | 220 use_qp = TRUE; |
252 253 /* 254 ** Multipart requires special processing. 255 ** 256 ** Do a recursive descent into the message. 257 */ 258 | 221 222 /* 223 ** Multipart requires special processing. 224 ** 225 ** Do a recursive descent into the message. 226 */ 227 |
259 if (sm_strcasecmp(type, "multipart") == 0 && 260 (!bitset(M87F_NO8BIT, flags) || bitset(M87F_NO8TO7, flags)) && 261 !bitset(EF_TOODEEP, e->e_flags) 262 ) | 228 if (strcasecmp(type, "multipart") == 0 && !bitset(M87F_NO8BIT, flags)) |
263 { | 229 { |
230 int blen; |
|
264 | 231 |
265 if (sm_strcasecmp(subtype, "digest") == 0) | 232 if (strcasecmp(subtype, "digest") == 0) |
266 flags |= M87F_DIGEST; 267 268 for (i = 0; i < argc; i++) 269 { | 233 flags |= M87F_DIGEST; 234 235 for (i = 0; i < argc; i++) 236 { |
270 if (sm_strcasecmp(argv[i].a_field, "boundary") == 0) | 237 if (strcasecmp(argv[i].field, "boundary") == 0) |
271 break; 272 } | 238 break; 239 } |
273 if (i >= argc || argv[i].a_value == NULL) | 240 if (i >= argc || argv[i].value == NULL) |
274 { | 241 { |
275 usrerr("mime8to7: Content-Type: \"%s\": %s boundary", | 242 syserr("mime8to7: Content-Type: \"%s\": %s boundary", |
276 i >= argc ? "missing" : "bogus", p); 277 p = "---"; 278 279 /* avoid bounce loops */ 280 e->e_flags |= EF_DONT_MIME; 281 } 282 else 283 { | 243 i >= argc ? "missing" : "bogus", p); 244 p = "---"; 245 246 /* avoid bounce loops */ 247 e->e_flags |= EF_DONT_MIME; 248 } 249 else 250 { |
284 p = argv[i].a_value; | 251 p = argv[i].value; |
285 stripquotes(p); 286 } | 252 stripquotes(p); 253 } |
287 if (sm_strlcpy(bbuf, p, sizeof(bbuf)) >= sizeof(bbuf)) | 254 blen = strlen(p); 255 if (blen > sizeof bbuf - 1) |
288 { | 256 { |
289 usrerr("mime8to7: multipart boundary \"%s\" too long", | 257 syserr("mime8to7: multipart boundary \"%s\" too long", |
290 p); | 258 p); |
259 blen = sizeof bbuf - 1; |
|
291 292 /* avoid bounce loops */ 293 e->e_flags |= EF_DONT_MIME; 294 } | 260 261 /* avoid bounce loops */ 262 e->e_flags |= EF_DONT_MIME; 263 } |
295 | 264 strncpy(bbuf, p, blen); 265 bbuf[blen] = '\0'; |
296 if (tTd(43, 1)) | 266 if (tTd(43, 1)) |
297 sm_dprintf("mime8to7: multipart boundary \"%s\"\n", 298 bbuf); | 267 printf("mime8to7: multipart boundary \"%s\"\n", bbuf); |
299 for (i = 0; i < MAXMIMENESTING; i++) | 268 for (i = 0; i < MAXMIMENESTING; i++) |
300 { | |
301 if (boundaries[i] == NULL) 302 break; | 269 if (boundaries[i] == NULL) 270 break; |
303 } | |
304 if (i >= MAXMIMENESTING) 305 { | 271 if (i >= MAXMIMENESTING) 272 { |
306 if (tTd(43, 4)) 307 sm_dprintf("mime8to7: too deep, i=%d\n", i); 308 if (!bitset(EF_TOODEEP, e->e_flags)) 309 usrerr("mime8to7: multipart nesting boundary too deep"); | 273 syserr("mime8to7: multipart nesting boundary too deep"); |
310 311 /* avoid bounce loops */ | 274 275 /* avoid bounce loops */ |
312 e->e_flags |= EF_DONT_MIME|EF_TOODEEP; | 276 e->e_flags |= EF_DONT_MIME; |
313 } 314 else 315 { 316 boundaries[i] = bbuf; 317 boundaries[i + 1] = NULL; 318 } 319 mci->mci_flags |= MCIF_INMIME; 320 321 /* skip the early "comment" prologue */ | 277 } 278 else 279 { 280 boundaries[i] = bbuf; 281 boundaries[i + 1] = NULL; 282 } 283 mci->mci_flags |= MCIF_INMIME; 284 285 /* skip the early "comment" prologue */ |
322 if (!putline("", mci)) 323 goto writeerr; | 286 putline("", mci); |
324 mci->mci_flags &= ~MCIF_INHEADER; | 287 mci->mci_flags &= ~MCIF_INHEADER; |
325 bt = MBT_FINAL; 326 while ((blen = sm_io_fgets(e->e_dfp, SM_TIME_DEFAULT, buf, 327 sizeof(buf))) >= 0) | 288 while (fgets(buf, sizeof buf, e->e_dfp) != NULL) |
328 { 329 bt = mimeboundary(buf, boundaries); 330 if (bt != MBT_NOTSEP) 331 break; | 289 { 290 bt = mimeboundary(buf, boundaries); 291 if (bt != MBT_NOTSEP) 292 break; |
332 if (!putxline(buf, blen, mci, 333 PXLF_MAPFROM|PXLF_STRIP8BIT)) 334 goto writeerr; | 293 putxline(buf, strlen(buf), mci, PXLF_MAPFROM|PXLF_STRIP8BIT); |
335 if (tTd(43, 99)) | 294 if (tTd(43, 99)) |
336 sm_dprintf(" ...%s", buf); | 295 printf(" ...%s", buf); |
337 } | 296 } |
338 if (sm_io_eof(e->e_dfp)) | 297 if (feof(e->e_dfp)) |
339 bt = MBT_FINAL; 340 while (bt != MBT_FINAL) 341 { 342 auto HDR *hdr = NULL; 343 | 298 bt = MBT_FINAL; 299 while (bt != MBT_FINAL) 300 { 301 auto HDR *hdr = NULL; 302 |
344 (void) sm_strlcpyn(buf, sizeof(buf), 2, "--", bbuf); 345 if (!putline(buf, mci)) 346 goto writeerr; | 303 snprintf(buf, sizeof buf, "--%s", bbuf); 304 putline(buf, mci); |
347 if (tTd(43, 35)) | 305 if (tTd(43, 35)) |
348 sm_dprintf(" ...%s\n", buf); 349 collect(e->e_dfp, false, &hdr, e, false); | 306 printf(" ...%s\n", buf); 307 collect(e->e_dfp, FALSE, &hdr, e); |
350 if (tTd(43, 101)) 351 putline("+++after collect", mci); | 308 if (tTd(43, 101)) 309 putline("+++after collect", mci); |
352 if (!putheader(mci, hdr, e, flags)) 353 goto writeerr; | 310 putheader(mci, hdr, e); |
354 if (tTd(43, 101)) 355 putline("+++after putheader", mci); | 311 if (tTd(43, 101)) 312 putline("+++after putheader", mci); |
356 bt = mime8to7(mci, hdr, e, boundaries, flags, 357 level + 1); 358 if (bt == SM_IO_EOF) 359 goto writeerr; | 313 bt = mime8to7(mci, hdr, e, boundaries, flags); |
360 } | 314 } |
361 (void) sm_strlcpyn(buf, sizeof(buf), 3, "--", bbuf, "--"); 362 if (!putline(buf, mci)) 363 goto writeerr; | 315 snprintf(buf, sizeof buf, "--%s--", bbuf); 316 putline(buf, mci); |
364 if (tTd(43, 35)) | 317 if (tTd(43, 35)) |
365 sm_dprintf(" ...%s\n", buf); | 318 printf(" ...%s\n", buf); |
366 boundaries[i] = NULL; 367 mci->mci_flags &= ~MCIF_INMIME; 368 369 /* skip the late "comment" epilogue */ | 319 boundaries[i] = NULL; 320 mci->mci_flags &= ~MCIF_INMIME; 321 322 /* skip the late "comment" epilogue */ |
370 while ((blen = sm_io_fgets(e->e_dfp, SM_TIME_DEFAULT, buf, 371 sizeof(buf))) >= 0) | 323 while (fgets(buf, sizeof buf, e->e_dfp) != NULL) |
372 { 373 bt = mimeboundary(buf, boundaries); 374 if (bt != MBT_NOTSEP) 375 break; | 324 { 325 bt = mimeboundary(buf, boundaries); 326 if (bt != MBT_NOTSEP) 327 break; |
376 if (!putxline(buf, blen, mci, 377 PXLF_MAPFROM|PXLF_STRIP8BIT)) 378 goto writeerr; | 328 putxline(buf, strlen(buf), mci, PXLF_MAPFROM|PXLF_STRIP8BIT); |
379 if (tTd(43, 99)) | 329 if (tTd(43, 99)) |
380 sm_dprintf(" ...%s", buf); | 330 printf(" ...%s", buf); |
381 } | 331 } |
382 if (sm_io_eof(e->e_dfp)) | 332 if (feof(e->e_dfp)) |
383 bt = MBT_FINAL; 384 if (tTd(43, 3)) | 333 bt = MBT_FINAL; 334 if (tTd(43, 3)) |
385 sm_dprintf("\t\t\tmime8to7=>%s (multipart)\n", | 335 printf("\t\t\tmime8to7=>%s (multipart)\n", |
386 MimeBoundaryNames[bt]); 387 return bt; 388 } 389 390 /* 391 ** Message/xxx types -- recurse exactly once. 392 ** 393 ** Class 's' is predefined to have "rfc822" only. 394 */ 395 | 336 MimeBoundaryNames[bt]); 337 return bt; 338 } 339 340 /* 341 ** Message/xxx types -- recurse exactly once. 342 ** 343 ** Class 's' is predefined to have "rfc822" only. 344 */ 345 |
396 if (sm_strcasecmp(type, "message") == 0) | 346 if (strcasecmp(type, "message") == 0) |
397 { | 347 { |
398 if (!wordinclass(subtype, 's') || 399 bitset(EF_TOODEEP, e->e_flags)) | 348 if (!wordinclass(subtype, 's')) |
400 { 401 flags |= M87F_NO8BIT; 402 } 403 else 404 { 405 auto HDR *hdr = NULL; 406 | 349 { 350 flags |= M87F_NO8BIT; 351 } 352 else 353 { 354 auto HDR *hdr = NULL; 355 |
407 if (!putline("", mci)) 408 goto writeerr; | 356 putline("", mci); |
409 410 mci->mci_flags |= MCIF_INMIME; | 357 358 mci->mci_flags |= MCIF_INMIME; |
411 collect(e->e_dfp, false, &hdr, e, false); | 359 collect(e->e_dfp, FALSE, &hdr, e); |
412 if (tTd(43, 101)) 413 putline("+++after collect", mci); | 360 if (tTd(43, 101)) 361 putline("+++after collect", mci); |
414 if (!putheader(mci, hdr, e, flags)) 415 goto writeerr; | 362 putheader(mci, hdr, e); |
416 if (tTd(43, 101)) 417 putline("+++after putheader", mci); | 363 if (tTd(43, 101)) 364 putline("+++after putheader", mci); |
418 if (hvalue("MIME-Version", hdr) == NULL && 419 !bitset(M87F_NO8TO7, flags) && 420 !putline("MIME-Version: 1.0", mci)) 421 goto writeerr; 422 bt = mime8to7(mci, hdr, e, boundaries, flags, 423 level + 1); | 365 if (hvalue("MIME-Version", hdr) == NULL) 366 putline("MIME-Version: 1.0", mci); 367 bt = mime8to7(mci, hdr, e, boundaries, flags); |
424 mci->mci_flags &= ~MCIF_INMIME; 425 return bt; 426 } 427 } 428 429 /* 430 ** Non-compound body type 431 ** 432 ** Compute the ratio of seven to eight bit characters; 433 ** use that as a heuristic to decide how to do the 434 ** encoding. 435 */ 436 437 sectionsize = sectionhighbits = 0; | 368 mci->mci_flags &= ~MCIF_INMIME; 369 return bt; 370 } 371 } 372 373 /* 374 ** Non-compound body type 375 ** 376 ** Compute the ratio of seven to eight bit characters; 377 ** use that as a heuristic to decide how to do the 378 ** encoding. 379 */ 380 381 sectionsize = sectionhighbits = 0; |
438 if (!bitset(M87F_NO8BIT|M87F_NO8TO7, flags)) | 382 if (!bitset(M87F_NO8BIT, flags)) |
439 { 440 /* remember where we were */ | 383 { 384 /* remember where we were */ |
441 offset = sm_io_tell(e->e_dfp, SM_TIME_DEFAULT); | 385 offset = ftell(e->e_dfp); |
442 if (offset == -1) | 386 if (offset == -1) |
443 syserr("mime8to7: cannot sm_io_tell on %cf%s", 444 DATAFL_LETTER, e->e_id); | 387 syserr("mime8to7: cannot ftell on df%s", e->e_id); |
445 446 /* do a scan of this body type to count character types */ | 388 389 /* do a scan of this body type to count character types */ |
447 while ((blen = sm_io_fgets(e->e_dfp, SM_TIME_DEFAULT, buf, 448 sizeof(buf))) >= 0) | 390 while (fgets(buf, sizeof buf, e->e_dfp) != NULL) |
449 { 450 if (mimeboundary(buf, boundaries) != MBT_NOTSEP) 451 break; | 391 { 392 if (mimeboundary(buf, boundaries) != MBT_NOTSEP) 393 break; |
452 for (i = 0; i < blen; i++) | 394 for (p = buf; *p != '\0'; p++) |
453 { 454 /* count bytes with the high bit set */ 455 sectionsize++; | 395 { 396 /* count bytes with the high bit set */ 397 sectionsize++; |
456 if (bitset(0200, buf[i])) | 398 if (bitset(0200, *p)) |
457 sectionhighbits++; 458 } 459 460 /* 461 ** Heuristic: if 1/4 of the first 4K bytes are 8-bit, 462 ** assume base64. This heuristic avoids double-reading 463 ** large graphics or video files. 464 */ 465 466 if (sectionsize >= 4096 && 467 sectionhighbits > sectionsize / 4) 468 break; 469 } 470 471 /* return to the original offset for processing */ 472 /* XXX use relative seeks to handle >31 bit file sizes? */ | 399 sectionhighbits++; 400 } 401 402 /* 403 ** Heuristic: if 1/4 of the first 4K bytes are 8-bit, 404 ** assume base64. This heuristic avoids double-reading 405 ** large graphics or video files. 406 */ 407 408 if (sectionsize >= 4096 && 409 sectionhighbits > sectionsize / 4) 410 break; 411 } 412 413 /* return to the original offset for processing */ 414 /* XXX use relative seeks to handle >31 bit file sizes? */ |
473 if (sm_io_seek(e->e_dfp, SM_TIME_DEFAULT, offset, SEEK_SET) < 0) 474 syserr("mime8to7: cannot sm_io_fseek on %cf%s", 475 DATAFL_LETTER, e->e_id); | 415 if (fseek(e->e_dfp, offset, SEEK_SET) < 0) 416 syserr("mime8to7: cannot fseek on df%s", e->e_id); |
476 else | 417 else |
477 sm_io_clearerr(e->e_dfp); | 418 clearerr(e->e_dfp); |
478 } 479 480 /* 481 ** Heuristically determine encoding method. 482 ** If more than 1/8 of the total characters have the 483 ** eighth bit set, use base64; else use quoted-printable. 484 ** However, only encode binary encoded data as base64, 485 ** since otherwise the NL=>CRLF mapping will be a problem. 486 */ 487 488 if (tTd(43, 8)) 489 { | 419 } 420 421 /* 422 ** Heuristically determine encoding method. 423 ** If more than 1/8 of the total characters have the 424 ** eighth bit set, use base64; else use quoted-printable. 425 ** However, only encode binary encoded data as base64, 426 ** since otherwise the NL=>CRLF mapping will be a problem. 427 */ 428 429 if (tTd(43, 8)) 430 { |
490 sm_dprintf("mime8to7: %ld high bit(s) in %ld byte(s), cte=%s, type=%s/%s\n", | 431 printf("mime8to7: %ld high bit(s) in %ld byte(s), cte=%s, type=%s/%s\n", |
491 (long) sectionhighbits, (long) sectionsize, 492 cte == NULL ? "[none]" : cte, 493 type == NULL ? "[none]" : type, 494 subtype == NULL ? "[none]" : subtype); 495 } | 432 (long) sectionhighbits, (long) sectionsize, 433 cte == NULL ? "[none]" : cte, 434 type == NULL ? "[none]" : type, 435 subtype == NULL ? "[none]" : subtype); 436 } |
496 if (cte != NULL && sm_strcasecmp(cte, "binary") == 0) | 437 if (cte != NULL && strcasecmp(cte, "binary") == 0) |
497 sectionsize = sectionhighbits; 498 linelen = 0; 499 bp = buf; 500 if (sectionhighbits == 0) 501 { 502 /* no encoding necessary */ | 438 sectionsize = sectionhighbits; 439 linelen = 0; 440 bp = buf; 441 if (sectionhighbits == 0) 442 { 443 /* no encoding necessary */ |
503 if (cte != NULL && 504 bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, 505 mci->mci_flags) && 506 !bitset(M87F_NO8TO7, flags)) | 444 if (cte != NULL) |
507 { | 445 { |
508 /* 509 ** Skip _unless_ in MIME mode and potentially 510 ** converting from 8 bit to 7 bit MIME. See 511 ** putheader() for the counterpart where the 512 ** CTE header is skipped in the opposite 513 ** situation. 514 */ 515 516 (void) sm_snprintf(buf, sizeof(buf), | 446 snprintf(buf, sizeof buf, |
517 "Content-Transfer-Encoding: %.200s", cte); | 447 "Content-Transfer-Encoding: %.200s", cte); |
518 if (!putline(buf, mci)) 519 goto writeerr; | 448 putline(buf, mci); |
520 if (tTd(43, 36)) | 449 if (tTd(43, 36)) |
521 sm_dprintf(" ...%s\n", buf); | 450 printf(" ...%s\n", buf); |
522 } | 451 } |
523 if (!putline("", mci)) 524 goto writeerr; | 452 putline("", mci); |
525 mci->mci_flags &= ~MCIF_INHEADER; | 453 mci->mci_flags &= ~MCIF_INHEADER; |
526 while ((blen = sm_io_fgets(e->e_dfp, SM_TIME_DEFAULT, buf, 527 sizeof(buf))) >= 0) | 454 while (fgets(buf, sizeof buf, e->e_dfp) != NULL) |
528 { | 455 { |
529 if (!bitset(MCIF_INLONGLINE, mci->mci_flags)) 530 { 531 bt = mimeboundary(buf, boundaries); 532 if (bt != MBT_NOTSEP) 533 break; 534 } 535 if (!putxline(buf, blen, mci, 536 PXLF_MAPFROM|PXLF_NOADDEOL)) 537 goto writeerr; | 456 bt = mimeboundary(buf, boundaries); 457 if (bt != MBT_NOTSEP) 458 break; 459 putline(buf, mci); |
538 } | 460 } |
539 if (sm_io_eof(e->e_dfp)) | 461 if (feof(e->e_dfp)) |
540 bt = MBT_FINAL; 541 } 542 else if (!MapNLtoCRLF || 543 (sectionsize / 8 < sectionhighbits && !use_qp)) 544 { 545 /* use base64 encoding */ 546 int c1, c2; 547 548 if (tTd(43, 36)) | 462 bt = MBT_FINAL; 463 } 464 else if (!MapNLtoCRLF || 465 (sectionsize / 8 < sectionhighbits && !use_qp)) 466 { 467 /* use base64 encoding */ 468 int c1, c2; 469 470 if (tTd(43, 36)) |
549 sm_dprintf(" ...Content-Transfer-Encoding: base64\n"); 550 if (!putline("Content-Transfer-Encoding: base64", mci)) 551 goto writeerr; 552 (void) sm_snprintf(buf, sizeof(buf), | 471 printf(" ...Content-Transfer-Encoding: base64\n"); 472 putline("Content-Transfer-Encoding: base64", mci); 473 snprintf(buf, sizeof buf, |
553 "X-MIME-Autoconverted: from 8bit to base64 by %s id %s", 554 MyHostName, e->e_id); | 474 "X-MIME-Autoconverted: from 8bit to base64 by %s id %s", 475 MyHostName, e->e_id); |
555 if (!putline(buf, mci) || !putline("", mci)) 556 goto writeerr; | 476 putline(buf, mci); 477 putline("", mci); |
557 mci->mci_flags &= ~MCIF_INHEADER; | 478 mci->mci_flags &= ~MCIF_INHEADER; |
558 while ((c1 = mime_getchar_crlf(e->e_dfp, boundaries, &bt)) != 559 SM_IO_EOF) | 479 while ((c1 = mime_getchar_crlf(e->e_dfp, boundaries, &bt)) != EOF) |
560 { 561 if (linelen > 71) 562 { 563 *bp = '\0'; | 480 { 481 if (linelen > 71) 482 { 483 *bp = '\0'; |
564 if (!putline(buf, mci)) 565 goto writeerr; | 484 putline(buf, mci); |
566 linelen = 0; 567 bp = buf; 568 } 569 linelen += 4; 570 *bp++ = Base64Code[(c1 >> 2)]; 571 c1 = (c1 & 0x03) << 4; 572 c2 = mime_getchar_crlf(e->e_dfp, boundaries, &bt); | 485 linelen = 0; 486 bp = buf; 487 } 488 linelen += 4; 489 *bp++ = Base64Code[(c1 >> 2)]; 490 c1 = (c1 & 0x03) << 4; 491 c2 = mime_getchar_crlf(e->e_dfp, boundaries, &bt); |
573 if (c2 == SM_IO_EOF) | 492 if (c2 == EOF) |
574 { 575 *bp++ = Base64Code[c1]; 576 *bp++ = '='; 577 *bp++ = '='; 578 break; 579 } 580 c1 |= (c2 >> 4) & 0x0f; 581 *bp++ = Base64Code[c1]; 582 c1 = (c2 & 0x0f) << 2; 583 c2 = mime_getchar_crlf(e->e_dfp, boundaries, &bt); | 493 { 494 *bp++ = Base64Code[c1]; 495 *bp++ = '='; 496 *bp++ = '='; 497 break; 498 } 499 c1 |= (c2 >> 4) & 0x0f; 500 *bp++ = Base64Code[c1]; 501 c1 = (c2 & 0x0f) << 2; 502 c2 = mime_getchar_crlf(e->e_dfp, boundaries, &bt); |
584 if (c2 == SM_IO_EOF) | 503 if (c2 == EOF) |
585 { 586 *bp++ = Base64Code[c1]; 587 *bp++ = '='; 588 break; 589 } 590 c1 |= (c2 >> 6) & 0x03; 591 *bp++ = Base64Code[c1]; 592 *bp++ = Base64Code[c2 & 0x3f]; 593 } 594 *bp = '\0'; | 504 { 505 *bp++ = Base64Code[c1]; 506 *bp++ = '='; 507 break; 508 } 509 c1 |= (c2 >> 6) & 0x03; 510 *bp++ = Base64Code[c1]; 511 *bp++ = Base64Code[c2 & 0x3f]; 512 } 513 *bp = '\0'; |
595 if (!putline(buf, mci)) 596 goto writeerr; | 514 putline(buf, mci); |
597 } 598 else 599 { 600 /* use quoted-printable encoding */ 601 int c1, c2; 602 int fromstate; | 515 } 516 else 517 { 518 /* use quoted-printable encoding */ 519 int c1, c2; 520 int fromstate; |
603 BITMAP256 badchars; | 521 BITMAP badchars; |
604 605 /* set up map of characters that must be mapped */ 606 clrbitmap(badchars); 607 for (c1 = 0x00; c1 < 0x20; c1++) 608 setbitn(c1, badchars); 609 clrbitn('\t', badchars); 610 for (c1 = 0x7f; c1 < 0x100; c1++) 611 setbitn(c1, badchars); 612 setbitn('=', badchars); 613 if (bitnset(M_EBCDIC, mci->mci_mailer->m_flags)) 614 for (p = "!\"#$@[\\]^`{|}~"; *p != '\0'; p++) 615 setbitn(*p, badchars); 616 617 if (tTd(43, 36)) | 522 523 /* set up map of characters that must be mapped */ 524 clrbitmap(badchars); 525 for (c1 = 0x00; c1 < 0x20; c1++) 526 setbitn(c1, badchars); 527 clrbitn('\t', badchars); 528 for (c1 = 0x7f; c1 < 0x100; c1++) 529 setbitn(c1, badchars); 530 setbitn('=', badchars); 531 if (bitnset(M_EBCDIC, mci->mci_mailer->m_flags)) 532 for (p = "!\"#$@[\\]^`{|}~"; *p != '\0'; p++) 533 setbitn(*p, badchars); 534 535 if (tTd(43, 36)) |
618 sm_dprintf(" ...Content-Transfer-Encoding: quoted-printable\n"); 619 if (!putline("Content-Transfer-Encoding: quoted-printable", 620 mci)) 621 goto writeerr; 622 (void) sm_snprintf(buf, sizeof(buf), | 536 printf(" ...Content-Transfer-Encoding: quoted-printable\n"); 537 putline("Content-Transfer-Encoding: quoted-printable", mci); 538 snprintf(buf, sizeof buf, |
623 "X-MIME-Autoconverted: from 8bit to quoted-printable by %s id %s", 624 MyHostName, e->e_id); | 539 "X-MIME-Autoconverted: from 8bit to quoted-printable by %s id %s", 540 MyHostName, e->e_id); |
625 if (!putline(buf, mci) || !putline("", mci)) 626 goto writeerr; | 541 putline(buf, mci); 542 putline("", mci); |
627 mci->mci_flags &= ~MCIF_INHEADER; 628 fromstate = 0; 629 c2 = '\n'; | 543 mci->mci_flags &= ~MCIF_INHEADER; 544 fromstate = 0; 545 c2 = '\n'; |
630 while ((c1 = mime_getchar(e->e_dfp, boundaries, &bt)) != 631 SM_IO_EOF) | 546 while ((c1 = mime_getchar(e->e_dfp, boundaries, &bt)) != EOF) |
632 { 633 if (c1 == '\n') 634 { 635 if (c2 == ' ' || c2 == '\t') 636 { 637 *bp++ = '='; 638 *bp++ = Base16Code[(c2 >> 4) & 0x0f]; 639 *bp++ = Base16Code[c2 & 0x0f]; 640 } 641 if (buf[0] == '.' && bp == &buf[1]) 642 { 643 buf[0] = '='; 644 *bp++ = Base16Code[('.' >> 4) & 0x0f]; 645 *bp++ = Base16Code['.' & 0x0f]; 646 } 647 *bp = '\0'; | 547 { 548 if (c1 == '\n') 549 { 550 if (c2 == ' ' || c2 == '\t') 551 { 552 *bp++ = '='; 553 *bp++ = Base16Code[(c2 >> 4) & 0x0f]; 554 *bp++ = Base16Code[c2 & 0x0f]; 555 } 556 if (buf[0] == '.' && bp == &buf[1]) 557 { 558 buf[0] = '='; 559 *bp++ = Base16Code[('.' >> 4) & 0x0f]; 560 *bp++ = Base16Code['.' & 0x0f]; 561 } 562 *bp = '\0'; |
648 if (!putline(buf, mci)) 649 goto writeerr; | 563 putline(buf, mci); |
650 linelen = fromstate = 0; 651 bp = buf; 652 c2 = c1; 653 continue; 654 } 655 if (c2 == ' ' && linelen == 4 && fromstate == 4 && 656 bitnset(M_ESCFROM, mci->mci_mailer->m_flags)) 657 { --- 12 unchanged lines hidden (view full) --- 670 (linelen > 73 && c2 == '.'))) 671 { 672 if (linelen > 73 && c2 == '.') 673 bp--; 674 else 675 c2 = '\n'; 676 *bp++ = '='; 677 *bp = '\0'; | 564 linelen = fromstate = 0; 565 bp = buf; 566 c2 = c1; 567 continue; 568 } 569 if (c2 == ' ' && linelen == 4 && fromstate == 4 && 570 bitnset(M_ESCFROM, mci->mci_mailer->m_flags)) 571 { --- 12 unchanged lines hidden (view full) --- 584 (linelen > 73 && c2 == '.'))) 585 { 586 if (linelen > 73 && c2 == '.') 587 bp--; 588 else 589 c2 = '\n'; 590 *bp++ = '='; 591 *bp = '\0'; |
678 if (!putline(buf, mci)) 679 goto writeerr; | 592 putline(buf, mci); |
680 linelen = fromstate = 0; 681 bp = buf; 682 if (c2 == '.') 683 { 684 *bp++ = '.'; 685 linelen++; 686 } 687 } | 593 linelen = fromstate = 0; 594 bp = buf; 595 if (c2 == '.') 596 { 597 *bp++ = '.'; 598 linelen++; 599 } 600 } |
688 if (bitnset(bitidx(c1), badchars)) | 601 if (bitnset(c1 & 0xff, badchars)) |
689 { 690 *bp++ = '='; 691 *bp++ = Base16Code[(c1 >> 4) & 0x0f]; 692 *bp++ = Base16Code[c1 & 0x0f]; 693 linelen += 3; 694 } 695 else if (c1 != ' ' && c1 != '\t') 696 { --- 12 unchanged lines hidden (view full) --- 709 *bp++ = Base16Code[(c2 >> 4) & 0x0f]; 710 *bp++ = Base16Code[c2 & 0x0f]; 711 linelen += 3; 712 } 713 714 if (linelen > 0 || boundaries[0] != NULL) 715 { 716 *bp = '\0'; | 602 { 603 *bp++ = '='; 604 *bp++ = Base16Code[(c1 >> 4) & 0x0f]; 605 *bp++ = Base16Code[c1 & 0x0f]; 606 linelen += 3; 607 } 608 else if (c1 != ' ' && c1 != '\t') 609 { --- 12 unchanged lines hidden (view full) --- 622 *bp++ = Base16Code[(c2 >> 4) & 0x0f]; 623 *bp++ = Base16Code[c2 & 0x0f]; 624 linelen += 3; 625 } 626 627 if (linelen > 0 || boundaries[0] != NULL) 628 { 629 *bp = '\0'; |
717 if (!putline(buf, mci)) 718 goto writeerr; | 630 putline(buf, mci); |
719 } 720 721 } 722 if (tTd(43, 3)) | 631 } 632 633 } 634 if (tTd(43, 3)) |
723 sm_dprintf("\t\t\tmime8to7=>%s (basic)\n", MimeBoundaryNames[bt]); | 635 printf("\t\t\tmime8to7=>%s (basic)\n", MimeBoundaryNames[bt]); |
724 return bt; | 636 return bt; |
725 726 writeerr: 727 return SM_IO_EOF; | |
728} | 637} |
729/* | 638/* |
730** MIME_GETCHAR -- get a character for MIME processing 731** | 639** MIME_GETCHAR -- get a character for MIME processing 640** |
732** Treats boundaries as SM_IO_EOF. | 641** Treats boundaries as EOF. |
733** 734** Parameters: 735** fp -- the input file. 736** boundaries -- the current MIME boundaries. | 642** 643** Parameters: 644** fp -- the input file. 645** boundaries -- the current MIME boundaries. |
737** btp -- if the return value is SM_IO_EOF, *btp is set to | 646** btp -- if the return value is EOF, *btp is set to |
738** the type of the boundary. 739** 740** Returns: 741** The next character in the input stream. 742*/ 743 | 647** the type of the boundary. 648** 649** Returns: 650** The next character in the input stream. 651*/ 652 |
744static int | 653int |
745mime_getchar(fp, boundaries, btp) | 654mime_getchar(fp, boundaries, btp) |
746 register SM_FILE_T *fp; | 655 register FILE *fp; |
747 char **boundaries; 748 int *btp; 749{ 750 int c; | 656 char **boundaries; 657 int *btp; 658{ 659 int c; |
751 static unsigned char *bp = NULL; | 660 static u_char *bp = NULL; |
752 static int buflen = 0; | 661 static int buflen = 0; |
753 static bool atbol = true; /* at beginning of line */ 754 static int bt = MBT_SYNTAX; /* boundary type of next SM_IO_EOF */ 755 static unsigned char buf[128]; /* need not be a full line */ 756 int start = 0; /* indicates position of - in buffer */ | 662 static bool atbol = TRUE; /* at beginning of line */ 663 static int bt = MBT_SYNTAX; /* boundary type of next EOF */ 664 static u_char buf[128]; /* need not be a full line */ |
757 | 665 |
758 if (buflen == 1 && *bp == '\n') | 666 if (buflen > 0) |
759 { | 667 { |
760 /* last \n in buffer may be part of next MIME boundary */ 761 c = *bp; 762 } 763 else if (buflen > 0) 764 { | |
765 buflen--; 766 return *bp++; 767 } | 668 buflen--; 669 return *bp++; 670 } |
768 else 769 c = sm_io_getc(fp, SM_TIME_DEFAULT); | |
770 bp = buf; 771 buflen = 0; | 671 bp = buf; 672 buflen = 0; |
673 c = getc(fp); |
|
772 if (c == '\n') 773 { 774 /* might be part of a MIME boundary */ 775 *bp++ = c; | 674 if (c == '\n') 675 { 676 /* might be part of a MIME boundary */ 677 *bp++ = c; |
776 atbol = true; 777 c = sm_io_getc(fp, SM_TIME_DEFAULT); | 678 atbol = TRUE; 679 c = getc(fp); |
778 if (c == '\n') 779 { | 680 if (c == '\n') 681 { |
780 (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c); | 682 ungetc(c, fp); |
781 return c; 782 } | 683 return c; 684 } |
783 start = 1; | |
784 } | 685 } |
785 if (c != SM_IO_EOF) | 686 if (c != EOF) |
786 *bp++ = c; 787 else 788 bt = MBT_FINAL; 789 if (atbol && c == '-') 790 { 791 /* check for a message boundary */ | 687 *bp++ = c; 688 else 689 bt = MBT_FINAL; 690 if (atbol && c == '-') 691 { 692 /* check for a message boundary */ |
792 c = sm_io_getc(fp, SM_TIME_DEFAULT); | 693 c = getc(fp); |
793 if (c != '-') 794 { | 694 if (c != '-') 695 { |
795 if (c != SM_IO_EOF) | 696 if (c != EOF) |
796 *bp++ = c; 797 else 798 bt = MBT_FINAL; 799 buflen = bp - buf - 1; 800 bp = buf; 801 return *bp++; 802 } 803 804 /* got "--", now check for rest of separator */ 805 *bp++ = '-'; | 697 *bp++ = c; 698 else 699 bt = MBT_FINAL; 700 buflen = bp - buf - 1; 701 bp = buf; 702 return *bp++; 703 } 704 705 /* got "--", now check for rest of separator */ 706 *bp++ = '-'; |
806 while (bp < &buf[sizeof(buf) - 2] && 807 (c = sm_io_getc(fp, SM_TIME_DEFAULT)) != SM_IO_EOF && 808 c != '\n') | 707 while (bp < &buf[sizeof buf - 2] && 708 (c = getc(fp)) != EOF && c != '\n') |
809 { 810 *bp++ = c; 811 } | 709 { 710 *bp++ = c; 711 } |
812 *bp = '\0'; /* XXX simply cut off? */ 813 bt = mimeboundary((char *) &buf[start], boundaries); | 712 *bp = '\0'; 713 bt = mimeboundary((char *) &buf[1], boundaries); |
814 switch (bt) 815 { 816 case MBT_FINAL: 817 case MBT_INTERMED: 818 /* we have a message boundary */ 819 buflen = 0; 820 *btp = bt; | 714 switch (bt) 715 { 716 case MBT_FINAL: 717 case MBT_INTERMED: 718 /* we have a message boundary */ 719 buflen = 0; 720 *btp = bt; |
821 return SM_IO_EOF; | 721 return EOF; |
822 } 823 | 722 } 723 |
824 if (bp < &buf[sizeof(buf) - 2] && c != SM_IO_EOF) | 724 atbol = c == '\n'; 725 if (c != EOF) |
825 *bp++ = c; 826 } 827 | 726 *bp++ = c; 727 } 728 |
828 atbol = c == '\n'; | |
829 buflen = bp - buf - 1; 830 if (buflen < 0) 831 { 832 *btp = bt; | 729 buflen = bp - buf - 1; 730 if (buflen < 0) 731 { 732 *btp = bt; |
833 return SM_IO_EOF; | 733 return EOF; |
834 } 835 bp = buf; 836 return *bp++; 837} | 734 } 735 bp = buf; 736 return *bp++; 737} |
838/* | 738/* |
839** MIME_GETCHAR_CRLF -- do mime_getchar, but translate NL => CRLF 840** 841** Parameters: 842** fp -- the input file. 843** boundaries -- the current MIME boundaries. | 739** MIME_GETCHAR_CRLF -- do mime_getchar, but translate NL => CRLF 740** 741** Parameters: 742** fp -- the input file. 743** boundaries -- the current MIME boundaries. |
844** btp -- if the return value is SM_IO_EOF, *btp is set to | 744** btp -- if the return value is EOF, *btp is set to |
845** the type of the boundary. 846** 847** Returns: 848** The next character in the input stream. 849*/ 850 | 745** the type of the boundary. 746** 747** Returns: 748** The next character in the input stream. 749*/ 750 |
851static int | 751int |
852mime_getchar_crlf(fp, boundaries, btp) | 752mime_getchar_crlf(fp, boundaries, btp) |
853 register SM_FILE_T *fp; | 753 register FILE *fp; |
854 char **boundaries; 855 int *btp; 856{ | 754 char **boundaries; 755 int *btp; 756{ |
857 static bool sendlf = false; | 757 static bool sendlf = FALSE; |
858 int c; 859 860 if (sendlf) 861 { | 758 int c; 759 760 if (sendlf) 761 { |
862 sendlf = false; | 762 sendlf = FALSE; |
863 return '\n'; 864 } 865 c = mime_getchar(fp, boundaries, btp); 866 if (c == '\n' && MapNLtoCRLF) 867 { | 763 return '\n'; 764 } 765 c = mime_getchar(fp, boundaries, btp); 766 if (c == '\n' && MapNLtoCRLF) 767 { |
868 sendlf = true; | 768 sendlf = TRUE; |
869 return '\r'; 870 } 871 return c; 872} | 769 return '\r'; 770 } 771 return c; 772} |
873/* | 773/* |
874** MIMEBOUNDARY -- determine if this line is a MIME boundary & its type 875** 876** Parameters: 877** line -- the input line. 878** boundaries -- the set of currently pending boundaries. 879** 880** Returns: 881** MBT_NOTSEP -- if this is not a separator line 882** MBT_INTERMED -- if this is an intermediate separator 883** MBT_FINAL -- if this is a final boundary 884** MBT_SYNTAX -- if this is a boundary for the wrong 885** enclosure -- i.e., a syntax error. 886*/ 887 | 774** MIMEBOUNDARY -- determine if this line is a MIME boundary & its type 775** 776** Parameters: 777** line -- the input line. 778** boundaries -- the set of currently pending boundaries. 779** 780** Returns: 781** MBT_NOTSEP -- if this is not a separator line 782** MBT_INTERMED -- if this is an intermediate separator 783** MBT_FINAL -- if this is a final boundary 784** MBT_SYNTAX -- if this is a boundary for the wrong 785** enclosure -- i.e., a syntax error. 786*/ 787 |
888static int | 788int |
889mimeboundary(line, boundaries) 890 register char *line; 891 char **boundaries; 892{ 893 int type = MBT_NOTSEP; 894 int i; 895 int savec; | 789mimeboundary(line, boundaries) 790 register char *line; 791 char **boundaries; 792{ 793 int type = MBT_NOTSEP; 794 int i; 795 int savec; |
796 extern int isboundary __P((char *, char **)); |
|
896 897 if (line[0] != '-' || line[1] != '-' || boundaries == NULL) 898 return MBT_NOTSEP; 899 i = strlen(line); | 797 798 if (line[0] != '-' || line[1] != '-' || boundaries == NULL) 799 return MBT_NOTSEP; 800 i = strlen(line); |
900 if (i > 0 && line[i - 1] == '\n') | 801 if (line[i - 1] == '\n') |
901 i--; 902 903 /* strip off trailing whitespace */ | 802 i--; 803 804 /* strip off trailing whitespace */ |
904 while (i > 0 && (line[i - 1] == ' ' || line[i - 1] == '\t' 905#if _FFR_MIME_CR_OK 906 || line[i - 1] == '\r' 907#endif /* _FFR_MIME_CR_OK */ 908 )) | 805 while (line[i - 1] == ' ' || line[i - 1] == '\t') |
909 i--; 910 savec = line[i]; 911 line[i] = '\0'; 912 913 if (tTd(43, 5)) | 806 i--; 807 savec = line[i]; 808 line[i] = '\0'; 809 810 if (tTd(43, 5)) |
914 sm_dprintf("mimeboundary: line=\"%s\"... ", line); | 811 printf("mimeboundary: line=\"%s\"... ", line); |
915 916 /* check for this as an intermediate boundary */ 917 if (isboundary(&line[2], boundaries) >= 0) 918 type = MBT_INTERMED; 919 else if (i > 2 && strncmp(&line[i - 2], "--", 2) == 0) 920 { 921 /* check for a final boundary */ 922 line[i - 2] = '\0'; 923 if (isboundary(&line[2], boundaries) >= 0) 924 type = MBT_FINAL; 925 line[i - 2] = '-'; 926 } 927 928 line[i] = savec; 929 if (tTd(43, 5)) | 812 813 /* check for this as an intermediate boundary */ 814 if (isboundary(&line[2], boundaries) >= 0) 815 type = MBT_INTERMED; 816 else if (i > 2 && strncmp(&line[i - 2], "--", 2) == 0) 817 { 818 /* check for a final boundary */ 819 line[i - 2] = '\0'; 820 if (isboundary(&line[2], boundaries) >= 0) 821 type = MBT_FINAL; 822 line[i - 2] = '-'; 823 } 824 825 line[i] = savec; 826 if (tTd(43, 5)) |
930 sm_dprintf("%s\n", MimeBoundaryNames[type]); | 827 printf("%s\n", MimeBoundaryNames[type]); |
931 return type; 932} | 828 return type; 829} |
933/* | 830/* |
934** DEFCHARSET -- return default character set for message 935** 936** The first choice for character set is for the mailer 937** corresponding to the envelope sender. If neither that 938** nor the global configuration file has a default character 939** set defined, return "unknown-8bit" as recommended by 940** RFC 1428 section 3. 941** --- 10 unchanged lines hidden (view full) --- 952{ 953 if (e != NULL && e->e_from.q_mailer != NULL && 954 e->e_from.q_mailer->m_defcharset != NULL) 955 return e->e_from.q_mailer->m_defcharset; 956 if (DefaultCharSet != NULL) 957 return DefaultCharSet; 958 return "unknown-8bit"; 959} | 831** DEFCHARSET -- return default character set for message 832** 833** The first choice for character set is for the mailer 834** corresponding to the envelope sender. If neither that 835** nor the global configuration file has a default character 836** set defined, return "unknown-8bit" as recommended by 837** RFC 1428 section 3. 838** --- 10 unchanged lines hidden (view full) --- 849{ 850 if (e != NULL && e->e_from.q_mailer != NULL && 851 e->e_from.q_mailer->m_defcharset != NULL) 852 return e->e_from.q_mailer->m_defcharset; 853 if (DefaultCharSet != NULL) 854 return DefaultCharSet; 855 return "unknown-8bit"; 856} |
960/* | 857/* |
961** ISBOUNDARY -- is a given string a currently valid boundary? 962** 963** Parameters: 964** line -- the current input line. 965** boundaries -- the list of valid boundaries. 966** 967** Returns: 968** The index number in boundaries if the line is found. 969** -1 -- otherwise. 970** 971*/ 972 | 858** ISBOUNDARY -- is a given string a currently valid boundary? 859** 860** Parameters: 861** line -- the current input line. 862** boundaries -- the list of valid boundaries. 863** 864** Returns: 865** The index number in boundaries if the line is found. 866** -1 -- otherwise. 867** 868*/ 869 |
973static int | 870int |
974isboundary(line, boundaries) 975 char *line; 976 char **boundaries; 977{ 978 register int i; 979 | 871isboundary(line, boundaries) 872 char *line; 873 char **boundaries; 874{ 875 register int i; 876 |
980 for (i = 0; i <= MAXMIMENESTING && boundaries[i] != NULL; i++) | 877 for (i = 0; boundaries[i] != NULL; i++) |
981 { 982 if (strcmp(line, boundaries[i]) == 0) 983 return i; 984 } 985 return -1; 986} | 878 { 879 if (strcmp(line, boundaries[i]) == 0) 880 return i; 881 } 882 return -1; 883} |
987#endif /* MIME8TO7 */ | |
988 | 884 |
885#endif /* MIME8TO7 */ 886 |
|
989#if MIME7TO8 | 887#if MIME7TO8 |
990static int mime_fromqp __P((unsigned char *, unsigned char **, int)); | |
991 992/* 993** MIME7TO8 -- output 7 bit encoded MIME body in 8 bit format 994** 995** This is a hack. Supports translating the two 7-bit body-encodings 996** (quoted-printable and base64) to 8-bit coded bodies. 997** 998** There is not much point in supporting multipart here, as the UA 999** will be able to deal with encoded MIME bodies if it can parse MIME 1000** multipart messages. 1001** | 888 889/* 890** MIME7TO8 -- output 7 bit encoded MIME body in 8 bit format 891** 892** This is a hack. Supports translating the two 7-bit body-encodings 893** (quoted-printable and base64) to 8-bit coded bodies. 894** 895** There is not much point in supporting multipart here, as the UA 896** will be able to deal with encoded MIME bodies if it can parse MIME 897** multipart messages. 898** |
1002** Note also that we won't be called unless it is a text/plain MIME | 899** Note also that we wont be called unless it is a text/plain MIME |
1003** message, encoded base64 or QP and mailer flag '9' has been defined 1004** on mailer. 1005** 1006** Contributed by Marius Olaffson <marius@rhi.hi.is>. 1007** 1008** Parameters: 1009** mci -- mailer connection information. 1010** header -- the header for this body part. 1011** e -- envelope. 1012** 1013** Returns: | 900** message, encoded base64 or QP and mailer flag '9' has been defined 901** on mailer. 902** 903** Contributed by Marius Olaffson <marius@rhi.hi.is>. 904** 905** Parameters: 906** mci -- mailer connection information. 907** header -- the header for this body part. 908** e -- envelope. 909** 910** Returns: |
1014** true iff body was written successfully | 911** none. |
1015*/ 1016 | 912*/ 913 |
914extern int mime_fromqp __P((u_char *, u_char **, int, int)); 915 |
|
1017static char index_64[128] = 1018{ 1019 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, 1020 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, 1021 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, 1022 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1, 1023 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, 1024 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, 1025 -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, 1026 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 1027}; 1028 | 916static char index_64[128] = 917{ 918 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, 919 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, 920 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, 921 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1, 922 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, 923 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, 924 -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, 925 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 926}; 927 |
1029# define CHAR64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)]) | 928#define CHAR64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)]) |
1030 | 929 |
1031bool | 930 931void |
1032mime7to8(mci, header, e) 1033 register MCI *mci; 1034 HDR *header; 1035 register ENVELOPE *e; 1036{ | 932mime7to8(mci, header, e) 933 register MCI *mci; 934 HDR *header; 935 register ENVELOPE *e; 936{ |
1037 int pxflags, blen; | |
1038 register char *p; 1039 char *cte; 1040 char **pvp; | 937 register char *p; 938 char *cte; 939 char **pvp; |
1041 unsigned char *fbufp; | 940 u_char *fbufp; |
1042 char buf[MAXLINE]; | 941 char buf[MAXLINE]; |
1043 unsigned char fbuf[MAXLINE + 1]; | 942 u_char fbuf[MAXLINE + 1]; |
1044 char pvpbuf[MAXLINE]; | 943 char pvpbuf[MAXLINE]; |
1045 extern unsigned char MimeTokenTab[256]; | 944 extern u_char MimeTokenTab[256]; |
1046 1047 p = hvalue("Content-Transfer-Encoding", header); 1048 if (p == NULL || | 945 946 p = hvalue("Content-Transfer-Encoding", header); 947 if (p == NULL || |
1049 (pvp = prescan(p, '\0', pvpbuf, sizeof(pvpbuf), NULL, 1050 MimeTokenTab, false)) == NULL || | 948 (pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL, 949 MimeTokenTab)) == NULL || |
1051 pvp[0] == NULL) 1052 { 1053 /* "can't happen" -- upper level should have caught this */ 1054 syserr("mime7to8: unparsable CTE %s", p == NULL ? "<NULL>" : p); 1055 1056 /* avoid bounce loops */ 1057 e->e_flags |= EF_DONT_MIME; 1058 1059 /* cheap failsafe algorithm -- should work on text/plain */ 1060 if (p != NULL) 1061 { | 950 pvp[0] == NULL) 951 { 952 /* "can't happen" -- upper level should have caught this */ 953 syserr("mime7to8: unparsable CTE %s", p == NULL ? "<NULL>" : p); 954 955 /* avoid bounce loops */ 956 e->e_flags |= EF_DONT_MIME; 957 958 /* cheap failsafe algorithm -- should work on text/plain */ 959 if (p != NULL) 960 { |
1062 (void) sm_snprintf(buf, sizeof(buf), | 961 snprintf(buf, sizeof buf, |
1063 "Content-Transfer-Encoding: %s", p); | 962 "Content-Transfer-Encoding: %s", p); |
1064 if (!putline(buf, mci)) 1065 goto writeerr; | 963 putline(buf, mci); |
1066 } | 964 } |
1067 if (!putline("", mci)) 1068 goto writeerr; | 965 putline("", mci); |
1069 mci->mci_flags &= ~MCIF_INHEADER; | 966 mci->mci_flags &= ~MCIF_INHEADER; |
1070 while ((blen = sm_io_fgets(e->e_dfp, SM_TIME_DEFAULT, buf, 1071 sizeof(buf))) >= 0) 1072 { 1073 if (!putxline(buf, blen, mci, PXLF_MAPFROM)) 1074 goto writeerr; 1075 } 1076 return true; | 967 while (fgets(buf, sizeof buf, e->e_dfp) != NULL) 968 putline(buf, mci); 969 return; |
1077 } | 970 } |
1078 cataddr(pvp, NULL, buf, sizeof(buf), '\0', false); 1079 cte = sm_rpool_strdup_x(e->e_rpool, buf); | 971 cataddr(pvp, NULL, buf, sizeof buf, '\0'); 972 cte = newstr(buf); |
1080 1081 mci->mci_flags |= MCIF_INHEADER; | 973 974 mci->mci_flags |= MCIF_INHEADER; |
1082 if (!putline("Content-Transfer-Encoding: 8bit", mci)) 1083 goto writeerr; 1084 (void) sm_snprintf(buf, sizeof(buf), | 975 putline("Content-Transfer-Encoding: 8bit", mci); 976 snprintf(buf, sizeof buf, |
1085 "X-MIME-Autoconverted: from %.200s to 8bit by %s id %s", 1086 cte, MyHostName, e->e_id); | 977 "X-MIME-Autoconverted: from %.200s to 8bit by %s id %s", 978 cte, MyHostName, e->e_id); |
1087 if (!putline(buf, mci) || !putline("", mci)) 1088 goto writeerr; | 979 putline(buf, mci); 980 putline("", mci); |
1089 mci->mci_flags &= ~MCIF_INHEADER; 1090 1091 /* 1092 ** Translate body encoding to 8-bit. Supports two types of 1093 ** encodings; "base64" and "quoted-printable". Assume qp if 1094 ** it is not base64. 1095 */ 1096 | 981 mci->mci_flags &= ~MCIF_INHEADER; 982 983 /* 984 ** Translate body encoding to 8-bit. Supports two types of 985 ** encodings; "base64" and "quoted-printable". Assume qp if 986 ** it is not base64. 987 */ 988 |
1097 pxflags = PXLF_MAPFROM; 1098 if (sm_strcasecmp(cte, "base64") == 0) | 989 if (strcasecmp(cte, "base64") == 0) |
1099 { 1100 int c1, c2, c3, c4; 1101 1102 fbufp = fbuf; | 990 { 991 int c1, c2, c3, c4; 992 993 fbufp = fbuf; |
1103 while ((c1 = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT)) != 1104 SM_IO_EOF) | 994 while ((c1 = fgetc(e->e_dfp)) != EOF) |
1105 { 1106 if (isascii(c1) && isspace(c1)) 1107 continue; 1108 1109 do 1110 { | 995 { 996 if (isascii(c1) && isspace(c1)) 997 continue; 998 999 do 1000 { |
1111 c2 = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT); | 1001 c2 = fgetc(e->e_dfp); |
1112 } while (isascii(c2) && isspace(c2)); | 1002 } while (isascii(c2) && isspace(c2)); |
1113 if (c2 == SM_IO_EOF) | 1003 if (c2 == EOF) |
1114 break; 1115 1116 do 1117 { | 1004 break; 1005 1006 do 1007 { |
1118 c3 = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT); | 1008 c3 = fgetc(e->e_dfp); |
1119 } while (isascii(c3) && isspace(c3)); | 1009 } while (isascii(c3) && isspace(c3)); |
1120 if (c3 == SM_IO_EOF) | 1010 if (c3 == EOF) |
1121 break; 1122 1123 do 1124 { | 1011 break; 1012 1013 do 1014 { |
1125 c4 = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT); | 1015 c4 = fgetc(e->e_dfp); |
1126 } while (isascii(c4) && isspace(c4)); | 1016 } while (isascii(c4) && isspace(c4)); |
1127 if (c4 == SM_IO_EOF) | 1017 if (c4 == EOF) |
1128 break; 1129 1130 if (c1 == '=' || c2 == '=') 1131 continue; 1132 c1 = CHAR64(c1); 1133 c2 = CHAR64(c2); 1134 | 1018 break; 1019 1020 if (c1 == '=' || c2 == '=') 1021 continue; 1022 c1 = CHAR64(c1); 1023 c2 = CHAR64(c2); 1024 |
1135#if MIME7TO8_OLD 1136#define CHK_EOL if (*--fbufp != '\n' || (fbufp > fbuf && *--fbufp != '\r')) \ 1137 ++fbufp; 1138#else /* MIME7TO8_OLD */ 1139#define CHK_EOL if (*--fbufp != '\n' || (fbufp > fbuf && *--fbufp != '\r')) \ 1140 { \ 1141 ++fbufp; \ 1142 pxflags |= PXLF_NOADDEOL; \ 1143 } 1144#endif /* MIME7TO8_OLD */ 1145 1146#define PUTLINE64 \ 1147 do \ 1148 { \ 1149 if (*fbufp++ == '\n' || fbufp >= &fbuf[MAXLINE]) \ 1150 { \ 1151 CHK_EOL; \ 1152 if (!putxline((char *) fbuf, fbufp - fbuf, mci, pxflags)) \ 1153 goto writeerr; \ 1154 pxflags &= ~PXLF_NOADDEOL; \ 1155 fbufp = fbuf; \ 1156 } \ 1157 } while (0) 1158 | |
1159 *fbufp = (c1 << 2) | ((c2 & 0x30) >> 4); | 1025 *fbufp = (c1 << 2) | ((c2 & 0x30) >> 4); |
1160 PUTLINE64; | 1026 if (*fbufp++ == '\n' || fbufp >= &fbuf[MAXLINE]) 1027 { 1028 if (*--fbufp != '\n' || 1029 (fbufp > fbuf && *--fbufp != '\r')) 1030 fbufp++; 1031 putxline((char *) fbuf, fbufp - fbuf, 1032 mci, PXLF_MAPFROM); 1033 fbufp = fbuf; 1034 } |
1161 if (c3 == '=') 1162 continue; 1163 c3 = CHAR64(c3); 1164 *fbufp = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2); | 1035 if (c3 == '=') 1036 continue; 1037 c3 = CHAR64(c3); 1038 *fbufp = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2); |
1165 PUTLINE64; | 1039 if (*fbufp++ == '\n' || fbufp >= &fbuf[MAXLINE]) 1040 { 1041 if (*--fbufp != '\n' || 1042 (fbufp > fbuf && *--fbufp != '\r')) 1043 fbufp++; 1044 putxline((char *) fbuf, fbufp - fbuf, 1045 mci, PXLF_MAPFROM); 1046 fbufp = fbuf; 1047 } |
1166 if (c4 == '=') 1167 continue; 1168 c4 = CHAR64(c4); 1169 *fbufp = ((c3 & 0x03) << 6) | c4; | 1048 if (c4 == '=') 1049 continue; 1050 c4 = CHAR64(c4); 1051 *fbufp = ((c3 & 0x03) << 6) | c4; |
1170 PUTLINE64; | 1052 if (*fbufp++ == '\n' || fbufp >= &fbuf[MAXLINE]) 1053 { 1054 if (*--fbufp != '\n' || 1055 (fbufp > fbuf && *--fbufp != '\r')) 1056 fbufp++; 1057 putxline((char *) fbuf, fbufp - fbuf, 1058 mci, PXLF_MAPFROM); 1059 fbufp = fbuf; 1060 } |
1171 } 1172 } 1173 else 1174 { | 1061 } 1062 } 1063 else 1064 { |
1175 int off; 1176 | |
1177 /* quoted-printable */ | 1065 /* quoted-printable */ |
1178 pxflags |= PXLF_NOADDEOL; | |
1179 fbufp = fbuf; | 1066 fbufp = fbuf; |
1180 while (sm_io_fgets(e->e_dfp, SM_TIME_DEFAULT, buf, 1181 sizeof(buf)) >= 0) | 1067 while (fgets(buf, sizeof buf, e->e_dfp) != NULL) |
1182 { | 1068 { |
1183 off = mime_fromqp((unsigned char *) buf, &fbufp, 1184 &fbuf[MAXLINE] - fbufp); 1185again: 1186 if (off < -1) | 1069 if (mime_fromqp((u_char *) buf, &fbufp, 0, 1070 &fbuf[MAXLINE] - fbufp) == 0) |
1187 continue; 1188 1189 if (fbufp - fbuf > 0) | 1071 continue; 1072 1073 if (fbufp - fbuf > 0) |
1190 { 1191 if (!putxline((char *) fbuf, fbufp - fbuf - 1, 1192 mci, pxflags)) 1193 goto writeerr; 1194 } | 1074 putxline((char *) fbuf, fbufp - fbuf - 1, mci, 1075 PXLF_MAPFROM); |
1195 fbufp = fbuf; | 1076 fbufp = fbuf; |
1196 if (off >= 0 && buf[off] != '\0') 1197 { 1198 off = mime_fromqp((unsigned char *) (buf + off), 1199 &fbufp, 1200 &fbuf[MAXLINE] - fbufp); 1201 goto again; 1202 } | |
1203 } 1204 } 1205 1206 /* force out partial last line */ 1207 if (fbufp > fbuf) 1208 { 1209 *fbufp = '\0'; | 1077 } 1078 } 1079 1080 /* force out partial last line */ 1081 if (fbufp > fbuf) 1082 { 1083 *fbufp = '\0'; |
1210 if (!putxline((char *) fbuf, fbufp - fbuf, mci, pxflags)) 1211 goto writeerr; | 1084 putxline((char *) fbuf, fbufp - fbuf, mci, PXLF_MAPFROM); |
1212 } | 1085 } |
1213 1214 /* 1215 ** The decoded text may end without an EOL. Since this function 1216 ** is only called for text/plain MIME messages, it is safe to 1217 ** add an extra one at the end just in case. This is a hack, 1218 ** but so is auto-converting MIME in the first place. 1219 */ 1220 1221 if (!putline("", mci)) 1222 goto writeerr; 1223 | |
1224 if (tTd(43, 3)) | 1086 if (tTd(43, 3)) |
1225 sm_dprintf("\t\t\tmime7to8 => %s to 8bit done\n", cte); 1226 return true; 1227 1228 writeerr: 1229 return false; | 1087 printf("\t\t\tmime7to8 => %s to 8bit done\n", cte); |
1230} | 1088} |
1231/* | 1089/* |
1232** The following is based on Borenstein's "codes.c" module, with simplifying 1233** changes as we do not deal with multipart, and to do the translation in-core, 1234** with an attempt to prevent overrun of output buffers. 1235** | 1090** The following is based on Borenstein's "codes.c" module, with simplifying 1091** changes as we do not deal with multipart, and to do the translation in-core, 1092** with an attempt to prevent overrun of output buffers. 1093** |
1236** What is needed here are changes to defend this code better against | 1094** What is needed here are changes to defned this code better against |
1237** bad encodings. Questionable to always return 0xFF for bad mappings. 1238*/ 1239 1240static char index_hex[128] = 1241{ 1242 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, 1243 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, 1244 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, 1245 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1, 1246 -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1, 1247 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, 1248 -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1, 1249 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1 1250}; 1251 | 1095** bad encodings. Questionable to always return 0xFF for bad mappings. 1096*/ 1097 1098static char index_hex[128] = 1099{ 1100 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, 1101 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, 1102 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, 1103 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1, 1104 -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1, 1105 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, 1106 -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1, 1107 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1 1108}; 1109 |
1252# define HEXCHAR(c) (((c) < 0 || (c) > 127) ? -1 : index_hex[(c)]) | 1110#define HEXCHAR(c) (((c) < 0 || (c) > 127) ? -1 : index_hex[(c)]) |
1253 | 1111 |
1254/* 1255** MIME_FROMQP -- decode quoted printable string 1256** 1257** Parameters: 1258** infile -- input (encoded) string 1259** outfile -- output string 1260** maxlen -- size of output buffer 1261** 1262** Returns: 1263** -2 if decoding failure 1264** -1 if infile completely decoded into outfile 1265** >= 0 is the position in infile decoding 1266** reached before maxlen was reached 1267*/ 1268 1269static int 1270mime_fromqp(infile, outfile, maxlen) 1271 unsigned char *infile; 1272 unsigned char **outfile; | 1112int 1113mime_fromqp(infile, outfile, state, maxlen) 1114 u_char *infile; 1115 u_char **outfile; 1116 int state; /* Decoding body (0) or header (1) */ |
1273 int maxlen; /* Max # of chars allowed in outfile */ 1274{ 1275 int c1, c2; 1276 int nchar = 0; | 1117 int maxlen; /* Max # of chars allowed in outfile */ 1118{ 1119 int c1, c2; 1120 int nchar = 0; |
1277 unsigned char *b; | |
1278 | 1121 |
1279 /* decrement by one for trailing '\0', at least one other char */ 1280 if (--maxlen < 1) 1281 return 0; 1282 1283 b = infile; 1284 while ((c1 = *infile++) != '\0' && nchar < maxlen) | 1122 while ((c1 = *infile++) != '\0') |
1285 { 1286 if (c1 == '=') 1287 { | 1123 { 1124 if (c1 == '=') 1125 { |
1288 if ((c1 = *infile++) == '\0') | 1126 if ((c1 = *infile++) == 0) |
1289 break; 1290 1291 if (c1 == '\n' || (c1 = HEXCHAR(c1)) == -1) 1292 { | 1127 break; 1128 1129 if (c1 == '\n' || (c1 = HEXCHAR(c1)) == -1) 1130 { |
1293 /* ignore it and the rest of the buffer */ 1294 return -2; | 1131 /* ignore it */ 1132 if (state == 0) 1133 return 0; |
1295 } 1296 else 1297 { 1298 do 1299 { 1300 if ((c2 = *infile++) == '\0') 1301 { 1302 c2 = -1; 1303 break; 1304 } 1305 } while ((c2 = HEXCHAR(c2)) == -1); 1306 | 1134 } 1135 else 1136 { 1137 do 1138 { 1139 if ((c2 = *infile++) == '\0') 1140 { 1141 c2 = -1; 1142 break; 1143 } 1144 } while ((c2 = HEXCHAR(c2)) == -1); 1145 |
1307 if (c2 == -1) | 1146 if (c2 == -1 || ++nchar > maxlen) |
1308 break; | 1147 break; |
1309 nchar++; | 1148 |
1310 *(*outfile)++ = c1 << 4 | c2; 1311 } 1312 } 1313 else 1314 { | 1149 *(*outfile)++ = c1 << 4 | c2; 1150 } 1151 } 1152 else 1153 { |
1315 nchar++; | 1154 if (state == 1 && c1 == '_') 1155 c1 = ' '; 1156 1157 if (++nchar > maxlen) 1158 break; 1159 |
1316 *(*outfile)++ = c1; | 1160 *(*outfile)++ = c1; |
1161 |
|
1317 if (c1 == '\n') 1318 break; 1319 } 1320 } 1321 *(*outfile)++ = '\0'; | 1162 if (c1 == '\n') 1163 break; 1164 } 1165 } 1166 *(*outfile)++ = '\0'; |
1322 if (nchar >= maxlen) 1323 return (infile - b - 1); 1324 return -1; | 1167 return 1; |
1325} | 1168} |
1169 1170 |
|
1326#endif /* MIME7TO8 */ | 1171#endif /* MIME7TO8 */ |