]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/uudecode/uudecode.c
This commit was generated by cvs2svn to compensate for changes in r80785,
[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/stat.h>
56
57 #include <err.h>
58 #include <fnmatch.h>
59 #include <pwd.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <unistd.h>
64
65 char *filename;
66 int cflag, iflag, pflag, sflag;
67
68 static void usage __P((void));
69 int     decode __P((void));
70 int     decode2 __P((int));
71
72 int
73 main(argc, argv)
74         int argc;
75         char *argv[];
76 {
77         int rval, ch;
78
79         while ((ch = getopt(argc, argv, "cips")) != -1) {
80                 switch(ch) {
81                 case 'c':
82                         cflag = 1; /* multiple uudecode'd files */
83                         break;
84                 case 'i':
85                         iflag = 1; /* ask before override files */
86                         break;
87                 case 'p':
88                         pflag = 1; /* print output to stdout */
89                         break;
90                 case 's':
91                         sflag = 1; /* do not strip pathnames for output */
92                         break;
93                 default:
94                         usage();
95                 }
96         }
97         argc -= optind;
98         argv += optind;
99
100                         
101         if (*argv) {
102                 rval = 0;
103                 do {
104                         if (!freopen(filename = *argv, "r", stdin)) {
105                                 warn("%s", *argv);
106                                 rval = 1;
107                                 continue;
108                         }
109                         rval |= decode();
110                 } while (*++argv);
111         } else {
112                 filename = "stdin";
113                 rval = decode();
114         }
115         exit(rval);
116 }
117
118 int
119 decode ()
120 {
121         int flag;
122
123         /* decode only one file per input stream */
124         if (!cflag) 
125                 return(decode2(0));
126
127         /* multiple uudecode'd files */
128         for (flag = 0; ; flag++)
129                 if (decode2(flag))
130                         return(1);
131                 else if (feof(stdin))
132                         break;
133
134         return(0);
135 }
136
137 int
138 decode2(flag)
139         int flag;
140 {
141         struct passwd *pw;
142         register int n;
143         register char ch, *p;
144         int ignore, mode, n1;
145         char buf[MAXPATHLEN];
146         char buffn[MAXPATHLEN]; /* file name buffer */
147
148         ignore = 0;
149         /* search for header line */
150         do {
151                 if (!fgets(buf, sizeof(buf), stdin)) {
152                         if (flag) /* no error */
153                                 return(0);
154
155                         warnx("%s: no \"begin\" line", filename);
156                         return(1);
157                 }
158         } while (strncmp(buf, "begin ", 6) || 
159                  fnmatch("begin [0-7]* *", buf, 0));
160
161         (void)sscanf(buf, "begin %o %[^\n\r]", &mode, buf);
162
163         if (!sflag && !pflag) {
164                 strncpy(buffn, buf, sizeof(buffn)); 
165                 if (strrchr(buffn, '/') != NULL)
166                         strncpy(buf, strrchr(buffn, '/') + 1, sizeof(buf));
167                 if (buf[0] == '\0') {
168                         warnx("%s: illegal filename", buffn);
169                         return(1);
170                 }
171         }
172
173         /* handle ~user/file format */
174         if (buf[0] == '~') {
175                 if (!(p = index(buf, '/'))) {
176                         warnx("%s: illegal ~user", filename);
177                         return(1);
178                 }
179                 *p++ = '\0';
180                 if (!(pw = getpwnam(buf + 1))) {
181                         warnx("%s: no user %s", filename, buf);
182                         return(1);
183                 }
184                 n = strlen(pw->pw_dir);
185                 n1 = strlen(p);
186                 if (n + n1 + 2 > MAXPATHLEN) {
187                         warnx("%s: path too long", filename);
188                         return(1);
189                 }
190                 bcopy(p, buf + n + 1, n1 + 1);
191                 bcopy(pw->pw_dir, buf, n);
192                 buf[n] = '/';
193         }
194
195         /* create output file, set mode */
196         if (pflag)
197                 ; /* print to stdout */
198
199         else {
200                 if (iflag && !access(buf, F_OK)) {
201                         (void)fprintf(stderr, "not overwritten: %s\n", buf);
202                         ignore++;
203                 } else if (!freopen(buf, "w", stdout) ||
204                     fchmod(fileno(stdout), mode&0666)) {
205                         warn("%s: %s", buf, filename);
206                         return(1);
207                 }
208         }
209         strcpy(buffn, buf); /* store file name from header line */
210
211         /* for each input line */
212         for (;;) {
213                 if (!fgets(p = buf, sizeof(buf), stdin)) {
214                         warnx("%s: short file", filename);
215                         return(1);
216                 }
217 #define DEC(c)  (((c) - ' ') & 077)             /* single character decode */
218 #define IS_DEC(c) ( (((c) - ' ') >= 0) &&  (((c) - ' ') <= 077 + 1) )
219 /* #define IS_DEC(c) (1) */
220
221 #define OUT_OF_RANGE \
222 {       \
223     warnx( \
224 "\n\tinput file: %s\n\tencoded file: %s\n\tcharacter out of range: [%d-%d]", \
225         filename, buffn, 1 + ' ', 077 + ' ' + 1); \
226         return(1); \
227 }
228 #define PUTCHAR(c) \
229 if (!ignore) \
230         putchar(c)
231
232
233                 /*
234                  * `n' is used to avoid writing out all the characters
235                  * at the end of the file.
236                  */
237                 if ((n = DEC(*p)) <= 0)
238                         break;
239                 for (++p; n > 0; p += 4, n -= 3)
240                         if (n >= 3) {
241                                 if (!(IS_DEC(*p) && IS_DEC(*(p + 1)) && 
242                                      IS_DEC(*(p + 2)) && IS_DEC(*(p + 3))))
243                                         OUT_OF_RANGE
244
245                                 ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
246                                 PUTCHAR(ch);
247                                 ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
248                                 PUTCHAR(ch);
249                                 ch = DEC(p[2]) << 6 | DEC(p[3]);
250                                 PUTCHAR(ch);
251                                 
252                         }
253                         else {
254                                 if (n >= 1) {
255                                         if (!(IS_DEC(*p) && IS_DEC(*(p + 1))))
256                                                 OUT_OF_RANGE
257                                         ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
258                                         PUTCHAR(ch);
259                                 }
260                                 if (n >= 2) {
261                                         if (!(IS_DEC(*(p + 1)) && 
262                                                 IS_DEC(*(p + 2))))
263                                                 OUT_OF_RANGE
264
265                                         ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
266                                         PUTCHAR(ch);
267                                 }
268                                 if (n >= 3) {
269                                         if (!(IS_DEC(*(p + 2)) && 
270                                                 IS_DEC(*(p + 3))))
271                                                 OUT_OF_RANGE
272                                         ch = DEC(p[2]) << 6 | DEC(p[3]);
273                                         PUTCHAR(ch);
274                                 }
275                         }
276         }
277         if (fgets(buf, sizeof(buf), stdin) == NULL || 
278             (strcmp(buf, "end") && strcmp(buf, "end\n") &&
279              strcmp(buf, "end\r\n"))) {
280                 warnx("%s: no \"end\" line", filename);
281                 return(1);
282         }
283         return(0);
284 }
285
286 static void
287 usage()
288 {
289         (void)fprintf(stderr, "usage: uudecode [-cips] [file ...]\n");
290         exit(1);
291 }