17dd7cddfSDavid du Colombier #include <u.h> 27dd7cddfSDavid du Colombier #include <libc.h> 359cc4ca5SDavid du Colombier #include <ctype.h> 47dd7cddfSDavid du Colombier #include <bio.h> 559cc4ca5SDavid du Colombier #include <ip.h> 6*106486e8SDavid du Colombier #include <libsec.h> 77dd7cddfSDavid du Colombier 87dd7cddfSDavid du Colombier typedef struct URL URL; 97dd7cddfSDavid du Colombier struct URL 107dd7cddfSDavid du Colombier { 117dd7cddfSDavid du Colombier int method; 127dd7cddfSDavid du Colombier char *host; 137dd7cddfSDavid du Colombier char *port; 147dd7cddfSDavid du Colombier char *page; 157dd7cddfSDavid du Colombier char *etag; 167dd7cddfSDavid du Colombier char *redirect; 1759cc4ca5SDavid du Colombier char *postbody; 187dd7cddfSDavid du Colombier long mtime; 197dd7cddfSDavid du Colombier }; 207dd7cddfSDavid du Colombier 217dd7cddfSDavid du Colombier typedef struct Range Range; 227dd7cddfSDavid du Colombier struct Range 237dd7cddfSDavid du Colombier { 247dd7cddfSDavid du Colombier long start; /* only 2 gig supported, tdb */ 257dd7cddfSDavid du Colombier long end; 267dd7cddfSDavid du Colombier }; 277dd7cddfSDavid du Colombier 287dd7cddfSDavid du Colombier enum 297dd7cddfSDavid du Colombier { 307dd7cddfSDavid du Colombier Http, 31*106486e8SDavid du Colombier Https, 327dd7cddfSDavid du Colombier Ftp, 337dd7cddfSDavid du Colombier Other 347dd7cddfSDavid du Colombier }; 357dd7cddfSDavid du Colombier 367dd7cddfSDavid du Colombier enum 377dd7cddfSDavid du Colombier { 387dd7cddfSDavid du Colombier Eof = 0, 397dd7cddfSDavid du Colombier Error = -1, 407dd7cddfSDavid du Colombier Server = -2, 417dd7cddfSDavid du Colombier Changed = -3, 427dd7cddfSDavid du Colombier }; 437dd7cddfSDavid du Colombier 447dd7cddfSDavid du Colombier int debug; 457dd7cddfSDavid du Colombier char *ofile; 467dd7cddfSDavid du Colombier 477dd7cddfSDavid du Colombier int doftp(URL*, Range*, int, long); 487dd7cddfSDavid du Colombier int dohttp(URL*, Range*, int, long); 497dd7cddfSDavid du Colombier int crackurl(URL*, char*); 507dd7cddfSDavid du Colombier Range* crackrange(char*); 517dd7cddfSDavid du Colombier int getheader(int, char*, int); 529a747e4fSDavid du Colombier int httpheaders(int, int, URL*, Range*); 537dd7cddfSDavid du Colombier int httprcode(int); 547dd7cddfSDavid du Colombier int cistrncmp(char*, char*, int); 557dd7cddfSDavid du Colombier int cistrcmp(char*, char*); 567dd7cddfSDavid du Colombier void initibuf(void); 577dd7cddfSDavid du Colombier int readline(int, char*, int); 587dd7cddfSDavid du Colombier int readibuf(int, char*, int); 597dd7cddfSDavid du Colombier int dfprint(int, char*, ...); 607dd7cddfSDavid du Colombier void unreadline(char*); 6159cc4ca5SDavid du Colombier 627dd7cddfSDavid du Colombier int verbose; 6359cc4ca5SDavid du Colombier char *net; 6459cc4ca5SDavid du Colombier char tcpdir[64]; 657dd7cddfSDavid du Colombier 667dd7cddfSDavid du Colombier struct { 677dd7cddfSDavid du Colombier char *name; 687dd7cddfSDavid du Colombier int (*f)(URL*, Range*, int, long); 697dd7cddfSDavid du Colombier } method[] = { 707dd7cddfSDavid du Colombier [Http] { "http", dohttp }, 71*106486e8SDavid du Colombier [Https] { "https", dohttp }, 727dd7cddfSDavid du Colombier [Ftp] { "ftp", doftp }, 737dd7cddfSDavid du Colombier [Other] { "_______", nil }, 747dd7cddfSDavid du Colombier }; 757dd7cddfSDavid du Colombier 767dd7cddfSDavid du Colombier void 777dd7cddfSDavid du Colombier usage(void) 787dd7cddfSDavid du Colombier { 7959cc4ca5SDavid du Colombier fprint(2, "usage: %s [-v] [-o outfile] [-p body] [-x netmtpt] url\n", argv0); 807dd7cddfSDavid du Colombier exits("usage"); 817dd7cddfSDavid du Colombier } 827dd7cddfSDavid du Colombier 837dd7cddfSDavid du Colombier void 847dd7cddfSDavid du Colombier main(int argc, char **argv) 857dd7cddfSDavid du Colombier { 867dd7cddfSDavid du Colombier URL u; 877dd7cddfSDavid du Colombier Range r; 887dd7cddfSDavid du Colombier int fd, errs, n; 899a747e4fSDavid du Colombier ulong mtime; 909a747e4fSDavid du Colombier Dir *d; 9159cc4ca5SDavid du Colombier char postbody[4096], *p, *e, *t; 927dd7cddfSDavid du Colombier 937dd7cddfSDavid du Colombier ofile = nil; 9459cc4ca5SDavid du Colombier p = postbody; 9559cc4ca5SDavid du Colombier e = p + sizeof(postbody); 967dd7cddfSDavid du Colombier r.start = 0; 977dd7cddfSDavid du Colombier r.end = -1; 989a747e4fSDavid du Colombier mtime = 0; 9959cc4ca5SDavid du Colombier memset(&u, 0, sizeof(u)); 1007dd7cddfSDavid du Colombier 1017dd7cddfSDavid du Colombier ARGBEGIN { 1027dd7cddfSDavid du Colombier case 'o': 1037dd7cddfSDavid du Colombier ofile = ARGF(); 1047dd7cddfSDavid du Colombier break; 1057dd7cddfSDavid du Colombier case 'd': 1067dd7cddfSDavid du Colombier debug = 1; 1077dd7cddfSDavid du Colombier break; 1087dd7cddfSDavid du Colombier case 'v': 1097dd7cddfSDavid du Colombier verbose = 1; 1107dd7cddfSDavid du Colombier break; 11159cc4ca5SDavid du Colombier case 'x': 11259cc4ca5SDavid du Colombier net = ARGF(); 11359cc4ca5SDavid du Colombier if(net == nil) 11459cc4ca5SDavid du Colombier usage(); 11559cc4ca5SDavid du Colombier break; 11659cc4ca5SDavid du Colombier case 'p': 11759cc4ca5SDavid du Colombier t = ARGF(); 11859cc4ca5SDavid du Colombier if(t == nil) 11959cc4ca5SDavid du Colombier usage(); 12059cc4ca5SDavid du Colombier if(p != postbody) 12159cc4ca5SDavid du Colombier p = seprint(p, e, "&%s", t); 12259cc4ca5SDavid du Colombier else 12359cc4ca5SDavid du Colombier p = seprint(p, e, "%s", t); 12459cc4ca5SDavid du Colombier u.postbody = postbody; 12559cc4ca5SDavid du Colombier 12659cc4ca5SDavid du Colombier break; 1277dd7cddfSDavid du Colombier default: 1287dd7cddfSDavid du Colombier usage(); 1297dd7cddfSDavid du Colombier } ARGEND; 1307dd7cddfSDavid du Colombier 13159cc4ca5SDavid du Colombier if(net != nil){ 13259cc4ca5SDavid du Colombier if(strlen(net) > sizeof(tcpdir)-5) 13359cc4ca5SDavid du Colombier sysfatal("network mount point too long"); 13459cc4ca5SDavid du Colombier snprint(tcpdir, sizeof(tcpdir), "%s/tcp", net); 13559cc4ca5SDavid du Colombier } else 13659cc4ca5SDavid du Colombier snprint(tcpdir, sizeof(tcpdir), "tcp"); 13759cc4ca5SDavid du Colombier 1387dd7cddfSDavid du Colombier if(argc != 1) 1397dd7cddfSDavid du Colombier usage(); 1407dd7cddfSDavid du Colombier 1417dd7cddfSDavid du Colombier fd = 1; 1427dd7cddfSDavid du Colombier if(ofile != nil){ 1439a747e4fSDavid du Colombier d = dirstat(ofile); 1449a747e4fSDavid du Colombier if(d == nil){ 1457dd7cddfSDavid du Colombier fd = create(ofile, OWRITE, 0664); 1467dd7cddfSDavid du Colombier if(fd < 0) 1477dd7cddfSDavid du Colombier sysfatal("creating %s: %r", ofile); 1487dd7cddfSDavid du Colombier } else { 1497dd7cddfSDavid du Colombier fd = open(ofile, OWRITE); 1507dd7cddfSDavid du Colombier if(fd < 0) 1517dd7cddfSDavid du Colombier sysfatal("can't open %s: %r", ofile); 1529a747e4fSDavid du Colombier r.start = d->length; 1539a747e4fSDavid du Colombier mtime = d->mtime; 1549a747e4fSDavid du Colombier free(d); 1557dd7cddfSDavid du Colombier } 1567dd7cddfSDavid du Colombier } 1577dd7cddfSDavid du Colombier 1587dd7cddfSDavid du Colombier errs = 0; 1597dd7cddfSDavid du Colombier 1607dd7cddfSDavid du Colombier if(crackurl(&u, argv[0]) < 0) 1617dd7cddfSDavid du Colombier sysfatal("%r"); 1627dd7cddfSDavid du Colombier 1637dd7cddfSDavid du Colombier for(;;){ 1647dd7cddfSDavid du Colombier /* transfer data */ 1657dd7cddfSDavid du Colombier werrstr(""); 16659cc4ca5SDavid du Colombier seek(fd, 0, 0); 1679a747e4fSDavid du Colombier n = (*method[u.method].f)(&u, &r, fd, mtime); 1687dd7cddfSDavid du Colombier 1697dd7cddfSDavid du Colombier switch(n){ 1707dd7cddfSDavid du Colombier case Eof: 1717dd7cddfSDavid du Colombier exits(0); 1727dd7cddfSDavid du Colombier break; 1737dd7cddfSDavid du Colombier case Error: 1747dd7cddfSDavid du Colombier if(errs++ < 10) 1757dd7cddfSDavid du Colombier continue; 1767dd7cddfSDavid du Colombier sysfatal("too many errors with no progress %r"); 1777dd7cddfSDavid du Colombier break; 1787dd7cddfSDavid du Colombier case Server: 1797dd7cddfSDavid du Colombier sysfatal("server returned: %r"); 1807dd7cddfSDavid du Colombier break; 1817dd7cddfSDavid du Colombier } 1827dd7cddfSDavid du Colombier 1837dd7cddfSDavid du Colombier /* forward progress */ 1847dd7cddfSDavid du Colombier errs = 0; 1857dd7cddfSDavid du Colombier r.start += n; 1867dd7cddfSDavid du Colombier if(r.start >= r.end) 1877dd7cddfSDavid du Colombier break; 1887dd7cddfSDavid du Colombier } 1897dd7cddfSDavid du Colombier 1907dd7cddfSDavid du Colombier exits(0); 1917dd7cddfSDavid du Colombier } 1927dd7cddfSDavid du Colombier 1937dd7cddfSDavid du Colombier int 1947dd7cddfSDavid du Colombier crackurl(URL *u, char *s) 1957dd7cddfSDavid du Colombier { 1967dd7cddfSDavid du Colombier char *p; 1977dd7cddfSDavid du Colombier int i; 1987dd7cddfSDavid du Colombier 1997dd7cddfSDavid du Colombier if(u->host != nil){ 2007dd7cddfSDavid du Colombier free(u->host); 2017dd7cddfSDavid du Colombier u->host = nil; 2027dd7cddfSDavid du Colombier } 2037dd7cddfSDavid du Colombier if(u->page != nil){ 2047dd7cddfSDavid du Colombier free(u->page); 2057dd7cddfSDavid du Colombier u->page = nil; 2067dd7cddfSDavid du Colombier } 2077dd7cddfSDavid du Colombier 2087dd7cddfSDavid du Colombier /* get type */ 2097dd7cddfSDavid du Colombier u->method = Other; 2107dd7cddfSDavid du Colombier for(p = s; *p; p++){ 2117dd7cddfSDavid du Colombier if(*p == '/'){ 2127dd7cddfSDavid du Colombier u->method = Http; 2137dd7cddfSDavid du Colombier p = s; 2147dd7cddfSDavid du Colombier break; 2157dd7cddfSDavid du Colombier } 2167dd7cddfSDavid du Colombier if(*p == ':' && *(p+1)=='/' && *(p+2)=='/'){ 2177dd7cddfSDavid du Colombier *p = 0; 2187dd7cddfSDavid du Colombier p += 3; 2197dd7cddfSDavid du Colombier for(i = 0; i < nelem(method); i++){ 2207dd7cddfSDavid du Colombier if(cistrcmp(s, method[i].name) == 0){ 2217dd7cddfSDavid du Colombier u->method = i; 2227dd7cddfSDavid du Colombier break; 2237dd7cddfSDavid du Colombier } 2247dd7cddfSDavid du Colombier } 2257dd7cddfSDavid du Colombier break; 2267dd7cddfSDavid du Colombier } 2277dd7cddfSDavid du Colombier } 2287dd7cddfSDavid du Colombier 2297dd7cddfSDavid du Colombier if(u->method == Other){ 2307dd7cddfSDavid du Colombier werrstr("unsupported URL type %s", s); 2317dd7cddfSDavid du Colombier return -1; 2327dd7cddfSDavid du Colombier } 2337dd7cddfSDavid du Colombier 2347dd7cddfSDavid du Colombier /* get system */ 2357dd7cddfSDavid du Colombier s = p; 2367dd7cddfSDavid du Colombier p = strchr(s, '/'); 2377dd7cddfSDavid du Colombier if(p == nil){ 2387dd7cddfSDavid du Colombier u->host = strdup(s); 2397dd7cddfSDavid du Colombier u->page = strdup("/"); 2407dd7cddfSDavid du Colombier } else { 2417dd7cddfSDavid du Colombier u->page = strdup(p); 2427dd7cddfSDavid du Colombier *p = 0; 2437dd7cddfSDavid du Colombier u->host = strdup(s); 2447dd7cddfSDavid du Colombier *p = '/'; 2457dd7cddfSDavid du Colombier } 2467dd7cddfSDavid du Colombier 2477dd7cddfSDavid du Colombier if(p = strchr(u->host, ':')) { 2487dd7cddfSDavid du Colombier *p++ = 0; 2497dd7cddfSDavid du Colombier u->port = p; 2507dd7cddfSDavid du Colombier } else 25159cc4ca5SDavid du Colombier u->port = method[u->method].name; 2527dd7cddfSDavid du Colombier 2537dd7cddfSDavid du Colombier if(*(u->host) == 0){ 2547dd7cddfSDavid du Colombier werrstr("bad url, null host"); 2557dd7cddfSDavid du Colombier return -1; 2567dd7cddfSDavid du Colombier } 2577dd7cddfSDavid du Colombier 2587dd7cddfSDavid du Colombier return 0; 2597dd7cddfSDavid du Colombier } 2607dd7cddfSDavid du Colombier 2617dd7cddfSDavid du Colombier char *day[] = { 2627dd7cddfSDavid du Colombier "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 2637dd7cddfSDavid du Colombier }; 2647dd7cddfSDavid du Colombier 2657dd7cddfSDavid du Colombier char *month[] = { 2667dd7cddfSDavid du Colombier "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 2677dd7cddfSDavid du Colombier }; 2687dd7cddfSDavid du Colombier 2697dd7cddfSDavid du Colombier struct 2707dd7cddfSDavid du Colombier { 2717dd7cddfSDavid du Colombier int fd; 2727dd7cddfSDavid du Colombier long mtime; 2737dd7cddfSDavid du Colombier } note; 2747dd7cddfSDavid du Colombier 2757dd7cddfSDavid du Colombier void 2767dd7cddfSDavid du Colombier catch(void*, char*) 2777dd7cddfSDavid du Colombier { 2787dd7cddfSDavid du Colombier Dir d; 2797dd7cddfSDavid du Colombier 2809a747e4fSDavid du Colombier nulldir(&d); 2817dd7cddfSDavid du Colombier d.mtime = note.mtime; 2827dd7cddfSDavid du Colombier if(dirfwstat(note.fd, &d) < 0) 2837dd7cddfSDavid du Colombier sysfatal("catch: can't dirfwstat: %r"); 2847dd7cddfSDavid du Colombier noted(NDFLT); 2857dd7cddfSDavid du Colombier } 2867dd7cddfSDavid du Colombier 2877dd7cddfSDavid du Colombier int 2887dd7cddfSDavid du Colombier dohttp(URL *u, Range *r, int out, long mtime) 2897dd7cddfSDavid du Colombier { 2909a747e4fSDavid du Colombier int fd, cfd; 2917dd7cddfSDavid du Colombier int redirect, loop; 2927dd7cddfSDavid du Colombier int n, rv, code; 2937dd7cddfSDavid du Colombier long tot, vtime; 2947dd7cddfSDavid du Colombier Tm *tm; 2957dd7cddfSDavid du Colombier char buf[1024]; 2969a747e4fSDavid du Colombier char err[ERRMAX]; 2977dd7cddfSDavid du Colombier 29859cc4ca5SDavid du Colombier 29959cc4ca5SDavid du Colombier /* always move back to a previous 512 byte bound because some 30059cc4ca5SDavid du Colombier * servers can't seem to deal with requests that start at the 30159cc4ca5SDavid du Colombier * end of the file 30259cc4ca5SDavid du Colombier */ 30359cc4ca5SDavid du Colombier if(r->start) 30459cc4ca5SDavid du Colombier r->start = ((r->start-1)/512)*512; 30559cc4ca5SDavid du Colombier 3067dd7cddfSDavid du Colombier /* loop for redirects, requires reading both response code and headers */ 3077dd7cddfSDavid du Colombier fd = -1; 3087dd7cddfSDavid du Colombier for(loop = 0; loop < 32; loop++){ 30959cc4ca5SDavid du Colombier fd = dial(netmkaddr(u->host, tcpdir, u->port), 0, 0, 0); 3107dd7cddfSDavid du Colombier if(fd < 0) 3117dd7cddfSDavid du Colombier return Error; 3127dd7cddfSDavid du Colombier 313*106486e8SDavid du Colombier if(u->method == Https){ 314*106486e8SDavid du Colombier int tfd; 315*106486e8SDavid du Colombier TLSconn conn; 316*106486e8SDavid du Colombier 317*106486e8SDavid du Colombier memset(&conn, 0, sizeof conn); 318*106486e8SDavid du Colombier tfd = tlsClient(fd, &conn); 319*106486e8SDavid du Colombier if(tfd < 0){ 320*106486e8SDavid du Colombier fprint(2, "tlsClient: %r\n"); 321*106486e8SDavid du Colombier close(fd); 322*106486e8SDavid du Colombier return Error; 323*106486e8SDavid du Colombier } 324*106486e8SDavid du Colombier /* BUG: check cert here? */ 325*106486e8SDavid du Colombier if(conn.cert) 326*106486e8SDavid du Colombier free(conn.cert); 327*106486e8SDavid du Colombier close(fd); 328*106486e8SDavid du Colombier fd = tfd; 329*106486e8SDavid du Colombier } 330*106486e8SDavid du Colombier 3317dd7cddfSDavid du Colombier /* write request, use range if not start of file */ 33259cc4ca5SDavid du Colombier if(u->postbody == nil){ 33359cc4ca5SDavid du Colombier dfprint(fd, "GET %s HTTP/1.0\r\n" 33459cc4ca5SDavid du Colombier "Host: %s\r\n" 33559cc4ca5SDavid du Colombier "User-agent: Plan9/hget\r\n", 33659cc4ca5SDavid du Colombier u->page, u->host); 33759cc4ca5SDavid du Colombier } else { 33859cc4ca5SDavid du Colombier dfprint(fd, "POST %s HTTP/1.0\r\n" 33959cc4ca5SDavid du Colombier "Host: %s\r\n" 34059cc4ca5SDavid du Colombier "Content-type: application/x-www-form-urlencoded\r\n" 34159cc4ca5SDavid du Colombier "Content-length: %d\r\n" 34259cc4ca5SDavid du Colombier "User-agent: Plan9/hget\r\n" 34359cc4ca5SDavid du Colombier "\r\n", 34459cc4ca5SDavid du Colombier u->page, u->host, strlen(u->postbody)); 34559cc4ca5SDavid du Colombier dfprint(fd, "%s", u->postbody); 34659cc4ca5SDavid du Colombier } 3477dd7cddfSDavid du Colombier if(r->start != 0){ 3487dd7cddfSDavid du Colombier dfprint(fd, "Range: bytes=%d-\n", r->start); 3497dd7cddfSDavid du Colombier if(u->etag != nil){ 3507dd7cddfSDavid du Colombier dfprint(fd, "If-range: %s\n", u->etag); 3517dd7cddfSDavid du Colombier } else { 3527dd7cddfSDavid du Colombier tm = gmtime(mtime); 3537dd7cddfSDavid du Colombier dfprint(fd, "If-range: %s, %d %s %d %2d:%2.2d:%2.2d GMT\n", 3547dd7cddfSDavid du Colombier day[tm->wday], tm->mday, month[tm->mon], 3557dd7cddfSDavid du Colombier tm->year+1900, tm->hour, tm->min, tm->sec); 3567dd7cddfSDavid du Colombier } 3577dd7cddfSDavid du Colombier } 3589a747e4fSDavid du Colombier if((cfd = open("/mnt/webcookies/http", ORDWR)) >= 0){ 3599a747e4fSDavid du Colombier if(fprint(cfd, "http://%s%s", u->host, u->page) > 0){ 3609a747e4fSDavid du Colombier while((n = read(cfd, buf, sizeof buf)) > 0){ 3619a747e4fSDavid du Colombier if(debug) 3629a747e4fSDavid du Colombier write(2, buf, n); 3639a747e4fSDavid du Colombier write(fd, buf, n); 3649a747e4fSDavid du Colombier } 3659a747e4fSDavid du Colombier }else{ 3669a747e4fSDavid du Colombier close(cfd); 3679a747e4fSDavid du Colombier cfd = -1; 3689a747e4fSDavid du Colombier } 3699a747e4fSDavid du Colombier } 3707dd7cddfSDavid du Colombier dfprint(fd, "\r\n", u->host); 3717dd7cddfSDavid du Colombier 3727dd7cddfSDavid du Colombier redirect = 0; 3737dd7cddfSDavid du Colombier initibuf(); 3747dd7cddfSDavid du Colombier code = httprcode(fd); 3757dd7cddfSDavid du Colombier switch(code){ 3767dd7cddfSDavid du Colombier case Error: /* connection timed out */ 3777dd7cddfSDavid du Colombier case Eof: 37859cc4ca5SDavid du Colombier close(fd); 3799a747e4fSDavid du Colombier close(cfd); 3807dd7cddfSDavid du Colombier return code; 3817dd7cddfSDavid du Colombier 3827dd7cddfSDavid du Colombier case 200: /* OK */ 3837dd7cddfSDavid du Colombier case 201: /* Created */ 3847dd7cddfSDavid du Colombier case 202: /* Accepted */ 3857dd7cddfSDavid du Colombier if(ofile == nil && r->start != 0) 3867dd7cddfSDavid du Colombier sysfatal("page changed underfoot"); 3877dd7cddfSDavid du Colombier break; 3887dd7cddfSDavid du Colombier 3897dd7cddfSDavid du Colombier case 204: /* No Content */ 3907dd7cddfSDavid du Colombier sysfatal("No Content"); 3917dd7cddfSDavid du Colombier 3927dd7cddfSDavid du Colombier case 206: /* Partial Content */ 3937dd7cddfSDavid du Colombier seek(out, r->start, 0); 3947dd7cddfSDavid du Colombier break; 3957dd7cddfSDavid du Colombier 3967dd7cddfSDavid du Colombier case 301: /* Moved Permanently */ 3977dd7cddfSDavid du Colombier case 302: /* Moved Temporarily */ 3987dd7cddfSDavid du Colombier redirect = 1; 3999a747e4fSDavid du Colombier u->postbody = nil; 4007dd7cddfSDavid du Colombier break; 4017dd7cddfSDavid du Colombier 4027dd7cddfSDavid du Colombier case 304: /* Not Modified */ 4037dd7cddfSDavid du Colombier break; 4047dd7cddfSDavid du Colombier 4057dd7cddfSDavid du Colombier case 400: /* Bad Request */ 4067dd7cddfSDavid du Colombier sysfatal("Bad Request"); 4077dd7cddfSDavid du Colombier 4087dd7cddfSDavid du Colombier case 401: /* Unauthorized */ 4097dd7cddfSDavid du Colombier case 402: /* ??? */ 4107dd7cddfSDavid du Colombier sysfatal("Unauthorized"); 4117dd7cddfSDavid du Colombier 4127dd7cddfSDavid du Colombier case 403: /* Forbidden */ 4137dd7cddfSDavid du Colombier sysfatal("Forbidden by server"); 4147dd7cddfSDavid du Colombier 4157dd7cddfSDavid du Colombier case 404: /* Not Found */ 4167dd7cddfSDavid du Colombier sysfatal("Not found on server"); 4177dd7cddfSDavid du Colombier 4187dd7cddfSDavid du Colombier case 500: /* Internal server error */ 4197dd7cddfSDavid du Colombier sysfatal("Server choked"); 4207dd7cddfSDavid du Colombier 4217dd7cddfSDavid du Colombier case 501: /* Not implemented */ 4227dd7cddfSDavid du Colombier sysfatal("Server can't do it!"); 4237dd7cddfSDavid du Colombier 4247dd7cddfSDavid du Colombier case 502: /* Bad gateway */ 4257dd7cddfSDavid du Colombier sysfatal("Bad gateway"); 4267dd7cddfSDavid du Colombier 4277dd7cddfSDavid du Colombier case 503: /* Service unavailable */ 4287dd7cddfSDavid du Colombier sysfatal("Service unavailable"); 4297dd7cddfSDavid du Colombier 4307dd7cddfSDavid du Colombier default: 431d9306527SDavid du Colombier sysfatal("Unknown response code %d", code); 4327dd7cddfSDavid du Colombier } 4337dd7cddfSDavid du Colombier 4347dd7cddfSDavid du Colombier if(u->redirect != nil){ 4357dd7cddfSDavid du Colombier free(u->redirect); 4367dd7cddfSDavid du Colombier u->redirect = nil; 4377dd7cddfSDavid du Colombier } 4387dd7cddfSDavid du Colombier 4399a747e4fSDavid du Colombier rv = httpheaders(fd, cfd, u, r); 4409a747e4fSDavid du Colombier close(cfd); 44159cc4ca5SDavid du Colombier if(rv != 0){ 44259cc4ca5SDavid du Colombier close(fd); 4437dd7cddfSDavid du Colombier return rv; 44459cc4ca5SDavid du Colombier } 4457dd7cddfSDavid du Colombier 4467dd7cddfSDavid du Colombier if(!redirect) 4477dd7cddfSDavid du Colombier break; 4487dd7cddfSDavid du Colombier 4497dd7cddfSDavid du Colombier if(u->redirect == nil) 4507dd7cddfSDavid du Colombier sysfatal("redirect: no URL"); 4517dd7cddfSDavid du Colombier if(crackurl(u, u->redirect) < 0) 4527dd7cddfSDavid du Colombier sysfatal("redirect: %r"); 4537dd7cddfSDavid du Colombier } 4547dd7cddfSDavid du Colombier 4557dd7cddfSDavid du Colombier /* transfer whatever you get */ 4567dd7cddfSDavid du Colombier if(ofile != nil && u->mtime != 0){ 4577dd7cddfSDavid du Colombier note.fd = out; 4587dd7cddfSDavid du Colombier note.mtime = u->mtime; 4597dd7cddfSDavid du Colombier notify(catch); 4607dd7cddfSDavid du Colombier } 4617dd7cddfSDavid du Colombier 4627dd7cddfSDavid du Colombier tot = 0; 4637dd7cddfSDavid du Colombier vtime = 0; 4647dd7cddfSDavid du Colombier for(;;){ 4657dd7cddfSDavid du Colombier n = readibuf(fd, buf, sizeof(buf)); 4667dd7cddfSDavid du Colombier if(n <= 0) 4677dd7cddfSDavid du Colombier break; 4687dd7cddfSDavid du Colombier if(write(out, buf, n) != n) 4697dd7cddfSDavid du Colombier break; 4707dd7cddfSDavid du Colombier tot += n; 4717dd7cddfSDavid du Colombier if(verbose && vtime != time(0)) { 4727dd7cddfSDavid du Colombier vtime = time(0); 4737dd7cddfSDavid du Colombier fprint(2, "%ld %ld\n", r->start+tot, r->end); 4747dd7cddfSDavid du Colombier } 4757dd7cddfSDavid du Colombier } 4767dd7cddfSDavid du Colombier notify(nil); 47759cc4ca5SDavid du Colombier close(fd); 4787dd7cddfSDavid du Colombier 4797dd7cddfSDavid du Colombier if(ofile != nil && u->mtime != 0){ 4807dd7cddfSDavid du Colombier Dir d; 4817dd7cddfSDavid du Colombier 4829a747e4fSDavid du Colombier rerrstr(err, sizeof err); 4839a747e4fSDavid du Colombier nulldir(&d); 4847dd7cddfSDavid du Colombier d.mtime = u->mtime; 4857dd7cddfSDavid du Colombier if(dirfwstat(out, &d) < 0) 4867dd7cddfSDavid du Colombier fprint(2, "couldn't set mtime: %r\n"); 4879a747e4fSDavid du Colombier errstr(err, sizeof err); 4887dd7cddfSDavid du Colombier } 4897dd7cddfSDavid du Colombier 4907dd7cddfSDavid du Colombier return tot; 4917dd7cddfSDavid du Colombier } 4927dd7cddfSDavid du Colombier 4937dd7cddfSDavid du Colombier /* get the http response code */ 4947dd7cddfSDavid du Colombier int 4957dd7cddfSDavid du Colombier httprcode(int fd) 4967dd7cddfSDavid du Colombier { 4977dd7cddfSDavid du Colombier int n; 4987dd7cddfSDavid du Colombier char *p; 4997dd7cddfSDavid du Colombier char buf[256]; 5007dd7cddfSDavid du Colombier 5017dd7cddfSDavid du Colombier n = readline(fd, buf, sizeof(buf)-1); 5027dd7cddfSDavid du Colombier if(n <= 0) 5037dd7cddfSDavid du Colombier return n; 5047dd7cddfSDavid du Colombier if(debug) 5057dd7cddfSDavid du Colombier fprint(2, "%d <- %s\n", fd, buf); 5067dd7cddfSDavid du Colombier p = strchr(buf, ' '); 5077dd7cddfSDavid du Colombier if(strncmp(buf, "HTTP/", 5) != 0 || p == nil){ 5087dd7cddfSDavid du Colombier werrstr("bad response from server"); 5097dd7cddfSDavid du Colombier return -1; 5107dd7cddfSDavid du Colombier } 5117dd7cddfSDavid du Colombier buf[n] = 0; 5127dd7cddfSDavid du Colombier return atoi(p+1); 5137dd7cddfSDavid du Colombier } 5147dd7cddfSDavid du Colombier 5157dd7cddfSDavid du Colombier /* read in and crack the http headers, update u and r */ 5167dd7cddfSDavid du Colombier void hhetag(char*, URL*, Range*); 5177dd7cddfSDavid du Colombier void hhmtime(char*, URL*, Range*); 5187dd7cddfSDavid du Colombier void hhclen(char*, URL*, Range*); 5197dd7cddfSDavid du Colombier void hhcrange(char*, URL*, Range*); 5207dd7cddfSDavid du Colombier void hhuri(char*, URL*, Range*); 5217dd7cddfSDavid du Colombier void hhlocation(char*, URL*, Range*); 5227dd7cddfSDavid du Colombier 5237dd7cddfSDavid du Colombier struct { 5247dd7cddfSDavid du Colombier char *name; 5257dd7cddfSDavid du Colombier void (*f)(char*, URL*, Range*); 5267dd7cddfSDavid du Colombier } headers[] = { 5277dd7cddfSDavid du Colombier { "etag:", hhetag }, 5287dd7cddfSDavid du Colombier { "last-modified:", hhmtime }, 5297dd7cddfSDavid du Colombier { "content-length:", hhclen }, 5307dd7cddfSDavid du Colombier { "content-range:", hhcrange }, 5317dd7cddfSDavid du Colombier { "uri:", hhuri }, 5327dd7cddfSDavid du Colombier { "location:", hhlocation }, 5337dd7cddfSDavid du Colombier }; 5347dd7cddfSDavid du Colombier int 5359a747e4fSDavid du Colombier httpheaders(int fd, int cfd, URL *u, Range *r) 5367dd7cddfSDavid du Colombier { 5377dd7cddfSDavid du Colombier char buf[2048]; 5387dd7cddfSDavid du Colombier char *p; 5397dd7cddfSDavid du Colombier int i, n; 5407dd7cddfSDavid du Colombier 5417dd7cddfSDavid du Colombier for(;;){ 5427dd7cddfSDavid du Colombier n = getheader(fd, buf, sizeof(buf)); 5437dd7cddfSDavid du Colombier if(n <= 0) 5447dd7cddfSDavid du Colombier break; 5459a747e4fSDavid du Colombier if(cfd >= 0) 5469a747e4fSDavid du Colombier fprint(cfd, "%s\n", buf); 5477dd7cddfSDavid du Colombier for(i = 0; i < nelem(headers); i++){ 5487dd7cddfSDavid du Colombier n = strlen(headers[i].name); 5497dd7cddfSDavid du Colombier if(cistrncmp(buf, headers[i].name, n) == 0){ 5507dd7cddfSDavid du Colombier /* skip field name and leading white */ 5517dd7cddfSDavid du Colombier p = buf + n; 5527dd7cddfSDavid du Colombier while(*p == ' ' || *p == '\t') 5537dd7cddfSDavid du Colombier p++; 5547dd7cddfSDavid du Colombier 5557dd7cddfSDavid du Colombier (*headers[i].f)(p, u, r); 5567dd7cddfSDavid du Colombier break; 5577dd7cddfSDavid du Colombier } 5587dd7cddfSDavid du Colombier } 5597dd7cddfSDavid du Colombier } 5607dd7cddfSDavid du Colombier return n; 5617dd7cddfSDavid du Colombier } 5627dd7cddfSDavid du Colombier 5637dd7cddfSDavid du Colombier /* 5647dd7cddfSDavid du Colombier * read a single mime header, collect continuations. 5657dd7cddfSDavid du Colombier * 5667dd7cddfSDavid du Colombier * this routine assumes that there is a blank line twixt 5677dd7cddfSDavid du Colombier * the header and the message body, otherwise bytes will 5687dd7cddfSDavid du Colombier * be lost. 5697dd7cddfSDavid du Colombier */ 5707dd7cddfSDavid du Colombier int 5717dd7cddfSDavid du Colombier getheader(int fd, char *buf, int n) 5727dd7cddfSDavid du Colombier { 5737dd7cddfSDavid du Colombier char *p, *e; 5747dd7cddfSDavid du Colombier int i; 5757dd7cddfSDavid du Colombier 5767dd7cddfSDavid du Colombier n--; 5777dd7cddfSDavid du Colombier p = buf; 5787dd7cddfSDavid du Colombier for(e = p + n; ; p += i){ 5797dd7cddfSDavid du Colombier i = readline(fd, p, e-p); 5807dd7cddfSDavid du Colombier if(i < 0) 5817dd7cddfSDavid du Colombier return i; 5827dd7cddfSDavid du Colombier 5837dd7cddfSDavid du Colombier if(p == buf){ 5847dd7cddfSDavid du Colombier /* first line */ 5857dd7cddfSDavid du Colombier if(strchr(buf, ':') == nil) 5867dd7cddfSDavid du Colombier break; /* end of headers */ 5877dd7cddfSDavid du Colombier } else { 5887dd7cddfSDavid du Colombier /* continuation line */ 5897dd7cddfSDavid du Colombier if(*p != ' ' && *p != '\t'){ 5907dd7cddfSDavid du Colombier unreadline(p); 5917dd7cddfSDavid du Colombier *p = 0; 5927dd7cddfSDavid du Colombier break; /* end of this header */ 5937dd7cddfSDavid du Colombier } 5947dd7cddfSDavid du Colombier } 5957dd7cddfSDavid du Colombier } 5967dd7cddfSDavid du Colombier 5977dd7cddfSDavid du Colombier if(debug) 5987dd7cddfSDavid du Colombier fprint(2, "%d <- %s\n", fd, buf); 5997dd7cddfSDavid du Colombier return p-buf; 6007dd7cddfSDavid du Colombier } 6017dd7cddfSDavid du Colombier 6027dd7cddfSDavid du Colombier void 6037dd7cddfSDavid du Colombier hhetag(char *p, URL *u, Range*) 6047dd7cddfSDavid du Colombier { 6057dd7cddfSDavid du Colombier if(u->etag != nil){ 6067dd7cddfSDavid du Colombier if(strcmp(u->etag, p) != 0) 6077dd7cddfSDavid du Colombier sysfatal("file changed underfoot"); 6087dd7cddfSDavid du Colombier } else 6097dd7cddfSDavid du Colombier u->etag = strdup(p); 6107dd7cddfSDavid du Colombier } 6117dd7cddfSDavid du Colombier 6127dd7cddfSDavid du Colombier char* monthchars = "janfebmaraprmayjunjulaugsepoctnovdec"; 6137dd7cddfSDavid du Colombier 6147dd7cddfSDavid du Colombier void 6157dd7cddfSDavid du Colombier hhmtime(char *p, URL *u, Range*) 6167dd7cddfSDavid du Colombier { 6177dd7cddfSDavid du Colombier char *month, *day, *yr, *hms; 6187dd7cddfSDavid du Colombier char *fields[6]; 6197dd7cddfSDavid du Colombier Tm tm, now; 6207dd7cddfSDavid du Colombier int i; 6217dd7cddfSDavid du Colombier 6227dd7cddfSDavid du Colombier i = getfields(p, fields, 6, 1, " \t"); 6237dd7cddfSDavid du Colombier if(i < 5) 6247dd7cddfSDavid du Colombier return; 6257dd7cddfSDavid du Colombier 6267dd7cddfSDavid du Colombier day = fields[1]; 6277dd7cddfSDavid du Colombier month = fields[2]; 6287dd7cddfSDavid du Colombier yr = fields[3]; 6297dd7cddfSDavid du Colombier hms = fields[4]; 6307dd7cddfSDavid du Colombier 6317dd7cddfSDavid du Colombier /* default time */ 6327dd7cddfSDavid du Colombier now = *gmtime(time(0)); 6337dd7cddfSDavid du Colombier tm = now; 6347dd7cddfSDavid du Colombier 6357dd7cddfSDavid du Colombier /* convert ascii month to a number twixt 1 and 12 */ 6367dd7cddfSDavid du Colombier if(*month >= '0' && *month <= '9'){ 6377dd7cddfSDavid du Colombier tm.mon = atoi(month) - 1; 6387dd7cddfSDavid du Colombier if(tm.mon < 0 || tm.mon > 11) 6397dd7cddfSDavid du Colombier tm.mon = 5; 6407dd7cddfSDavid du Colombier } else { 6417dd7cddfSDavid du Colombier for(p = month; *p; p++) 6427dd7cddfSDavid du Colombier *p = tolower(*p); 6437dd7cddfSDavid du Colombier for(i = 0; i < 12; i++) 6447dd7cddfSDavid du Colombier if(strncmp(&monthchars[i*3], month, 3) == 0){ 6457dd7cddfSDavid du Colombier tm.mon = i; 6467dd7cddfSDavid du Colombier break; 6477dd7cddfSDavid du Colombier } 6487dd7cddfSDavid du Colombier } 6497dd7cddfSDavid du Colombier 6507dd7cddfSDavid du Colombier tm.mday = atoi(day); 6517dd7cddfSDavid du Colombier 6527dd7cddfSDavid du Colombier if(hms) { 6537dd7cddfSDavid du Colombier tm.hour = strtoul(hms, &p, 10); 6547dd7cddfSDavid du Colombier if(*p == ':') { 6557dd7cddfSDavid du Colombier p++; 6567dd7cddfSDavid du Colombier tm.min = strtoul(p, &p, 10); 6577dd7cddfSDavid du Colombier if(*p == ':') { 6587dd7cddfSDavid du Colombier p++; 6597dd7cddfSDavid du Colombier tm.sec = strtoul(p, &p, 10); 6607dd7cddfSDavid du Colombier } 6617dd7cddfSDavid du Colombier } 6627dd7cddfSDavid du Colombier if(tolower(*p) == 'p') 6637dd7cddfSDavid du Colombier tm.hour += 12; 6647dd7cddfSDavid du Colombier } 6657dd7cddfSDavid du Colombier 6667dd7cddfSDavid du Colombier if(yr) { 6677dd7cddfSDavid du Colombier tm.year = atoi(yr); 6687dd7cddfSDavid du Colombier if(tm.year >= 1900) 6697dd7cddfSDavid du Colombier tm.year -= 1900; 6707dd7cddfSDavid du Colombier } else { 6717dd7cddfSDavid du Colombier if(tm.mon > now.mon || (tm.mon == now.mon && tm.mday > now.mday+1)) 6727dd7cddfSDavid du Colombier tm.year--; 6737dd7cddfSDavid du Colombier } 6747dd7cddfSDavid du Colombier 6757dd7cddfSDavid du Colombier strcpy(tm.zone, "GMT"); 6767dd7cddfSDavid du Colombier /* convert to epoch seconds */ 6777dd7cddfSDavid du Colombier u->mtime = tm2sec(&tm); 6787dd7cddfSDavid du Colombier } 6797dd7cddfSDavid du Colombier 6807dd7cddfSDavid du Colombier void 6817dd7cddfSDavid du Colombier hhclen(char *p, URL*, Range *r) 6827dd7cddfSDavid du Colombier { 6837dd7cddfSDavid du Colombier r->end = atoi(p); 6847dd7cddfSDavid du Colombier } 6857dd7cddfSDavid du Colombier 6867dd7cddfSDavid du Colombier void 6877dd7cddfSDavid du Colombier hhcrange(char *p, URL*, Range *r) 6887dd7cddfSDavid du Colombier { 6897dd7cddfSDavid du Colombier char *x; 6907dd7cddfSDavid du Colombier vlong l; 6917dd7cddfSDavid du Colombier 6927dd7cddfSDavid du Colombier l = 0; 6937dd7cddfSDavid du Colombier x = strchr(p, '/'); 6947dd7cddfSDavid du Colombier if(x) 6957dd7cddfSDavid du Colombier l = atoll(x+1); 6967dd7cddfSDavid du Colombier if(l == 0) 6977dd7cddfSDavid du Colombier x = strchr(p, '-'); 6987dd7cddfSDavid du Colombier if(x) 6997dd7cddfSDavid du Colombier l = atoll(x+1); 7007dd7cddfSDavid du Colombier if(l) 7017dd7cddfSDavid du Colombier r->end = l; 7027dd7cddfSDavid du Colombier } 7037dd7cddfSDavid du Colombier 7047dd7cddfSDavid du Colombier void 7057dd7cddfSDavid du Colombier hhuri(char *p, URL *u, Range*) 7067dd7cddfSDavid du Colombier { 7077dd7cddfSDavid du Colombier if(*p != '<') 7087dd7cddfSDavid du Colombier return; 7097dd7cddfSDavid du Colombier u->redirect = strdup(p+1); 7107dd7cddfSDavid du Colombier p = strchr(u->redirect, '>'); 7117dd7cddfSDavid du Colombier if(p != nil) 7127dd7cddfSDavid du Colombier *p = 0; 7137dd7cddfSDavid du Colombier } 7147dd7cddfSDavid du Colombier 7157dd7cddfSDavid du Colombier void 7167dd7cddfSDavid du Colombier hhlocation(char *p, URL *u, Range*) 7177dd7cddfSDavid du Colombier { 7187dd7cddfSDavid du Colombier u->redirect = strdup(p); 7197dd7cddfSDavid du Colombier } 7207dd7cddfSDavid du Colombier 72159cc4ca5SDavid du Colombier enum 72259cc4ca5SDavid du Colombier { 72359cc4ca5SDavid du Colombier /* ftp return codes */ 72459cc4ca5SDavid du Colombier Extra= 1, 72559cc4ca5SDavid du Colombier Success= 2, 72659cc4ca5SDavid du Colombier Incomplete= 3, 72759cc4ca5SDavid du Colombier TempFail= 4, 72859cc4ca5SDavid du Colombier PermFail= 5, 72959cc4ca5SDavid du Colombier 73059cc4ca5SDavid du Colombier Nnetdir= 64, /* max length of network directory paths */ 73159cc4ca5SDavid du Colombier Ndialstr= 64, /* max length of dial strings */ 73259cc4ca5SDavid du Colombier }; 73359cc4ca5SDavid du Colombier 73459cc4ca5SDavid du Colombier int ftpcmd(int, char*, ...); 73559cc4ca5SDavid du Colombier int ftprcode(int, char*, int); 73659cc4ca5SDavid du Colombier int hello(int); 73759cc4ca5SDavid du Colombier int logon(int); 73859cc4ca5SDavid du Colombier int xfertype(int, char*); 73959cc4ca5SDavid du Colombier int passive(int, URL*); 74059cc4ca5SDavid du Colombier int active(int, URL*); 74159cc4ca5SDavid du Colombier int ftpxfer(int, int, Range*); 74259cc4ca5SDavid du Colombier int terminateftp(int, int); 74359cc4ca5SDavid du Colombier int getaddrport(char*, uchar*, uchar*); 74459cc4ca5SDavid du Colombier int ftprestart(int, int, URL*, Range*, long); 74559cc4ca5SDavid du Colombier 74659cc4ca5SDavid du Colombier int 74759cc4ca5SDavid du Colombier doftp(URL *u, Range *r, int out, long mtime) 74859cc4ca5SDavid du Colombier { 7499a747e4fSDavid du Colombier int pid, ctl, data, rv; 7509a747e4fSDavid du Colombier Waitmsg *w; 75159cc4ca5SDavid du Colombier char msg[64]; 75259cc4ca5SDavid du Colombier char conndir[NETPATHLEN]; 75359cc4ca5SDavid du Colombier char *p; 75459cc4ca5SDavid du Colombier 75559cc4ca5SDavid du Colombier ctl = dial(netmkaddr(u->host, tcpdir, u->port), 0, conndir, 0); 75659cc4ca5SDavid du Colombier if(ctl < 0) 75759cc4ca5SDavid du Colombier return Error; 75859cc4ca5SDavid du Colombier if(net == nil){ 75959cc4ca5SDavid du Colombier p = strrchr(conndir, '/'); 76059cc4ca5SDavid du Colombier *p = 0; 76159cc4ca5SDavid du Colombier snprint(tcpdir, sizeof(tcpdir), conndir); 76259cc4ca5SDavid du Colombier } 76359cc4ca5SDavid du Colombier 76459cc4ca5SDavid du Colombier initibuf(); 76559cc4ca5SDavid du Colombier 76659cc4ca5SDavid du Colombier rv = hello(ctl); 76759cc4ca5SDavid du Colombier if(rv < 0) 76859cc4ca5SDavid du Colombier return terminateftp(ctl, rv); 76959cc4ca5SDavid du Colombier 77059cc4ca5SDavid du Colombier rv = logon(ctl); 77159cc4ca5SDavid du Colombier if(rv < 0) 77259cc4ca5SDavid du Colombier return terminateftp(ctl, rv); 77359cc4ca5SDavid du Colombier 77459cc4ca5SDavid du Colombier rv = xfertype(ctl, "I"); 77559cc4ca5SDavid du Colombier if(rv < 0) 77659cc4ca5SDavid du Colombier return terminateftp(ctl, rv); 77759cc4ca5SDavid du Colombier 77859cc4ca5SDavid du Colombier /* if file is up to date and the right size, stop */ 77959cc4ca5SDavid du Colombier if(ftprestart(ctl, out, u, r, mtime) > 0){ 78059cc4ca5SDavid du Colombier close(ctl); 78159cc4ca5SDavid du Colombier return Eof; 78259cc4ca5SDavid du Colombier } 78359cc4ca5SDavid du Colombier 78459cc4ca5SDavid du Colombier /* first try passive mode, then active */ 78559cc4ca5SDavid du Colombier data = passive(ctl, u); 78659cc4ca5SDavid du Colombier if(data < 0){ 78759cc4ca5SDavid du Colombier data = active(ctl, u); 78859cc4ca5SDavid du Colombier if(data < 0) 78959cc4ca5SDavid du Colombier return Error; 79059cc4ca5SDavid du Colombier } 79159cc4ca5SDavid du Colombier 79259cc4ca5SDavid du Colombier /* fork */ 79359cc4ca5SDavid du Colombier switch(pid = rfork(RFPROC|RFFDG|RFMEM)){ 79459cc4ca5SDavid du Colombier case -1: 79559cc4ca5SDavid du Colombier close(data); 79659cc4ca5SDavid du Colombier return terminateftp(ctl, Error); 79759cc4ca5SDavid du Colombier case 0: 79859cc4ca5SDavid du Colombier ftpxfer(data, out, r); 79959cc4ca5SDavid du Colombier close(data); 80059cc4ca5SDavid du Colombier _exits(0); 80159cc4ca5SDavid du Colombier default: 80259cc4ca5SDavid du Colombier close(data); 80359cc4ca5SDavid du Colombier break; 80459cc4ca5SDavid du Colombier } 80559cc4ca5SDavid du Colombier 80659cc4ca5SDavid du Colombier /* wait for reply message */ 80759cc4ca5SDavid du Colombier rv = ftprcode(ctl, msg, sizeof(msg)); 80859cc4ca5SDavid du Colombier close(ctl); 80959cc4ca5SDavid du Colombier 81059cc4ca5SDavid du Colombier /* wait for process to terminate */ 8119a747e4fSDavid du Colombier w = nil; 81259cc4ca5SDavid du Colombier for(;;){ 8139a747e4fSDavid du Colombier free(w); 8149a747e4fSDavid du Colombier w = wait(); 8159a747e4fSDavid du Colombier if(w == nil) 81659cc4ca5SDavid du Colombier return Error; 8179a747e4fSDavid du Colombier if(w->pid == pid){ 8189a747e4fSDavid du Colombier if(w->msg[0] == 0){ 8199a747e4fSDavid du Colombier free(w); 82059cc4ca5SDavid du Colombier break; 8219a747e4fSDavid du Colombier } 8229a747e4fSDavid du Colombier werrstr("xfer: %s", w->msg); 8239a747e4fSDavid du Colombier free(w); 82459cc4ca5SDavid du Colombier return Error; 82559cc4ca5SDavid du Colombier } 82659cc4ca5SDavid du Colombier } 82759cc4ca5SDavid du Colombier 82859cc4ca5SDavid du Colombier switch(rv){ 82959cc4ca5SDavid du Colombier case Success: 83059cc4ca5SDavid du Colombier return Eof; 83159cc4ca5SDavid du Colombier case TempFail: 83259cc4ca5SDavid du Colombier return Server; 83359cc4ca5SDavid du Colombier default: 83459cc4ca5SDavid du Colombier return Error; 83559cc4ca5SDavid du Colombier } 83659cc4ca5SDavid du Colombier } 83759cc4ca5SDavid du Colombier 83859cc4ca5SDavid du Colombier int 83959cc4ca5SDavid du Colombier ftpcmd(int ctl, char *fmt, ...) 84059cc4ca5SDavid du Colombier { 84159cc4ca5SDavid du Colombier va_list arg; 84259cc4ca5SDavid du Colombier char buf[2*1024], *s; 84359cc4ca5SDavid du Colombier 84459cc4ca5SDavid du Colombier va_start(arg, fmt); 8459a747e4fSDavid du Colombier s = vseprint(buf, buf + (sizeof(buf)-4) / sizeof(*buf), fmt, arg); 84659cc4ca5SDavid du Colombier va_end(arg); 84759cc4ca5SDavid du Colombier if(debug) 84859cc4ca5SDavid du Colombier fprint(2, "%d -> %s\n", ctl, buf); 84959cc4ca5SDavid du Colombier *s++ = '\r'; 85059cc4ca5SDavid du Colombier *s++ = '\n'; 85159cc4ca5SDavid du Colombier if(write(ctl, buf, s - buf) != s - buf) 85259cc4ca5SDavid du Colombier return -1; 85359cc4ca5SDavid du Colombier return 0; 85459cc4ca5SDavid du Colombier } 85559cc4ca5SDavid du Colombier 85659cc4ca5SDavid du Colombier int 85759cc4ca5SDavid du Colombier ftprcode(int ctl, char *msg, int len) 85859cc4ca5SDavid du Colombier { 85959cc4ca5SDavid du Colombier int rv; 86059cc4ca5SDavid du Colombier int i; 861d9306527SDavid du Colombier char *p; 86259cc4ca5SDavid du Colombier 86359cc4ca5SDavid du Colombier len--; /* room for terminating null */ 86459cc4ca5SDavid du Colombier for(;;){ 86559cc4ca5SDavid du Colombier *msg = 0; 86659cc4ca5SDavid du Colombier i = readline(ctl, msg, len); 86759cc4ca5SDavid du Colombier if(i < 0) 86859cc4ca5SDavid du Colombier break; 86959cc4ca5SDavid du Colombier if(debug) 87059cc4ca5SDavid du Colombier fprint(2, "%d <- %s\n", ctl, msg); 87159cc4ca5SDavid du Colombier 87259cc4ca5SDavid du Colombier /* stop if not a continuation */ 873d9306527SDavid du Colombier rv = strtol(msg, &p, 10); 874d9306527SDavid du Colombier if(rv >= 100 && rv < 600 && p==msg+3 && *p == ' ') 87559cc4ca5SDavid du Colombier return rv/100; 87659cc4ca5SDavid du Colombier } 87759cc4ca5SDavid du Colombier *msg = 0; 87859cc4ca5SDavid du Colombier 87959cc4ca5SDavid du Colombier return -1; 88059cc4ca5SDavid du Colombier } 88159cc4ca5SDavid du Colombier 88259cc4ca5SDavid du Colombier int 88359cc4ca5SDavid du Colombier hello(int ctl) 88459cc4ca5SDavid du Colombier { 88559cc4ca5SDavid du Colombier char msg[1024]; 88659cc4ca5SDavid du Colombier 88759cc4ca5SDavid du Colombier /* wait for hello from other side */ 88859cc4ca5SDavid du Colombier if(ftprcode(ctl, msg, sizeof(msg)) != Success){ 88959cc4ca5SDavid du Colombier werrstr("HELLO: %s", msg); 89059cc4ca5SDavid du Colombier return Server; 89159cc4ca5SDavid du Colombier } 89259cc4ca5SDavid du Colombier return 0; 89359cc4ca5SDavid du Colombier } 89459cc4ca5SDavid du Colombier 89559cc4ca5SDavid du Colombier int 89659cc4ca5SDavid du Colombier getdec(char *p, int n) 89759cc4ca5SDavid du Colombier { 89859cc4ca5SDavid du Colombier int x = 0; 89959cc4ca5SDavid du Colombier int i; 90059cc4ca5SDavid du Colombier 90159cc4ca5SDavid du Colombier for(i = 0; i < n; i++) 90259cc4ca5SDavid du Colombier x = x*10 + (*p++ - '0'); 90359cc4ca5SDavid du Colombier return x; 90459cc4ca5SDavid du Colombier } 90559cc4ca5SDavid du Colombier 90659cc4ca5SDavid du Colombier int 90759cc4ca5SDavid du Colombier ftprestart(int ctl, int out, URL *u, Range *r, long mtime) 90859cc4ca5SDavid du Colombier { 90959cc4ca5SDavid du Colombier Tm tm; 91059cc4ca5SDavid du Colombier char msg[1024]; 91159cc4ca5SDavid du Colombier long x, rmtime; 91259cc4ca5SDavid du Colombier 91359cc4ca5SDavid du Colombier ftpcmd(ctl, "MDTM %s", u->page); 91459cc4ca5SDavid du Colombier if(ftprcode(ctl, msg, sizeof(msg)) != Success){ 91559cc4ca5SDavid du Colombier r->start = 0; 91659cc4ca5SDavid du Colombier return 0; /* need to do something */ 91759cc4ca5SDavid du Colombier } 91859cc4ca5SDavid du Colombier 91959cc4ca5SDavid du Colombier /* decode modification time */ 92059cc4ca5SDavid du Colombier if(strlen(msg) < 4 + 4 + 2 + 2 + 2 + 2 + 2){ 92159cc4ca5SDavid du Colombier r->start = 0; 92259cc4ca5SDavid du Colombier return 0; /* need to do something */ 92359cc4ca5SDavid du Colombier } 92459cc4ca5SDavid du Colombier memset(&tm, 0, sizeof(tm)); 92559cc4ca5SDavid du Colombier tm.year = getdec(msg+4, 4) - 1900; 92659cc4ca5SDavid du Colombier tm.mon = getdec(msg+4+4, 2) - 1; 92759cc4ca5SDavid du Colombier tm.mday = getdec(msg+4+4+2, 2); 92859cc4ca5SDavid du Colombier tm.hour = getdec(msg+4+4+2+2, 2); 92959cc4ca5SDavid du Colombier tm.min = getdec(msg+4+4+2+2+2, 2); 93059cc4ca5SDavid du Colombier tm.sec = getdec(msg+4+4+2+2+2+2, 2); 93159cc4ca5SDavid du Colombier strcpy(tm.zone, "GMT"); 93259cc4ca5SDavid du Colombier rmtime = tm2sec(&tm); 93359cc4ca5SDavid du Colombier if(rmtime > mtime) 93459cc4ca5SDavid du Colombier r->start = 0; 93559cc4ca5SDavid du Colombier 93659cc4ca5SDavid du Colombier /* get size */ 93759cc4ca5SDavid du Colombier ftpcmd(ctl, "SIZE %s", u->page); 93859cc4ca5SDavid du Colombier if(ftprcode(ctl, msg, sizeof(msg)) == Success){ 93959cc4ca5SDavid du Colombier x = atol(msg+4); 94059cc4ca5SDavid du Colombier if(r->start == x) 94159cc4ca5SDavid du Colombier return 1; /* we're up to date */ 94259cc4ca5SDavid du Colombier r->end = x; 94359cc4ca5SDavid du Colombier } 94459cc4ca5SDavid du Colombier 94559cc4ca5SDavid du Colombier /* seek to restart point */ 94659cc4ca5SDavid du Colombier if(r->start > 0){ 94759cc4ca5SDavid du Colombier ftpcmd(ctl, "REST %lud", r->start); 94859cc4ca5SDavid du Colombier if(ftprcode(ctl, msg, sizeof(msg)) == Incomplete) 94959cc4ca5SDavid du Colombier seek(out, r->start, 0); 95059cc4ca5SDavid du Colombier else 95159cc4ca5SDavid du Colombier r->start = 0; 95259cc4ca5SDavid du Colombier } 95359cc4ca5SDavid du Colombier 95459cc4ca5SDavid du Colombier return 0; /* need to do something */ 95559cc4ca5SDavid du Colombier } 95659cc4ca5SDavid du Colombier 95759cc4ca5SDavid du Colombier int 95859cc4ca5SDavid du Colombier logon(int ctl) 95959cc4ca5SDavid du Colombier { 96059cc4ca5SDavid du Colombier char msg[1024]; 96159cc4ca5SDavid du Colombier 96259cc4ca5SDavid du Colombier /* login anonymous */ 96359cc4ca5SDavid du Colombier ftpcmd(ctl, "USER anonymous"); 96459cc4ca5SDavid du Colombier switch(ftprcode(ctl, msg, sizeof(msg))){ 96559cc4ca5SDavid du Colombier case Success: 96659cc4ca5SDavid du Colombier return 0; 96759cc4ca5SDavid du Colombier case Incomplete: 96859cc4ca5SDavid du Colombier break; /* need password */ 96959cc4ca5SDavid du Colombier default: 97059cc4ca5SDavid du Colombier werrstr("USER: %s", msg); 97159cc4ca5SDavid du Colombier return Server; 97259cc4ca5SDavid du Colombier } 97359cc4ca5SDavid du Colombier 97459cc4ca5SDavid du Colombier /* send user id as password */ 97559cc4ca5SDavid du Colombier sprint(msg, "%s@closedmind.org", getuser()); 97659cc4ca5SDavid du Colombier ftpcmd(ctl, "PASS %s", msg); 97759cc4ca5SDavid du Colombier if(ftprcode(ctl, msg, sizeof(msg)) != Success){ 97859cc4ca5SDavid du Colombier werrstr("PASS: %s", msg); 97959cc4ca5SDavid du Colombier return Server; 98059cc4ca5SDavid du Colombier } 98159cc4ca5SDavid du Colombier 98259cc4ca5SDavid du Colombier return 0; 98359cc4ca5SDavid du Colombier } 98459cc4ca5SDavid du Colombier 98559cc4ca5SDavid du Colombier int 98659cc4ca5SDavid du Colombier xfertype(int ctl, char *t) 98759cc4ca5SDavid du Colombier { 98859cc4ca5SDavid du Colombier char msg[1024]; 98959cc4ca5SDavid du Colombier 99059cc4ca5SDavid du Colombier ftpcmd(ctl, "TYPE %s", t); 99159cc4ca5SDavid du Colombier if(ftprcode(ctl, msg, sizeof(msg)) != Success){ 99259cc4ca5SDavid du Colombier werrstr("TYPE %s: %s", t, msg); 99359cc4ca5SDavid du Colombier return Server; 99459cc4ca5SDavid du Colombier } 99559cc4ca5SDavid du Colombier 99659cc4ca5SDavid du Colombier return 0; 99759cc4ca5SDavid du Colombier } 99859cc4ca5SDavid du Colombier 99959cc4ca5SDavid du Colombier int 100059cc4ca5SDavid du Colombier passive(int ctl, URL *u) 100159cc4ca5SDavid du Colombier { 100259cc4ca5SDavid du Colombier char msg[1024]; 100359cc4ca5SDavid du Colombier char ipaddr[32]; 100459cc4ca5SDavid du Colombier char *f[6]; 100559cc4ca5SDavid du Colombier char *p; 100659cc4ca5SDavid du Colombier int fd; 100759cc4ca5SDavid du Colombier int port; 100859cc4ca5SDavid du Colombier char aport[12]; 100959cc4ca5SDavid du Colombier 101059cc4ca5SDavid du Colombier ftpcmd(ctl, "PASV"); 101159cc4ca5SDavid du Colombier if(ftprcode(ctl, msg, sizeof(msg)) != Success) 101259cc4ca5SDavid du Colombier return Error; 101359cc4ca5SDavid du Colombier 101459cc4ca5SDavid du Colombier /* get address and port number from reply, this is AI */ 101559cc4ca5SDavid du Colombier p = strchr(msg, '('); 101659cc4ca5SDavid du Colombier if(p == nil){ 101759cc4ca5SDavid du Colombier for(p = msg+3; *p; p++) 101859cc4ca5SDavid du Colombier if(isdigit(*p)) 101959cc4ca5SDavid du Colombier break; 102059cc4ca5SDavid du Colombier } else 102159cc4ca5SDavid du Colombier p++; 102259cc4ca5SDavid du Colombier if(getfields(p, f, 6, 0, ",)") < 6){ 102359cc4ca5SDavid du Colombier werrstr("ftp protocol botch"); 102459cc4ca5SDavid du Colombier return Server; 102559cc4ca5SDavid du Colombier } 102659cc4ca5SDavid du Colombier snprint(ipaddr, sizeof(ipaddr), "%s.%s.%s.%s", 102759cc4ca5SDavid du Colombier f[0], f[1], f[2], f[3]); 102859cc4ca5SDavid du Colombier port = ((atoi(f[4])&0xff)<<8) + (atoi(f[5])&0xff); 102959cc4ca5SDavid du Colombier sprint(aport, "%d", port); 103059cc4ca5SDavid du Colombier 103159cc4ca5SDavid du Colombier /* open data connection */ 103259cc4ca5SDavid du Colombier fd = dial(netmkaddr(ipaddr, tcpdir, aport), 0, 0, 0); 103359cc4ca5SDavid du Colombier if(fd < 0){ 103459cc4ca5SDavid du Colombier werrstr("passive mode failed: %r"); 103559cc4ca5SDavid du Colombier return Error; 103659cc4ca5SDavid du Colombier } 103759cc4ca5SDavid du Colombier 103859cc4ca5SDavid du Colombier /* tell remote to send a file */ 103959cc4ca5SDavid du Colombier ftpcmd(ctl, "RETR %s", u->page); 104059cc4ca5SDavid du Colombier if(ftprcode(ctl, msg, sizeof(msg)) != Extra){ 104159cc4ca5SDavid du Colombier werrstr("RETR %s: %s", u->page, msg); 104259cc4ca5SDavid du Colombier return Error; 104359cc4ca5SDavid du Colombier } 104459cc4ca5SDavid du Colombier return fd; 104559cc4ca5SDavid du Colombier } 104659cc4ca5SDavid du Colombier 104759cc4ca5SDavid du Colombier int 104859cc4ca5SDavid du Colombier active(int ctl, URL *u) 104959cc4ca5SDavid du Colombier { 105059cc4ca5SDavid du Colombier char msg[1024]; 105159cc4ca5SDavid du Colombier char dir[40], ldir[40]; 105259cc4ca5SDavid du Colombier uchar ipaddr[4]; 105359cc4ca5SDavid du Colombier uchar port[2]; 105459cc4ca5SDavid du Colombier int lcfd, dfd, afd; 105559cc4ca5SDavid du Colombier 105659cc4ca5SDavid du Colombier /* announce a port for the call back */ 105759cc4ca5SDavid du Colombier snprint(msg, sizeof(msg), "%s!*!0", tcpdir); 105859cc4ca5SDavid du Colombier afd = announce(msg, dir); 105959cc4ca5SDavid du Colombier if(afd < 0) 106059cc4ca5SDavid du Colombier return Error; 106159cc4ca5SDavid du Colombier 106259cc4ca5SDavid du Colombier /* get a local address/port of the annoucement */ 106359cc4ca5SDavid du Colombier if(getaddrport(dir, ipaddr, port) < 0){ 106459cc4ca5SDavid du Colombier close(afd); 106559cc4ca5SDavid du Colombier return Error; 106659cc4ca5SDavid du Colombier } 106759cc4ca5SDavid du Colombier 106859cc4ca5SDavid du Colombier /* tell remote side address and port*/ 106959cc4ca5SDavid du Colombier ftpcmd(ctl, "PORT %d,%d,%d,%d,%d,%d", ipaddr[0], ipaddr[1], ipaddr[2], 107059cc4ca5SDavid du Colombier ipaddr[3], port[0], port[1]); 107159cc4ca5SDavid du Colombier if(ftprcode(ctl, msg, sizeof(msg)) != Success){ 107259cc4ca5SDavid du Colombier close(afd); 107359cc4ca5SDavid du Colombier werrstr("active: %s", msg); 107459cc4ca5SDavid du Colombier return Error; 107559cc4ca5SDavid du Colombier } 107659cc4ca5SDavid du Colombier 107759cc4ca5SDavid du Colombier /* tell remote to send a file */ 107859cc4ca5SDavid du Colombier ftpcmd(ctl, "RETR %s", u->page); 107959cc4ca5SDavid du Colombier if(ftprcode(ctl, msg, sizeof(msg)) != Extra){ 108059cc4ca5SDavid du Colombier close(afd); 108159cc4ca5SDavid du Colombier werrstr("RETR: %s", msg); 108259cc4ca5SDavid du Colombier return Server; 108359cc4ca5SDavid du Colombier } 108459cc4ca5SDavid du Colombier 108559cc4ca5SDavid du Colombier /* wait for a connection */ 108659cc4ca5SDavid du Colombier lcfd = listen(dir, ldir); 108759cc4ca5SDavid du Colombier if(lcfd < 0){ 108859cc4ca5SDavid du Colombier close(afd); 108959cc4ca5SDavid du Colombier return Error; 109059cc4ca5SDavid du Colombier } 109159cc4ca5SDavid du Colombier dfd = accept(lcfd, ldir); 109259cc4ca5SDavid du Colombier if(dfd < 0){ 109359cc4ca5SDavid du Colombier close(afd); 109459cc4ca5SDavid du Colombier close(lcfd); 109559cc4ca5SDavid du Colombier return Error; 109659cc4ca5SDavid du Colombier } 109759cc4ca5SDavid du Colombier close(afd); 109859cc4ca5SDavid du Colombier close(lcfd); 109959cc4ca5SDavid du Colombier 110059cc4ca5SDavid du Colombier return dfd; 110159cc4ca5SDavid du Colombier } 110259cc4ca5SDavid du Colombier 110359cc4ca5SDavid du Colombier int 110459cc4ca5SDavid du Colombier ftpxfer(int in, int out, Range *r) 110559cc4ca5SDavid du Colombier { 110659cc4ca5SDavid du Colombier char buf[1024]; 110759cc4ca5SDavid du Colombier long vtime; 110859cc4ca5SDavid du Colombier int i, n; 110959cc4ca5SDavid du Colombier 111059cc4ca5SDavid du Colombier vtime = 0; 111159cc4ca5SDavid du Colombier for(n = 0;;n += i){ 111259cc4ca5SDavid du Colombier i = read(in, buf, sizeof(buf)); 111359cc4ca5SDavid du Colombier if(i == 0) 111459cc4ca5SDavid du Colombier break; 111559cc4ca5SDavid du Colombier if(i < 0) 111659cc4ca5SDavid du Colombier return Error; 111759cc4ca5SDavid du Colombier if(write(out, buf, i) != i) 111859cc4ca5SDavid du Colombier return Error; 111959cc4ca5SDavid du Colombier r->start += i; 112059cc4ca5SDavid du Colombier if(verbose && vtime != time(0)) { 112159cc4ca5SDavid du Colombier vtime = time(0); 112259cc4ca5SDavid du Colombier fprint(2, "%ld %ld\n", r->start, r->end); 112359cc4ca5SDavid du Colombier } 112459cc4ca5SDavid du Colombier } 112559cc4ca5SDavid du Colombier return n; 112659cc4ca5SDavid du Colombier } 112759cc4ca5SDavid du Colombier 112859cc4ca5SDavid du Colombier int 112959cc4ca5SDavid du Colombier terminateftp(int ctl, int rv) 113059cc4ca5SDavid du Colombier { 113159cc4ca5SDavid du Colombier close(ctl); 113259cc4ca5SDavid du Colombier return rv; 113359cc4ca5SDavid du Colombier } 113459cc4ca5SDavid du Colombier 113559cc4ca5SDavid du Colombier /* 113659cc4ca5SDavid du Colombier * case insensitive strcmp (why aren't these in libc?) 113759cc4ca5SDavid du Colombier */ 11387dd7cddfSDavid du Colombier int 11397dd7cddfSDavid du Colombier cistrncmp(char *a, char *b, int n) 11407dd7cddfSDavid du Colombier { 11417dd7cddfSDavid du Colombier while(n-- > 0){ 11427dd7cddfSDavid du Colombier if(tolower(*a++) != tolower(*b++)) 11437dd7cddfSDavid du Colombier return -1; 11447dd7cddfSDavid du Colombier } 11457dd7cddfSDavid du Colombier return 0; 11467dd7cddfSDavid du Colombier } 11477dd7cddfSDavid du Colombier 11487dd7cddfSDavid du Colombier int 11497dd7cddfSDavid du Colombier cistrcmp(char *a, char *b) 11507dd7cddfSDavid du Colombier { 11517dd7cddfSDavid du Colombier while(*a || *b) 11527dd7cddfSDavid du Colombier if(tolower(*a++) != tolower(*b++)) 11537dd7cddfSDavid du Colombier return -1; 11547dd7cddfSDavid du Colombier 11557dd7cddfSDavid du Colombier return 0; 11567dd7cddfSDavid du Colombier } 11577dd7cddfSDavid du Colombier 11587dd7cddfSDavid du Colombier /* 11597dd7cddfSDavid du Colombier * buffered io 11607dd7cddfSDavid du Colombier */ 11617dd7cddfSDavid du Colombier struct 11627dd7cddfSDavid du Colombier { 11637dd7cddfSDavid du Colombier char *rp; 11647dd7cddfSDavid du Colombier char *wp; 11657dd7cddfSDavid du Colombier char buf[4*1024]; 11667dd7cddfSDavid du Colombier } b; 11677dd7cddfSDavid du Colombier 11687dd7cddfSDavid du Colombier void 11697dd7cddfSDavid du Colombier initibuf(void) 11707dd7cddfSDavid du Colombier { 11717dd7cddfSDavid du Colombier b.rp = b.wp = b.buf; 11727dd7cddfSDavid du Colombier } 11737dd7cddfSDavid du Colombier 117459cc4ca5SDavid du Colombier /* 117559cc4ca5SDavid du Colombier * read a possibly buffered line, strip off trailing while 117659cc4ca5SDavid du Colombier */ 11777dd7cddfSDavid du Colombier int 11787dd7cddfSDavid du Colombier readline(int fd, char *buf, int len) 11797dd7cddfSDavid du Colombier { 11807dd7cddfSDavid du Colombier int n; 11817dd7cddfSDavid du Colombier char *p; 118259cc4ca5SDavid du Colombier int eof = 0; 11837dd7cddfSDavid du Colombier 11847dd7cddfSDavid du Colombier len--; 11857dd7cddfSDavid du Colombier 11867dd7cddfSDavid du Colombier for(p = buf;;){ 11877dd7cddfSDavid du Colombier if(b.rp >= b.wp){ 11887dd7cddfSDavid du Colombier n = read(fd, b.wp, sizeof(b.buf)/2); 11897dd7cddfSDavid du Colombier if(n < 0) 11907dd7cddfSDavid du Colombier return -1; 119159cc4ca5SDavid du Colombier if(n == 0){ 119259cc4ca5SDavid du Colombier eof = 1; 11937dd7cddfSDavid du Colombier break; 119459cc4ca5SDavid du Colombier } 11957dd7cddfSDavid du Colombier b.wp += n; 11967dd7cddfSDavid du Colombier } 11977dd7cddfSDavid du Colombier n = *b.rp++; 11987dd7cddfSDavid du Colombier if(len > 0){ 11997dd7cddfSDavid du Colombier *p++ = n; 12007dd7cddfSDavid du Colombier len--; 12017dd7cddfSDavid du Colombier } 12027dd7cddfSDavid du Colombier if(n == '\n') 12037dd7cddfSDavid du Colombier break; 12047dd7cddfSDavid du Colombier } 12057dd7cddfSDavid du Colombier 12067dd7cddfSDavid du Colombier /* drop trailing white */ 12077dd7cddfSDavid du Colombier for(;;){ 12087dd7cddfSDavid du Colombier if(p <= buf) 12097dd7cddfSDavid du Colombier break; 12107dd7cddfSDavid du Colombier n = *(p-1); 12117dd7cddfSDavid du Colombier if(n != ' ' && n != '\t' && n != '\r' && n != '\n') 12127dd7cddfSDavid du Colombier break; 12137dd7cddfSDavid du Colombier p--; 12147dd7cddfSDavid du Colombier } 12157dd7cddfSDavid du Colombier *p = 0; 121659cc4ca5SDavid du Colombier 121759cc4ca5SDavid du Colombier if(eof && p == buf) 121859cc4ca5SDavid du Colombier return -1; 121959cc4ca5SDavid du Colombier 12207dd7cddfSDavid du Colombier return p-buf; 12217dd7cddfSDavid du Colombier } 12227dd7cddfSDavid du Colombier 12237dd7cddfSDavid du Colombier void 12247dd7cddfSDavid du Colombier unreadline(char *line) 12257dd7cddfSDavid du Colombier { 12267dd7cddfSDavid du Colombier int i, n; 12277dd7cddfSDavid du Colombier 12287dd7cddfSDavid du Colombier i = strlen(line); 12297dd7cddfSDavid du Colombier n = b.wp-b.rp; 12307dd7cddfSDavid du Colombier memmove(&b.buf[i+1], b.rp, n); 12317dd7cddfSDavid du Colombier memmove(b.buf, line, i); 12327dd7cddfSDavid du Colombier b.buf[i] = '\n'; 12337dd7cddfSDavid du Colombier b.rp = b.buf; 12347dd7cddfSDavid du Colombier b.wp = b.rp + i + 1 + n; 12357dd7cddfSDavid du Colombier } 12367dd7cddfSDavid du Colombier 12377dd7cddfSDavid du Colombier int 12387dd7cddfSDavid du Colombier readibuf(int fd, char *buf, int len) 12397dd7cddfSDavid du Colombier { 12407dd7cddfSDavid du Colombier int n; 12417dd7cddfSDavid du Colombier 12427dd7cddfSDavid du Colombier n = b.wp-b.rp; 12437dd7cddfSDavid du Colombier if(n > 0){ 12447dd7cddfSDavid du Colombier if(n > len) 12457dd7cddfSDavid du Colombier n = len; 12467dd7cddfSDavid du Colombier memmove(buf, b.rp, n); 12477dd7cddfSDavid du Colombier b.rp += n; 12487dd7cddfSDavid du Colombier return n; 12497dd7cddfSDavid du Colombier } 12507dd7cddfSDavid du Colombier return read(fd, buf, len); 12517dd7cddfSDavid du Colombier } 12527dd7cddfSDavid du Colombier 12537dd7cddfSDavid du Colombier int 12547dd7cddfSDavid du Colombier dfprint(int fd, char *fmt, ...) 12557dd7cddfSDavid du Colombier { 12567dd7cddfSDavid du Colombier char buf[4*1024]; 12577dd7cddfSDavid du Colombier va_list arg; 12587dd7cddfSDavid du Colombier 12597dd7cddfSDavid du Colombier va_start(arg, fmt); 12609a747e4fSDavid du Colombier vseprint(buf, buf+sizeof(buf), fmt, arg); 12617dd7cddfSDavid du Colombier va_end(arg); 12627dd7cddfSDavid du Colombier if(debug) 12637dd7cddfSDavid du Colombier fprint(2, "%d -> %s", fd, buf); 12647dd7cddfSDavid du Colombier return fprint(fd, "%s", buf); 12657dd7cddfSDavid du Colombier } 126659cc4ca5SDavid du Colombier 126759cc4ca5SDavid du Colombier int 126859cc4ca5SDavid du Colombier getaddrport(char *dir, uchar *ipaddr, uchar *port) 126959cc4ca5SDavid du Colombier { 127059cc4ca5SDavid du Colombier char buf[256]; 127159cc4ca5SDavid du Colombier int fd, i; 127259cc4ca5SDavid du Colombier char *p; 127359cc4ca5SDavid du Colombier 127459cc4ca5SDavid du Colombier snprint(buf, sizeof(buf), "%s/local", dir); 127559cc4ca5SDavid du Colombier fd = open(buf, OREAD); 127659cc4ca5SDavid du Colombier if(fd < 0) 127759cc4ca5SDavid du Colombier return -1; 127859cc4ca5SDavid du Colombier i = read(fd, buf, sizeof(buf)-1); 127959cc4ca5SDavid du Colombier close(fd); 128059cc4ca5SDavid du Colombier if(i <= 0) 128159cc4ca5SDavid du Colombier return -1; 128259cc4ca5SDavid du Colombier buf[i] = 0; 128359cc4ca5SDavid du Colombier p = strchr(buf, '!'); 128459cc4ca5SDavid du Colombier if(p != nil) 128559cc4ca5SDavid du Colombier *p++ = 0; 128659cc4ca5SDavid du Colombier v4parseip(ipaddr, buf); 128759cc4ca5SDavid du Colombier i = atoi(p); 128859cc4ca5SDavid du Colombier port[0] = i>>8; 128959cc4ca5SDavid du Colombier port[1] = i; 129059cc4ca5SDavid du Colombier return 0; 129159cc4ca5SDavid du Colombier } 1292