Gopher.c (2879B)
1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 5 const char *scheme = "gopher://"; 6 char *rroot = "/mnt/richterm"; 7 8 void 9 usage(void) 10 { 11 fprint(2, "usage: %s [gopher_url]\n", argv0); 12 exits("usage"); 13 } 14 15 void 16 printtext(char *buf, long size) 17 { 18 Biobuf* bd; 19 long n; 20 bd = Bfdopen(1, OWRITE); 21 Bprint(bd, "f\nl\n" "."); 22 for (n = 0; n < size; n++) { 23 if (buf[n] == '\r') continue; 24 else if (buf[n] == '\n') Bprint(bd, "\n" "n\n" "."); 25 else Bputc(bd, buf[n]); 26 } 27 Bprint(bd, "\n"); 28 } 29 30 void 31 printmenu(char *buf, long size) 32 { 33 char *lbuf, *ls, *le, type, *port, *host, *path, url[1024]; 34 long lsize, n; 35 int urlblank; 36 37 ls = buf; 38 lsize = 1024; 39 lbuf = malloc(lsize); 40 urlblank = 0; 41 while (ls < buf + size) { 42 le = strchr(ls, '\n'); 43 if (le == nil) break; 44 n = le - ls; 45 if (lsize < n) { 46 lsize = n; 47 free(lbuf); 48 lbuf = malloc(lsize); 49 } 50 memcpy(lbuf, ls, n); 51 lbuf[n - 1] = '\0'; 52 type = lbuf[0]; 53 ls = le + 1; 54 if (type == '.') break; 55 le = strchr(lbuf, '\t'); 56 if (le == nil) return; // sysfatal("gopher menu is malformed\n"); 57 *le = '\0'; 58 switch (type) { 59 case 'i': 60 case 'e': 61 url[0] = '\0'; 62 break; 63 default: 64 path = le + 1; 65 le = strchr(path, '\t'); 66 *le = '\0'; 67 host = le + 1; 68 le = strchr(host, '\t'); 69 *le = '\0'; 70 port = le + 1; 71 snprint(url, 1024, "gopher://%s:%s/%c%s", host, port, type, path); 72 } 73 74 if (url[0] != '\0') { 75 print("l%s\n", url); 76 urlblank = 0; 77 } else if (urlblank == 0) { 78 print("l\n"); 79 urlblank = 1; 80 } 81 82 if (lbuf[1] != '\0') { 83 print(".%s\n", lbuf + 1); 84 } 85 86 print("n\n"); 87 } 88 } 89 90 void 91 main(int argc, char **argv) 92 { 93 char *url, *up, *host, *port, type, *path, *netaddr, *buf; 94 int fd; 95 long n, size; 96 void (*printfunc) (char *, long); 97 argv0 = argv[0]; 98 printfunc = nil; 99 if ((argc == 1) || (argc > 2)) usage(); 100 url = argv[1]; 101 if (strncmp(scheme, url, strlen(scheme)) != 0) { 102 fprint(2, "%s: invalid url\n", url); 103 exits("invalid url"); 104 } 105 type = '1'; 106 path = "/"; 107 port = "70"; 108 url = url + strlen(scheme); 109 up = strchr(url, '/'); 110 if (up != nil) { 111 host = mallocz(up - url + 1, 1); 112 memcpy(host, url, up - url); 113 up++; 114 if (up < url + strlen(url)) { 115 type = *(up); 116 path = ++up; 117 } 118 up = strchr(host, ':'); 119 if (up != nil) { 120 *up = '\0'; 121 port = up + 1; 122 } 123 } else { 124 host = url; 125 } 126 switch (type) { 127 case '0': 128 printfunc = printtext; 129 break; 130 case '1': 131 printfunc = printmenu; 132 break; 133 default: 134 sysfatal("unknown gopher type: %c\n", type); 135 } 136 netaddr = netmkaddr(host, "tcp", port); 137 fd = dial(netaddr, nil, nil, nil); 138 if (fd < 0) { 139 fprint(2, "url: %s\n", argv[1]); 140 fprint(2, "netaddr: %s\n", netaddr); 141 sysfatal("dial: %r"); 142 } 143 write(fd, path, strlen(path)); 144 write(fd, "\n", 1); 145 buf = malloc(4096); 146 size = 0; 147 while((n = read(fd, buf + size, 4096)) > 0) { 148 size += n; 149 buf = realloc(buf, size + 4096); 150 } 151 close(fd); 152 printfunc(buf, size); 153 }