11507Shannesw/*-
21507Shannesw * SPDX-License-Identifier: BSD-2-Clause
31507Shannesw *
41507Shannesw * Copyright (c) 2022 The FreeBSD Foundation
51507Shannesw *
61507Shannesw * Redistribution and use in source and binary forms, with or without
71507Shannesw * modification, are permitted provided that the following conditions
81507Shannesw * are met:
91507Shannesw * 1. Redistributions of source code must retain the above copyright
101507Shannesw *    notice, this list of conditions and the following disclaimer.
111507Shannesw * 2. Redistributions in binary form must reproduce the above copyright
121507Shannesw *    notice, this list of conditions and the following disclaimer in the
131507Shannesw *    documentation and/or other materials provided with the distribution.
141507Shannesw *
151507Shannesw * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
161507Shannesw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
171507Shannesw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
181507Shannesw * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
191507Shannesw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
201507Shannesw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
211507Shannesw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
221507Shannesw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
231507Shannesw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
241507Shannesw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
251507Shannesw * SUCH DAMAGE.
261507Shannesw */
271507Shannesw
281507Shannesw#include <sys/param.h>
291507Shannesw#include <getopt.h>
301507Shannesw#include <libgen.h>
311507Shannesw#include <stdbool.h>
321507Shannesw#include <stdio.h>
331507Shannesw#include <stdlib.h>
341507Shannesw#include <string.h>
351507Shannesw#include <sysexits.h>
361507Shannesw
371507Shanneswextern int	main_decode(int, char *[]);
381507Shanneswextern int	main_encode(int, char *[]);
391507Shanneswextern int	main_base64_decode(const char *);
401507Shanneswextern int	main_base64_encode(const char *, const char *);
411507Shanneswextern int	main_quotedprintable(int, char*[]);
421507Shannesw
431507Shanneswstatic int	search(const char *const);
441507Shanneswstatic void	usage_base64(bool);
451507Shanneswstatic void	version_base64(void);
461507Shanneswstatic void	base64_encode_or_decode(int, char *[]);
471507Shannesw
481507Shanneswenum coders {
491507Shannesw	uuencode, uudecode, b64encode, b64decode, base64, qp
501507Shannesw};
511507Shannesw
521507Shanneswint
531507Shanneswmain(int argc, char *argv[])
541507Shannesw{
551507Shannesw	const char *const progname = getprogname();
561507Shannesw	int coder = search(progname);
571507Shannesw
581507Shannesw	if (coder == -1 && argc > 1) {
591507Shannesw		argc--;
601507Shannesw		argv++;
611507Shannesw		coder = search(argv[0]);
621507Shannesw	}
631507Shannesw	switch (coder) {
641507Shannesw	case uuencode:
651507Shannesw	case b64encode:
661507Shannesw		main_encode(argc, argv);
671507Shannesw		break;
681507Shannesw	case uudecode:
691507Shannesw	case b64decode:
701507Shannesw		main_decode(argc, argv);
711507Shannesw		break;
721507Shannesw	case base64:
731507Shannesw		base64_encode_or_decode(argc, argv);
741507Shannesw		break;
751507Shannesw	case qp:
761507Shannesw		main_quotedprintable(argc, argv);
771507Shannesw		break;
781507Shannesw	default:
791507Shannesw		(void)fprintf(stderr,
801507Shannesw		    "usage: %1$s <uuencode | uudecode> ...\n"
811507Shannesw		    "       %1$s <b64encode | b64decode> ...\n"
821507Shannesw		    "       %1$s <base64> ...\n"
831507Shannesw		    "       %1$s <qp> ...\n",
841507Shannesw		    progname);
851507Shannesw		exit(EX_USAGE);
861507Shannesw	}
871507Shannesw}
881507Shannesw
891507Shanneswstatic int
901507Shanneswsearch(const char *const progname)
911507Shannesw{
921507Shannesw#define DESIGNATE(item) [item] = #item
931507Shannesw	const char *const known[] = {
941507Shannesw		DESIGNATE(uuencode),
951507Shannesw		DESIGNATE(uudecode),
961507Shannesw		DESIGNATE(b64encode),
971507Shannesw		DESIGNATE(b64decode),
981507Shannesw		DESIGNATE(base64),
991507Shannesw		DESIGNATE(qp)
1001507Shannesw	};
1011507Shannesw
1021507Shannesw	for (size_t i = 0; i < nitems(known); i++)
1031507Shannesw		if (strcmp(progname, known[i]) == 0)
1041507Shannesw			return ((int)i);
1051507Shannesw	return (-1);
1061507Shannesw}
1071507Shannesw
1081507Shanneswstatic void
1091507Shanneswusage_base64(bool failure)
1101507Shannesw{
1111507Shannesw	(void)fputs("usage: base64 [-w col | --wrap=col] "
1121507Shannesw	    "[-d | --decode] [FILE]\n"
1131507Shannesw	    "       base64 --help\n"
1141507Shannesw	    "       base64 --version\n", stderr);
1151507Shannesw	exit(failure ? EXIT_FAILURE : EXIT_SUCCESS);
1161507Shannesw}
1171507Shannesw
1181507Shanneswstatic void
1191507Shanneswversion_base64(void)
1201507Shannesw{
1211507Shannesw	(void)fputs("FreeBSD base64\n", stderr);
1221507Shannesw	exit(EXIT_SUCCESS);
1231507Shannesw}
1241507Shannesw
1251507Shanneswstatic void
1261507Shanneswbase64_encode_or_decode(int argc, char *argv[])
1271507Shannesw{
1281507Shannesw	int ch;
1291507Shannesw	bool decode = false;
1301507Shannesw	const char *w = NULL;
1311507Shannesw	enum { HELP, VERSION };
1321507Shannesw	static const struct option opts[] =
1331507Shannesw	{
1341507Shannesw		{"decode",	no_argument,		NULL, 'd'},
1351507Shannesw		{"ignore-garbage",no_argument,		NULL, 'i'},
1361507Shannesw		{"wrap",	required_argument,	NULL, 'w'},
1371507Shannesw		{"help",	no_argument,		NULL, HELP},
1381507Shannesw		{"version",	no_argument,		NULL, VERSION},
1391507Shannesw		{NULL,		no_argument,		NULL, 0}
1401507Shannesw	};
1411507Shannesw
1421507Shannesw	while ((ch = getopt_long(argc, argv, "diw:", opts, NULL)) != -1)
1431507Shannesw		switch (ch) {
1441507Shannesw		case 'd':
1451507Shannesw			decode = true;
1461507Shannesw			break;
1471507Shannesw		case 'w':
1481507Shannesw			w = optarg;
1491507Shannesw			break;
1501507Shannesw		case 'i':
1511507Shannesw			/* silently ignore */
1521507Shannesw			break;
1531507Shannesw		case VERSION:
1541507Shannesw			version_base64();
1551507Shannesw			break;
1561507Shannesw		case HELP:
1571507Shannesw		default:
1581507Shannesw			usage_base64(ch == '?');
1591507Shannesw		}
1601507Shannesw
1611507Shannesw	if (decode)
1621507Shannesw		main_base64_decode(argv[optind]);
1631507Shannesw	else
1641507Shannesw		main_base64_encode(argv[optind], w);
1651507Shannesw}
1661507Shannesw