uudecode.c revision 1.11 1 1.11 kleink /* $NetBSD: uudecode.c,v 1.11 1999/03/18 23:57:11 kleink Exp $ */
2 1.5 jtc
3 1.5 jtc /*-
4 1.5 jtc * Copyright (c) 1983, 1993
5 1.5 jtc * The Regents of the University of California. All rights reserved.
6 1.1 cgd *
7 1.1 cgd * Redistribution and use in source and binary forms, with or without
8 1.1 cgd * modification, are permitted provided that the following conditions
9 1.1 cgd * are met:
10 1.1 cgd * 1. Redistributions of source code must retain the above copyright
11 1.1 cgd * notice, this list of conditions and the following disclaimer.
12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 cgd * notice, this list of conditions and the following disclaimer in the
14 1.1 cgd * documentation and/or other materials provided with the distribution.
15 1.1 cgd * 3. All advertising materials mentioning features or use of this software
16 1.1 cgd * must display the following acknowledgement:
17 1.1 cgd * This product includes software developed by the University of
18 1.1 cgd * California, Berkeley and its contributors.
19 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
20 1.1 cgd * may be used to endorse or promote products derived from this software
21 1.1 cgd * without specific prior written permission.
22 1.1 cgd *
23 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 1.1 cgd * SUCH DAMAGE.
34 1.1 cgd */
35 1.1 cgd
36 1.8 lukem #include <sys/cdefs.h>
37 1.8 lukem #ifndef lint
38 1.8 lukem __COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
39 1.8 lukem The Regents of the University of California. All rights reserved.\n");
40 1.8 lukem #endif
41 1.5 jtc
42 1.1 cgd #ifndef lint
43 1.5 jtc #if 0
44 1.5 jtc static char sccsid[] = "@(#)uudecode.c 8.2 (Berkeley) 4/2/94";
45 1.5 jtc #endif
46 1.11 kleink __RCSID("$NetBSD: uudecode.c,v 1.11 1999/03/18 23:57:11 kleink Exp $");
47 1.1 cgd #endif /* not lint */
48 1.1 cgd
49 1.1 cgd /*
50 1.1 cgd * uudecode [file ...]
51 1.1 cgd *
52 1.1 cgd * create the specified file, decoding as you go.
53 1.1 cgd * used with uuencode.
54 1.1 cgd */
55 1.1 cgd #include <sys/param.h>
56 1.1 cgd #include <sys/stat.h>
57 1.8 lukem #include <err.h>
58 1.8 lukem #include <errno.h>
59 1.8 lukem #include <locale.h>
60 1.1 cgd #include <pwd.h>
61 1.8 lukem #include <stdio.h>
62 1.8 lukem #include <string.h>
63 1.4 jtc #include <unistd.h>
64 1.10 hubertf #include <ctype.h>
65 1.10 hubertf #include <stdlib.h>
66 1.10 hubertf #include <limits.h>
67 1.1 cgd
68 1.8 lukem static int decode __P((void));
69 1.8 lukem static void usage __P((void));
70 1.8 lukem int main __P((int, char **));
71 1.8 lukem
72 1.11 kleink int pflag;
73 1.1 cgd char *filename;
74 1.1 cgd
75 1.3 jtc int
76 1.1 cgd main(argc, argv)
77 1.1 cgd int argc;
78 1.5 jtc char *argv[];
79 1.1 cgd {
80 1.11 kleink int ch, rval;
81 1.1 cgd
82 1.4 jtc setlocale(LC_ALL, "");
83 1.4 jtc
84 1.11 kleink pflag = 0;
85 1.11 kleink while ((ch = getopt(argc, argv, "p")) != -1)
86 1.11 kleink switch (ch) {
87 1.11 kleink case 'p':
88 1.11 kleink pflag = 1;
89 1.11 kleink break;
90 1.11 kleink default:
91 1.11 kleink usage();
92 1.11 kleink }
93 1.4 jtc argc -= optind;
94 1.4 jtc argv += optind;
95 1.4 jtc
96 1.4 jtc if (*argv) {
97 1.1 cgd rval = 0;
98 1.1 cgd do {
99 1.1 cgd if (!freopen(filename = *argv, "r", stdin)) {
100 1.8 lukem warnx("%s", *argv);
101 1.1 cgd rval = 1;
102 1.1 cgd continue;
103 1.1 cgd }
104 1.1 cgd rval |= decode();
105 1.1 cgd } while (*++argv);
106 1.1 cgd } else {
107 1.1 cgd filename = "stdin";
108 1.1 cgd rval = decode();
109 1.1 cgd }
110 1.1 cgd exit(rval);
111 1.1 cgd }
112 1.1 cgd
113 1.3 jtc static int
114 1.1 cgd decode()
115 1.1 cgd {
116 1.1 cgd struct passwd *pw;
117 1.8 lukem int n;
118 1.8 lukem char ch, *p;
119 1.10 hubertf int n1;
120 1.10 hubertf long mode;
121 1.10 hubertf char *fn;
122 1.1 cgd char buf[MAXPATHLEN];
123 1.1 cgd
124 1.1 cgd /* search for header line */
125 1.1 cgd do {
126 1.1 cgd if (!fgets(buf, sizeof(buf), stdin)) {
127 1.8 lukem warnx("%s: no \"begin\" line", filename);
128 1.1 cgd return(1);
129 1.1 cgd }
130 1.1 cgd } while (strncmp(buf, "begin ", 6));
131 1.10 hubertf /* must be followed by an octal mode and a space */
132 1.10 hubertf mode = strtol(buf + 6, &fn, 8);
133 1.10 hubertf if (fn == (buf+6) || !isspace(*fn) || mode==LONG_MIN || mode==LONG_MAX)
134 1.10 hubertf {
135 1.10 hubertf warnx("%s: invalid mode on \"begin\" line\n", filename);
136 1.10 hubertf return(1);
137 1.10 hubertf }
138 1.10 hubertf /* skip whitespace for file name */
139 1.10 hubertf while (*fn && isspace(*fn)) fn++;
140 1.10 hubertf if (*fn == 0) {
141 1.10 hubertf warnx("%s: no filename on \"begin\" line\n", filename);
142 1.10 hubertf return(1);
143 1.10 hubertf }
144 1.10 hubertf /* zap newline */
145 1.10 hubertf for (p = fn; *p && *p != '\n'; p++)
146 1.10 hubertf ;
147 1.10 hubertf if (*p) *p = 0;
148 1.10 hubertf
149 1.1 cgd /* handle ~user/file format */
150 1.10 hubertf if (*fn == '~') {
151 1.10 hubertf if (!(p = strchr(fn, '/'))) {
152 1.8 lukem warnx("%s: illegal ~user.", filename);
153 1.1 cgd return(1);
154 1.1 cgd }
155 1.7 pk *p++ = '\0';
156 1.10 hubertf if (!(pw = getpwnam(fn + 1))) {
157 1.8 lukem warnx("%s: no user %s.", filename, buf);
158 1.1 cgd return(1);
159 1.1 cgd }
160 1.1 cgd n = strlen(pw->pw_dir);
161 1.1 cgd n1 = strlen(p);
162 1.1 cgd if (n + n1 + 2 > MAXPATHLEN) {
163 1.8 lukem warnx("%s: path too long.", filename);
164 1.1 cgd return(1);
165 1.1 cgd }
166 1.10 hubertf /* make space at beginning of buf by moving end of pathname */
167 1.8 lukem memmove(buf + n + 1, p, n1 + 1);
168 1.8 lukem memmove(buf, pw->pw_dir, n);
169 1.1 cgd buf[n] = '/';
170 1.10 hubertf fn = buf;
171 1.1 cgd }
172 1.1 cgd
173 1.1 cgd /* create output file, set mode */
174 1.11 kleink if (!pflag && (!freopen(buf, "w", stdout) ||
175 1.11 kleink fchmod(fileno(stdout), mode & 0666))) {
176 1.10 hubertf warnx("%s: %s", fn, filename);
177 1.1 cgd return(1);
178 1.1 cgd }
179 1.1 cgd
180 1.1 cgd /* for each input line */
181 1.1 cgd for (;;) {
182 1.1 cgd if (!fgets(p = buf, sizeof(buf), stdin)) {
183 1.8 lukem warnx("%s: short file.", filename);
184 1.1 cgd return(1);
185 1.1 cgd }
186 1.1 cgd #define DEC(c) (((c) - ' ') & 077) /* single character decode */
187 1.1 cgd /*
188 1.1 cgd * `n' is used to avoid writing out all the characters
189 1.1 cgd * at the end of the file.
190 1.1 cgd */
191 1.1 cgd if ((n = DEC(*p)) <= 0)
192 1.1 cgd break;
193 1.1 cgd for (++p; n > 0; p += 4, n -= 3)
194 1.1 cgd if (n >= 3) {
195 1.1 cgd ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
196 1.1 cgd putchar(ch);
197 1.1 cgd ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
198 1.1 cgd putchar(ch);
199 1.1 cgd ch = DEC(p[2]) << 6 | DEC(p[3]);
200 1.1 cgd putchar(ch);
201 1.1 cgd }
202 1.1 cgd else {
203 1.1 cgd if (n >= 1) {
204 1.1 cgd ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
205 1.1 cgd putchar(ch);
206 1.1 cgd }
207 1.1 cgd if (n >= 2) {
208 1.1 cgd ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
209 1.1 cgd putchar(ch);
210 1.1 cgd }
211 1.1 cgd if (n >= 3) {
212 1.1 cgd ch = DEC(p[2]) << 6 | DEC(p[3]);
213 1.1 cgd putchar(ch);
214 1.1 cgd }
215 1.1 cgd }
216 1.1 cgd }
217 1.1 cgd if (!fgets(buf, sizeof(buf), stdin) || strcmp(buf, "end\n")) {
218 1.8 lukem warnx("%s: no \"end\" line.", filename);
219 1.1 cgd return(1);
220 1.1 cgd }
221 1.1 cgd return(0);
222 1.1 cgd }
223 1.1 cgd
224 1.3 jtc static void
225 1.1 cgd usage()
226 1.1 cgd {
227 1.11 kleink (void)fprintf(stderr, "usage: uudecode [ -p ] [ file ... ]\n");
228 1.1 cgd exit(1);
229 1.1 cgd }
230