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 flag2, flag3, bflag, cflag, hflag, Nflag, Vflag, vflag;
23 int
24 main(int argc, char **argv)
25 {
26 struct iri iri;
27 struct tls_config *conf;
28 struct tls *ctx;
29 char iribuf[GEMINI_URL_LEN], buf[GEMINI_URL_LEN];
30 const char *parse_err = "unknown error", *port = "1965";
31 const char *hostname;
32 char *t;
33 int ch;
34 int handshake;
35 ssize_t len;
37 hostname = NULL;
38 while ((ch = getopt(argc, argv, "23cbH:hNVv")) != -1) {
39 switch (ch) {
40 case '2':
41 flag2 = 1;
42 break;
43 case '3':
44 flag3 = 1;
45 break;
46 case 'b':
47 bflag = 1;
48 break;
49 case 'c':
50 cflag = 1;
51 break;
52 case 'H':
53 hostname = optarg;
54 break;
55 case 'h':
56 hflag = 1;
57 break;
58 case 'N':
59 Nflag = 1;
60 break;
61 case 'V':
62 Vflag = 1;
63 break;
64 case 'v':
65 vflag = 1;
66 break;
67 default:
68 fprintf(stderr, "USAGE: %s [-23cbhNVv] [-H hostname]\n",
69 *argv);
70 return 1;
71 }
72 }
73 argc -= optind;
74 argv += optind;
76 if ((bflag + cflag + hflag + Vflag) > 1)
77 errx(1, "only one of bchr flags can be used.");
79 if (flag2 + flag3 > 1)
80 errx(1, "only -2 or -3 can be specified at the same time.");
82 if (argc != 1)
83 errx(1, "missing IRI");
85 if (strlcpy(iribuf, argv[0], sizeof(iribuf)) >= sizeof(iribuf))
86 errx(1, "request too long: %s", argv[0]);
87 if (strlcpy(buf, argv[0], sizeof(buf)) >= sizeof(iribuf))
88 errx(1, "request too long: %s", argv[0]);
89 if (strlcat(buf, "\r\n", sizeof(buf)) >= sizeof(buf))
90 errx(1, "request too long: %s", argv[0]);
92 if (!parse_iri(iribuf, &iri, &parse_err))
93 errx(1, "invalid IRI: %s", parse_err);
95 if (Vflag)
96 errx(0, "IRI: OK");
98 if ((conf = tls_config_new()) == NULL)
99 errx(1, "tls_config_new");
101 tls_config_insecure_noverifycert(conf);
102 if (Nflag)
103 tls_config_insecure_noverifyname(conf);
105 if (flag2 && tls_config_set_protocols(conf, TLS_PROTOCOL_TLSv1_2) == -1)
106 errx(1, "cannot set TLSv1.2");
107 if (flag3 && tls_config_set_protocols(conf, TLS_PROTOCOL_TLSv1_3) == -1)
108 errx(1, "cannot set TLSv1.3");
110 if ((ctx = tls_client()) == NULL)
111 errx(1, "tls_client creation failed");
113 if (tls_configure(ctx, conf) == -1)
114 errx(1, "tls_configure: %s", tls_error(ctx));
116 if (*iri.port != '\0')
117 port = iri.port;
119 if (hostname == NULL)
120 hostname = iri.host;
122 if (tls_connect_servername(ctx, iri.host, port, hostname) == -1)
123 errx(1, "tls_connect: %s", tls_error(ctx));
125 for (handshake = 0; !handshake;) {
126 switch (tls_handshake(ctx)) {
127 case 0:
128 case -1:
129 handshake = 1;
130 break;
134 if (vflag)
135 printf("%s", buf);
136 if (tls_write(ctx, buf, strlen(buf)) == -1)
137 errx(1, "tls_write: %s", tls_error(ctx));
139 for (;;) {
140 switch (len = tls_read(ctx, buf, sizeof(buf))) {
141 case 0:
142 case -1:
143 goto end;
144 case TLS_WANT_POLLIN:
145 case TLS_WANT_POLLOUT:
146 continue;
149 if (bflag) {
150 bflag = 0;
151 if ((t = strchr(buf, '\r')) != NULL)
152 t += 2;
153 else if ((t = strchr(buf, '\n')) != NULL)
154 t += 1;
155 else
156 continue;
157 len -= t - buf;
158 write(1, t, len);
159 continue;
162 if (cflag) {
163 write(1, buf, 2);
164 write(1, "\n", 1);
165 break;
168 if (hflag) {
169 t = strchr(buf, '\r');
170 if (t == NULL)
171 t = strchr(buf, '\n');
172 if (t == NULL)
173 t = &buf[len];
174 write(1, buf, t - buf);
175 write(1, "\n", 1);
176 break;
179 write(1, buf, len);
181 end:
183 tls_close(ctx);
184 tls_free(ctx);
186 return 0;