17dd7cddfSDavid du Colombier #include <u.h> 27dd7cddfSDavid du Colombier #include <libc.h> 3*59cc4ca5SDavid du Colombier #include <ctype.h> 47dd7cddfSDavid du Colombier #include <bio.h> 5*59cc4ca5SDavid du Colombier #include <ip.h> 67dd7cddfSDavid du Colombier 77dd7cddfSDavid du Colombier typedef struct URL URL; 87dd7cddfSDavid du Colombier struct URL 97dd7cddfSDavid du Colombier { 107dd7cddfSDavid du Colombier int method; 117dd7cddfSDavid du Colombier char *host; 127dd7cddfSDavid du Colombier char *port; 137dd7cddfSDavid du Colombier char *page; 147dd7cddfSDavid du Colombier char *etag; 157dd7cddfSDavid du Colombier char *redirect; 16*59cc4ca5SDavid du Colombier char *postbody; 177dd7cddfSDavid du Colombier long mtime; 187dd7cddfSDavid du Colombier }; 197dd7cddfSDavid du Colombier 207dd7cddfSDavid du Colombier typedef struct Range Range; 217dd7cddfSDavid du Colombier struct Range 227dd7cddfSDavid du Colombier { 237dd7cddfSDavid du Colombier long start; /* only 2 gig supported, tdb */ 247dd7cddfSDavid du Colombier long end; 257dd7cddfSDavid du Colombier }; 267dd7cddfSDavid du Colombier 277dd7cddfSDavid du Colombier enum 287dd7cddfSDavid du Colombier { 297dd7cddfSDavid du Colombier Http, 307dd7cddfSDavid du Colombier Ftp, 317dd7cddfSDavid du Colombier Other 327dd7cddfSDavid du Colombier }; 337dd7cddfSDavid du Colombier 347dd7cddfSDavid du Colombier enum 357dd7cddfSDavid du Colombier { 367dd7cddfSDavid du Colombier Eof = 0, 377dd7cddfSDavid du Colombier Error = -1, 387dd7cddfSDavid du Colombier Server = -2, 397dd7cddfSDavid du Colombier Changed = -3, 407dd7cddfSDavid du Colombier }; 417dd7cddfSDavid du Colombier 427dd7cddfSDavid du Colombier int debug; 437dd7cddfSDavid du Colombier char *ofile; 447dd7cddfSDavid du Colombier 457dd7cddfSDavid du Colombier int doftp(URL*, Range*, int, long); 467dd7cddfSDavid du Colombier int dohttp(URL*, Range*, int, long); 477dd7cddfSDavid du Colombier int crackurl(URL*, char*); 487dd7cddfSDavid du Colombier Range* crackrange(char*); 497dd7cddfSDavid du Colombier int getheader(int, char*, int); 507dd7cddfSDavid du Colombier int httpheaders(int, URL*, Range*); 517dd7cddfSDavid du Colombier int httprcode(int); 527dd7cddfSDavid du Colombier int cistrncmp(char*, char*, int); 537dd7cddfSDavid du Colombier int cistrcmp(char*, char*); 547dd7cddfSDavid du Colombier void initibuf(void); 557dd7cddfSDavid du Colombier int readline(int, char*, int); 567dd7cddfSDavid du Colombier int readibuf(int, char*, int); 577dd7cddfSDavid du Colombier int dfprint(int, char*, ...); 587dd7cddfSDavid du Colombier void unreadline(char*); 59*59cc4ca5SDavid du Colombier 607dd7cddfSDavid du Colombier int verbose; 61*59cc4ca5SDavid du Colombier char *net; 62*59cc4ca5SDavid du Colombier char tcpdir[64]; 637dd7cddfSDavid du Colombier 647dd7cddfSDavid du Colombier struct { 657dd7cddfSDavid du Colombier char *name; 667dd7cddfSDavid du Colombier int (*f)(URL*, Range*, int, long); 677dd7cddfSDavid du Colombier } method[] = { 687dd7cddfSDavid du Colombier [Http] { "http", dohttp }, 697dd7cddfSDavid du Colombier [Ftp] { "ftp", doftp }, 707dd7cddfSDavid du Colombier [Other] { "_______", nil }, 717dd7cddfSDavid du Colombier }; 727dd7cddfSDavid du Colombier 737dd7cddfSDavid du Colombier void 747dd7cddfSDavid du Colombier usage(void) 757dd7cddfSDavid du Colombier { 76*59cc4ca5SDavid du Colombier fprint(2, "usage: %s [-v] [-o outfile] [-p body] [-x netmtpt] url\n", argv0); 777dd7cddfSDavid du Colombier exits("usage"); 787dd7cddfSDavid du Colombier } 797dd7cddfSDavid du Colombier 807dd7cddfSDavid du Colombier void 817dd7cddfSDavid du Colombier main(int argc, char **argv) 827dd7cddfSDavid du Colombier { 837dd7cddfSDavid du Colombier URL u; 847dd7cddfSDavid du Colombier Range r; 857dd7cddfSDavid du Colombier int fd, errs, n; 867dd7cddfSDavid du Colombier Dir d; 87*59cc4ca5SDavid du Colombier char postbody[4096], *p, *e, *t; 887dd7cddfSDavid du Colombier 897dd7cddfSDavid du Colombier ofile = nil; 90*59cc4ca5SDavid du Colombier p = postbody; 91*59cc4ca5SDavid du Colombier e = p + sizeof(postbody); 927dd7cddfSDavid du Colombier r.start = 0; 937dd7cddfSDavid du Colombier r.end = -1; 947dd7cddfSDavid du Colombier d.mtime = 0; 95*59cc4ca5SDavid du Colombier memset(&u, 0, sizeof(u)); 967dd7cddfSDavid du Colombier 977dd7cddfSDavid du Colombier ARGBEGIN { 987dd7cddfSDavid du Colombier case 'o': 997dd7cddfSDavid du Colombier ofile = ARGF(); 1007dd7cddfSDavid du Colombier break; 1017dd7cddfSDavid du Colombier case 'd': 1027dd7cddfSDavid du Colombier debug = 1; 1037dd7cddfSDavid du Colombier break; 1047dd7cddfSDavid du Colombier case 'v': 1057dd7cddfSDavid du Colombier verbose = 1; 1067dd7cddfSDavid du Colombier break; 107*59cc4ca5SDavid du Colombier case 'x': 108*59cc4ca5SDavid du Colombier net = ARGF(); 109*59cc4ca5SDavid du Colombier if(net == nil) 110*59cc4ca5SDavid du Colombier usage(); 111*59cc4ca5SDavid du Colombier break; 112*59cc4ca5SDavid du Colombier case 'p': 113*59cc4ca5SDavid du Colombier t = ARGF(); 114*59cc4ca5SDavid du Colombier if(t == nil) 115*59cc4ca5SDavid du Colombier usage(); 116*59cc4ca5SDavid du Colombier if(p != postbody) 117*59cc4ca5SDavid du Colombier p = seprint(p, e, "&%s", t); 118*59cc4ca5SDavid du Colombier else 119*59cc4ca5SDavid du Colombier p = seprint(p, e, "%s", t); 120*59cc4ca5SDavid du Colombier u.postbody = postbody; 121*59cc4ca5SDavid du Colombier 122*59cc4ca5SDavid du Colombier break; 1237dd7cddfSDavid du Colombier default: 1247dd7cddfSDavid du Colombier usage(); 1257dd7cddfSDavid du Colombier } ARGEND; 1267dd7cddfSDavid du Colombier 127*59cc4ca5SDavid du Colombier if(net != nil){ 128*59cc4ca5SDavid du Colombier if(strlen(net) > sizeof(tcpdir)-5) 129*59cc4ca5SDavid du Colombier sysfatal("network mount point too long"); 130*59cc4ca5SDavid du Colombier snprint(tcpdir, sizeof(tcpdir), "%s/tcp", net); 131*59cc4ca5SDavid du Colombier } else 132*59cc4ca5SDavid du Colombier snprint(tcpdir, sizeof(tcpdir), "tcp"); 133*59cc4ca5SDavid du Colombier 1347dd7cddfSDavid du Colombier if(argc != 1) 1357dd7cddfSDavid du Colombier usage(); 1367dd7cddfSDavid du Colombier 1377dd7cddfSDavid du Colombier fd = 1; 1387dd7cddfSDavid du Colombier if(ofile != nil){ 1397dd7cddfSDavid du Colombier if(dirstat(ofile, &d) < 0){ 1407dd7cddfSDavid du Colombier fd = create(ofile, OWRITE, 0664); 1417dd7cddfSDavid du Colombier if(fd < 0) 1427dd7cddfSDavid du Colombier sysfatal("creating %s: %r", ofile); 1437dd7cddfSDavid du Colombier } else { 1447dd7cddfSDavid du Colombier fd = open(ofile, OWRITE); 1457dd7cddfSDavid du Colombier if(fd < 0) 1467dd7cddfSDavid du Colombier sysfatal("can't open %s: %r", ofile); 1477dd7cddfSDavid du Colombier r.start = d.length; 1487dd7cddfSDavid du Colombier } 1497dd7cddfSDavid du Colombier } 1507dd7cddfSDavid du Colombier 1517dd7cddfSDavid du Colombier errs = 0; 1527dd7cddfSDavid du Colombier 1537dd7cddfSDavid du Colombier if(crackurl(&u, argv[0]) < 0) 1547dd7cddfSDavid du Colombier sysfatal("%r"); 1557dd7cddfSDavid du Colombier 1567dd7cddfSDavid du Colombier for(;;){ 1577dd7cddfSDavid du Colombier /* transfer data */ 1587dd7cddfSDavid du Colombier werrstr(""); 159*59cc4ca5SDavid du Colombier seek(fd, 0, 0); 1607dd7cddfSDavid du Colombier n = (*method[u.method].f)(&u, &r, fd, d.mtime); 1617dd7cddfSDavid du Colombier 1627dd7cddfSDavid du Colombier switch(n){ 1637dd7cddfSDavid du Colombier case Eof: 1647dd7cddfSDavid du Colombier exits(0); 1657dd7cddfSDavid du Colombier break; 1667dd7cddfSDavid du Colombier case Error: 1677dd7cddfSDavid du Colombier if(errs++ < 10) 1687dd7cddfSDavid du Colombier continue; 1697dd7cddfSDavid du Colombier sysfatal("too many errors with no progress %r"); 1707dd7cddfSDavid du Colombier break; 1717dd7cddfSDavid du Colombier case Server: 1727dd7cddfSDavid du Colombier sysfatal("server returned: %r"); 1737dd7cddfSDavid du Colombier break; 1747dd7cddfSDavid du Colombier } 1757dd7cddfSDavid du Colombier 1767dd7cddfSDavid du Colombier /* forward progress */ 1777dd7cddfSDavid du Colombier errs = 0; 1787dd7cddfSDavid du Colombier r.start += n; 1797dd7cddfSDavid du Colombier if(r.start >= r.end) 1807dd7cddfSDavid du Colombier break; 1817dd7cddfSDavid du Colombier } 1827dd7cddfSDavid du Colombier 1837dd7cddfSDavid du Colombier exits(0); 1847dd7cddfSDavid du Colombier } 1857dd7cddfSDavid du Colombier 1867dd7cddfSDavid du Colombier int 1877dd7cddfSDavid du Colombier crackurl(URL *u, char *s) 1887dd7cddfSDavid du Colombier { 1897dd7cddfSDavid du Colombier char *p; 1907dd7cddfSDavid du Colombier int i; 1917dd7cddfSDavid du Colombier 1927dd7cddfSDavid du Colombier if(u->host != nil){ 1937dd7cddfSDavid du Colombier free(u->host); 1947dd7cddfSDavid du Colombier u->host = nil; 1957dd7cddfSDavid du Colombier } 1967dd7cddfSDavid du Colombier if(u->page != nil){ 1977dd7cddfSDavid du Colombier free(u->page); 1987dd7cddfSDavid du Colombier u->page = nil; 1997dd7cddfSDavid du Colombier } 2007dd7cddfSDavid du Colombier 2017dd7cddfSDavid du Colombier /* get type */ 2027dd7cddfSDavid du Colombier u->method = Other; 2037dd7cddfSDavid du Colombier for(p = s; *p; p++){ 2047dd7cddfSDavid du Colombier if(*p == '/'){ 2057dd7cddfSDavid du Colombier u->method = Http; 2067dd7cddfSDavid du Colombier p = s; 2077dd7cddfSDavid du Colombier break; 2087dd7cddfSDavid du Colombier } 2097dd7cddfSDavid du Colombier if(*p == ':' && *(p+1)=='/' && *(p+2)=='/'){ 2107dd7cddfSDavid du Colombier *p = 0; 2117dd7cddfSDavid du Colombier p += 3; 2127dd7cddfSDavid du Colombier for(i = 0; i < nelem(method); i++){ 2137dd7cddfSDavid du Colombier if(cistrcmp(s, method[i].name) == 0){ 2147dd7cddfSDavid du Colombier u->method = i; 2157dd7cddfSDavid du Colombier break; 2167dd7cddfSDavid du Colombier } 2177dd7cddfSDavid du Colombier } 2187dd7cddfSDavid du Colombier break; 2197dd7cddfSDavid du Colombier } 2207dd7cddfSDavid du Colombier } 2217dd7cddfSDavid du Colombier 2227dd7cddfSDavid du Colombier if(u->method == Other){ 2237dd7cddfSDavid du Colombier werrstr("unsupported URL type %s", s); 2247dd7cddfSDavid du Colombier return -1; 2257dd7cddfSDavid du Colombier } 2267dd7cddfSDavid du Colombier 2277dd7cddfSDavid du Colombier /* get system */ 2287dd7cddfSDavid du Colombier s = p; 2297dd7cddfSDavid du Colombier p = strchr(s, '/'); 2307dd7cddfSDavid du Colombier if(p == nil){ 2317dd7cddfSDavid du Colombier u->host = strdup(s); 2327dd7cddfSDavid du Colombier u->page = strdup("/"); 2337dd7cddfSDavid du Colombier } else { 2347dd7cddfSDavid du Colombier u->page = strdup(p); 2357dd7cddfSDavid du Colombier *p = 0; 2367dd7cddfSDavid du Colombier u->host = strdup(s); 2377dd7cddfSDavid du Colombier *p = '/'; 2387dd7cddfSDavid du Colombier } 2397dd7cddfSDavid du Colombier 2407dd7cddfSDavid du Colombier if(p = strchr(u->host, ':')) { 2417dd7cddfSDavid du Colombier *p++ = 0; 2427dd7cddfSDavid du Colombier u->port = p; 2437dd7cddfSDavid du Colombier } else 244*59cc4ca5SDavid du Colombier u->port = method[u->method].name; 2457dd7cddfSDavid du Colombier 2467dd7cddfSDavid du Colombier if(*(u->host) == 0){ 2477dd7cddfSDavid du Colombier werrstr("bad url, null host"); 2487dd7cddfSDavid du Colombier return -1; 2497dd7cddfSDavid du Colombier } 2507dd7cddfSDavid du Colombier 2517dd7cddfSDavid du Colombier return 0; 2527dd7cddfSDavid du Colombier } 2537dd7cddfSDavid du Colombier 2547dd7cddfSDavid du Colombier char *day[] = { 2557dd7cddfSDavid du Colombier "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 2567dd7cddfSDavid du Colombier }; 2577dd7cddfSDavid du Colombier 2587dd7cddfSDavid du Colombier char *month[] = { 2597dd7cddfSDavid du Colombier "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 2607dd7cddfSDavid du Colombier }; 2617dd7cddfSDavid du Colombier 2627dd7cddfSDavid du Colombier struct 2637dd7cddfSDavid du Colombier { 2647dd7cddfSDavid du Colombier int fd; 2657dd7cddfSDavid du Colombier long mtime; 2667dd7cddfSDavid du Colombier } note; 2677dd7cddfSDavid du Colombier 2687dd7cddfSDavid du Colombier void 2697dd7cddfSDavid du Colombier catch(void*, char*) 2707dd7cddfSDavid du Colombier { 2717dd7cddfSDavid du Colombier Dir d; 2727dd7cddfSDavid du Colombier 2737dd7cddfSDavid du Colombier if(dirfstat(note.fd, &d) < 0) 2747dd7cddfSDavid du Colombier sysfatal("catch: can't dirfstat: %r"); 2757dd7cddfSDavid du Colombier d.mtime = note.mtime; 2767dd7cddfSDavid du Colombier if(dirfwstat(note.fd, &d) < 0) 2777dd7cddfSDavid du Colombier sysfatal("catch: can't dirfwstat: %r"); 2787dd7cddfSDavid du Colombier noted(NDFLT); 2797dd7cddfSDavid du Colombier } 2807dd7cddfSDavid du Colombier 2817dd7cddfSDavid du Colombier int 2827dd7cddfSDavid du Colombier dohttp(URL *u, Range *r, int out, long mtime) 2837dd7cddfSDavid du Colombier { 2847dd7cddfSDavid du Colombier int fd; 2857dd7cddfSDavid du Colombier int redirect, loop; 2867dd7cddfSDavid du Colombier int n, rv, code; 2877dd7cddfSDavid du Colombier long tot, vtime; 2887dd7cddfSDavid du Colombier Tm *tm; 2897dd7cddfSDavid du Colombier char buf[1024]; 2907dd7cddfSDavid du Colombier char err[ERRLEN]; 2917dd7cddfSDavid du Colombier 292*59cc4ca5SDavid du Colombier 293*59cc4ca5SDavid du Colombier /* always move back to a previous 512 byte bound because some 294*59cc4ca5SDavid du Colombier * servers can't seem to deal with requests that start at the 295*59cc4ca5SDavid du Colombier * end of the file 296*59cc4ca5SDavid du Colombier */ 297*59cc4ca5SDavid du Colombier if(r->start) 298*59cc4ca5SDavid du Colombier r->start = ((r->start-1)/512)*512; 299*59cc4ca5SDavid du Colombier 3007dd7cddfSDavid du Colombier /* loop for redirects, requires reading both response code and headers */ 3017dd7cddfSDavid du Colombier fd = -1; 3027dd7cddfSDavid du Colombier for(loop = 0; loop < 32; loop++){ 303*59cc4ca5SDavid du Colombier fd = dial(netmkaddr(u->host, tcpdir, u->port), 0, 0, 0); 3047dd7cddfSDavid du Colombier if(fd < 0) 3057dd7cddfSDavid du Colombier return Error; 3067dd7cddfSDavid du Colombier 3077dd7cddfSDavid du Colombier /* write request, use range if not start of file */ 308*59cc4ca5SDavid du Colombier if(u->postbody == nil){ 309*59cc4ca5SDavid du Colombier dfprint(fd, "GET %s HTTP/1.0\r\n" 310*59cc4ca5SDavid du Colombier "Host: %s\r\n" 311*59cc4ca5SDavid du Colombier "User-agent: Plan9/hget\r\n", 312*59cc4ca5SDavid du Colombier u->page, u->host); 313*59cc4ca5SDavid du Colombier } else { 314*59cc4ca5SDavid du Colombier dfprint(fd, "POST %s HTTP/1.0\r\n" 315*59cc4ca5SDavid du Colombier "Host: %s\r\n" 316*59cc4ca5SDavid du Colombier "Content-type: application/x-www-form-urlencoded\r\n" 317*59cc4ca5SDavid du Colombier "Content-length: %d\r\n" 318*59cc4ca5SDavid du Colombier "User-agent: Plan9/hget\r\n" 319*59cc4ca5SDavid du Colombier "\r\n", 320*59cc4ca5SDavid du Colombier u->page, u->host, strlen(u->postbody)); 321*59cc4ca5SDavid du Colombier dfprint(fd, "%s", u->postbody); 322*59cc4ca5SDavid du Colombier } 3237dd7cddfSDavid du Colombier if(r->start != 0){ 3247dd7cddfSDavid du Colombier dfprint(fd, "Range: bytes=%d-\n", r->start); 3257dd7cddfSDavid du Colombier if(u->etag != nil){ 3267dd7cddfSDavid du Colombier dfprint(fd, "If-range: %s\n", u->etag); 3277dd7cddfSDavid du Colombier } else { 3287dd7cddfSDavid du Colombier tm = gmtime(mtime); 3297dd7cddfSDavid du Colombier dfprint(fd, "If-range: %s, %d %s %d %2d:%2.2d:%2.2d GMT\n", 3307dd7cddfSDavid du Colombier day[tm->wday], tm->mday, month[tm->mon], 3317dd7cddfSDavid du Colombier tm->year+1900, tm->hour, tm->min, tm->sec); 3327dd7cddfSDavid du Colombier } 3337dd7cddfSDavid du Colombier } 3347dd7cddfSDavid du Colombier dfprint(fd, "\r\n", u->host); 3357dd7cddfSDavid du Colombier 3367dd7cddfSDavid du Colombier redirect = 0; 3377dd7cddfSDavid du Colombier initibuf(); 3387dd7cddfSDavid du Colombier code = httprcode(fd); 3397dd7cddfSDavid du Colombier switch(code){ 3407dd7cddfSDavid du Colombier case Error: /* connection timed out */ 3417dd7cddfSDavid du Colombier case Eof: 342*59cc4ca5SDavid du Colombier close(fd); 3437dd7cddfSDavid du Colombier return code; 3447dd7cddfSDavid du Colombier 3457dd7cddfSDavid du Colombier case 200: /* OK */ 3467dd7cddfSDavid du Colombier case 201: /* Created */ 3477dd7cddfSDavid du Colombier case 202: /* Accepted */ 3487dd7cddfSDavid du Colombier if(ofile == nil && r->start != 0) 3497dd7cddfSDavid du Colombier sysfatal("page changed underfoot"); 3507dd7cddfSDavid du Colombier break; 3517dd7cddfSDavid du Colombier 3527dd7cddfSDavid du Colombier case 204: /* No Content */ 3537dd7cddfSDavid du Colombier sysfatal("No Content"); 3547dd7cddfSDavid du Colombier 3557dd7cddfSDavid du Colombier case 206: /* Partial Content */ 3567dd7cddfSDavid du Colombier seek(out, r->start, 0); 3577dd7cddfSDavid du Colombier break; 3587dd7cddfSDavid du Colombier 3597dd7cddfSDavid du Colombier case 301: /* Moved Permanently */ 3607dd7cddfSDavid du Colombier case 302: /* Moved Temporarily */ 3617dd7cddfSDavid du Colombier redirect = 1; 3627dd7cddfSDavid du Colombier break; 3637dd7cddfSDavid du Colombier 3647dd7cddfSDavid du Colombier case 304: /* Not Modified */ 3657dd7cddfSDavid du Colombier break; 3667dd7cddfSDavid du Colombier 3677dd7cddfSDavid du Colombier case 400: /* Bad Request */ 3687dd7cddfSDavid du Colombier sysfatal("Bad Request"); 3697dd7cddfSDavid du Colombier 3707dd7cddfSDavid du Colombier case 401: /* Unauthorized */ 3717dd7cddfSDavid du Colombier case 402: /* ??? */ 3727dd7cddfSDavid du Colombier sysfatal("Unauthorized"); 3737dd7cddfSDavid du Colombier 3747dd7cddfSDavid du Colombier case 403: /* Forbidden */ 3757dd7cddfSDavid du Colombier sysfatal("Forbidden by server"); 3767dd7cddfSDavid du Colombier 3777dd7cddfSDavid du Colombier case 404: /* Not Found */ 3787dd7cddfSDavid du Colombier sysfatal("Not found on server"); 3797dd7cddfSDavid du Colombier 3807dd7cddfSDavid du Colombier case 500: /* Internal server error */ 3817dd7cddfSDavid du Colombier sysfatal("Server choked"); 3827dd7cddfSDavid du Colombier 3837dd7cddfSDavid du Colombier case 501: /* Not implemented */ 3847dd7cddfSDavid du Colombier sysfatal("Server can't do it!"); 3857dd7cddfSDavid du Colombier 3867dd7cddfSDavid du Colombier case 502: /* Bad gateway */ 3877dd7cddfSDavid du Colombier sysfatal("Bad gateway"); 3887dd7cddfSDavid du Colombier 3897dd7cddfSDavid du Colombier case 503: /* Service unavailable */ 3907dd7cddfSDavid du Colombier sysfatal("Service unavailable"); 3917dd7cddfSDavid du Colombier 3927dd7cddfSDavid du Colombier default: 3937dd7cddfSDavid du Colombier sysfatal("Unknown response code"); 3947dd7cddfSDavid du Colombier } 3957dd7cddfSDavid du Colombier 3967dd7cddfSDavid du Colombier if(u->redirect != nil){ 3977dd7cddfSDavid du Colombier free(u->redirect); 3987dd7cddfSDavid du Colombier u->redirect = nil; 3997dd7cddfSDavid du Colombier } 4007dd7cddfSDavid du Colombier 4017dd7cddfSDavid du Colombier rv = httpheaders(fd, u, r); 402*59cc4ca5SDavid du Colombier if(rv != 0){ 403*59cc4ca5SDavid du Colombier close(fd); 4047dd7cddfSDavid du Colombier return rv; 405*59cc4ca5SDavid du Colombier } 4067dd7cddfSDavid du Colombier 4077dd7cddfSDavid du Colombier if(!redirect) 4087dd7cddfSDavid du Colombier break; 4097dd7cddfSDavid du Colombier 4107dd7cddfSDavid du Colombier if(u->redirect == nil) 4117dd7cddfSDavid du Colombier sysfatal("redirect: no URL"); 4127dd7cddfSDavid du Colombier if(crackurl(u, u->redirect) < 0) 4137dd7cddfSDavid du Colombier sysfatal("redirect: %r"); 4147dd7cddfSDavid du Colombier } 4157dd7cddfSDavid du Colombier 4167dd7cddfSDavid du Colombier /* transfer whatever you get */ 4177dd7cddfSDavid du Colombier if(ofile != nil && u->mtime != 0){ 4187dd7cddfSDavid du Colombier note.fd = out; 4197dd7cddfSDavid du Colombier note.mtime = u->mtime; 4207dd7cddfSDavid du Colombier notify(catch); 4217dd7cddfSDavid du Colombier } 4227dd7cddfSDavid du Colombier 4237dd7cddfSDavid du Colombier tot = 0; 4247dd7cddfSDavid du Colombier vtime = 0; 4257dd7cddfSDavid du Colombier for(;;){ 4267dd7cddfSDavid du Colombier n = readibuf(fd, buf, sizeof(buf)); 4277dd7cddfSDavid du Colombier if(n <= 0) 4287dd7cddfSDavid du Colombier break; 4297dd7cddfSDavid du Colombier if(write(out, buf, n) != n) 4307dd7cddfSDavid du Colombier break; 4317dd7cddfSDavid du Colombier tot += n; 4327dd7cddfSDavid du Colombier if(verbose && vtime != time(0)) { 4337dd7cddfSDavid du Colombier vtime = time(0); 4347dd7cddfSDavid du Colombier fprint(2, "%ld %ld\n", r->start+tot, r->end); 4357dd7cddfSDavid du Colombier } 4367dd7cddfSDavid du Colombier } 4377dd7cddfSDavid du Colombier notify(nil); 438*59cc4ca5SDavid du Colombier close(fd); 4397dd7cddfSDavid du Colombier 4407dd7cddfSDavid du Colombier errstr(err); 4417dd7cddfSDavid du Colombier if(ofile != nil && u->mtime != 0){ 4427dd7cddfSDavid du Colombier Dir d; 4437dd7cddfSDavid du Colombier 4447dd7cddfSDavid du Colombier dirfstat(out, &d); 4457dd7cddfSDavid du Colombier d.mtime = u->mtime; 4467dd7cddfSDavid du Colombier if(dirfwstat(out, &d) < 0) 4477dd7cddfSDavid du Colombier fprint(2, "couldn't set mtime: %r\n"); 4487dd7cddfSDavid du Colombier } 4497dd7cddfSDavid du Colombier errstr(err); 4507dd7cddfSDavid du Colombier 4517dd7cddfSDavid du Colombier return tot; 4527dd7cddfSDavid du Colombier } 4537dd7cddfSDavid du Colombier 4547dd7cddfSDavid du Colombier /* get the http response code */ 4557dd7cddfSDavid du Colombier int 4567dd7cddfSDavid du Colombier httprcode(int fd) 4577dd7cddfSDavid du Colombier { 4587dd7cddfSDavid du Colombier int n; 4597dd7cddfSDavid du Colombier char *p; 4607dd7cddfSDavid du Colombier char buf[256]; 4617dd7cddfSDavid du Colombier 4627dd7cddfSDavid du Colombier n = readline(fd, buf, sizeof(buf)-1); 4637dd7cddfSDavid du Colombier if(n <= 0) 4647dd7cddfSDavid du Colombier return n; 4657dd7cddfSDavid du Colombier if(debug) 4667dd7cddfSDavid du Colombier fprint(2, "%d <- %s\n", fd, buf); 4677dd7cddfSDavid du Colombier p = strchr(buf, ' '); 4687dd7cddfSDavid du Colombier if(strncmp(buf, "HTTP/", 5) != 0 || p == nil){ 4697dd7cddfSDavid du Colombier werrstr("bad response from server"); 4707dd7cddfSDavid du Colombier return -1; 4717dd7cddfSDavid du Colombier } 4727dd7cddfSDavid du Colombier buf[n] = 0; 4737dd7cddfSDavid du Colombier return atoi(p+1); 4747dd7cddfSDavid du Colombier } 4757dd7cddfSDavid du Colombier 4767dd7cddfSDavid du Colombier /* read in and crack the http headers, update u and r */ 4777dd7cddfSDavid du Colombier void hhetag(char*, URL*, Range*); 4787dd7cddfSDavid du Colombier void hhmtime(char*, URL*, Range*); 4797dd7cddfSDavid du Colombier void hhclen(char*, URL*, Range*); 4807dd7cddfSDavid du Colombier void hhcrange(char*, URL*, Range*); 4817dd7cddfSDavid du Colombier void hhuri(char*, URL*, Range*); 4827dd7cddfSDavid du Colombier void hhlocation(char*, URL*, Range*); 4837dd7cddfSDavid du Colombier 4847dd7cddfSDavid du Colombier struct { 4857dd7cddfSDavid du Colombier char *name; 4867dd7cddfSDavid du Colombier void (*f)(char*, URL*, Range*); 4877dd7cddfSDavid du Colombier } headers[] = { 4887dd7cddfSDavid du Colombier { "etag:", hhetag }, 4897dd7cddfSDavid du Colombier { "last-modified:", hhmtime }, 4907dd7cddfSDavid du Colombier { "content-length:", hhclen }, 4917dd7cddfSDavid du Colombier { "content-range:", hhcrange }, 4927dd7cddfSDavid du Colombier { "uri:", hhuri }, 4937dd7cddfSDavid du Colombier { "location:", hhlocation }, 4947dd7cddfSDavid du Colombier }; 4957dd7cddfSDavid du Colombier int 4967dd7cddfSDavid du Colombier httpheaders(int fd, URL *u, Range *r) 4977dd7cddfSDavid du Colombier { 4987dd7cddfSDavid du Colombier char buf[2048]; 4997dd7cddfSDavid du Colombier char *p; 5007dd7cddfSDavid du Colombier int i, n; 5017dd7cddfSDavid du Colombier 5027dd7cddfSDavid du Colombier for(;;){ 5037dd7cddfSDavid du Colombier n = getheader(fd, buf, sizeof(buf)); 5047dd7cddfSDavid du Colombier if(n <= 0) 5057dd7cddfSDavid du Colombier break; 5067dd7cddfSDavid du Colombier for(i = 0; i < nelem(headers); i++){ 5077dd7cddfSDavid du Colombier n = strlen(headers[i].name); 5087dd7cddfSDavid du Colombier if(cistrncmp(buf, headers[i].name, n) == 0){ 5097dd7cddfSDavid du Colombier /* skip field name and leading white */ 5107dd7cddfSDavid du Colombier p = buf + n; 5117dd7cddfSDavid du Colombier while(*p == ' ' || *p == '\t') 5127dd7cddfSDavid du Colombier p++; 5137dd7cddfSDavid du Colombier 5147dd7cddfSDavid du Colombier (*headers[i].f)(p, u, r); 5157dd7cddfSDavid du Colombier break; 5167dd7cddfSDavid du Colombier } 5177dd7cddfSDavid du Colombier } 5187dd7cddfSDavid du Colombier } 5197dd7cddfSDavid du Colombier return n; 5207dd7cddfSDavid du Colombier } 5217dd7cddfSDavid du Colombier 5227dd7cddfSDavid du Colombier /* 5237dd7cddfSDavid du Colombier * read a single mime header, collect continuations. 5247dd7cddfSDavid du Colombier * 5257dd7cddfSDavid du Colombier * this routine assumes that there is a blank line twixt 5267dd7cddfSDavid du Colombier * the header and the message body, otherwise bytes will 5277dd7cddfSDavid du Colombier * be lost. 5287dd7cddfSDavid du Colombier */ 5297dd7cddfSDavid du Colombier int 5307dd7cddfSDavid du Colombier getheader(int fd, char *buf, int n) 5317dd7cddfSDavid du Colombier { 5327dd7cddfSDavid du Colombier char *p, *e; 5337dd7cddfSDavid du Colombier int i; 5347dd7cddfSDavid du Colombier 5357dd7cddfSDavid du Colombier n--; 5367dd7cddfSDavid du Colombier p = buf; 5377dd7cddfSDavid du Colombier for(e = p + n; ; p += i){ 5387dd7cddfSDavid du Colombier i = readline(fd, p, e-p); 5397dd7cddfSDavid du Colombier if(i < 0) 5407dd7cddfSDavid du Colombier return i; 5417dd7cddfSDavid du Colombier 5427dd7cddfSDavid du Colombier if(p == buf){ 5437dd7cddfSDavid du Colombier /* first line */ 5447dd7cddfSDavid du Colombier if(strchr(buf, ':') == nil) 5457dd7cddfSDavid du Colombier break; /* end of headers */ 5467dd7cddfSDavid du Colombier } else { 5477dd7cddfSDavid du Colombier /* continuation line */ 5487dd7cddfSDavid du Colombier if(*p != ' ' && *p != '\t'){ 5497dd7cddfSDavid du Colombier unreadline(p); 5507dd7cddfSDavid du Colombier *p = 0; 5517dd7cddfSDavid du Colombier break; /* end of this header */ 5527dd7cddfSDavid du Colombier } 5537dd7cddfSDavid du Colombier } 5547dd7cddfSDavid du Colombier } 5557dd7cddfSDavid du Colombier 5567dd7cddfSDavid du Colombier if(debug) 5577dd7cddfSDavid du Colombier fprint(2, "%d <- %s\n", fd, buf); 5587dd7cddfSDavid du Colombier return p-buf; 5597dd7cddfSDavid du Colombier } 5607dd7cddfSDavid du Colombier 5617dd7cddfSDavid du Colombier void 5627dd7cddfSDavid du Colombier hhetag(char *p, URL *u, Range*) 5637dd7cddfSDavid du Colombier { 5647dd7cddfSDavid du Colombier if(u->etag != nil){ 5657dd7cddfSDavid du Colombier if(strcmp(u->etag, p) != 0) 5667dd7cddfSDavid du Colombier sysfatal("file changed underfoot"); 5677dd7cddfSDavid du Colombier } else 5687dd7cddfSDavid du Colombier u->etag = strdup(p); 5697dd7cddfSDavid du Colombier } 5707dd7cddfSDavid du Colombier 5717dd7cddfSDavid du Colombier char* monthchars = "janfebmaraprmayjunjulaugsepoctnovdec"; 5727dd7cddfSDavid du Colombier 5737dd7cddfSDavid du Colombier void 5747dd7cddfSDavid du Colombier hhmtime(char *p, URL *u, Range*) 5757dd7cddfSDavid du Colombier { 5767dd7cddfSDavid du Colombier char *month, *day, *yr, *hms; 5777dd7cddfSDavid du Colombier char *fields[6]; 5787dd7cddfSDavid du Colombier Tm tm, now; 5797dd7cddfSDavid du Colombier int i; 5807dd7cddfSDavid du Colombier 5817dd7cddfSDavid du Colombier i = getfields(p, fields, 6, 1, " \t"); 5827dd7cddfSDavid du Colombier if(i < 5) 5837dd7cddfSDavid du Colombier return; 5847dd7cddfSDavid du Colombier 5857dd7cddfSDavid du Colombier day = fields[1]; 5867dd7cddfSDavid du Colombier month = fields[2]; 5877dd7cddfSDavid du Colombier yr = fields[3]; 5887dd7cddfSDavid du Colombier hms = fields[4]; 5897dd7cddfSDavid du Colombier 5907dd7cddfSDavid du Colombier /* default time */ 5917dd7cddfSDavid du Colombier now = *gmtime(time(0)); 5927dd7cddfSDavid du Colombier tm = now; 5937dd7cddfSDavid du Colombier 5947dd7cddfSDavid du Colombier /* convert ascii month to a number twixt 1 and 12 */ 5957dd7cddfSDavid du Colombier if(*month >= '0' && *month <= '9'){ 5967dd7cddfSDavid du Colombier tm.mon = atoi(month) - 1; 5977dd7cddfSDavid du Colombier if(tm.mon < 0 || tm.mon > 11) 5987dd7cddfSDavid du Colombier tm.mon = 5; 5997dd7cddfSDavid du Colombier } else { 6007dd7cddfSDavid du Colombier for(p = month; *p; p++) 6017dd7cddfSDavid du Colombier *p = tolower(*p); 6027dd7cddfSDavid du Colombier for(i = 0; i < 12; i++) 6037dd7cddfSDavid du Colombier if(strncmp(&monthchars[i*3], month, 3) == 0){ 6047dd7cddfSDavid du Colombier tm.mon = i; 6057dd7cddfSDavid du Colombier break; 6067dd7cddfSDavid du Colombier } 6077dd7cddfSDavid du Colombier } 6087dd7cddfSDavid du Colombier 6097dd7cddfSDavid du Colombier tm.mday = atoi(day); 6107dd7cddfSDavid du Colombier 6117dd7cddfSDavid du Colombier if(hms) { 6127dd7cddfSDavid du Colombier tm.hour = strtoul(hms, &p, 10); 6137dd7cddfSDavid du Colombier if(*p == ':') { 6147dd7cddfSDavid du Colombier p++; 6157dd7cddfSDavid du Colombier tm.min = strtoul(p, &p, 10); 6167dd7cddfSDavid du Colombier if(*p == ':') { 6177dd7cddfSDavid du Colombier p++; 6187dd7cddfSDavid du Colombier tm.sec = strtoul(p, &p, 10); 6197dd7cddfSDavid du Colombier } 6207dd7cddfSDavid du Colombier } 6217dd7cddfSDavid du Colombier if(tolower(*p) == 'p') 6227dd7cddfSDavid du Colombier tm.hour += 12; 6237dd7cddfSDavid du Colombier } 6247dd7cddfSDavid du Colombier 6257dd7cddfSDavid du Colombier if(yr) { 6267dd7cddfSDavid du Colombier tm.year = atoi(yr); 6277dd7cddfSDavid du Colombier if(tm.year >= 1900) 6287dd7cddfSDavid du Colombier tm.year -= 1900; 6297dd7cddfSDavid du Colombier } else { 6307dd7cddfSDavid du Colombier if(tm.mon > now.mon || (tm.mon == now.mon && tm.mday > now.mday+1)) 6317dd7cddfSDavid du Colombier tm.year--; 6327dd7cddfSDavid du Colombier } 6337dd7cddfSDavid du Colombier 6347dd7cddfSDavid du Colombier strcpy(tm.zone, "GMT"); 6357dd7cddfSDavid du Colombier /* convert to epoch seconds */ 6367dd7cddfSDavid du Colombier u->mtime = tm2sec(&tm); 6377dd7cddfSDavid du Colombier } 6387dd7cddfSDavid du Colombier 6397dd7cddfSDavid du Colombier void 6407dd7cddfSDavid du Colombier hhclen(char *p, URL*, Range *r) 6417dd7cddfSDavid du Colombier { 6427dd7cddfSDavid du Colombier r->end = atoi(p); 6437dd7cddfSDavid du Colombier } 6447dd7cddfSDavid du Colombier 6457dd7cddfSDavid du Colombier void 6467dd7cddfSDavid du Colombier hhcrange(char *p, URL*, Range *r) 6477dd7cddfSDavid du Colombier { 6487dd7cddfSDavid du Colombier char *x; 6497dd7cddfSDavid du Colombier vlong l; 6507dd7cddfSDavid du Colombier 6517dd7cddfSDavid du Colombier l = 0; 6527dd7cddfSDavid du Colombier x = strchr(p, '/'); 6537dd7cddfSDavid du Colombier if(x) 6547dd7cddfSDavid du Colombier l = atoll(x+1); 6557dd7cddfSDavid du Colombier if(l == 0) 6567dd7cddfSDavid du Colombier x = strchr(p, '-'); 6577dd7cddfSDavid du Colombier if(x) 6587dd7cddfSDavid du Colombier l = atoll(x+1); 6597dd7cddfSDavid du Colombier if(l) 6607dd7cddfSDavid du Colombier r->end = l; 6617dd7cddfSDavid du Colombier } 6627dd7cddfSDavid du Colombier 6637dd7cddfSDavid du Colombier void 6647dd7cddfSDavid du Colombier hhuri(char *p, URL *u, Range*) 6657dd7cddfSDavid du Colombier { 6667dd7cddfSDavid du Colombier if(*p != '<') 6677dd7cddfSDavid du Colombier return; 6687dd7cddfSDavid du Colombier u->redirect = strdup(p+1); 6697dd7cddfSDavid du Colombier p = strchr(u->redirect, '>'); 6707dd7cddfSDavid du Colombier if(p != nil) 6717dd7cddfSDavid du Colombier *p = 0; 6727dd7cddfSDavid du Colombier } 6737dd7cddfSDavid du Colombier 6747dd7cddfSDavid du Colombier void 6757dd7cddfSDavid du Colombier hhlocation(char *p, URL *u, Range*) 6767dd7cddfSDavid du Colombier { 6777dd7cddfSDavid du Colombier u->redirect = strdup(p); 6787dd7cddfSDavid du Colombier } 6797dd7cddfSDavid du Colombier 680*59cc4ca5SDavid du Colombier enum 681*59cc4ca5SDavid du Colombier { 682*59cc4ca5SDavid du Colombier /* ftp return codes */ 683*59cc4ca5SDavid du Colombier Extra= 1, 684*59cc4ca5SDavid du Colombier Success= 2, 685*59cc4ca5SDavid du Colombier Incomplete= 3, 686*59cc4ca5SDavid du Colombier TempFail= 4, 687*59cc4ca5SDavid du Colombier PermFail= 5, 688*59cc4ca5SDavid du Colombier 689*59cc4ca5SDavid du Colombier Nnetdir= 64, /* max length of network directory paths */ 690*59cc4ca5SDavid du Colombier Ndialstr= 64, /* max length of dial strings */ 691*59cc4ca5SDavid du Colombier }; 692*59cc4ca5SDavid du Colombier 693*59cc4ca5SDavid du Colombier int ftpcmd(int, char*, ...); 694*59cc4ca5SDavid du Colombier int ftprcode(int, char*, int); 695*59cc4ca5SDavid du Colombier int hello(int); 696*59cc4ca5SDavid du Colombier int logon(int); 697*59cc4ca5SDavid du Colombier int xfertype(int, char*); 698*59cc4ca5SDavid du Colombier int passive(int, URL*); 699*59cc4ca5SDavid du Colombier int active(int, URL*); 700*59cc4ca5SDavid du Colombier int ftpxfer(int, int, Range*); 701*59cc4ca5SDavid du Colombier int terminateftp(int, int); 702*59cc4ca5SDavid du Colombier int getaddrport(char*, uchar*, uchar*); 703*59cc4ca5SDavid du Colombier int ftprestart(int, int, URL*, Range*, long); 704*59cc4ca5SDavid du Colombier 705*59cc4ca5SDavid du Colombier int 706*59cc4ca5SDavid du Colombier doftp(URL *u, Range *r, int out, long mtime) 707*59cc4ca5SDavid du Colombier { 708*59cc4ca5SDavid du Colombier int pid, ctl, data, rv, wrv; 709*59cc4ca5SDavid du Colombier Waitmsg w; 710*59cc4ca5SDavid du Colombier char msg[64]; 711*59cc4ca5SDavid du Colombier char conndir[NETPATHLEN]; 712*59cc4ca5SDavid du Colombier char *p; 713*59cc4ca5SDavid du Colombier 714*59cc4ca5SDavid du Colombier ctl = dial(netmkaddr(u->host, tcpdir, u->port), 0, conndir, 0); 715*59cc4ca5SDavid du Colombier if(ctl < 0) 716*59cc4ca5SDavid du Colombier return Error; 717*59cc4ca5SDavid du Colombier if(net == nil){ 718*59cc4ca5SDavid du Colombier p = strrchr(conndir, '/'); 719*59cc4ca5SDavid du Colombier *p = 0; 720*59cc4ca5SDavid du Colombier snprint(tcpdir, sizeof(tcpdir), conndir); 721*59cc4ca5SDavid du Colombier } 722*59cc4ca5SDavid du Colombier 723*59cc4ca5SDavid du Colombier initibuf(); 724*59cc4ca5SDavid du Colombier 725*59cc4ca5SDavid du Colombier rv = hello(ctl); 726*59cc4ca5SDavid du Colombier if(rv < 0) 727*59cc4ca5SDavid du Colombier return terminateftp(ctl, rv); 728*59cc4ca5SDavid du Colombier 729*59cc4ca5SDavid du Colombier rv = logon(ctl); 730*59cc4ca5SDavid du Colombier if(rv < 0) 731*59cc4ca5SDavid du Colombier return terminateftp(ctl, rv); 732*59cc4ca5SDavid du Colombier 733*59cc4ca5SDavid du Colombier rv = xfertype(ctl, "I"); 734*59cc4ca5SDavid du Colombier if(rv < 0) 735*59cc4ca5SDavid du Colombier return terminateftp(ctl, rv); 736*59cc4ca5SDavid du Colombier 737*59cc4ca5SDavid du Colombier /* if file is up to date and the right size, stop */ 738*59cc4ca5SDavid du Colombier if(ftprestart(ctl, out, u, r, mtime) > 0){ 739*59cc4ca5SDavid du Colombier close(ctl); 740*59cc4ca5SDavid du Colombier return Eof; 741*59cc4ca5SDavid du Colombier } 742*59cc4ca5SDavid du Colombier 743*59cc4ca5SDavid du Colombier /* first try passive mode, then active */ 744*59cc4ca5SDavid du Colombier data = passive(ctl, u); 745*59cc4ca5SDavid du Colombier if(data < 0){ 746*59cc4ca5SDavid du Colombier data = active(ctl, u); 747*59cc4ca5SDavid du Colombier if(data < 0) 748*59cc4ca5SDavid du Colombier return Error; 749*59cc4ca5SDavid du Colombier } 750*59cc4ca5SDavid du Colombier 751*59cc4ca5SDavid du Colombier /* fork */ 752*59cc4ca5SDavid du Colombier switch(pid = rfork(RFPROC|RFFDG|RFMEM)){ 753*59cc4ca5SDavid du Colombier case -1: 754*59cc4ca5SDavid du Colombier close(data); 755*59cc4ca5SDavid du Colombier return terminateftp(ctl, Error); 756*59cc4ca5SDavid du Colombier case 0: 757*59cc4ca5SDavid du Colombier ftpxfer(data, out, r); 758*59cc4ca5SDavid du Colombier close(data); 759*59cc4ca5SDavid du Colombier _exits(0); 760*59cc4ca5SDavid du Colombier default: 761*59cc4ca5SDavid du Colombier close(data); 762*59cc4ca5SDavid du Colombier break; 763*59cc4ca5SDavid du Colombier } 764*59cc4ca5SDavid du Colombier 765*59cc4ca5SDavid du Colombier /* wait for reply message */ 766*59cc4ca5SDavid du Colombier rv = ftprcode(ctl, msg, sizeof(msg)); 767*59cc4ca5SDavid du Colombier close(ctl); 768*59cc4ca5SDavid du Colombier 769*59cc4ca5SDavid du Colombier /* wait for process to terminate */ 770*59cc4ca5SDavid du Colombier for(;;){ 771*59cc4ca5SDavid du Colombier wrv = wait(&w); 772*59cc4ca5SDavid du Colombier if(wrv < 0) 773*59cc4ca5SDavid du Colombier return Error; 774*59cc4ca5SDavid du Colombier if(wrv == pid){ 775*59cc4ca5SDavid du Colombier if(w.msg[0] == 0) 776*59cc4ca5SDavid du Colombier break; 777*59cc4ca5SDavid du Colombier werrstr("xfer: %s", w.msg); 778*59cc4ca5SDavid du Colombier return Error; 779*59cc4ca5SDavid du Colombier } 780*59cc4ca5SDavid du Colombier } 781*59cc4ca5SDavid du Colombier 782*59cc4ca5SDavid du Colombier switch(rv){ 783*59cc4ca5SDavid du Colombier case Success: 784*59cc4ca5SDavid du Colombier return Eof; 785*59cc4ca5SDavid du Colombier case TempFail: 786*59cc4ca5SDavid du Colombier return Server; 787*59cc4ca5SDavid du Colombier default: 788*59cc4ca5SDavid du Colombier return Error; 789*59cc4ca5SDavid du Colombier } 790*59cc4ca5SDavid du Colombier } 791*59cc4ca5SDavid du Colombier 792*59cc4ca5SDavid du Colombier int 793*59cc4ca5SDavid du Colombier ftpcmd(int ctl, char *fmt, ...) 794*59cc4ca5SDavid du Colombier { 795*59cc4ca5SDavid du Colombier va_list arg; 796*59cc4ca5SDavid du Colombier char buf[2*1024], *s; 797*59cc4ca5SDavid du Colombier 798*59cc4ca5SDavid du Colombier va_start(arg, fmt); 799*59cc4ca5SDavid du Colombier s = doprint(buf, buf + (sizeof(buf)-4) / sizeof(*buf), fmt, arg); 800*59cc4ca5SDavid du Colombier va_end(arg); 801*59cc4ca5SDavid du Colombier if(debug) 802*59cc4ca5SDavid du Colombier fprint(2, "%d -> %s\n", ctl, buf); 803*59cc4ca5SDavid du Colombier *s++ = '\r'; 804*59cc4ca5SDavid du Colombier *s++ = '\n'; 805*59cc4ca5SDavid du Colombier if(write(ctl, buf, s - buf) != s - buf) 806*59cc4ca5SDavid du Colombier return -1; 807*59cc4ca5SDavid du Colombier return 0; 808*59cc4ca5SDavid du Colombier } 809*59cc4ca5SDavid du Colombier 810*59cc4ca5SDavid du Colombier int 811*59cc4ca5SDavid du Colombier ftprcode(int ctl, char *msg, int len) 812*59cc4ca5SDavid du Colombier { 813*59cc4ca5SDavid du Colombier int rv; 814*59cc4ca5SDavid du Colombier int i; 815*59cc4ca5SDavid du Colombier 816*59cc4ca5SDavid du Colombier len--; /* room for terminating null */ 817*59cc4ca5SDavid du Colombier for(;;){ 818*59cc4ca5SDavid du Colombier *msg = 0; 819*59cc4ca5SDavid du Colombier i = readline(ctl, msg, len); 820*59cc4ca5SDavid du Colombier if(i < 0) 821*59cc4ca5SDavid du Colombier break; 822*59cc4ca5SDavid du Colombier if(debug) 823*59cc4ca5SDavid du Colombier fprint(2, "%d <- %s\n", ctl, msg); 824*59cc4ca5SDavid du Colombier 825*59cc4ca5SDavid du Colombier /* stop if not a continuation */ 826*59cc4ca5SDavid du Colombier rv = atoi(msg); 827*59cc4ca5SDavid du Colombier if(rv >= 100 && rv < 600 && (i > 3 && msg[3] == ' ')) 828*59cc4ca5SDavid du Colombier return rv/100; 829*59cc4ca5SDavid du Colombier } 830*59cc4ca5SDavid du Colombier *msg = 0; 831*59cc4ca5SDavid du Colombier 832*59cc4ca5SDavid du Colombier return -1; 833*59cc4ca5SDavid du Colombier } 834*59cc4ca5SDavid du Colombier 835*59cc4ca5SDavid du Colombier int 836*59cc4ca5SDavid du Colombier hello(int ctl) 837*59cc4ca5SDavid du Colombier { 838*59cc4ca5SDavid du Colombier char msg[1024]; 839*59cc4ca5SDavid du Colombier 840*59cc4ca5SDavid du Colombier /* wait for hello from other side */ 841*59cc4ca5SDavid du Colombier if(ftprcode(ctl, msg, sizeof(msg)) != Success){ 842*59cc4ca5SDavid du Colombier werrstr("HELLO: %s", msg); 843*59cc4ca5SDavid du Colombier return Server; 844*59cc4ca5SDavid du Colombier } 845*59cc4ca5SDavid du Colombier return 0; 846*59cc4ca5SDavid du Colombier } 847*59cc4ca5SDavid du Colombier 848*59cc4ca5SDavid du Colombier int 849*59cc4ca5SDavid du Colombier getdec(char *p, int n) 850*59cc4ca5SDavid du Colombier { 851*59cc4ca5SDavid du Colombier int x = 0; 852*59cc4ca5SDavid du Colombier int i; 853*59cc4ca5SDavid du Colombier 854*59cc4ca5SDavid du Colombier for(i = 0; i < n; i++) 855*59cc4ca5SDavid du Colombier x = x*10 + (*p++ - '0'); 856*59cc4ca5SDavid du Colombier return x; 857*59cc4ca5SDavid du Colombier } 858*59cc4ca5SDavid du Colombier 859*59cc4ca5SDavid du Colombier int 860*59cc4ca5SDavid du Colombier ftprestart(int ctl, int out, URL *u, Range *r, long mtime) 861*59cc4ca5SDavid du Colombier { 862*59cc4ca5SDavid du Colombier Tm tm; 863*59cc4ca5SDavid du Colombier char msg[1024]; 864*59cc4ca5SDavid du Colombier long x, rmtime; 865*59cc4ca5SDavid du Colombier 866*59cc4ca5SDavid du Colombier ftpcmd(ctl, "MDTM %s", u->page); 867*59cc4ca5SDavid du Colombier if(ftprcode(ctl, msg, sizeof(msg)) != Success){ 868*59cc4ca5SDavid du Colombier r->start = 0; 869*59cc4ca5SDavid du Colombier return 0; /* need to do something */ 870*59cc4ca5SDavid du Colombier } 871*59cc4ca5SDavid du Colombier 872*59cc4ca5SDavid du Colombier /* decode modification time */ 873*59cc4ca5SDavid du Colombier if(strlen(msg) < 4 + 4 + 2 + 2 + 2 + 2 + 2){ 874*59cc4ca5SDavid du Colombier r->start = 0; 875*59cc4ca5SDavid du Colombier return 0; /* need to do something */ 876*59cc4ca5SDavid du Colombier } 877*59cc4ca5SDavid du Colombier memset(&tm, 0, sizeof(tm)); 878*59cc4ca5SDavid du Colombier tm.year = getdec(msg+4, 4) - 1900; 879*59cc4ca5SDavid du Colombier tm.mon = getdec(msg+4+4, 2) - 1; 880*59cc4ca5SDavid du Colombier tm.mday = getdec(msg+4+4+2, 2); 881*59cc4ca5SDavid du Colombier tm.hour = getdec(msg+4+4+2+2, 2); 882*59cc4ca5SDavid du Colombier tm.min = getdec(msg+4+4+2+2+2, 2); 883*59cc4ca5SDavid du Colombier tm.sec = getdec(msg+4+4+2+2+2+2, 2); 884*59cc4ca5SDavid du Colombier strcpy(tm.zone, "GMT"); 885*59cc4ca5SDavid du Colombier rmtime = tm2sec(&tm); 886*59cc4ca5SDavid du Colombier if(rmtime > mtime) 887*59cc4ca5SDavid du Colombier r->start = 0; 888*59cc4ca5SDavid du Colombier 889*59cc4ca5SDavid du Colombier /* get size */ 890*59cc4ca5SDavid du Colombier ftpcmd(ctl, "SIZE %s", u->page); 891*59cc4ca5SDavid du Colombier if(ftprcode(ctl, msg, sizeof(msg)) == Success){ 892*59cc4ca5SDavid du Colombier x = atol(msg+4); 893*59cc4ca5SDavid du Colombier if(r->start == x) 894*59cc4ca5SDavid du Colombier return 1; /* we're up to date */ 895*59cc4ca5SDavid du Colombier r->end = x; 896*59cc4ca5SDavid du Colombier } 897*59cc4ca5SDavid du Colombier 898*59cc4ca5SDavid du Colombier /* seek to restart point */ 899*59cc4ca5SDavid du Colombier if(r->start > 0){ 900*59cc4ca5SDavid du Colombier ftpcmd(ctl, "REST %lud", r->start); 901*59cc4ca5SDavid du Colombier if(ftprcode(ctl, msg, sizeof(msg)) == Incomplete) 902*59cc4ca5SDavid du Colombier seek(out, r->start, 0); 903*59cc4ca5SDavid du Colombier else 904*59cc4ca5SDavid du Colombier r->start = 0; 905*59cc4ca5SDavid du Colombier } 906*59cc4ca5SDavid du Colombier 907*59cc4ca5SDavid du Colombier return 0; /* need to do something */ 908*59cc4ca5SDavid du Colombier } 909*59cc4ca5SDavid du Colombier 910*59cc4ca5SDavid du Colombier int 911*59cc4ca5SDavid du Colombier logon(int ctl) 912*59cc4ca5SDavid du Colombier { 913*59cc4ca5SDavid du Colombier char msg[1024]; 914*59cc4ca5SDavid du Colombier 915*59cc4ca5SDavid du Colombier /* login anonymous */ 916*59cc4ca5SDavid du Colombier ftpcmd(ctl, "USER anonymous"); 917*59cc4ca5SDavid du Colombier switch(ftprcode(ctl, msg, sizeof(msg))){ 918*59cc4ca5SDavid du Colombier case Success: 919*59cc4ca5SDavid du Colombier return 0; 920*59cc4ca5SDavid du Colombier case Incomplete: 921*59cc4ca5SDavid du Colombier break; /* need password */ 922*59cc4ca5SDavid du Colombier default: 923*59cc4ca5SDavid du Colombier werrstr("USER: %s", msg); 924*59cc4ca5SDavid du Colombier return Server; 925*59cc4ca5SDavid du Colombier } 926*59cc4ca5SDavid du Colombier 927*59cc4ca5SDavid du Colombier /* send user id as password */ 928*59cc4ca5SDavid du Colombier sprint(msg, "%s@closedmind.org", getuser()); 929*59cc4ca5SDavid du Colombier ftpcmd(ctl, "PASS %s", msg); 930*59cc4ca5SDavid du Colombier if(ftprcode(ctl, msg, sizeof(msg)) != Success){ 931*59cc4ca5SDavid du Colombier werrstr("PASS: %s", msg); 932*59cc4ca5SDavid du Colombier return Server; 933*59cc4ca5SDavid du Colombier } 934*59cc4ca5SDavid du Colombier 935*59cc4ca5SDavid du Colombier return 0; 936*59cc4ca5SDavid du Colombier } 937*59cc4ca5SDavid du Colombier 938*59cc4ca5SDavid du Colombier int 939*59cc4ca5SDavid du Colombier xfertype(int ctl, char *t) 940*59cc4ca5SDavid du Colombier { 941*59cc4ca5SDavid du Colombier char msg[1024]; 942*59cc4ca5SDavid du Colombier 943*59cc4ca5SDavid du Colombier ftpcmd(ctl, "TYPE %s", t); 944*59cc4ca5SDavid du Colombier if(ftprcode(ctl, msg, sizeof(msg)) != Success){ 945*59cc4ca5SDavid du Colombier werrstr("TYPE %s: %s", t, msg); 946*59cc4ca5SDavid du Colombier return Server; 947*59cc4ca5SDavid du Colombier } 948*59cc4ca5SDavid du Colombier 949*59cc4ca5SDavid du Colombier return 0; 950*59cc4ca5SDavid du Colombier } 951*59cc4ca5SDavid du Colombier 952*59cc4ca5SDavid du Colombier int 953*59cc4ca5SDavid du Colombier passive(int ctl, URL *u) 954*59cc4ca5SDavid du Colombier { 955*59cc4ca5SDavid du Colombier char msg[1024]; 956*59cc4ca5SDavid du Colombier char ipaddr[32]; 957*59cc4ca5SDavid du Colombier char *f[6]; 958*59cc4ca5SDavid du Colombier char *p; 959*59cc4ca5SDavid du Colombier int fd; 960*59cc4ca5SDavid du Colombier int port; 961*59cc4ca5SDavid du Colombier char aport[12]; 962*59cc4ca5SDavid du Colombier 963*59cc4ca5SDavid du Colombier ftpcmd(ctl, "PASV"); 964*59cc4ca5SDavid du Colombier if(ftprcode(ctl, msg, sizeof(msg)) != Success) 965*59cc4ca5SDavid du Colombier return Error; 966*59cc4ca5SDavid du Colombier 967*59cc4ca5SDavid du Colombier /* get address and port number from reply, this is AI */ 968*59cc4ca5SDavid du Colombier p = strchr(msg, '('); 969*59cc4ca5SDavid du Colombier if(p == nil){ 970*59cc4ca5SDavid du Colombier for(p = msg+3; *p; p++) 971*59cc4ca5SDavid du Colombier if(isdigit(*p)) 972*59cc4ca5SDavid du Colombier break; 973*59cc4ca5SDavid du Colombier } else 974*59cc4ca5SDavid du Colombier p++; 975*59cc4ca5SDavid du Colombier if(getfields(p, f, 6, 0, ",)") < 6){ 976*59cc4ca5SDavid du Colombier werrstr("ftp protocol botch"); 977*59cc4ca5SDavid du Colombier return Server; 978*59cc4ca5SDavid du Colombier } 979*59cc4ca5SDavid du Colombier snprint(ipaddr, sizeof(ipaddr), "%s.%s.%s.%s", 980*59cc4ca5SDavid du Colombier f[0], f[1], f[2], f[3]); 981*59cc4ca5SDavid du Colombier port = ((atoi(f[4])&0xff)<<8) + (atoi(f[5])&0xff); 982*59cc4ca5SDavid du Colombier sprint(aport, "%d", port); 983*59cc4ca5SDavid du Colombier 984*59cc4ca5SDavid du Colombier /* open data connection */ 985*59cc4ca5SDavid du Colombier fd = dial(netmkaddr(ipaddr, tcpdir, aport), 0, 0, 0); 986*59cc4ca5SDavid du Colombier if(fd < 0){ 987*59cc4ca5SDavid du Colombier werrstr("passive mode failed: %r"); 988*59cc4ca5SDavid du Colombier return Error; 989*59cc4ca5SDavid du Colombier } 990*59cc4ca5SDavid du Colombier 991*59cc4ca5SDavid du Colombier /* tell remote to send a file */ 992*59cc4ca5SDavid du Colombier ftpcmd(ctl, "RETR %s", u->page); 993*59cc4ca5SDavid du Colombier if(ftprcode(ctl, msg, sizeof(msg)) != Extra){ 994*59cc4ca5SDavid du Colombier werrstr("RETR %s: %s", u->page, msg); 995*59cc4ca5SDavid du Colombier return Error; 996*59cc4ca5SDavid du Colombier } 997*59cc4ca5SDavid du Colombier return fd; 998*59cc4ca5SDavid du Colombier } 999*59cc4ca5SDavid du Colombier 1000*59cc4ca5SDavid du Colombier int 1001*59cc4ca5SDavid du Colombier active(int ctl, URL *u) 1002*59cc4ca5SDavid du Colombier { 1003*59cc4ca5SDavid du Colombier char msg[1024]; 1004*59cc4ca5SDavid du Colombier char dir[40], ldir[40]; 1005*59cc4ca5SDavid du Colombier uchar ipaddr[4]; 1006*59cc4ca5SDavid du Colombier uchar port[2]; 1007*59cc4ca5SDavid du Colombier int lcfd, dfd, afd; 1008*59cc4ca5SDavid du Colombier 1009*59cc4ca5SDavid du Colombier /* announce a port for the call back */ 1010*59cc4ca5SDavid du Colombier snprint(msg, sizeof(msg), "%s!*!0", tcpdir); 1011*59cc4ca5SDavid du Colombier afd = announce(msg, dir); 1012*59cc4ca5SDavid du Colombier if(afd < 0) 1013*59cc4ca5SDavid du Colombier return Error; 1014*59cc4ca5SDavid du Colombier 1015*59cc4ca5SDavid du Colombier /* get a local address/port of the annoucement */ 1016*59cc4ca5SDavid du Colombier if(getaddrport(dir, ipaddr, port) < 0){ 1017*59cc4ca5SDavid du Colombier close(afd); 1018*59cc4ca5SDavid du Colombier return Error; 1019*59cc4ca5SDavid du Colombier } 1020*59cc4ca5SDavid du Colombier 1021*59cc4ca5SDavid du Colombier /* tell remote side address and port*/ 1022*59cc4ca5SDavid du Colombier ftpcmd(ctl, "PORT %d,%d,%d,%d,%d,%d", ipaddr[0], ipaddr[1], ipaddr[2], 1023*59cc4ca5SDavid du Colombier ipaddr[3], port[0], port[1]); 1024*59cc4ca5SDavid du Colombier if(ftprcode(ctl, msg, sizeof(msg)) != Success){ 1025*59cc4ca5SDavid du Colombier close(afd); 1026*59cc4ca5SDavid du Colombier werrstr("active: %s", msg); 1027*59cc4ca5SDavid du Colombier return Error; 1028*59cc4ca5SDavid du Colombier } 1029*59cc4ca5SDavid du Colombier 1030*59cc4ca5SDavid du Colombier /* tell remote to send a file */ 1031*59cc4ca5SDavid du Colombier ftpcmd(ctl, "RETR %s", u->page); 1032*59cc4ca5SDavid du Colombier if(ftprcode(ctl, msg, sizeof(msg)) != Extra){ 1033*59cc4ca5SDavid du Colombier close(afd); 1034*59cc4ca5SDavid du Colombier werrstr("RETR: %s", msg); 1035*59cc4ca5SDavid du Colombier return Server; 1036*59cc4ca5SDavid du Colombier } 1037*59cc4ca5SDavid du Colombier 1038*59cc4ca5SDavid du Colombier /* wait for a connection */ 1039*59cc4ca5SDavid du Colombier lcfd = listen(dir, ldir); 1040*59cc4ca5SDavid du Colombier if(lcfd < 0){ 1041*59cc4ca5SDavid du Colombier close(afd); 1042*59cc4ca5SDavid du Colombier return Error; 1043*59cc4ca5SDavid du Colombier } 1044*59cc4ca5SDavid du Colombier dfd = accept(lcfd, ldir); 1045*59cc4ca5SDavid du Colombier if(dfd < 0){ 1046*59cc4ca5SDavid du Colombier close(afd); 1047*59cc4ca5SDavid du Colombier close(lcfd); 1048*59cc4ca5SDavid du Colombier return Error; 1049*59cc4ca5SDavid du Colombier } 1050*59cc4ca5SDavid du Colombier close(afd); 1051*59cc4ca5SDavid du Colombier close(lcfd); 1052*59cc4ca5SDavid du Colombier 1053*59cc4ca5SDavid du Colombier return dfd; 1054*59cc4ca5SDavid du Colombier } 1055*59cc4ca5SDavid du Colombier 1056*59cc4ca5SDavid du Colombier int 1057*59cc4ca5SDavid du Colombier ftpxfer(int in, int out, Range *r) 1058*59cc4ca5SDavid du Colombier { 1059*59cc4ca5SDavid du Colombier char buf[1024]; 1060*59cc4ca5SDavid du Colombier long vtime; 1061*59cc4ca5SDavid du Colombier int i, n; 1062*59cc4ca5SDavid du Colombier 1063*59cc4ca5SDavid du Colombier vtime = 0; 1064*59cc4ca5SDavid du Colombier for(n = 0;;n += i){ 1065*59cc4ca5SDavid du Colombier i = read(in, buf, sizeof(buf)); 1066*59cc4ca5SDavid du Colombier if(i == 0) 1067*59cc4ca5SDavid du Colombier break; 1068*59cc4ca5SDavid du Colombier if(i < 0) 1069*59cc4ca5SDavid du Colombier return Error; 1070*59cc4ca5SDavid du Colombier if(write(out, buf, i) != i) 1071*59cc4ca5SDavid du Colombier return Error; 1072*59cc4ca5SDavid du Colombier r->start += i; 1073*59cc4ca5SDavid du Colombier if(verbose && vtime != time(0)) { 1074*59cc4ca5SDavid du Colombier vtime = time(0); 1075*59cc4ca5SDavid du Colombier fprint(2, "%ld %ld\n", r->start, r->end); 1076*59cc4ca5SDavid du Colombier } 1077*59cc4ca5SDavid du Colombier } 1078*59cc4ca5SDavid du Colombier return n; 1079*59cc4ca5SDavid du Colombier } 1080*59cc4ca5SDavid du Colombier 1081*59cc4ca5SDavid du Colombier int 1082*59cc4ca5SDavid du Colombier terminateftp(int ctl, int rv) 1083*59cc4ca5SDavid du Colombier { 1084*59cc4ca5SDavid du Colombier close(ctl); 1085*59cc4ca5SDavid du Colombier return rv; 1086*59cc4ca5SDavid du Colombier } 1087*59cc4ca5SDavid du Colombier 1088*59cc4ca5SDavid du Colombier /* 1089*59cc4ca5SDavid du Colombier * case insensitive strcmp (why aren't these in libc?) 1090*59cc4ca5SDavid du Colombier */ 10917dd7cddfSDavid du Colombier int 10927dd7cddfSDavid du Colombier cistrncmp(char *a, char *b, int n) 10937dd7cddfSDavid du Colombier { 10947dd7cddfSDavid du Colombier while(n-- > 0){ 10957dd7cddfSDavid du Colombier if(tolower(*a++) != tolower(*b++)) 10967dd7cddfSDavid du Colombier return -1; 10977dd7cddfSDavid du Colombier } 10987dd7cddfSDavid du Colombier return 0; 10997dd7cddfSDavid du Colombier } 11007dd7cddfSDavid du Colombier 11017dd7cddfSDavid du Colombier int 11027dd7cddfSDavid du Colombier cistrcmp(char *a, char *b) 11037dd7cddfSDavid du Colombier { 11047dd7cddfSDavid du Colombier while(*a || *b) 11057dd7cddfSDavid du Colombier if(tolower(*a++) != tolower(*b++)) 11067dd7cddfSDavid du Colombier return -1; 11077dd7cddfSDavid du Colombier 11087dd7cddfSDavid du Colombier return 0; 11097dd7cddfSDavid du Colombier } 11107dd7cddfSDavid du Colombier 11117dd7cddfSDavid du Colombier /* 11127dd7cddfSDavid du Colombier * buffered io 11137dd7cddfSDavid du Colombier */ 11147dd7cddfSDavid du Colombier struct 11157dd7cddfSDavid du Colombier { 11167dd7cddfSDavid du Colombier char *rp; 11177dd7cddfSDavid du Colombier char *wp; 11187dd7cddfSDavid du Colombier char buf[4*1024]; 11197dd7cddfSDavid du Colombier } b; 11207dd7cddfSDavid du Colombier 11217dd7cddfSDavid du Colombier void 11227dd7cddfSDavid du Colombier initibuf(void) 11237dd7cddfSDavid du Colombier { 11247dd7cddfSDavid du Colombier b.rp = b.wp = b.buf; 11257dd7cddfSDavid du Colombier } 11267dd7cddfSDavid du Colombier 1127*59cc4ca5SDavid du Colombier /* 1128*59cc4ca5SDavid du Colombier * read a possibly buffered line, strip off trailing while 1129*59cc4ca5SDavid du Colombier */ 11307dd7cddfSDavid du Colombier int 11317dd7cddfSDavid du Colombier readline(int fd, char *buf, int len) 11327dd7cddfSDavid du Colombier { 11337dd7cddfSDavid du Colombier int n; 11347dd7cddfSDavid du Colombier char *p; 1135*59cc4ca5SDavid du Colombier int eof = 0; 11367dd7cddfSDavid du Colombier 11377dd7cddfSDavid du Colombier len--; 11387dd7cddfSDavid du Colombier 11397dd7cddfSDavid du Colombier for(p = buf;;){ 11407dd7cddfSDavid du Colombier if(b.rp >= b.wp){ 11417dd7cddfSDavid du Colombier n = read(fd, b.wp, sizeof(b.buf)/2); 11427dd7cddfSDavid du Colombier if(n < 0) 11437dd7cddfSDavid du Colombier return -1; 1144*59cc4ca5SDavid du Colombier if(n == 0){ 1145*59cc4ca5SDavid du Colombier eof = 1; 11467dd7cddfSDavid du Colombier break; 1147*59cc4ca5SDavid du Colombier } 11487dd7cddfSDavid du Colombier b.wp += n; 11497dd7cddfSDavid du Colombier } 11507dd7cddfSDavid du Colombier n = *b.rp++; 11517dd7cddfSDavid du Colombier if(len > 0){ 11527dd7cddfSDavid du Colombier *p++ = n; 11537dd7cddfSDavid du Colombier len--; 11547dd7cddfSDavid du Colombier } 11557dd7cddfSDavid du Colombier if(n == '\n') 11567dd7cddfSDavid du Colombier break; 11577dd7cddfSDavid du Colombier } 11587dd7cddfSDavid du Colombier 11597dd7cddfSDavid du Colombier /* drop trailing white */ 11607dd7cddfSDavid du Colombier for(;;){ 11617dd7cddfSDavid du Colombier if(p <= buf) 11627dd7cddfSDavid du Colombier break; 11637dd7cddfSDavid du Colombier n = *(p-1); 11647dd7cddfSDavid du Colombier if(n != ' ' && n != '\t' && n != '\r' && n != '\n') 11657dd7cddfSDavid du Colombier break; 11667dd7cddfSDavid du Colombier p--; 11677dd7cddfSDavid du Colombier } 11687dd7cddfSDavid du Colombier *p = 0; 1169*59cc4ca5SDavid du Colombier 1170*59cc4ca5SDavid du Colombier if(eof && p == buf) 1171*59cc4ca5SDavid du Colombier return -1; 1172*59cc4ca5SDavid du Colombier 11737dd7cddfSDavid du Colombier return p-buf; 11747dd7cddfSDavid du Colombier } 11757dd7cddfSDavid du Colombier 11767dd7cddfSDavid du Colombier void 11777dd7cddfSDavid du Colombier unreadline(char *line) 11787dd7cddfSDavid du Colombier { 11797dd7cddfSDavid du Colombier int i, n; 11807dd7cddfSDavid du Colombier 11817dd7cddfSDavid du Colombier i = strlen(line); 11827dd7cddfSDavid du Colombier n = b.wp-b.rp; 11837dd7cddfSDavid du Colombier memmove(&b.buf[i+1], b.rp, n); 11847dd7cddfSDavid du Colombier memmove(b.buf, line, i); 11857dd7cddfSDavid du Colombier b.buf[i] = '\n'; 11867dd7cddfSDavid du Colombier b.rp = b.buf; 11877dd7cddfSDavid du Colombier b.wp = b.rp + i + 1 + n; 11887dd7cddfSDavid du Colombier } 11897dd7cddfSDavid du Colombier 11907dd7cddfSDavid du Colombier int 11917dd7cddfSDavid du Colombier readibuf(int fd, char *buf, int len) 11927dd7cddfSDavid du Colombier { 11937dd7cddfSDavid du Colombier int n; 11947dd7cddfSDavid du Colombier 11957dd7cddfSDavid du Colombier n = b.wp-b.rp; 11967dd7cddfSDavid du Colombier if(n > 0){ 11977dd7cddfSDavid du Colombier if(n > len) 11987dd7cddfSDavid du Colombier n = len; 11997dd7cddfSDavid du Colombier memmove(buf, b.rp, n); 12007dd7cddfSDavid du Colombier b.rp += n; 12017dd7cddfSDavid du Colombier return n; 12027dd7cddfSDavid du Colombier } 12037dd7cddfSDavid du Colombier return read(fd, buf, len); 12047dd7cddfSDavid du Colombier } 12057dd7cddfSDavid du Colombier 12067dd7cddfSDavid du Colombier int 12077dd7cddfSDavid du Colombier dfprint(int fd, char *fmt, ...) 12087dd7cddfSDavid du Colombier { 12097dd7cddfSDavid du Colombier char buf[4*1024]; 12107dd7cddfSDavid du Colombier va_list arg; 12117dd7cddfSDavid du Colombier 12127dd7cddfSDavid du Colombier va_start(arg, fmt); 12137dd7cddfSDavid du Colombier doprint(buf, buf+sizeof(buf), fmt, arg); 12147dd7cddfSDavid du Colombier va_end(arg); 12157dd7cddfSDavid du Colombier if(debug) 12167dd7cddfSDavid du Colombier fprint(2, "%d -> %s", fd, buf); 12177dd7cddfSDavid du Colombier return fprint(fd, "%s", buf); 12187dd7cddfSDavid du Colombier } 1219*59cc4ca5SDavid du Colombier 1220*59cc4ca5SDavid du Colombier int 1221*59cc4ca5SDavid du Colombier getaddrport(char *dir, uchar *ipaddr, uchar *port) 1222*59cc4ca5SDavid du Colombier { 1223*59cc4ca5SDavid du Colombier char buf[256]; 1224*59cc4ca5SDavid du Colombier int fd, i; 1225*59cc4ca5SDavid du Colombier char *p; 1226*59cc4ca5SDavid du Colombier 1227*59cc4ca5SDavid du Colombier snprint(buf, sizeof(buf), "%s/local", dir); 1228*59cc4ca5SDavid du Colombier fd = open(buf, OREAD); 1229*59cc4ca5SDavid du Colombier if(fd < 0) 1230*59cc4ca5SDavid du Colombier return -1; 1231*59cc4ca5SDavid du Colombier i = read(fd, buf, sizeof(buf)-1); 1232*59cc4ca5SDavid du Colombier close(fd); 1233*59cc4ca5SDavid du Colombier if(i <= 0) 1234*59cc4ca5SDavid du Colombier return -1; 1235*59cc4ca5SDavid du Colombier buf[i] = 0; 1236*59cc4ca5SDavid du Colombier p = strchr(buf, '!'); 1237*59cc4ca5SDavid du Colombier if(p != nil) 1238*59cc4ca5SDavid du Colombier *p++ = 0; 1239*59cc4ca5SDavid du Colombier v4parseip(ipaddr, buf); 1240*59cc4ca5SDavid du Colombier i = atoi(p); 1241*59cc4ca5SDavid du Colombier port[0] = i>>8; 1242*59cc4ca5SDavid du Colombier port[1] = i; 1243*59cc4ca5SDavid du Colombier return 0; 1244*59cc4ca5SDavid du Colombier } 1245