xref: /openbsd-src/usr.bin/uuencode/uuencode.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: uuencode.c,v 1.9 2008/07/29 18:25:28 sobrado Exp $	*/
2 /*	$FreeBSD: uuencode.c,v 1.18 2004/01/22 07:23:35 grehan Exp $	*/
3 
4 /*-
5  * Copyright (c) 1983, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #ifndef lint
34 static const char copyright[] =
35 "@(#) Copyright (c) 1983, 1993\n\
36 	The Regents of the University of California.  All rights reserved.\n";
37 #endif /* not lint */
38 
39 #ifndef lint
40 #if 0
41 static const char sccsid[] = "@(#)uuencode.c	8.2 (Berkeley) 4/2/94";
42 #endif
43 static const char rcsid[] = "$OpenBSD: uuencode.c,v 1.9 2008/07/29 18:25:28 sobrado Exp $";
44 #endif /* not lint */
45 
46 /*
47  * Encode a file so it can be mailed to a remote system.
48  */
49 
50 #include <sys/param.h>
51 #include <sys/socket.h>
52 #include <sys/stat.h>
53 
54 #include <netinet/in.h>
55 
56 #include <err.h>
57 #include <locale.h>
58 #include <resolv.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <unistd.h>
63 
64 void encode(void);
65 void base64_encode(void);
66 static void usage(void);
67 
68 FILE *output;
69 int mode;
70 char **av;
71 
72 enum program_mode {
73 	MODE_ENCODE,
74 	MODE_B64ENCODE
75 } pmode;
76 
77 int
78 main(int argc, char *argv[])
79 {
80 	struct stat sb;
81 	int base64, ch;
82 	char *outfile;
83 	extern char *__progname;
84 	static const char *optstr[2] = {
85 		"mo:",
86 		"o:"
87 	};
88 
89 	base64 = 0;
90 	outfile = NULL;
91 
92 	pmode = MODE_ENCODE;
93 	if (strcmp(__progname, "b64encode") == 0) {
94 		base64 = 1;
95 		pmode = MODE_B64ENCODE;
96 	}
97 
98 	setlocale(LC_ALL, "");
99 	while ((ch = getopt(argc, argv, optstr[pmode])) != -1) {
100 		switch (ch) {
101 		case 'm':
102 			base64 = 1;
103 			break;
104 		case 'o':
105 			outfile = optarg;
106 			break;
107 		case '?':
108 		default:
109 			usage();
110 		}
111 	}
112 	argv += optind;
113 	argc -= optind;
114 
115 	switch(argc) {
116 	case 2:			/* optional first argument is input file */
117 		if (!freopen(*argv, "r", stdin) || fstat(fileno(stdin), &sb))
118 			err(1, "%s", *argv);
119 #define	RWX	(S_IRWXU|S_IRWXG|S_IRWXO)
120 		mode = sb.st_mode & RWX;
121 		++argv;
122 		break;
123 	case 1:
124 #define	RW	(S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
125 		mode = RW & ~umask(RW);
126 		break;
127 	case 0:
128 	default:
129 		usage();
130 	}
131 
132 	av = argv;
133 
134 	if (outfile != NULL) {
135 		output = fopen(outfile, "w+");
136 		if (output == NULL)
137 			err(1, "unable to open %s for output", outfile);
138 	} else
139 		output = stdout;
140 	if (base64)
141 		base64_encode();
142 	else
143 		encode();
144 	if (ferror(output))
145 		errx(1, "write error");
146 	exit(0);
147 }
148 
149 /* ENC is the basic 1 character encoding function to make a char printing */
150 #define	ENC(c) ((c) ? ((c) & 077) + ' ': '`')
151 
152 /*
153  * Copy from in to out, encoding in base64 as you go along.
154  */
155 void
156 base64_encode(void)
157 {
158 	/*
159 	 * Output must fit into 80 columns, chunks come in 4, leave 1.
160 	 */
161 #define	GROUPS	((80 / 4) - 1)
162 	unsigned char buf[3];
163 	char buf2[sizeof(buf) * 2 + 1];
164 	size_t n;
165 	int rv, sequence;
166 
167 	sequence = 0;
168 
169 	fprintf(output, "begin-base64 %o %s\n", mode, *av);
170 	while ((n = fread(buf, 1, sizeof(buf), stdin))) {
171 		++sequence;
172 		rv = b64_ntop(buf, n, buf2, (sizeof(buf2) / sizeof(buf2[0])));
173 		if (rv == -1)
174 			errx(1, "b64_ntop: error encoding base64");
175 		fprintf(output, "%s%s", buf2, (sequence % GROUPS) ? "" : "\n");
176 	}
177 	if (sequence % GROUPS)
178 		fprintf(output, "\n");
179 	fprintf(output, "====\n");
180 }
181 
182 /*
183  * Copy from in to out, encoding as you go along.
184  */
185 void
186 encode(void)
187 {
188 	int ch, n;
189 	char *p;
190 	char buf[80];
191 
192 	(void)fprintf(output, "begin %o %s\n", mode, *av);
193 	while ((n = fread(buf, 1, 45, stdin))) {
194 		ch = ENC(n);
195 		if (fputc(ch, output) == EOF)
196 			break;
197 		for (p = buf; n > 0; n -= 3, p += 3) {
198 			/* Pad with nulls if not a multiple of 3. */
199 			if (n < 3) {
200 				p[2] = '\0';
201 				if (n < 2)
202 					p[1] = '\0';
203 			}
204 			ch = *p >> 2;
205 			ch = ENC(ch);
206 			if (fputc(ch, output) == EOF)
207 				break;
208 			ch = ((*p << 4) & 060) | ((p[1] >> 4) & 017);
209 			ch = ENC(ch);
210 			if (fputc(ch, output) == EOF)
211 				break;
212 			ch = ((p[1] << 2) & 074) | ((p[2] >> 6) & 03);
213 			ch = ENC(ch);
214 			if (fputc(ch, output) == EOF)
215 				break;
216 			ch = p[2] & 077;
217 			ch = ENC(ch);
218 			if (fputc(ch, output) == EOF)
219 				break;
220 		}
221 		if (fputc('\n', output) == EOF)
222 			break;
223 	}
224 	if (ferror(stdin))
225 		errx(1, "read error");
226 	(void)fprintf(output, "%c\nend\n", ENC('\0'));
227 }
228 
229 static void
230 usage(void)
231 {
232 	switch (pmode) {
233 	case MODE_ENCODE:
234 		(void)fprintf(stderr,
235 		    "usage: uuencode [-m] [-o output_file] [file] name\n");
236 		break;
237 	case MODE_B64ENCODE:
238 		(void)fprintf(stderr,
239 		    "usage: b64encode [-o output_file] [file] name\n");
240 		break;
241 	}
242 	exit(1);
243 }
244