]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/bintrans/quoted-printable.c
Merge llvm-project main llvmorg-14-init-10223-g401b76fdf2b3
[FreeBSD/FreeBSD.git] / usr.bin / bintrans / quoted-printable.c
1 /*
2 Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
3
4 Permission to use, copy, modify, and distribute this material
5 for any purpose and without fee is hereby granted, provided
6 that the above copyright notice and this permission notice
7 appear in all copies, and that the name of Bellcore not be
8 used in advertising or publicity pertaining to this
9 material without the specific, prior written permission
10 of an authorized representative of Bellcore.  BELLCORE
11 MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY
12 OF THIS MATERIAL FOR ANY PURPOSE.  IT IS PROVIDED "AS IS",
13 WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
14 */
15 #include <stdbool.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <ctype.h>
20
21 extern int      main_quotedprintable(int, char *[]);
22
23 static int
24 PendingBoundary(char *s, char **Boundaries, int *BoundaryCt)
25 {
26         int i;
27         size_t len;
28
29         if (s[0] != '-' || s[1] != '-')
30                 return (0);
31
32         for (i = 0; i < *BoundaryCt; ++i) {
33                 len = strlen(Boundaries[i]);
34                 if (strncmp(s, Boundaries[i], len) == 0) {
35                         if (s[len] == '-' && s[len + 1] == '-')
36                                 *BoundaryCt = i;
37                         return (1);
38                 }
39         }
40         return (0);
41 }
42
43 #define basis_hex "0123456789ABCDEF"
44 static const char index_hex[128] = {
45         -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
46         -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
47         -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
48          0, 1, 2, 3,  4, 5, 6, 7,  8, 9,-1,-1, -1,-1,-1,-1,
49         -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
50         -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
51         -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
52         -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
53 };
54
55 /* The following version generated complaints on Solaris. */
56 /* #define hexchar(c)  (((c) < 0 || (c) > 127) ? -1 : index_hex[(c)])  */
57 /*  Since we're no longer ever calling it with anything signed, this should work: */
58 #define hexchar(c)  (((c) > 127) ? -1 : index_hex[(c)])
59
60 static void
61 toqp(FILE *infile, FILE *outfile)
62 {
63         int c, ct = 0, prevc = 255;
64
65         while ((c = getc(infile)) != EOF) {
66                 if ((c < 32 && (c != '\n' && c != '\t'))
67                          || (c == '=')
68                          || (c >= 127)
69                          /* Following line is to avoid single periods alone on lines,
70                            which messes up some dumb smtp implementations, sigh... */
71                          || (ct == 0 && c == '.')) {
72                         putc('=', outfile);
73                         putc(basis_hex[c >> 4], outfile);
74                         putc(basis_hex[c & 0xF], outfile);
75                         ct += 3;
76                         prevc = 'A'; /* close enough */
77                 } else if (c == '\n') {
78                         if (prevc == ' ' || prevc == '\t') {
79                                 putc('=', outfile); /* soft & hard lines */
80                                 putc(c, outfile);
81                         }
82                         putc(c, outfile);
83                         ct = 0;
84                         prevc = c;
85                 } else {
86                         if (c == 'F' && prevc == '\n') {
87                                 /* HORRIBLE but clever hack suggested by MTR for sendmail-avoidance */
88                                 c = getc(infile);
89                                 if (c == 'r') {
90                                         c = getc(infile);
91                                         if (c == 'o') {
92                                                 c = getc(infile);
93                                                 if (c == 'm') {
94                                                         c = getc(infile);
95                                                         if (c == ' ') {
96                                                                 /* This is the case we are looking for */
97                                                                 fputs("=46rom", outfile);
98                                                                 ct += 6;
99                                                         } else {
100                                                                 fputs("From", outfile);
101                                                                 ct += 4;
102                                                         }
103                                                 } else {
104                                                         fputs("Fro", outfile);
105                                                         ct += 3;
106                                                 }
107                                         } else {
108                                                 fputs("Fr", outfile);
109                                                 ct += 2;
110                                         }
111                                 } else {
112                                         putc('F', outfile);
113                                         ++ct;
114                                 }
115                                 ungetc(c, infile);
116                                 prevc = 'x'; /* close enough -- printable */
117                         } else { /* END horrible hack */
118                                 putc(c, outfile);
119                                 ++ct;
120                                 prevc = c;
121                         }
122                 }
123                 if (ct > 72) {
124                         putc('=', outfile);
125                         putc('\n', outfile);
126                         ct = 0;
127                         prevc = '\n';
128                 }
129         }
130         if (ct) {
131                 putc('=', outfile);
132                 putc('\n', outfile);
133         }
134 }
135
136 static void
137 fromqp(FILE *infile, FILE *outfile, char **boundaries, int *boundaryct)
138 {
139         int c1, c2;
140         bool sawnewline = true, neednewline = false;
141         /* The neednewline hack is necessary because the newline leading into
142           a multipart boundary is part of the boundary, not the data */
143
144         while ((c1 = getc(infile)) != EOF) {
145                 if (sawnewline && boundaries && c1 == '-') {
146                         char Buf[200];
147                         unsigned char *s;
148
149                         ungetc(c1, infile);
150                         fgets(Buf, sizeof(Buf), infile);
151                         if (boundaries
152                                  && Buf[0] == '-'
153                                  && Buf[1] == '-'
154                                  && PendingBoundary(Buf, boundaries, boundaryct)) {
155                                 return;
156                         }
157                         /* Not a boundary, now we must treat THIS line as q-p, sigh */
158                         if (neednewline) {
159                                 putc('\n', outfile);
160                                 neednewline = false;
161                         }
162                         for (s = (unsigned char *)Buf; *s; ++s) {
163                                 if (*s == '=') {
164                                         if (*++s == 0)
165                                                 break;
166                                         if (*s == '\n') {
167                                                 /* ignore it */
168                                                 sawnewline = true;
169                                         } else {
170                                                 c1 = hexchar(*s);
171                                                 if (*++s == 0)
172                                                         break;
173                                                 c2 = hexchar(*s);
174                                                 putc(c1 << 4 | c2, outfile);
175                                         }
176                                 } else {
177                                         putc(*s, outfile);
178                                 }
179                         }
180                 } else {
181                         if (neednewline) {
182                                 putc('\n', outfile);
183                                 neednewline = false;
184                         }
185                         if (c1 == '=') {
186                                 sawnewline = false;
187                                 c1 = getc(infile);
188                                 if (c1 == '\n') {
189                                         /* ignore it */
190                                         sawnewline = true;
191                                 } else {
192                                         c2 = getc(infile);
193                                         c1 = hexchar(c1);
194                                         c2 = hexchar(c2);
195                                         putc(c1 << 4 | c2, outfile);
196                                         if (c2 == '\n')
197                                                 sawnewline = true;
198                                 }
199                         } else {
200                                 if (c1 == '\n') {
201                                         sawnewline = true;
202                                         neednewline = true;
203                                 } else {
204                                         sawnewline = false;
205                                         putc(c1, outfile);
206                                 }
207                         }
208                 }
209         }
210         if (neednewline) {
211                 putc('\n', outfile);
212                 neednewline = false;
213         }
214 }
215
216 static void
217 usage(void)
218 {
219         fprintf(stderr,
220            "usage: bintrans qp [-u] [-o outputfile] [file name]\n");
221 }
222
223 int
224 main_quotedprintable(int argc, char *argv[])
225 {
226         int i;
227         bool encode = true;
228         FILE *fp = stdin;
229         FILE *fpo = stdout;
230
231         for (i = 1; i < argc; ++i) {
232                 if (argv[i][0] == '-') {
233                         switch (argv[i][1]) {
234                         case 'o':
235                                 if (++i >= argc) {
236                                         fprintf(stderr, "qp: -o requires a file name.\n");
237                                         exit(EXIT_FAILURE);
238                                 }
239                                 fpo = fopen(argv[i], "w");
240                                 if (fpo == NULL) {
241                                         perror(argv[i]);
242                                         exit(EXIT_FAILURE);
243                                 }
244                                 break;
245                         case 'u':
246                                 encode = false;
247                                 break;
248                         default:
249                                 usage();
250                                 exit(EXIT_FAILURE);
251                         }
252                 } else {
253                         fp = fopen(argv[i], "r");
254                         if (fp == NULL) {
255                                 perror(argv[i]);
256                                 exit(EXIT_FAILURE);
257                         }
258                 }
259         }
260         if (encode)
261                 toqp(fp, fpo);
262         else
263                 fromqp(fp, fpo, NULL, 0);
264         return (0);
265 }