proto.c (4717B)
1 /* 2 * Copy me if you can. 3 * by 20h 4 */ 5 6 #include <unistd.h> 7 #include <stdarg.h> 8 #include <stdio.h> 9 #include <netdb.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <sys/types.h> 13 #include <sys/socket.h> 14 #include <netinet/in.h> 15 #include <arpa/inet.h> 16 #include <time.h> 17 #include "ind.h" 18 #include "sdb.h" 19 20 void 21 tprintf(int sock, char *fmt, ...) 22 { 23 va_list fmtargs; 24 int fd2; 25 FILE *fp; 26 27 fd2 = dup(sock); 28 fp = fdopen(fd2, "w"); 29 if(fp == nil) { 30 perror("fdopen"); 31 return; 32 } 33 34 va_start(fmtargs, fmt); 35 vfprintf(fp, fmt, fmtargs); 36 va_end(fmtargs); 37 38 fclose(fp); 39 40 return; 41 } 42 43 char * 44 readln(int fd) 45 { 46 char *ret; 47 int len, st; 48 49 len = 1; 50 51 ret = greallocz(nil, 2, 2); 52 while((st = read(fd, &ret[len - 1], 1)) > 0 && ret[len - 1] != '\n') 53 ret = greallocz(ret, ++len + 1, 0); 54 if(st < 0) { 55 free(ret); 56 return nil; 57 } 58 59 if(ret[len - 1] != '\n') { 60 free(ret); 61 return nil; 62 } 63 ret[len - 1] = '\0'; 64 if(ret[len - 2] == '\r') 65 ret[len - 2] = '\0'; 66 67 return ret; 68 } 69 70 int 71 connecttcp(char *host, char *service) 72 { 73 int sock; 74 struct addrinfo *ai, *a; 75 76 sock = -1; 77 78 if(getaddrinfo(host, service, nil, &ai) < 0) { 79 perror("getaddrinfo"); 80 return -1; 81 } 82 83 for(a = ai; a; a = a->ai_next) { 84 sock = socket(a->ai_family, a->ai_socktype, a->ai_protocol); 85 if(sock < 0) { 86 perror("socket"); 87 sock = -1; 88 break; 89 } 90 91 if(connect(sock, a->ai_addr, a->ai_addrlen) < 0) { 92 perror("connect"); 93 sock = -1; 94 break; 95 } else 96 break; 97 } 98 99 freeaddrinfo(ai); 100 101 return sock; 102 } 103 104 int 105 sendgopherreq(char *server, char *port, char *str) 106 { 107 int sock; 108 109 sock = connecttcp(server, port); 110 if(sock < 0) 111 return -1; 112 113 tprintf(sock, "%s\r\n", str); 114 115 return sock; 116 } 117 118 void 119 adddbentry(sdb *db, char type, char *dpath, char *path, char *name, 120 char *server, char *port) 121 { 122 char *uri, *more; 123 char *rdp; 124 int mlen; 125 time_t tim; 126 sdbe *e; 127 128 if(dpath[strlen(dpath) - 1] == '/') 129 rdp = ""; 130 else 131 rdp = "/"; 132 uri = greallocz(nil, strlen(dpath) + strlen(rdp) + strlen(name) + 1, 2); 133 sprintf(uri, "%s%s%s", dpath, rdp, name); 134 135 mlen = sizeof(char) + sizeof(time_t) + strlen(server) + strlen(port) + 136 strlen(path) + 3; 137 more = greallocz(nil, mlen, 2); 138 tim = time(nil); 139 more[0] = type; 140 memcpy(more + sizeof(char), &tim, sizeof(tim)); 141 sprintf(more + sizeof(char) + sizeof(time_t), "%s:%s/%s", server, 142 port, path); 143 144 e = getelem(db, uri, nil); 145 if(e != nil) { 146 free(e->v); 147 e->v = gmemdup(more, mlen); 148 e->l = mlen; 149 } else 150 addelem(db, uri, more, mlen); 151 152 free(more); 153 free(uri); 154 155 return; 156 } 157 158 int 159 parsegopher(int sock, sdb *db, char *dpath) 160 { 161 char *ln, type, *name, *path, *server, *port, *end; 162 163 while((ln = readln(sock)) != nil) { 164 type = ln[0]; 165 name = ln + 1; 166 path = strchr(name, '\t'); 167 if(path == nil) { 168 free(ln); 169 continue; 170 } 171 *path++ = '\0'; 172 server = strchr(path, '\t'); 173 if(server == nil) { 174 free(ln); 175 continue; 176 } 177 *server++ = '\0'; 178 port = strchr(server, '\t'); 179 if(port == nil) { 180 free(ln); 181 continue; 182 } 183 *port++ = '\0'; 184 end = strchr(port, '\t'); 185 if(end != nil) 186 *end = '\0'; 187 end = strchr(port, '\r'); 188 if(end != nil) 189 *end = '\0'; 190 191 if(name[0] == '.') { 192 if(name[1] == '\0') { 193 free(ln); 194 continue; 195 } 196 if(name[1] == '.' && name[2] == '\0') { 197 free(ln); 198 continue; 199 } 200 } 201 202 adddbentry(db, type, dpath, path, name, server, port); 203 free(ln); 204 } 205 206 return 0; 207 } 208 209 void 210 writetofile(int sock, int fd) 211 { 212 char buf[8192]; 213 int l; 214 215 for(;;) { 216 l = read(sock, buf, sizeof(buf)); 217 if(l <= 0) 218 return; 219 write(fd, buf, l); 220 } 221 222 return; 223 } 224 225 int 226 rnpggopher(char *srv, sdb *db, char *dpath, int fd) 227 { 228 char *server, *port, *path; 229 int sock, res; 230 231 res = 0; 232 233 server = gmemdup(srv, strlen(srv) + 1); 234 port = strchr(server, ':'); 235 path = strchr(server, '/'); 236 if(port == nil) 237 port = "70"; 238 else 239 *port++ = '\0'; 240 if(path == nil) 241 path = ""; 242 else 243 *path++ = '\0'; 244 245 sock = sendgopherreq(server, port, path); 246 if(sock < 0) { 247 perror("sendgopherreq"); 248 res = -1; 249 } else { 250 if(fd < 0) 251 parsegopher(sock, db, dpath); 252 else 253 writetofile(sock, fd); 254 } 255 256 free(server); 257 close(sock); 258 259 return res; 260 } 261 262 int 263 checkcache(sdb *db, char *path) 264 { 265 sdbe *e; 266 time_t tim; 267 int i; 268 269 e = getelem(db, path, nil); 270 for(i = 0; e != nil; e = getelem(db, path, e), i++) { 271 if(!strcmp(e->k, (char *)path)) 272 continue; 273 if(strchr(e->k + strlen(path) + 1, '/')) 274 continue; 275 276 memmove(&tim, e->v + sizeof(char), sizeof(time_t)); 277 if(time(nil) - tim > ECACHE) 278 return 1; 279 } 280 281 if(i < 2) 282 return 1; 283 284 return 0; 285 } 286