richterm

"terminal emulator" with support for text fonts and images for plan9
git clone git://nsmpr.xyz/richterm.git
Log | Files | Refs | README

Gemini.c (3477B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <mp.h>
      4 #include <libsec.h>
      5 #include <bio.h>
      6 
      7 #include "config.h"
      8 
      9 #define BSIZE 4096
     10 
     11 char *host;
     12 char * gethost(char *uri);
     13 void printheader(char *line);
     14 void printlink(char *);
     15 void getbody(char *header, Biobuf *bfd);
     16 
     17 void
     18 usage(void)
     19 {
     20 	fprint(2, "usage: %s [-h host] uri\n", argv0);
     21 	exits("usage");
     22 }
     23 
     24 void
     25 main(int argc, char **argv)
     26 {
     27 	char *header, *uri;
     28 	long n;
     29 	int fd, tlsfd;
     30 	Biobuf bfd;
     31 	TLSconn conn;
     32 
     33 	host = nil;
     34 
     35 	ARGBEGIN {
     36 	case 'h':
     37 		host = EARGF(usage());
     38 		break;
     39 	default:
     40 		usage();
     41 	} ARGEND
     42 
     43 	if (argc != 1) usage();
     44 
     45 	uri = argv[0];
     46 	if (host == nil) host = gethost(uri);
     47 	if (host == nil) sysfatal("gethost: %r");
     48 
     49 	fd = dial(netmkaddr(host, "tcp", "1965"), nil, nil, nil);
     50 	if (fd < 0) sysfatal("dial: %r");
     51 
     52 	memset(&conn, 0, sizeof(conn));
     53 	conn.serverName = host;
     54 	tlsfd = tlsClient(fd, &conn);
     55 	if (tlsfd < 0) sysfatal("tlsClient: %r");
     56 
     57 	if (Binit(&bfd, tlsfd, OREAD) < 0)
     58 		sysfatal("Binit: %r");
     59 
     60 	n = fprint(tlsfd, "%s\r\n", uri);
     61 	if (n < 0) sysfatal("fprint: %r");
     62 
     63 	header = Brdstr(&bfd, '\n', 1);
     64 	n = Blinelen(&bfd);
     65 	if (n > 1024 + 2)
     66 		fprint(2, "warning: header too long\n");
     67 	header[n-1] = '\0';
     68 
     69 	enum {
     70 		SCInput = 10,
     71 		SCSensitiveInput = 11,
     72 		SCSuccess = 20,
     73 		SCRedirect = 30,
     74 		SCPermRedirect = 31,
     75 	};
     76 
     77 	switch (atoi(header)) {
     78 	case SCInput:
     79 	case SCSensitiveInput:
     80 		// TODO:ask for input
     81 		print(".%s\n" "n\n" ".input is not supported\n" "n\n", header);
     82 		break;
     83 	case SCSuccess:
     84 		getbody(header, &bfd);
     85 		break;
     86 	case SCRedirect:
     87 	case SCPermRedirect:
     88 		print(".Redirect: \n" "l%s\n" ".%s\n" "n\n" "l\n", header + 3, header + 3);
     89 		break;
     90 	default:
     91 		// print header
     92 		print(".%s\n" "n\n", header);
     93 	}
     94 
     95 	Bterm(&bfd);
     96 	close(tlsfd);
     97 	close(fd);
     98 }
     99 
    100 
    101 char *
    102 gethost(char *uri)
    103 {
    104 	char *host, *sp, *ep;
    105 	long length;
    106 
    107 	sp = strstr(uri, "://");
    108 	if (sp == nil) {
    109 		werrstr("missing scheme:// in '%s'", uri);
    110 		return nil;
    111 	}
    112 	else sp += 3;
    113 	
    114 	ep = strchr(sp, '/');
    115 	if (ep == nil) ep = sp + strlen(sp);
    116 	length = ep - sp;
    117 	host = mallocz(sizeof(char) * (length+1), 1);
    118 	memcpy(host, sp, length);
    119 	return host;
    120 }
    121 
    122 void
    123 getbody(char *header, Biobuf *bfd)
    124 {
    125 	char *line;
    126 	int preform = 0;
    127 
    128 	if (strncmp(header + 3, "text", 4) == 0) {
    129 
    130 		while ((line = Brdstr(bfd, '\n', 1)) != nil) {
    131 			long n = Blinelen(bfd);
    132 			if (line[n-1] == '\r') line[n-1] = '\0';
    133 			if (line[0] == '#') printheader(line);
    134 			else if (strncmp(line, "```", 3) == 0) {
    135 				preform = !preform;
    136 				if (preform == 1) print("%s", fonts[Fcode]);
    137 				else print("f\n");
    138 			} else if (strncmp(line, "=>", 2) == 0) {
    139 				printlink(line);
    140 			} else {
    141 				print(".%s\n" "n\n", line);
    142 			}
    143 			free(line);
    144 		}
    145 		if (preform == 1) print("f\n");
    146 
    147 	} else {
    148 		print(".%s\n" "n\n", header);
    149 	}
    150 }
    151 
    152 void
    153 printheader(char *line)
    154 {
    155 	int i = 0;
    156 	while (line[i] == '#') i++;
    157 	char *font = (i > 3) ? fonts[Fheader3] : fonts[Fheader1  + i - 1];
    158 	while ((line[i] == ' ') | (line[i] == '\t')) i++;
    159 	print("f%s\n" ".%s\n" "n\n" "f\n", font, line + i);
    160 }
    161 
    162 void
    163 printlink(char *line)
    164 {
    165 	char *p, phost[1024];
    166 
    167 	for (p = line + 2; (*p == ' ') || (*p == '\t'); p++) if (*p == '\0') return;
    168 	line = strpbrk(p, " \t");
    169 
    170 	if (line != nil) {
    171 		*line = '\0';
    172 		line++;
    173 		for (; (*line == ' ') || (*line == '\t'); line++);
    174 	} else line = p;
    175 
    176 	phost[0] = '\0';
    177 	if (strstr(p, "://") == nil) {
    178 		strcat(phost, "gemini://");
    179 		strcat(phost, host);
    180 		if (p[0] != '/') strcat(phost, "/");
    181 	}
    182 
    183 	print("l%s%s\n" ".%s\n" "l\n" "n\n", phost, p, line);
    184 }