libgeminiclient/gemini-cat.c

133 lines
2.8 KiB
C

#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <err.h>
#include <sysexits.h>
#include <tls.h>
#include <libgeminiclient.h>
#ifndef BUFFER_SIZE
#define BUFFER_SIZE 4096
#endif
static ssize_t stripcntrl(char *, size_t, const char *, size_t);
int
main(int argc, char *argv[])
{
char b[BUFFER_SIZE];
struct gemini gemini = GEMINI_INITIALIZER;
ssize_t r;
size_t i;
int rawout;
int c;
rawout = !isatty(STDOUT_FILENO);
#ifdef __OpenBSD__
if (pledge("stdio cpath rpath wpath flock inet dns tty", NULL)
!= 0)
err(EX_NOPERM, "Failed pledge(2)");
#endif
while ((c = getopt(argc, argv, "RSc:ik:p:r:st:w")) != -1)
switch (c) {
case 'R':
rawout = 1;
break;
case 'S':
rawout = 0;
break;
case 'c':
gemini.certfile = optarg;
break;
case 'i':
gemini.flags |= GEMINI_PROMPT;
break;
case 'k':
gemini.keyfile = optarg;
break;
case 'p':
for (i = 0, gemini.port = 0;
optarg[i] >= '0' && optarg[i] <= '9'; i++)
gemini.port = gemini.port * 10 +
optarg[i] - '0';
break;
case 'r':
for (i = 0, gemini.maxredirects = 0;
gemini.maxredirects <= (INT_MAX - 9) / 10 &&
optarg[i] >= '0' && optarg[i] <= '9';
gemini.maxredirects = gemini.maxredirects *
10 + (optarg[i] - '0'), i++)
/* do nothing */;
if (i == 0 || optarg[i] != '\0')
warnx("Invalid number: %s", optarg);
break;
case 's':
gemini.flags |=
GEMINI_PROMPT | GEMINI_SECPROMPT;
break;
case 't':
gemini.tofufile = optarg;
break;
case 'w':
gemini.flags |= GEMINI_TOFU_WRITE;
break;
default:
goto usage;
}
argc -= optind;
argv += optind;
#ifdef __OpenBSD__
if (!(gemini.flags & GEMINI_TOFU_WRITE) &&
pledge("stdio rpath flock inet dns tty", NULL) != 0)
err(EX_NOPERM, "Failed pledge(2)");
#endif
for (i = 0; i < argc; i++) {
if (gemini_open(&gemini, argv[i]) != 0)
goto err;
#ifdef __OpenBSD__
if (i == 0 &&
pledge("stdio rpath flock inet dns tty", NULL) != 0)
err(EX_NOPERM, "Failed pledge(2)");
#endif
while ((r = gemini_read(&gemini, b, sizeof(b))) > 0) {
if (!rawout)
r = stripcntrl(b, sizeof(b), b, r);
(void)fwrite(b, 1, r, stdout);
}
if (r < 0)
goto err;
gemini_reset(&gemini);
}
gemini_close(&gemini);
return (0);
err:
gemini_close(&gemini);
return (EX_SOFTWARE);
usage:
(void)fprintf(stderr, "usage: gemini-cat [-RSisw] "
"[-c cert-file] [-k key-file] [-p port]\n"
" [-r max-redirects] [-t tofu-file] "
"URL...\n");
return (EX_USAGE);
}
ssize_t
stripcntrl(char *dst, size_t dl, const char *src, size_t sl)
{
size_t i;
size_t j;
for (i = 0, j = 0; i < sl && j < dl; i++)
if (!iscntrl(src[i]) || isspace(src[i]))
dst[j++] = src[i];
return (j);
}