blob: ff4a9d9e6b272d02bbf1f97c9cc724c116f7609a [file] [log] [blame]
Eric Andersen2b6ab3c2000-06-13 06:54:53 +00001/* uudecode.c -- uudecode utility.
2 * Copyright (C) 1994, 1995 Free Software Foundation, Inc.
3 *
4 * This product is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This product is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this product; see the file COPYING. If not, write to
16 * the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
Eric Andersen4e573f42000-11-14 23:29:24 +000018 *
19 * Reworked to GNU style by Ian Lance Taylor, ian@airs.com, August 93.
20 *
21 * Original copyright notice is retained at the end of this file.
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000022 */
23
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000024
Eric Andersen3570a342000-09-25 21:45:58 +000025#include "busybox.h"
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000026
27#include <stdio.h>
28#include <errno.h>
Eric Andersen999bf722000-07-09 06:59:58 +000029#include <getopt.h>
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000030#include <pwd.h>
31
32/*struct passwd *getpwnam();*/
33
34/* Single character decode. */
35#define DEC(Char) (((Char) - ' ') & 077)
36
37static int read_stduu (const char *inname)
38{
39 char buf[2 * BUFSIZ];
40
41 while (1) {
42 int n;
43 char *p;
44
45 if (fgets (buf, sizeof(buf), stdin) == NULL) {
Mark Whitleyf57c9442000-12-07 19:56:48 +000046 error_msg("%s: Short file\n", inname);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000047 return FALSE;
48 }
49 p = buf;
50
51 /* N is used to avoid writing out all the characters at the end of
52 the file. */
53 n = DEC (*p);
54 if (n <= 0)
55 break;
56 for (++p; n > 0; p += 4, n -= 3) {
57 char ch;
58
59 if (n >= 3) {
60 ch = DEC (p[0]) << 2 | DEC (p[1]) >> 4;
61 putchar (ch);
62 ch = DEC (p[1]) << 4 | DEC (p[2]) >> 2;
63 putchar (ch);
64 ch = DEC (p[2]) << 6 | DEC (p[3]);
65 putchar (ch);
66 } else {
67 if (n >= 1) {
68 ch = DEC (p[0]) << 2 | DEC (p[1]) >> 4;
69 putchar (ch);
70 }
71 if (n >= 2) {
72 ch = DEC (p[1]) << 4 | DEC (p[2]) >> 2;
73 putchar (ch);
74 }
75 }
76 }
77 }
78
79 if (fgets (buf, sizeof(buf), stdin) == NULL
80 || strcmp (buf, "end\n")) {
Mark Whitleyf57c9442000-12-07 19:56:48 +000081 error_msg("%s: No `end' line\n", inname);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +000082 return FALSE;
83 }
84
85 return TRUE;
86}
87
88static int read_base64 (const char *inname)
89{
90 static const char b64_tab[256] = {
91 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*000-007*/
92 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*010-017*/
93 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*020-027*/
94 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*030-037*/
95 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*040-047*/
96 '\177', '\177', '\177', '\76', '\177', '\177', '\177', '\77', /*050-057*/
97 '\64', '\65', '\66', '\67', '\70', '\71', '\72', '\73', /*060-067*/
98 '\74', '\75', '\177', '\177', '\177', '\100', '\177', '\177', /*070-077*/
99 '\177', '\0', '\1', '\2', '\3', '\4', '\5', '\6', /*100-107*/
100 '\7', '\10', '\11', '\12', '\13', '\14', '\15', '\16', /*110-117*/
101 '\17', '\20', '\21', '\22', '\23', '\24', '\25', '\26', /*120-127*/
102 '\27', '\30', '\31', '\177', '\177', '\177', '\177', '\177', /*130-137*/
103 '\177', '\32', '\33', '\34', '\35', '\36', '\37', '\40', /*140-147*/
104 '\41', '\42', '\43', '\44', '\45', '\46', '\47', '\50', /*150-157*/
105 '\51', '\52', '\53', '\54', '\55', '\56', '\57', '\60', /*160-167*/
106 '\61', '\62', '\63', '\177', '\177', '\177', '\177', '\177', /*170-177*/
107 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*200-207*/
108 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*210-217*/
109 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*220-227*/
110 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*230-237*/
111 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*240-247*/
112 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*250-257*/
113 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*260-267*/
114 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*270-277*/
115 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*300-307*/
116 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*310-317*/
117 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*320-327*/
118 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*330-337*/
119 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*340-347*/
120 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*350-357*/
121 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*360-367*/
122 '\177', '\177', '\177', '\177', '\177', '\177', '\177', '\177', /*370-377*/
123 };
124 unsigned char buf[2 * BUFSIZ];
125
126 while (1) {
127 int last_data = 0;
128 unsigned char *p;
129
130 if (fgets (buf, sizeof(buf), stdin) == NULL) {
Mark Whitleyf57c9442000-12-07 19:56:48 +0000131 error_msg("%s: Short file\n", inname);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000132 return FALSE;
133 }
134 p = buf;
135
136 if (memcmp (buf, "====", 4) == 0)
137 break;
138 if (last_data != 0) {
Mark Whitleyf57c9442000-12-07 19:56:48 +0000139 error_msg("%s: data following `=' padding character\n", inname);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000140 return FALSE;
141 }
142
143 /* The following implementation of the base64 decoding might look
144 a bit clumsy but I only try to follow the POSIX standard:
145 ``All line breaks or other characters not found in the table
146 [with base64 characters] shall be ignored by decoding
147 software.'' */
148 while (*p != '\n') {
149 char c1, c2, c3;
150
151 while ((b64_tab[*p] & '\100') != 0)
152 if (*p == '\n' || *p++ == '=')
153 break;
154 if (*p == '\n')
155 /* This leaves the loop. */
156 continue;
157 c1 = b64_tab[*p++];
158
159 while ((b64_tab[*p] & '\100') != 0)
160 if (*p == '\n' || *p++ == '=') {
Mark Whitleyf57c9442000-12-07 19:56:48 +0000161 error_msg("%s: illegal line\n", inname);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000162 return FALSE;
163 }
164 c2 = b64_tab[*p++];
165
166 while (b64_tab[*p] == '\177')
167 if (*p++ == '\n') {
Mark Whitleyf57c9442000-12-07 19:56:48 +0000168 error_msg("%s: illegal line\n", inname);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000169 return FALSE;
170 }
171 if (*p == '=') {
172 putchar (c1 << 2 | c2 >> 4);
173 last_data = 1;
174 break;
175 }
176 c3 = b64_tab[*p++];
177
178 while (b64_tab[*p] == '\177')
179 if (*p++ == '\n') {
Mark Whitleyf57c9442000-12-07 19:56:48 +0000180 error_msg("%s: illegal line\n", inname);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000181 return FALSE;
182 }
183 putchar (c1 << 2 | c2 >> 4);
184 putchar (c2 << 4 | c3 >> 2);
185 if (*p == '=') {
186 last_data = 1;
187 break;
188 }
189 else
190 putchar (c3 << 6 | b64_tab[*p++]);
191 }
192 }
193
194 return TRUE;
195}
196
197static int decode (const char *inname,
198 const char *forced_outname)
199{
200 struct passwd *pw;
201 register int n;
202 register char *p;
203 int mode, n1;
204 char buf[2 * BUFSIZ];
205 char *outname;
206 int do_base64 = 0;
207
208 /* Search for header line. */
209
210 while (1) {
211 if (fgets (buf, sizeof (buf), stdin) == NULL) {
Mark Whitleyf57c9442000-12-07 19:56:48 +0000212 error_msg("%s: No `begin' line\n", inname);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000213 return FALSE;
214 }
215
216 if (strncmp (buf, "begin", 5) == 0) {
217 if (sscanf (buf, "begin-base64 %o %s", &mode, buf) == 2) {
218 do_base64 = 1;
219 break;
220 } else if (sscanf (buf, "begin %o %s", &mode, buf) == 2)
221 break;
222 }
223 }
224
225 /* If the output file name is given on the command line this rules. */
226 if (forced_outname != NULL)
227 outname = (char *) forced_outname;
228 else {
229 /* Handle ~user/file format. */
230 if (buf[0] != '~')
231 outname = buf;
232 else {
233 p = buf + 1;
234 while (*p != '/')
235 ++p;
236 if (*p == '\0') {
Mark Whitleyf57c9442000-12-07 19:56:48 +0000237 error_msg("%s: Illegal ~user\n", inname);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000238 return FALSE;
239 }
240 *p++ = '\0';
241 pw = getpwnam (buf + 1);
242 if (pw == NULL) {
Mark Whitleyf57c9442000-12-07 19:56:48 +0000243 error_msg("%s: No user `%s'\n", inname, buf + 1);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000244 return FALSE;
245 }
246 n = strlen (pw->pw_dir);
247 n1 = strlen (p);
248 outname = (char *) alloca ((size_t) (n + n1 + 2));
249 memcpy (outname + n + 1, p, (size_t) (n1 + 1));
250 memcpy (outname, pw->pw_dir, (size_t) n);
251 outname[n] = '/';
252 }
253 }
254
255 /* Create output file and set mode. */
256 if (strcmp (outname, "/dev/stdout") != 0 && strcmp (outname, "-") != 0
257 && (freopen (outname, "w", stdout) == NULL
258 || chmod (outname, mode & (S_IRWXU | S_IRWXG | S_IRWXO))
259 )) {
Mark Whitleyf57c9442000-12-07 19:56:48 +0000260 error_msg("%s: %s %s\n", outname, inname, strerror(errno)); /* */
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000261 return FALSE;
262 }
263
264 /* We differenciate decoding standard UU encoding and base64. A
265 common function would only slow down the program. */
266
267 /* For each input line: */
268 if (do_base64)
269 return read_base64 (inname);
270 else
271 return read_stduu (inname);
272}
273
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000274int uudecode_main (int argc,
275 char **argv)
276{
277 int opt;
278 int exit_status;
279 const char *outname;
280 outname = NULL;
281
282 while ((opt = getopt(argc, argv, "o:")) != EOF) {
283 switch (opt) {
284 case 0:
285 break;
286
287 case 'o':
288 outname = optarg;
289 break;
290
291 default:
292 usage(uudecode_usage);
293 }
294 }
295
296 if (optind == argc)
Matt Kraai3e856ce2000-12-01 02:55:13 +0000297 exit_status = decode ("stdin", outname) == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000298 else {
Matt Kraai3e856ce2000-12-01 02:55:13 +0000299 exit_status = EXIT_SUCCESS;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000300 do {
301 if (freopen (argv[optind], "r", stdin) != NULL) {
302 if (decode (argv[optind], outname) != 0)
303 exit_status = FALSE;
304 } else {
Mark Whitleyf57c9442000-12-07 19:56:48 +0000305 error_msg("%s: %s\n", argv[optind], strerror(errno));
Matt Kraai3e856ce2000-12-01 02:55:13 +0000306 exit_status = EXIT_FAILURE;
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000307 }
308 optind++;
309 }
310 while (optind < argc);
311 }
Eric Andersenb6106152000-06-19 17:25:40 +0000312 return(exit_status);
Eric Andersen2b6ab3c2000-06-13 06:54:53 +0000313}
Eric Andersen4e573f42000-11-14 23:29:24 +0000314
315/* Copyright (c) 1983 Regents of the University of California.
316 * All rights reserved.
317 *
318 * Redistribution and use in source and binary forms, with or without
319 * modification, are permitted provided that the following conditions
320 * are met:
321 * 1. Redistributions of source code must retain the above copyright
322 * notice, this list of conditions and the following disclaimer.
323 * 2. Redistributions in binary form must reproduce the above copyright
324 * notice, this list of conditions and the following disclaimer in the
325 * documentation and/or other materials provided with the distribution.
326 *
327 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
328 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
329 *
330 * 4. Neither the name of the University nor the names of its contributors
331 * may be used to endorse or promote products derived from this software
332 * without specific prior written permission.
333 *
334 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
335 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
336 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
337 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
338 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
339 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
340 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
341 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
342 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
343 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
344 * SUCH DAMAGE.
345 */
346
347