Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.bin/bintrans/qp.c
34677 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2020 Baptiste Daroussin <[email protected]>
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*/
27
28
#include <ctype.h>
29
#include <getopt.h>
30
#include <stdbool.h>
31
#include <stdio.h>
32
#include <string.h>
33
#include <stdlib.h>
34
35
extern int main_quotedprintable(int, char *[]);
36
37
static int
38
hexval(int c)
39
{
40
if ('0' <= c && c <= '9')
41
return c - '0';
42
return (10 + c - 'A');
43
}
44
45
46
static int
47
decode_char(const char *s)
48
{
49
return (16 * hexval(toupper(s[1])) + hexval(toupper(s[2])));
50
}
51
52
53
static void
54
decode_quoted_printable(const char *body, FILE *fpo, bool rfc2047)
55
{
56
while (*body != '\0') {
57
switch (*body) {
58
case '=':
59
if (strlen(body) < 2) {
60
fputc(*body, fpo);
61
break;
62
}
63
64
if (body[1] == '\r' && body[2] == '\n') {
65
body += 2;
66
break;
67
}
68
if (body[1] == '\n') {
69
body++;
70
break;
71
}
72
if (strchr("0123456789ABCDEFabcdef", body[1]) == NULL) {
73
fputc(*body, fpo);
74
break;
75
}
76
if (strchr("0123456789ABCDEFabcdef", body[2]) == NULL) {
77
fputc(*body, fpo);
78
break;
79
}
80
fputc(decode_char(body), fpo);
81
body += 2;
82
break;
83
case '_':
84
if (rfc2047) {
85
fputc(0x20, fpo);
86
break;
87
}
88
/* FALLTHROUGH */
89
default:
90
fputc(*body, fpo);
91
break;
92
}
93
body++;
94
}
95
}
96
97
static void
98
encode_quoted_printable(const char *body, FILE *fpo, bool rfc2047)
99
{
100
const char *end = body + strlen(body);
101
size_t linelen = 0;
102
char prev = '\0';
103
104
while (*body != '\0') {
105
if (linelen == 75) {
106
fputs("=\r\n", fpo);
107
linelen = 0;
108
}
109
if (!isascii(*body) ||
110
*body == '=' ||
111
(*body == '.' && body + 1 < end &&
112
(body[1] == '\n' || body[1] == '\r'))) {
113
fprintf(fpo, "=%02X", (unsigned char)*body);
114
linelen += 2;
115
prev = *body;
116
} else if (*body < 33 && *body != '\n') {
117
if ((*body == ' ' || *body == '\t') &&
118
body + 1 < end &&
119
(body[1] != '\n' && body[1] != '\r')) {
120
if (*body == 0x20 && rfc2047)
121
fputc('_', fpo);
122
else
123
fputc(*body, fpo);
124
prev = *body;
125
} else {
126
fprintf(fpo, "=%02X", (unsigned char)*body);
127
linelen += 2;
128
prev = '_';
129
}
130
} else if (*body == '\n') {
131
if (prev == ' ' || prev == '\t') {
132
fputc('=', fpo);
133
}
134
fputc('\n', fpo);
135
linelen = 0;
136
prev = 0;
137
} else {
138
fputc(*body, fpo);
139
prev = *body;
140
}
141
body++;
142
linelen++;
143
}
144
}
145
146
static void
147
qp(FILE *fp, FILE *fpo, bool encode, bool rfc2047)
148
{
149
char *line = NULL;
150
size_t linecap = 0;
151
void (*codec)(const char *line, FILE *f, bool rfc2047);
152
153
codec = encode ? encode_quoted_printable : decode_quoted_printable ;
154
155
while (getline(&line, &linecap, fp) > 0)
156
codec(line, fpo, rfc2047);
157
free(line);
158
}
159
160
static void
161
usage(void)
162
{
163
fprintf(stderr,
164
"usage: bintrans qp [-d] [-r] [-o outputfile] [file name]\n");
165
}
166
167
int
168
main_quotedprintable(int argc, char *argv[])
169
{
170
int ch;
171
bool encode = true;
172
bool rfc2047 = false;
173
FILE *fp = stdin;
174
FILE *fpo = stdout;
175
176
static const struct option opts[] =
177
{
178
{ "decode", no_argument, NULL, 'd'},
179
{ "output", required_argument, NULL, 'o'},
180
{ "rfc2047", no_argument, NULL, 'r'},
181
{NULL, no_argument, NULL, 0}
182
};
183
184
while ((ch = getopt_long(argc, argv, "+do:ru", opts, NULL)) != -1) {
185
switch(ch) {
186
case 'o':
187
fpo = fopen(optarg, "w");
188
if (fpo == NULL) {
189
perror(optarg);
190
exit(EXIT_FAILURE);
191
}
192
break;
193
case 'u':
194
/* FALLTHROUGH for backward compatibility */
195
case 'd':
196
encode = false;
197
break;
198
case 'r':
199
rfc2047 = true;
200
break;
201
default:
202
usage();
203
exit(EXIT_FAILURE);
204
}
205
};
206
argc -= optind;
207
argv += optind;
208
if (argc > 0) {
209
fp = fopen(argv[0], "r");
210
if (fp == NULL) {
211
perror(argv[0]);
212
exit(EXIT_FAILURE);
213
}
214
}
215
qp(fp, fpo, encode, rfc2047);
216
217
return (EXIT_SUCCESS);
218
}
219
220