]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/uudecode/uudecode.c
This commit was generated by cvs2svn to compensate for changes in r93787,
[FreeBSD/FreeBSD.git] / usr.bin / uudecode / uudecode.c
1 /*-
2  * Copyright (c) 1983, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #ifndef lint
35 static const char copyright[] =
36 "@(#) Copyright (c) 1983, 1993\n\
37         The Regents of the University of California.  All rights reserved.\n";
38 #endif /* not lint */
39
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)uudecode.c  8.2 (Berkeley) 4/2/94";
43 #endif
44 static const char rcsid[] =
45   "$FreeBSD$";
46 #endif /* not lint */
47
48 /*
49  * uudecode [file ...]
50  *
51  * create the specified file, decoding as you go.
52  * used with uuencode.
53  */
54 #include <sys/param.h>
55 #include <sys/socket.h>
56 #include <sys/stat.h>
57
58 #include <netinet/in.h>
59
60 #include <err.h>
61 #include <pwd.h>
62 #include <resolv.h>
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <string.h>
66 #include <unistd.h>
67
68 const char *filename;
69 char *outfile;
70 int cflag, iflag, oflag, pflag, sflag;
71
72 static void usage(void);
73 int     decode(void);
74 int     decode2(int);
75 void    base64_decode(const char *);
76
77 int
78 main(argc, argv)
79         int argc;
80         char *argv[];
81 {
82         int rval, ch;
83
84         while ((ch = getopt(argc, argv, "cio:ps")) != -1) {
85                 switch(ch) {
86                 case 'c':
87                         if (oflag)
88                                 usage();
89                         cflag = 1; /* multiple uudecode'd files */
90                         break;
91                 case 'i':
92                         iflag = 1; /* ask before override files */
93                         break;
94                 case 'o':
95                         if (cflag || pflag || sflag)
96                                 usage();
97                         oflag = 1; /* output to the specified file */
98                         sflag = 1; /* do not strip pathnames for output */
99                         outfile = optarg; /* set the output filename */
100                         break;
101                 case 'p':
102                         if (oflag)
103                                 usage();
104                         pflag = 1; /* print output to stdout */
105                         break;
106                 case 's':
107                         if (oflag)
108                                 usage();
109                         sflag = 1; /* do not strip pathnames for output */
110                         break;
111                 default:
112                         usage();
113                 }
114         }
115         argc -= optind;
116         argv += optind;
117
118                         
119         if (*argv) {
120                 rval = 0;
121                 do {
122                         if (!freopen(filename = *argv, "r", stdin)) {
123                                 warn("%s", *argv);
124                                 rval = 1;
125                                 continue;
126                         }
127                         rval |= decode();
128                 } while (*++argv);
129         } else {
130                 filename = "stdin";
131                 rval = decode();
132         }
133         exit(rval);
134 }
135
136 int
137 decode ()
138 {
139         int flag;
140
141         /* decode only one file per input stream */
142         if (!cflag) 
143                 return(decode2(0));
144
145         /* multiple uudecode'd files */
146         for (flag = 0; ; flag++)
147                 if (decode2(flag))
148                         return(1);
149                 else if (feof(stdin))
150                         break;
151
152         return(0);
153 }
154
155 int
156 decode2(flag)
157         int flag;
158 {
159         struct passwd *pw;
160         register int n;
161         register char ch, *p;
162         int base64, ignore, n1;
163         char buf[MAXPATHLEN+1];
164         char buffn[MAXPATHLEN+1]; /* file name buffer */
165         char *mode, *s;
166         void *mode_handle;
167
168         base64 = ignore = 0;
169         /* search for header line */
170         do {
171                 if (!fgets(buf, sizeof(buf), stdin)) {
172                         if (flag) /* no error */
173                                 return(0);
174
175                         warnx("%s: no \"begin\" line", filename);
176                         return(1);
177                 }
178         } while (strncmp(buf, "begin", 5) != 0);
179
180         if (strncmp(buf, "begin-base64", 12) == 0)
181                 base64 = 1;
182
183         /* Parse the header: begin{,-base64} mode outfile. */
184         s = strtok(buf, " ");
185         if (s == NULL)
186                 errx(1, "no mode or filename in input file");
187         s = strtok(NULL, " ");
188         if (s == NULL)
189                 errx(1, "no mode in input file");
190         else {
191                 mode = strdup(s);
192                 if (mode == NULL)
193                         err(1, "strdup()");
194         }
195         if (!oflag) {
196                 outfile = strtok(NULL, "\r\n");
197                 if (outfile == NULL)
198                         errx(1, "no filename in input file");
199         }
200
201         if (strlcpy(buf, outfile, sizeof(buf)) >= sizeof(buf))
202                 errx(1, "%s: filename too long", outfile);
203         if (!sflag && !pflag) {
204                 strlcpy(buffn, buf, sizeof(buffn)); 
205                 if (strrchr(buffn, '/') != NULL)
206                         strncpy(buf, strrchr(buffn, '/') + 1, sizeof(buf));
207                 if (buf[0] == '\0') {
208                         warnx("%s: illegal filename", buffn);
209                         return(1);
210                 }
211
212                 /* handle ~user/file format */
213                 if (buf[0] == '~') {
214                         if (!(p = index(buf, '/'))) {
215                                 warnx("%s: illegal ~user", filename);
216                                 return(1);
217                         }
218                         *p++ = '\0';
219                         if (!(pw = getpwnam(buf + 1))) {
220                                 warnx("%s: no user %s", filename, buf);
221                                 return(1);
222                         }
223                         n = strlen(pw->pw_dir);
224                         n1 = strlen(p);
225                         if (n + n1 + 2 > MAXPATHLEN) {
226                                 warnx("%s: path too long", filename);
227                                 return(1);
228                         }
229                         bcopy(p, buf + n + 1, n1 + 1);
230                         bcopy(pw->pw_dir, buf, n);
231                         buf[n] = '/';
232                 }
233         }
234
235         /* create output file, set mode */
236         if (pflag)
237                 ; /* print to stdout */
238
239         else {
240                 mode_handle = setmode(mode);
241                 if (mode_handle == NULL)
242                         err(1, "setmode()");
243                 if (iflag && !access(buf, F_OK)) {
244                         (void)fprintf(stderr, "not overwritten: %s\n", buf);
245                         ignore++;
246                 } else if (!freopen(buf, "w", stdout) ||
247                     fchmod(fileno(stdout), getmode(mode_handle, 0) & 0666)) {
248                         warn("%s: %s", buf, filename);
249                         return(1);
250                 }
251                 free(mode_handle);
252                 free(mode);
253         }
254         strcpy(buffn, buf); /* store file name from header line */
255
256         /* for each input line */
257 next:
258         for (;;) {
259                 if (!fgets(p = buf, sizeof(buf), stdin)) {
260                         warnx("%s: short file", filename);
261                         return(1);
262                 }
263                 if (base64) {
264                         if (strncmp(buf, "====", 4) == 0)
265                                 return (0);
266                         base64_decode(buf);
267                         goto next;
268                 }
269 #define DEC(c)  (((c) - ' ') & 077)             /* single character decode */
270 #define IS_DEC(c) ( (((c) - ' ') >= 0) &&  (((c) - ' ') <= 077 + 1) )
271 /* #define IS_DEC(c) (1) */
272
273 #define OUT_OF_RANGE \
274 {       \
275     warnx( \
276 "\n\tinput file: %s\n\tencoded file: %s\n\tcharacter out of range: [%d-%d]", \
277         filename, buffn, 1 + ' ', 077 + ' ' + 1); \
278         return(1); \
279 }
280 #define PUTCHAR(c) \
281 if (!ignore) \
282         putchar(c)
283
284
285                 /*
286                  * `n' is used to avoid writing out all the characters
287                  * at the end of the file.
288                  */
289                 if ((n = DEC(*p)) <= 0)
290                         break;
291                 for (++p; n > 0; p += 4, n -= 3)
292                         if (n >= 3) {
293                                 if (!(IS_DEC(*p) && IS_DEC(*(p + 1)) && 
294                                      IS_DEC(*(p + 2)) && IS_DEC(*(p + 3))))
295                                         OUT_OF_RANGE
296
297                                 ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
298                                 PUTCHAR(ch);
299                                 ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
300                                 PUTCHAR(ch);
301                                 ch = DEC(p[2]) << 6 | DEC(p[3]);
302                                 PUTCHAR(ch);
303                                 
304                         }
305                         else {
306                                 if (n >= 1) {
307                                         if (!(IS_DEC(*p) && IS_DEC(*(p + 1))))
308                                                 OUT_OF_RANGE
309                                         ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
310                                         PUTCHAR(ch);
311                                 }
312                                 if (n >= 2) {
313                                         if (!(IS_DEC(*(p + 1)) && 
314                                                 IS_DEC(*(p + 2))))
315                                                 OUT_OF_RANGE
316
317                                         ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
318                                         PUTCHAR(ch);
319                                 }
320                                 if (n >= 3) {
321                                         if (!(IS_DEC(*(p + 2)) && 
322                                                 IS_DEC(*(p + 3))))
323                                                 OUT_OF_RANGE
324                                         ch = DEC(p[2]) << 6 | DEC(p[3]);
325                                         PUTCHAR(ch);
326                                 }
327                         }
328         }
329         if (fgets(buf, sizeof(buf), stdin) == NULL || 
330             (strcmp(buf, "end") && strcmp(buf, "end\n") &&
331              strcmp(buf, "end\r\n"))) {
332                 warnx("%s: no \"end\" line", filename);
333                 return(1);
334         }
335         return(0);
336 }
337
338 void
339 base64_decode(stream)
340         const char *stream;
341 {
342         unsigned char out[MAXPATHLEN * 4];
343         int rv;
344
345         rv = b64_pton(stream, out, (sizeof(out) / sizeof(out[0])));
346         if (rv == -1)
347                 errx(1, "b64_pton: error decoding base64 input stream");
348         printf("%s", out);
349 }
350
351 static void
352 usage()
353 {
354         (void)fprintf(stderr, "usage: uudecode [-cips] [file ...]\n");
355         (void)fprintf(stderr, "usage: uudecode [-i] -o output_file [file]\n");
356         exit(1);
357 }