2016-07-20 20:43:58 +00:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
2020-08-05 11:31:15 +00:00
|
|
|
#include <ctype.h>
|
2016-07-20 20:43:58 +00:00
|
|
|
#include <dirent.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
#include <search.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2022-12-07 21:34:37 +00:00
|
|
|
#include <strings.h>
|
2016-07-20 20:43:58 +00:00
|
|
|
#include <time.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include "blaze822.h"
|
2019-11-21 01:15:41 +00:00
|
|
|
#include "xpledge.h"
|
2016-07-20 20:43:58 +00:00
|
|
|
|
2016-08-02 12:09:28 +00:00
|
|
|
static int cflag;
|
2016-08-02 12:01:05 +00:00
|
|
|
static int rflag;
|
2017-05-26 20:00:55 +00:00
|
|
|
static char *tflag = "multipart/mixed";
|
2016-08-02 12:01:05 +00:00
|
|
|
|
2016-07-20 20:43:58 +00:00
|
|
|
int gen_b64(uint8_t *s, off_t size)
|
|
|
|
{
|
|
|
|
static char *b64 =
|
|
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
|
|
|
|
|
|
off_t i;
|
|
|
|
int l;
|
|
|
|
uint32_t v;
|
|
|
|
for (i = 0, l = 0; i+2 < size; i += 3) {
|
|
|
|
v = (s[i] << 16) | (s[i+1] << 8) | s[i+2];
|
|
|
|
putc_unlocked(b64[(v & 0xfc0000) >> 18], stdout);
|
|
|
|
putc_unlocked(b64[(v & 0x03f000) >> 12], stdout);
|
|
|
|
putc_unlocked(b64[(v & 0x000fc0) >> 6], stdout);
|
|
|
|
putc_unlocked(b64[(v & 0x3f)], stdout);
|
|
|
|
l += 4;
|
|
|
|
if (l > 72) {
|
|
|
|
l = 0;
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (size - i == 2) { // 2 bytes left, XXX=
|
|
|
|
v = (s[size - 2] << 16) | (s[size - 1] << 8);
|
|
|
|
putc_unlocked(b64[(v & 0xfc0000) >> 18], stdout);
|
|
|
|
putc_unlocked(b64[(v & 0x03f000) >> 12], stdout);
|
|
|
|
putc_unlocked(b64[(v & 0x000fc0) >> 6], stdout);
|
|
|
|
putc_unlocked('=', stdout);
|
|
|
|
} else if (size - i == 1) { // 1 byte left, XX==
|
|
|
|
v = s[size - 1] << 16;
|
|
|
|
putc_unlocked(b64[(v & 0xfc0000) >> 18], stdout);
|
|
|
|
putc_unlocked(b64[(v & 0x03f000) >> 12], stdout);
|
|
|
|
putc_unlocked('=', stdout);
|
|
|
|
putc_unlocked('=', stdout);
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-06-17 22:35:40 +00:00
|
|
|
#define qphrasevalid(c) ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || \
|
|
|
|
(c >= 'a' && c <= 'z') || \
|
|
|
|
c == '!' || c == '*' || c == '+' || c == '-' || \
|
|
|
|
c == '/')
|
|
|
|
|
2017-10-06 11:15:28 +00:00
|
|
|
size_t
|
|
|
|
gen_qp(uint8_t *s, off_t size, size_t maxlinelen, size_t linelen)
|
2016-07-20 20:43:58 +00:00
|
|
|
{
|
|
|
|
off_t i;
|
2017-03-27 23:03:40 +00:00
|
|
|
int header = linelen > 0;
|
2016-07-20 20:43:58 +00:00
|
|
|
char prev = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < size; i++) {
|
2017-06-29 14:43:47 +00:00
|
|
|
// inspect utf8 sequence to not wrap in between multibyte
|
|
|
|
int mb;
|
|
|
|
if ((s[i] & 0x80) == 0) mb = 3;
|
|
|
|
else if ((s[i] & 0xc0) == 0x80) mb = 3;
|
|
|
|
else if ((s[i] & 0xe0) == 0xc0) mb = 6;
|
|
|
|
else if ((s[i] & 0xf0) == 0xe0) mb = 9;
|
|
|
|
else if ((s[i] & 0xf8) == 0xf0) mb = 12;
|
|
|
|
else mb = 3;
|
|
|
|
|
|
|
|
if (linelen >= maxlinelen-mb-!!header) {
|
|
|
|
linelen = 0;
|
|
|
|
prev = '\n';
|
|
|
|
if (header) {
|
|
|
|
printf("?=\n =?UTF-8?Q?");
|
|
|
|
linelen += 11;
|
|
|
|
} else {
|
|
|
|
puts("=");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-20 20:43:58 +00:00
|
|
|
if ((s[i] > 126) ||
|
2017-09-21 12:53:13 +00:00
|
|
|
(s[i] == '=') ||
|
|
|
|
(linelen == 0 &&
|
|
|
|
(strncmp((char *)s, "From ", 5) == 0 ||
|
|
|
|
(s[i] == '.' && i+1 < size &&
|
|
|
|
(s[i+1] == '\n' || s[i+1] == '\r'))))) {
|
2016-07-20 20:43:58 +00:00
|
|
|
printf("=%02X", s[i]);
|
|
|
|
linelen += 3;
|
|
|
|
prev = s[i];
|
2016-07-25 13:19:19 +00:00
|
|
|
} else if (header &&
|
|
|
|
(s[i] == '\n' || s[i] == '\t' || s[i] == '_')) {
|
|
|
|
printf("=%02X", s[i]);
|
|
|
|
linelen += 3;
|
|
|
|
prev = '_';
|
|
|
|
} else if (header && s[i] == ' ') {
|
|
|
|
putc_unlocked('_', stdout);
|
|
|
|
linelen++;
|
|
|
|
prev = '_';
|
2017-09-19 14:43:58 +00:00
|
|
|
} else if (s[i] < 33 && s[i] != '\n') {
|
|
|
|
if ((s[i] == ' ' || s[i] == '\t') &&
|
|
|
|
i+1 < size &&
|
|
|
|
(s[i+1] != '\n' && s[i+1] != '\r')) {
|
|
|
|
putc_unlocked(s[i], stdout);
|
|
|
|
linelen += 1;
|
|
|
|
prev = s[i];
|
|
|
|
} else {
|
|
|
|
printf("=%02X", s[i]);
|
|
|
|
linelen += 3;
|
|
|
|
prev = '_';
|
|
|
|
}
|
2016-07-20 20:43:58 +00:00
|
|
|
} else if (s[i] == '\n') {
|
2016-07-25 13:19:19 +00:00
|
|
|
if (prev == ' ' || prev == '\t')
|
2016-07-20 20:43:58 +00:00
|
|
|
puts("=");
|
|
|
|
putc_unlocked('\n', stdout);
|
|
|
|
linelen = 0;
|
|
|
|
prev = 0;
|
2021-06-17 22:35:40 +00:00
|
|
|
} else if (header && !qphrasevalid(s[i])) {
|
|
|
|
printf("=%02X", s[i]);
|
|
|
|
linelen += 3;
|
|
|
|
prev = '_';
|
2016-07-20 20:43:58 +00:00
|
|
|
} else {
|
|
|
|
putc_unlocked(s[i], stdout);
|
|
|
|
linelen++;
|
|
|
|
prev = s[i];
|
|
|
|
}
|
|
|
|
}
|
2016-07-25 13:19:19 +00:00
|
|
|
if (linelen > 0 && !header)
|
2016-07-20 20:43:58 +00:00
|
|
|
puts("=");
|
2016-07-25 13:19:19 +00:00
|
|
|
return linelen;
|
2016-07-20 20:43:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
basenam(const char *s)
|
|
|
|
{
|
2017-01-26 19:27:26 +00:00
|
|
|
char *r = strrchr(s, '/');
|
|
|
|
return r ? r + 1 : s;
|
2016-07-20 20:43:58 +00:00
|
|
|
}
|
|
|
|
|
2017-04-06 18:54:01 +00:00
|
|
|
static void
|
2017-06-19 11:24:49 +00:00
|
|
|
gen_attachment(const char *filename, char *content_disposition)
|
2017-04-06 18:54:01 +00:00
|
|
|
{
|
|
|
|
const char *s = filename;
|
2017-06-12 13:31:27 +00:00
|
|
|
int quote = 0;
|
2017-04-06 18:54:01 +00:00
|
|
|
|
2017-06-19 11:26:40 +00:00
|
|
|
if (!*filename) {
|
|
|
|
printf("Content-Disposition: %s\n", content_disposition);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-08-31 15:30:17 +00:00
|
|
|
for (s = (char *)filename; *s; s++) {
|
2017-06-12 13:31:27 +00:00
|
|
|
if (*s < 32 || *s == '"' || *s >= 127 || s - filename > 35)
|
2017-04-06 18:54:01 +00:00
|
|
|
goto rfc2231;
|
2017-06-12 13:31:27 +00:00
|
|
|
if (strchr(" ()<>@,;:\\/[]?=", *s))
|
|
|
|
quote = 1;
|
|
|
|
}
|
2017-04-06 18:54:01 +00:00
|
|
|
|
2017-06-12 13:31:27 +00:00
|
|
|
// filename SHOULD be an atom if possible
|
2017-06-19 11:24:49 +00:00
|
|
|
printf("Content-Disposition: %s; filename=%s%s%s\n", content_disposition,
|
2017-06-12 13:31:27 +00:00
|
|
|
quote ? "\"" : "", filename, quote ? "\"" : "");
|
2017-04-06 18:54:01 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
rfc2231:
|
2017-06-19 11:24:49 +00:00
|
|
|
printf("Content-Disposition: %s", content_disposition);
|
2017-04-06 18:54:01 +00:00
|
|
|
int i = 0;
|
|
|
|
int d = 0;
|
|
|
|
|
|
|
|
s = filename;
|
|
|
|
|
|
|
|
while (*s) {
|
|
|
|
i = printf(";\n filename*%d*=", d);
|
|
|
|
if (d++ == 0) {
|
|
|
|
printf("UTF-8''");
|
|
|
|
i += 7;
|
|
|
|
}
|
|
|
|
while (*s && i < 78 - 3) {
|
2017-06-12 13:31:27 +00:00
|
|
|
if (*s <= 32 || *s == '"' || *s > 126)
|
2017-08-31 15:30:17 +00:00
|
|
|
i += printf("%%%02x", (uint8_t)*s++);
|
2017-04-06 18:54:01 +00:00
|
|
|
else
|
2017-08-31 15:30:17 +00:00
|
|
|
i += printf("%c", (uint8_t)*s++);
|
2017-04-06 18:54:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
gen_file(char *file, char *ct)
|
2016-07-20 20:43:58 +00:00
|
|
|
{
|
2016-10-05 12:45:42 +00:00
|
|
|
uint8_t *content;
|
|
|
|
off_t size;
|
2016-07-20 20:43:58 +00:00
|
|
|
|
2017-06-19 11:24:49 +00:00
|
|
|
char *cd = "attachment";
|
|
|
|
char *s = strchr(ct, '#');
|
|
|
|
if (s) {
|
|
|
|
*s = 0;
|
|
|
|
cd = s + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *filename = basenam(file);
|
|
|
|
s = strchr(file, '>');
|
|
|
|
if (s) {
|
|
|
|
*s = 0;
|
|
|
|
filename = s + 1;
|
|
|
|
}
|
|
|
|
|
2016-10-05 12:45:42 +00:00
|
|
|
int r = slurp(file, (char **)&content, &size);
|
|
|
|
if (r != 0) {
|
2017-03-30 13:40:05 +00:00
|
|
|
fprintf(stderr, "mmime: error attaching file '%s': %s\n",
|
2016-10-05 12:45:42 +00:00
|
|
|
file, strerror(r));
|
2016-07-20 20:43:58 +00:00
|
|
|
return -1;
|
2016-10-05 12:45:42 +00:00
|
|
|
}
|
2017-08-31 15:30:17 +00:00
|
|
|
|
2017-05-26 21:24:26 +00:00
|
|
|
if (strcmp(ct, "mblaze/raw") == 0)
|
|
|
|
goto raw;
|
|
|
|
|
2016-07-20 20:43:58 +00:00
|
|
|
off_t bithigh = 0;
|
|
|
|
off_t bitlow = 0;
|
|
|
|
off_t linelen = 0;
|
|
|
|
off_t maxlinelen = 0;
|
|
|
|
off_t i;
|
2016-10-05 12:45:42 +00:00
|
|
|
for (i = 0; i < size; i++) {
|
2016-07-20 20:43:58 +00:00
|
|
|
if (content[i] == '\n') {
|
|
|
|
if (maxlinelen < linelen)
|
|
|
|
maxlinelen = linelen;
|
|
|
|
linelen = 0;
|
|
|
|
} else {
|
|
|
|
linelen++;
|
|
|
|
}
|
|
|
|
if (content[i] != '\t' && content[i] != '\n' && content[i] < 32)
|
|
|
|
bitlow++;
|
|
|
|
if (content[i] > 127)
|
|
|
|
bithigh++;
|
|
|
|
}
|
|
|
|
|
2017-06-19 11:24:49 +00:00
|
|
|
gen_attachment(filename, cd);
|
2017-04-06 18:54:01 +00:00
|
|
|
|
2017-07-09 19:25:55 +00:00
|
|
|
if (strcmp(ct, "message/rfc822") == 0) {
|
|
|
|
printf("Content-Type: %s\n", ct);
|
|
|
|
printf("Content-Transfer-Encoding: %dbit\n\n",
|
|
|
|
(bitlow > 0 || bithigh > 0) ? 8 : 7);
|
|
|
|
fwrite(content, 1, size, stdout);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-07-20 20:43:58 +00:00
|
|
|
if (bitlow == 0 && bithigh == 0 &&
|
2019-04-23 10:35:12 +00:00
|
|
|
maxlinelen <= 78) {
|
2016-07-20 20:43:58 +00:00
|
|
|
if (!ct)
|
|
|
|
ct = "text/plain";
|
|
|
|
printf("Content-Type: %s\n", ct);
|
|
|
|
printf("Content-Transfer-Encoding: 7bit\n\n");
|
2017-05-26 21:24:26 +00:00
|
|
|
raw:
|
2016-10-05 12:45:42 +00:00
|
|
|
fwrite(content, 1, size, stdout);
|
2016-07-20 20:43:58 +00:00
|
|
|
return 0;
|
|
|
|
} else if (bitlow == 0 && bithigh == 0) {
|
|
|
|
if (!ct)
|
|
|
|
ct = "text/plain";
|
|
|
|
printf("Content-Type: %s\n", ct);
|
|
|
|
printf("Content-Transfer-Encoding: quoted-printable\n\n");
|
2016-10-05 12:45:42 +00:00
|
|
|
gen_qp(content, size, 78, 0);
|
2016-07-25 13:19:19 +00:00
|
|
|
return 0;
|
2016-10-05 12:45:42 +00:00
|
|
|
} else if (bitlow > size/10 || bithigh > size/4) {
|
2016-07-20 20:43:58 +00:00
|
|
|
if (!ct)
|
|
|
|
ct = "application/binary";
|
|
|
|
printf("Content-Type: %s\n", ct);
|
|
|
|
printf("Content-Transfer-Encoding: base64\n\n");
|
2016-10-05 12:45:42 +00:00
|
|
|
return gen_b64(content, size);
|
2016-07-20 20:43:58 +00:00
|
|
|
} else {
|
|
|
|
if (!ct)
|
|
|
|
ct = "text/plain";
|
|
|
|
printf("Content-Type: %s\n", ct);
|
|
|
|
printf("Content-Transfer-Encoding: quoted-printable\n\n");
|
2016-10-05 12:45:42 +00:00
|
|
|
gen_qp(content, size, 78, 0);
|
2016-07-25 13:19:19 +00:00
|
|
|
return 0;
|
2016-07-20 20:43:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-25 13:19:19 +00:00
|
|
|
void
|
|
|
|
print_header(char *line) {
|
|
|
|
char *s, *e;
|
|
|
|
size_t l = strlen(line);
|
|
|
|
|
2019-02-28 12:20:19 +00:00
|
|
|
if (l == 0)
|
|
|
|
return;
|
|
|
|
|
2016-07-25 13:19:19 +00:00
|
|
|
if (line[l-1] == '\n')
|
|
|
|
line[l-1] = 0;
|
|
|
|
|
|
|
|
/* iterate word-wise, encode words when needed. */
|
|
|
|
|
|
|
|
s = line;
|
|
|
|
|
|
|
|
if (!(*s == ' ' || *s == '\t')) {
|
|
|
|
// raw header name
|
|
|
|
while (*s && *s != ':')
|
|
|
|
putc_unlocked(*s++, stdout);
|
|
|
|
if (*s == ':')
|
|
|
|
putc_unlocked(*s++, stdout);
|
|
|
|
}
|
|
|
|
|
2017-03-27 23:03:40 +00:00
|
|
|
int prevq = 0; // was the previous word encoded as qp?
|
2021-06-17 23:55:07 +00:00
|
|
|
char prevqs = 0; // was the previous word a quoted-string?
|
2016-07-25 13:19:19 +00:00
|
|
|
|
2019-02-03 17:06:40 +00:00
|
|
|
ssize_t linelen = s - line;
|
2016-07-25 13:19:19 +00:00
|
|
|
|
|
|
|
while (*s) {
|
|
|
|
size_t highbit = 0;
|
2021-06-17 22:44:47 +00:00
|
|
|
int qs = 0;
|
2016-07-25 13:19:19 +00:00
|
|
|
e = s;
|
|
|
|
while (*e && *e == ' ')
|
|
|
|
e++;
|
2021-06-17 22:44:47 +00:00
|
|
|
|
|
|
|
if (*e == '"') { // scan quoted-string, encode at once
|
|
|
|
s = e;
|
|
|
|
for (e++; *e && *e != '"'; e++) {
|
|
|
|
if (*e == '\\')
|
|
|
|
e++;
|
|
|
|
if ((uint8_t)*e >= 127)
|
|
|
|
highbit++;
|
|
|
|
}
|
|
|
|
if (*e == '"')
|
|
|
|
e++;
|
|
|
|
qs = 1;
|
|
|
|
} else { // scan word
|
|
|
|
while (*e && *e == ' ')
|
|
|
|
e++;
|
|
|
|
for (; *e && *e != ' '; e++) {
|
|
|
|
if ((uint8_t)*e >= 127)
|
|
|
|
highbit++;
|
|
|
|
}
|
2016-07-25 13:19:19 +00:00
|
|
|
}
|
|
|
|
|
2017-03-27 23:03:40 +00:00
|
|
|
if (!highbit) {
|
2017-04-30 16:34:37 +00:00
|
|
|
if (e-s >= 998)
|
2017-03-27 23:03:40 +00:00
|
|
|
goto force_qp;
|
|
|
|
if (e-s >= 78 - linelen) {
|
|
|
|
// wrap in advance before long word
|
|
|
|
printf("\n");
|
2016-07-25 13:19:19 +00:00
|
|
|
linelen = 0;
|
|
|
|
}
|
2017-03-27 23:03:40 +00:00
|
|
|
if (linelen <= 1 && s[0] == ' ' && s[1] == ' ') {
|
|
|
|
// space at beginning of line
|
|
|
|
goto force_qp;
|
2016-07-25 13:19:19 +00:00
|
|
|
}
|
2021-06-17 23:55:07 +00:00
|
|
|
if (*s != ' ' && !(prevqs && !prevq && *(s-1) != ' ')) {
|
2017-03-27 23:03:40 +00:00
|
|
|
printf(" ");
|
|
|
|
linelen++;
|
2016-07-25 13:19:19 +00:00
|
|
|
}
|
|
|
|
fwrite(s, 1, e-s, stdout);
|
|
|
|
linelen += e-s;
|
|
|
|
prevq = 0;
|
2017-03-27 23:03:40 +00:00
|
|
|
} else {
|
|
|
|
force_qp:
|
|
|
|
if (!prevq && *s == ' ')
|
|
|
|
s++;
|
2021-06-17 22:44:47 +00:00
|
|
|
|
|
|
|
if (qs && *s == '"')
|
|
|
|
s++;
|
|
|
|
if (qs && e > s && *(e-1) == '"')
|
|
|
|
e--;
|
|
|
|
|
2017-03-27 23:03:40 +00:00
|
|
|
if (linelen >= 78 - 13 - 4 ||
|
|
|
|
(e-s < (78 - 13)/3 &&
|
|
|
|
e-s >= (78 - linelen - 13)/3)) {
|
|
|
|
// wrap in advance
|
|
|
|
printf("\n");
|
|
|
|
linelen = 0;
|
|
|
|
}
|
|
|
|
printf(" =?UTF-8?Q?");
|
|
|
|
linelen += 11;
|
|
|
|
linelen = gen_qp((uint8_t *)s, e-s, 78, linelen);
|
|
|
|
printf("?=");
|
|
|
|
linelen += 2;
|
|
|
|
prevq = 1;
|
2021-06-17 22:44:47 +00:00
|
|
|
|
|
|
|
if (qs && *e == '"')
|
|
|
|
e++;
|
2016-07-25 13:19:19 +00:00
|
|
|
}
|
2021-06-17 23:55:07 +00:00
|
|
|
prevqs = qs;
|
2016-07-25 13:19:19 +00:00
|
|
|
s = e;
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
|
2020-08-05 11:31:15 +00:00
|
|
|
static int
|
|
|
|
valid_content_type(char *s)
|
|
|
|
{
|
|
|
|
int slash = 0;
|
|
|
|
|
|
|
|
for (; *s; s++)
|
|
|
|
if (*s == '/')
|
|
|
|
slash++;
|
2020-08-22 13:15:26 +00:00
|
|
|
else if (isalnum(*s) || *s == '-' || *s == '+' || *s == '.' ||
|
2020-12-22 12:42:22 +00:00
|
|
|
*s == ';' || *s == '=' || *s == '#')
|
2020-08-05 11:31:15 +00:00
|
|
|
; /* ok */
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return slash == 1;
|
|
|
|
}
|
|
|
|
|
2016-07-20 20:43:58 +00:00
|
|
|
int
|
|
|
|
gen_build()
|
|
|
|
{
|
|
|
|
char sep[100];
|
|
|
|
snprintf(sep, sizeof sep, "----_=_%08lx%08lx%08lx_=_",
|
|
|
|
lrand48(), lrand48(), lrand48());
|
|
|
|
|
|
|
|
char *line = 0;
|
|
|
|
size_t linelen = 0;
|
|
|
|
int inheader = 1;
|
|
|
|
int intext = 0;
|
2021-08-07 17:33:08 +00:00
|
|
|
int emptybody = 1;
|
2020-11-08 13:55:36 +00:00
|
|
|
int ret = 0;
|
2021-05-09 14:23:18 +00:00
|
|
|
char *contenttype = 0;
|
|
|
|
char *contenttransferenc = 0;
|
2016-07-20 20:43:58 +00:00
|
|
|
|
|
|
|
while (1) {
|
2017-10-06 11:15:28 +00:00
|
|
|
ssize_t read = getdelim(&line, &linelen, '\n', stdin);
|
2016-07-20 20:43:58 +00:00
|
|
|
if (read == -1) {
|
2021-08-07 17:33:08 +00:00
|
|
|
if (feof(stdin)) {
|
|
|
|
if (!emptybody)
|
|
|
|
break;
|
2021-06-17 23:38:03 +00:00
|
|
|
line = strdup(inheader ? "\n" : "");
|
2021-08-07 17:33:08 +00:00
|
|
|
} else { // errored
|
2016-07-20 20:43:58 +00:00
|
|
|
exit(1);
|
2021-08-07 17:33:08 +00:00
|
|
|
}
|
2016-07-20 20:43:58 +00:00
|
|
|
}
|
|
|
|
if (inheader) {
|
|
|
|
if (line[0] == '\n') {
|
|
|
|
inheader = 0;
|
|
|
|
printf("MIME-Version: 1.0\n");
|
2016-08-02 12:01:05 +00:00
|
|
|
if (rflag) {
|
2021-05-09 14:23:18 +00:00
|
|
|
printf("Content-Type:%s", contenttype ? contenttype : " text/plain; charset=UTF-8\n");
|
|
|
|
printf("Content-Transfer-Encoding:%s", contenttransferenc ? contenttransferenc : " quoted-printable\n");
|
|
|
|
printf("\n");
|
2016-08-02 12:01:05 +00:00
|
|
|
} else {
|
2017-05-26 20:00:55 +00:00
|
|
|
printf("Content-Type: %s; boundary=\"%s\"\n", tflag, sep);
|
2016-08-02 12:01:05 +00:00
|
|
|
printf("\n");
|
2016-08-06 17:15:12 +00:00
|
|
|
printf("This is a multipart message in MIME format.\n");
|
2016-08-02 12:01:05 +00:00
|
|
|
}
|
2016-07-20 20:43:58 +00:00
|
|
|
} else {
|
2021-05-09 14:23:18 +00:00
|
|
|
if (strncasecmp(line, "Content-Type:", 13) == 0) {
|
|
|
|
free(contenttype);
|
|
|
|
contenttype = strdup(line+13);
|
|
|
|
} else if (strncasecmp(line, "Content-Transfer-Encoding:", 26) == 0) {
|
|
|
|
free(contenttransferenc);
|
|
|
|
contenttransferenc = strdup(line+26);
|
|
|
|
} else {
|
|
|
|
print_header(line);
|
|
|
|
}
|
2016-07-20 20:43:58 +00:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-08-02 12:01:05 +00:00
|
|
|
if (!rflag && line[0] == '#') {
|
2016-07-20 20:43:58 +00:00
|
|
|
char *f = strchr(line, ' ');
|
2016-10-05 12:31:41 +00:00
|
|
|
if (f) {
|
2016-11-08 15:34:34 +00:00
|
|
|
char of = *f;
|
2016-10-05 12:31:41 +00:00
|
|
|
*f = 0;
|
2020-08-05 11:31:15 +00:00
|
|
|
if (valid_content_type(line+1)) {
|
2016-10-05 12:31:41 +00:00
|
|
|
printf("\n--%s\n", sep);
|
|
|
|
if (line[read-1] == '\n')
|
|
|
|
line[read-1] = 0;
|
2020-11-08 13:55:36 +00:00
|
|
|
if (gen_file(f+1, line+1) != 0)
|
|
|
|
ret = 1;
|
2016-10-05 12:31:41 +00:00
|
|
|
intext = 0;
|
2021-08-07 17:33:08 +00:00
|
|
|
emptybody = 0;
|
2016-10-05 12:31:41 +00:00
|
|
|
continue;
|
|
|
|
}
|
2016-11-08 15:34:34 +00:00
|
|
|
*f = of;
|
2016-07-20 20:43:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-02 12:01:05 +00:00
|
|
|
if (!rflag && !intext) {
|
2016-08-06 17:15:12 +00:00
|
|
|
printf("\n--%s\n", sep);
|
2021-05-09 14:23:18 +00:00
|
|
|
printf("Content-Type:%s", contenttype ? contenttype : " text/plain; charset=UTF-8\n");
|
2016-07-20 20:43:58 +00:00
|
|
|
printf("Content-Disposition: inline\n");
|
2021-05-09 14:23:18 +00:00
|
|
|
printf("Content-Transfer-Encoding:%s", contenttransferenc ? contenttransferenc : " quoted-printable\n");
|
|
|
|
printf("\n");
|
2017-08-31 15:30:17 +00:00
|
|
|
|
2016-07-20 20:43:58 +00:00
|
|
|
intext = 1;
|
|
|
|
}
|
|
|
|
|
2021-05-09 14:23:18 +00:00
|
|
|
if (contenttransferenc)
|
|
|
|
printf("%s", line);
|
|
|
|
else
|
|
|
|
gen_qp((uint8_t *)line, strlen(line), 78, 0);
|
2021-08-07 17:33:08 +00:00
|
|
|
|
|
|
|
emptybody = 0;
|
2016-07-20 20:43:58 +00:00
|
|
|
}
|
2016-08-02 12:09:28 +00:00
|
|
|
if (!rflag && !inheader)
|
2016-08-06 17:15:12 +00:00
|
|
|
printf("\n--%s--\n", sep);
|
2016-07-20 20:43:58 +00:00
|
|
|
|
|
|
|
free(line);
|
2020-11-08 13:55:36 +00:00
|
|
|
return ret;
|
2016-07-20 20:43:58 +00:00
|
|
|
}
|
|
|
|
|
2016-08-02 12:09:28 +00:00
|
|
|
int
|
|
|
|
check()
|
|
|
|
{
|
|
|
|
off_t bithigh = 0;
|
|
|
|
off_t bitlow = 0;
|
|
|
|
off_t linelen = 0;
|
2017-04-30 16:26:49 +00:00
|
|
|
off_t maxheadlinelen = 0;
|
|
|
|
off_t maxbodylinelen = 0;
|
2022-01-25 13:08:37 +00:00
|
|
|
off_t bodylinelenlimit = getenv("MBLAZE_RELAXED_MIME") ? 998 : 78;
|
2016-08-02 12:09:28 +00:00
|
|
|
|
|
|
|
int c;
|
|
|
|
int l = -1;
|
|
|
|
|
|
|
|
while ((c = getchar()) != EOF) {
|
|
|
|
if (c == '\n') {
|
2017-04-30 16:26:49 +00:00
|
|
|
if (maxheadlinelen < linelen)
|
|
|
|
maxheadlinelen = linelen;
|
|
|
|
linelen = 0;
|
|
|
|
if (l == '\n')
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
linelen++;
|
|
|
|
}
|
|
|
|
if (c != '\t' && c != '\n' && c < 32)
|
|
|
|
bitlow++;
|
|
|
|
if (c > 127)
|
|
|
|
bithigh++;
|
|
|
|
l = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((c = getchar()) != EOF) {
|
|
|
|
if (c == '\n') {
|
|
|
|
if (maxbodylinelen < linelen)
|
|
|
|
maxbodylinelen = linelen;
|
2016-08-02 12:09:28 +00:00
|
|
|
linelen = 0;
|
|
|
|
} else {
|
|
|
|
linelen++;
|
|
|
|
}
|
|
|
|
if (c != '\t' && c != '\n' && c < 32)
|
|
|
|
bitlow++;
|
|
|
|
if (c > 127)
|
|
|
|
bithigh++;
|
|
|
|
l = c;
|
|
|
|
}
|
|
|
|
|
2017-04-30 16:26:49 +00:00
|
|
|
if (bitlow == 0 && bithigh == 0 &&
|
2022-01-25 13:08:37 +00:00
|
|
|
maxheadlinelen < 998 && maxbodylinelen <= bodylinelenlimit &&
|
2017-04-30 16:26:49 +00:00
|
|
|
l == '\n')
|
2016-08-02 12:09:28 +00:00
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2016-07-20 20:43:58 +00:00
|
|
|
int
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
srand48(time(0) ^ getpid());
|
|
|
|
|
2016-08-02 12:01:05 +00:00
|
|
|
int c;
|
2017-05-26 20:00:55 +00:00
|
|
|
while ((c = getopt(argc, argv, "crt:")) != -1)
|
2017-08-31 15:30:17 +00:00
|
|
|
switch (c) {
|
2016-08-02 12:01:05 +00:00
|
|
|
case 'r': rflag = 1; break;
|
2016-08-02 12:09:28 +00:00
|
|
|
case 'c': cflag = 1; break;
|
2017-05-26 20:00:55 +00:00
|
|
|
case 't': tflag = optarg; break;
|
2016-08-02 12:01:05 +00:00
|
|
|
default:
|
2017-08-31 15:30:17 +00:00
|
|
|
usage:
|
2017-05-26 20:00:55 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"Usage: mmime [-c|-r] [-t CONTENT-TYPE] < message\n");
|
2016-08-02 12:01:05 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (argc != optind)
|
|
|
|
goto usage;
|
|
|
|
|
2019-11-21 01:15:41 +00:00
|
|
|
xpledge("stdio rpath", "");
|
|
|
|
|
2016-08-02 12:09:28 +00:00
|
|
|
if (cflag)
|
|
|
|
return check();
|
|
|
|
|
2016-08-02 12:01:05 +00:00
|
|
|
return gen_build();
|
2016-07-20 20:43:58 +00:00
|
|
|
}
|