int httpopen(Client *c, Url *url) { int fd, code, redirect, authenticate; char *cookies; Ioproc *io; HttpState *hs; char *service; if(httpdebug) fprint(2, "httpopen\n"); io = c->io; hs = emalloc(sizeof(*hs)); hs->c = c; if(url->port) service = url->port; else service = url->scheme; hs->netaddr = estrdup(netmkaddr(url->host, 0, service)); c->aux = hs; if(httpdebug){ fprint(2, "dial %s\n", hs->netaddr); fprint(2, "dial port: %s\n", url->port); } fd = iotlsdial(io, hs->netaddr, 0, 0, 0, url->ischeme==UShttps); if(fd < 0){ Error: if(httpdebug) fprint(2, "iodial: %r\n"); free(hs->location); free(hs->setcookie); free(hs->netaddr); free(hs->credentials); if(fd >= 0) ioclose(io, hs->fd); hs->fd = -1; free(hs); c->aux = nil; return -1; } hs->fd = fd; if(httpdebug) fprint(2, "<- %s %s HTTP/1.0\n<- Host: %s\n", c->havepostbody? "POST": "GET", url->http.page_spec, url->host); ioprint(io, fd, "%s %s HTTP/1.0\r\nHost: %s\r\n", c->havepostbody? "POST" : "GET", url->http.page_spec, url->host); if(httpdebug) fprint(2, "<- User-Agent: %s\n", c->ctl.useragent); if(c->ctl.useragent) ioprint(io, fd, "User-Agent: %s\r\n", c->ctl.useragent); if(c->ctl.sendcookies){ /* should we use url->page here? sometimes it is nil. */ cookies = httpcookies(url->host, url->http.page_spec, url->ischeme == UShttps); if(cookies && cookies[0]) ioprint(io, fd, "%s", cookies); if(httpdebug) fprint(2, "<- %s", cookies); free(cookies); } if(c->havepostbody){ ioprint(io, fd, "Content-type: %s\r\n", PostContentType); ioprint(io, fd, "Content-length: %ud\r\n", c->npostbody); if(httpdebug){ fprint(2, "<- Content-type: %s\n", PostContentType); fprint(2, "<- Content-length: %ud\n", c->npostbody); } } if(c->authenticate){ ioprint(io, fd, "Authorization: %s\r\n", c->authenticate); if(httpdebug) fprint(2, "<- Authorization: %s\n", c->authenticate); } ioprint(io, fd, "\r\n"); if(c->havepostbody) if(iowrite(io, fd, c->postbody, c->npostbody) != c->npostbody) goto Error; redirect = 0; authenticate = 0; initibuf(&hs->b, io, fd); code = httprcode(hs); switch(code){ case -1: /* connection timed out */ goto Error; /* case Eof: werrstr("EOF from HTTP server"); goto Error; */ case 200: /* OK */ case 201: /* Created */ case 202: /* Accepted */ case 204: /* No Content */ case 205: /* Reset Content */ #ifdef NOT_DEFINED if(ofile == nil && r->start != 0) sysfatal("page changed underfoot"); #endif break; case 206: /* Partial Content */ werrstr("Partial Content (206)"); goto Error; case 301: /* Moved Permanently */ case 302: /* Moved Temporarily */ case 303: /* See Other */ case 307: /* Temporary Redirect */ redirect = 1; break; case 304: /* Not Modified */ break; case 400: /* Bad Request */ werrstr("Bad Request (400)"); goto Error; case 401: /* Unauthorized */ if(c->authenticate){ werrstr("Authentication failed (401)"); goto Error; } authenticate = 1; break; case 402: /* Payment Required */ werrstr("Payment Required (402)"); goto Error; case 403: /* Forbidden */ werrstr("Forbidden by server (403)"); goto Error; case 404: /* Not Found */ werrstr("Not found on server (404)"); goto Error; case 405: /* Method Not Allowed */ werrstr("Method not allowed (405)"); goto Error; case 406: /* Not Acceptable */ werrstr("Not Acceptable (406)"); goto Error; case 407: /* Proxy auth */ werrstr("Proxy authentication required (407)"); goto Error; case 408: /* Request Timeout */ werrstr("Request Timeout (408)"); goto Error; case 409: /* Conflict */ werrstr("Conflict (409)"); goto Error; case 410: /* Gone */ werrstr("Gone (410)"); goto Error; case 411: /* Length Required */ werrstr("Length Required (411)"); goto Error; case 412: /* Precondition Failed */ werrstr("Precondition Failed (412)"); goto Error; case 413: /* Request Entity Too Large */ werrstr("Request Entity Too Large (413)"); goto Error; case 414: /* Request-URI Too Long */ werrstr("Request-URI Too Long (414)"); goto Error; case 415: /* Unsupported Media Type */ werrstr("Unsupported Media Type (415)"); goto Error; case 416: /* Requested Range Not Satisfiable */ werrstr("Requested Range Not Satisfiable (416)"); goto Error; case 417: /* Expectation Failed */ werrstr("Expectation Failed (417)"); goto Error; case 500: /* Internal server error */ werrstr("Server choked (500)"); goto Error; case 501: /* Not implemented */ werrstr("Server can't do it (501)"); goto Error; case 502: /* Bad gateway */ werrstr("Bad gateway (502)"); goto Error; case 503: /* Service unavailable */ werrstr("Service unavailable (503)"); goto Error; default: /* Bogus: we should treat unknown code XYZ as code X00 */ werrstr("Unknown response code %d", code); goto Error; } if(httpheaders(hs) < 0) goto Error; if(c->ctl.acceptcookies && hs->setcookie) httpsetcookie(hs->setcookie, url->host, url->path); if(authenticate){ if(!hs->credentials){ if(hs->autherror[0]) werrstr("%s", hs->autherror); else werrstr("unauthorized; no www-authenticate: header"); goto Error; } c->authenticate = hs->credentials; hs->credentials = nil; }else if(c->authenticate) c->authenticate = 0; if(redirect){ if(!hs->location){ werrstr("redirection without Location: header"); goto Error; } c->redirect = hs->location; hs->location = nil; } return 0; }
int init_buffer(int buf, btype type, const char *bname, int nlines) { bufs[buf].type=type; bufs[buf].bname=strdup(bname); if(type==SERVER) bufs[buf].serverloc=strdup(bname); else bufs[buf].serverloc=NULL; bufs[buf].realsname=NULL; bufs[buf].nlist=NULL; bufs[buf].us=NULL; bufs[buf].ilist=NULL; bufs[buf].handle=0; bufs[buf].server=0; bufs[buf].nick=NULL; bufs[buf].topic=NULL; bufs[buf].logf=NULL; bufs[buf].nlines=nlines; bufs[buf].ptr=0; bufs[buf].scroll=0; bufs[buf].ascroll=0; bufs[buf].lm=malloc(nlines*sizeof(mtype)); bufs[buf].lq=malloc(nlines*sizeof(prio)); bufs[buf].lp=malloc(nlines); bufs[buf].ls=malloc(nlines*sizeof(bool)); bufs[buf].lt=malloc(nlines*sizeof(char *)); int i; for(i=0;i<bufs[buf].nlines;i++) { bufs[buf].lt[i]=NULL; } bufs[buf].ltag=malloc(nlines*sizeof(char *)); for(i=0;i<bufs[buf].nlines;i++) { bufs[buf].ltag[i]=NULL; } bufs[buf].lpl=malloc(nlines*sizeof(int)); bufs[buf].lpc=malloc(nlines*sizeof(colour)); bufs[buf].lpt=malloc(nlines*sizeof(char **)); for(i=0;i<nlines;i++) { bufs[buf].lpl[i]=0; bufs[buf].lpc[i]=(colour){.fore=7, .back=0, .hi=false, .ul=false}; bufs[buf].lpt[i]=NULL; } bufs[buf].dirty=false; bufs[buf].ts=malloc(nlines*sizeof(time_t)); bufs[buf].filled=false; bufs[buf].alert=false; bufs[buf].hi_alert=0; bufs[buf].ping=0; bufs[buf].last=time(NULL); bufs[buf].namreply=false; bufs[buf].live=false; bufs[buf].conninpr=false; initibuf(&bufs[buf].input); bufs[buf].casemapping=RFC1459; if(type==SERVER) { bufs[buf].npfx=2; bufs[buf].prefixes=malloc(2*sizeof(prefix)); bufs[buf].prefixes[0]=(prefix){.letter='o', .pfx='@'}; bufs[buf].prefixes[1]=(prefix){.letter='v', .pfx='+'}; } else { bufs[buf].npfx=0; bufs[buf].prefixes=NULL; } bufs[buf].autoent=NULL; bufs[buf].conf=conf; bufs[buf].key=NULL; bufs[buf].lastkey=NULL; return(0); } int free_buffer(int buf) { if(bufs[buf].live) { add_to_buffer(buf, ERR, NORMAL, 0, false, "Buffer is still live!", "free_buffer:"); return(1); } else { free(bufs[buf].bname); free(bufs[buf].serverloc); free(bufs[buf].realsname); n_free(bufs[buf].nlist); bufs[buf].nlist=NULL; n_free(bufs[buf].ilist); bufs[buf].ilist=NULL; free(bufs[buf].nick); free(bufs[buf].topic); if(bufs[buf].logf) fclose(bufs[buf].logf); free(bufs[buf].lm); free(bufs[buf].lq); free(bufs[buf].lp); free(bufs[buf].ls); int l; if(bufs[buf].lt) { for(l=0;l<bufs[buf].nlines;l++) free(bufs[buf].lt[l]); free(bufs[buf].lt); } if(bufs[buf].ltag) { for(l=0;l<bufs[buf].nlines;l++) free(bufs[buf].ltag[l]); free(bufs[buf].ltag); } if(bufs[buf].lpt) { for(l=0;l<bufs[buf].nlines;l++) { if(bufs[buf].lpt[l]) { if(bufs[buf].lpl) { int p; for(p=0;p<bufs[buf].lpl[l];p++) { free(bufs[buf].lpt[l][p]); } } free(bufs[buf].lpt[l]); } } free(bufs[buf].lpt); } free(bufs[buf].lpl); free(bufs[buf].lpc); free(bufs[buf].ts); freeibuf(&bufs[buf].input); free(bufs[buf].prefixes); free(bufs[buf].key); free(bufs[buf].lastkey); if(cbuf>=buf) cbuf--; nbufs--; int b; for(b=buf;b<nbufs;b++) { bufs[b]=bufs[b+1]; } for(b=0;b<nbufs;b++) { if(bufs[b].server==buf) { bufs[b].server=0; // orphaned; should not happen bufs[b].live=false; bufs[b].handle=0; // just in case } else if(bufs[b].server>buf) { bufs[b].server--; } } if(nbufs) redraw_buffer(); return(0); } } int add_to_buffer(int buf, mtype lm, prio lq, char lp, bool ls, const char *lt, const char *ltag) { if(buf>=nbufs) { if(bufs&&buf) { add_to_buffer(0, ERR, NORMAL, 0, false, "Line was written to bad buffer! Contents below.", "add_to_buffer(): "); add_to_buffer(0, lm, NORMAL, lp, ls, lt, ltag); } return(1); } if(!debug&&(lq==DEBUG)) { if(!d_buf.nlines) { init_ring(&d_buf); d_buf.loop=true; } return(add_to_ring(&d_buf, lm, lt, ltag)); } int optr=bufs[buf].ptr; bool scrollisptr=(bufs[buf].scroll==bufs[buf].ptr)&&(bufs[buf].ascroll==0); bufs[buf].lm[bufs[buf].ptr]=lm; bufs[buf].lq[bufs[buf].ptr]=lq; bufs[buf].lp[bufs[buf].ptr]=lp; bufs[buf].ls[bufs[buf].ptr]=ls; free(bufs[buf].lt[bufs[buf].ptr]); bufs[buf].lt[bufs[buf].ptr]=strdup(lt); free(bufs[buf].ltag[bufs[buf].ptr]); bufs[buf].ltag[bufs[buf].ptr]=strdup(ltag); time_t ts=bufs[buf].ts[bufs[buf].ptr]=time(NULL); bufs[buf].ptr=(bufs[buf].ptr+1)%bufs[buf].nlines; if(scrollisptr) { bufs[buf].scroll=bufs[buf].ptr; bufs[buf].ascroll=0; } if(bufs[buf].ptr==0) bufs[buf].filled=true; render_line(buf, optr); if(buf==cbuf) { int e=redraw_buffer(); if(e) return(e); } else { if(!( (bufs[buf].conf&&((lm==JOIN)||(lm==PART)||(lm==NICK)||(lm==MODE)||(lm==QUIT))) || (quiet&&(lq==QUIET)) || (!debug&&(lq==DEBUG)) )) bufs[buf].alert=true; } if(bufs[buf].logf) { int e=log_add(bufs[buf].logf, bufs[buf].logt, lm, lq, lp, ls, lt, ltag, ts); if(e) return(e); } return(0); } int redraw_buffer(void) { if(bufs[cbuf].dirty) { int e=render_buffer(cbuf); if(e) return(e); if(bufs[cbuf].dirty) return(1); } int uline=bufs[cbuf].scroll; int pline=bufs[cbuf].ascroll; while(pline<0) { uline--; if((bufs[cbuf].filled)&&(uline==bufs[cbuf].ptr)) { uline++; pline=0; break; } if(uline<0) { if(bufs[cbuf].filled) uline+=bufs[cbuf].nlines; else { uline=0; pline=0; break; } } pline+=bufs[cbuf].lpl[uline]; } if(uline==bufs[cbuf].ptr) { pline=0; } while(pline>=bufs[cbuf].lpl[uline]) { pline-=bufs[cbuf].lpl[uline]; if(bufs[cbuf].filled) { if(uline==bufs[cbuf].ptr) { pline=0; break; } uline=(uline+1)%bufs[cbuf].nlines; } else { if(uline>=bufs[cbuf].ptr) { uline=bufs[cbuf].ptr; pline=0; break; } uline++; } } bufs[cbuf].scroll=uline; bufs[cbuf].ascroll=pline; int row=height-2; //setcolour(bufs[cbuf].lpc[uline]); while(row>(tsb?1:0)) { bool breakit=false; pline--; while(pline<0) { uline--; if(uline<0) { if(bufs[cbuf].filled) uline+=bufs[cbuf].nlines; else { breakit=true; pline=0; break; } } if(uline==bufs[cbuf].ptr) { breakit=true; break; } pline+=bufs[cbuf].lpl[uline]; } if(breakit) break; locate(row, 0); fputs(bufs[cbuf].lpt[uline][pline], stdout); if(!full_width_colour) resetcol(); clr(); row--; } resetcol(); while(row>(tsb?1:0)) { locate(row--, 0); clr(); } switch(bufs[cbuf].type) { case STATUS: settitle("quIRC - status"); break; case SERVER: // have to scope it for the cstr 'variably modified type' { char cstr[16+strlen(bufs[cbuf].bname)]; sprintf(cstr, "quIRC - %s", bufs[cbuf].bname); settitle(cstr); } break; case CHANNEL: // have to scope it for the cstr 'variably modified type' { char cstr[16+strlen(bufs[cbuf].bname)+strlen(SERVER(cbuf).bname)]; sprintf(cstr, "quIRC - %s on %s", bufs[cbuf].bname, SERVER(cbuf).bname); settitle(cstr); } break; case PRIVATE: // have to scope it for the cstr 'variably modified type' { char cstr[16+strlen(bufs[cbuf].bname)+strlen(SERVER(cbuf).bname)]; sprintf(cstr, "quIRC - <%s> on %s", bufs[cbuf].bname, SERVER(cbuf).bname); settitle(cstr); } break; default: settitle("quIRC"); break; } if(tsb) titlebar(); bufs[cbuf].alert=false; return(0); } int mark_buffer_dirty(int buf) { bufs[buf].dirty=true; return(0); }