Blob


1 /*
2 * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
17 #include <string.h>
19 #include "gmid.h"
21 int
22 main(int argc, char **argv)
23 {
24 struct iri iri;
25 struct tls_config *conf;
26 struct tls *ctx;
27 char iribuf[GEMINI_URL_LEN], buf[GEMINI_URL_LEN];
28 const char *parse_err = "unknown error", *port = "1965";
29 char *t;
30 int ch, flag2, flag3, bflag, cflag, hflag, Nflag, Vflag;
31 ssize_t len;
33 flag2 = flag3 = bflag = cflag = hflag = Nflag = Vflag = 0;
34 while ((ch = getopt(argc, argv, "23cbhNV")) != -1) {
35 switch (ch) {
36 case '2':
37 flag2 = 1;
38 break;
39 case '3':
40 flag3 = 1;
41 break;
42 case 'b':
43 bflag = 1;
44 break;
45 case 'c':
46 cflag = 1;
47 break;
48 case 'h':
49 hflag = 1;
50 break;
51 case 'N':
52 Nflag = 1;
53 break;
54 case 'V':
55 Vflag = 1;
56 break;
57 default:
58 fprintf(stderr, "USAGE: %s [-23cbhNV]", *argv);
59 return 1;
60 }
61 }
62 argc -= optind;
63 argv += optind;
65 if ((bflag + cflag + hflag + Vflag) > 1)
66 errx(1, "only one of bchr flags can be used.");
68 if (flag2 + flag3 > 1)
69 errx(1, "only -2 or -3 can be specified at the same time.");
71 if (argc != 1)
72 errx(1, "missing IRI");
74 if (strlcpy(iribuf, argv[0], sizeof(iribuf)) >= sizeof(iribuf))
75 errx(1, "request too long: %s", argv[0]);
76 if (strlcpy(buf, argv[0], sizeof(buf)) >= sizeof(iribuf))
77 errx(1, "request too long: %s", argv[0]);
78 if (strlcat(buf, "\r\n", sizeof(buf)) >= sizeof(buf))
79 errx(1, "request too long: %s", argv[0]);
81 if (!parse_iri(iribuf, &iri, &parse_err))
82 errx(1, "invalid IRI: %s", parse_err);
84 if (Vflag)
85 errx(0, "IRI: OK");
87 if ((conf = tls_config_new()) == NULL)
88 errx(1, "tls_config_new");
90 tls_config_insecure_noverifycert(conf);
91 if (Nflag)
92 tls_config_insecure_noverifyname(conf);
94 if (flag2 && tls_config_set_protocols(conf, TLS_PROTOCOL_TLSv1_2) == -1)
95 errx(1, "cannot set TLSv1.2");
96 if (flag3 && tls_config_set_protocols(conf, TLS_PROTOCOL_TLSv1_3) == -1)
97 errx(1, "cannot set TLSv1.3");
99 if ((ctx = tls_client()) == NULL)
100 errx(1, "tls_client creation failed");
102 if (tls_configure(ctx, conf) == -1)
103 errx(1, "tls_configure: %s", tls_error(ctx));
105 if (*iri.port != '\0')
106 port = iri.port;
107 if (tls_connect(ctx, iri.host, port) == -1)
108 errx(1, "tls_connect: %s", tls_error(ctx));
110 tls_write(ctx, buf, strlen(buf));
111 /* if (tls_write(ctx, buf, strlen(buf)) != -1) */
112 /* errx(1, "tls_write: %s", tls_error(ctx)); */
114 for (;;) {
115 switch (len = tls_read(ctx, buf, sizeof(buf))) {
116 case 0:
117 case -1:
118 goto end;
119 case TLS_WANT_POLLIN:
120 case TLS_WANT_POLLOUT:
121 continue;
124 if (bflag) {
125 bflag = 0;
126 if ((t = strchr(buf, '\r')) != NULL)
127 t += 2;
128 else if ((t = strchr(buf, '\n')) != NULL)
129 t += 1;
130 else
131 continue;
132 len -= t - buf;
133 write(1, t, len);
134 continue;
137 if (cflag) {
138 write(1, buf, 2);
139 write(1, "\n", 1);
140 break;
143 if (hflag) {
144 t = strchr(buf, '\r');
145 if (t == NULL)
146 t = strchr(buf, '\n');
147 if (t == NULL)
148 t = &buf[len];
149 write(1, buf, t - buf);
150 write(1, "\n", 1);
151 break;
154 write(1, buf, len);
156 end:
158 tls_close(ctx);
159 tls_free(ctx);
161 return 0;