gemfetch

simple gemini fetcher for plan9
git clone git://nsmpr.xyz/gemfetch.git
Log | Files | Refs

gemfetch.c (1787B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <mp.h>
      4 #include <libsec.h>
      5 #include <bio.h>
      6 
      7 #define BSIZE 4096
      8 
      9 char *
     10 gethost(char *uri)
     11 {
     12 	char *host, *sp, *ep;
     13 	long length;
     14 
     15 	sp = strstr(uri, "://");
     16 	if (sp == nil) {
     17 		werrstr("missing scheme:// in '%s'", uri);
     18 		return nil;
     19 	}
     20 	else sp += 3;
     21 	
     22 	ep = strchr(sp, '/');
     23 	if (ep == nil) ep = sp + strlen(sp);
     24 	length = ep - sp;
     25 	host = mallocz(sizeof(char) * (length+1), 1);
     26 	memcpy(host, sp, length);
     27 	return host;
     28 }
     29 
     30 void
     31 usage(void)
     32 {
     33 	fprint(2, "usage: %s [-h host] uri\n", argv0);
     34 	exits("usage");
     35 }
     36 
     37 void
     38 main(int argc, char **argv)
     39 {
     40 	char *buf, *uri, *host;
     41 	long n, t;
     42 	int fd, tlsfd;
     43 	Biobuf bfd;
     44 	TLSconn conn;
     45 
     46 	host = nil;
     47 
     48 	ARGBEGIN {
     49 	case 'h':
     50 		host = EARGF(usage());
     51 		break;
     52 	default:
     53 		usage();
     54 	} ARGEND
     55 
     56 	if (argc != 1) usage();
     57 
     58 	uri = argv[0];
     59 	if (host == nil) host = gethost(uri);
     60 	if (host == nil) sysfatal("gethost: %r");
     61 
     62 	fprint(2, "fetching from %s\n", host);
     63 	fd = dial(netmkaddr(host, "tcp", "1965"), nil, nil, nil);
     64 	if (fd < 0) sysfatal("dial: %r");
     65 
     66 	memset(&conn, 0, sizeof(conn));
     67 	conn.serverName = host;
     68 	tlsfd = tlsClient(fd, &conn);
     69 	if (tlsfd < 0) sysfatal("tlsClient: %r");
     70 
     71 	if (Binit(&bfd, tlsfd, OREAD) < 0)
     72 		sysfatal("Binit: %r");
     73 
     74 	n = fprint(tlsfd, "%s\r\n", uri);
     75 	if (n < 0) sysfatal("fprint: %r");
     76 
     77 	buf = Brdstr(&bfd, '\n', 1);
     78 	n = Blinelen(&bfd);
     79 	if (n > 1024 + 2)
     80 		fprint(2, "warning: header too long\n");
     81 	buf[n-1] = '\0';
     82 	fprint(2, "%s\n", buf);
     83 
     84 	t = 0;
     85 
     86 	buf = realloc(buf, BSIZE);
     87 
     88 	while ((n = Bread(&bfd, buf, BSIZE)) > 0) {
     89 		t += n;
     90 		write(1, buf, n);
     91 	}
     92 	// read always returns with "i/o on hangup channel" errstr
     93 	// TODO: find a way to deal with it
     94 	// if (n < 0) fprint(2, "read: %r\n");
     95 
     96 	fprint(2, "total: %ld\n", t);
     97 
     98 	Bterm(&bfd);
     99 	close(tlsfd);
    100 	close(fd);
    101 }