char *unquoteurl(char *in) { struct charbuf buf; char *p; int c; bufinit(buf); p = in; while(*p) { if(*p == '%') { if(!p[1] || !p[2]) goto fail; c = 0; if((p[1] >= '0') && (p[1] <= '9')) c |= (p[1] - '0') << 4; else if((p[1] >= 'a') && (p[1] <= 'f')) c |= (p[1] - 'a' + 10) << 4; else if((p[1] >= 'A') && (p[1] <= 'F')) c |= (p[1] - 'A' + 10) << 4; else goto fail; if((p[2] >= '0') && (p[2] <= '9')) c |= (p[2] - '0'); else if((p[2] >= 'a') && (p[2] <= 'f')) c |= (p[2] - 'a' + 10); else if((p[2] >= 'A') && (p[2] <= 'F')) c |= (p[2] - 'A' + 10); else goto fail; bufadd(buf, c); p += 3; } else { bufadd(buf, *(p++)); } } bufadd(buf, 0); return(buf.b); fail: buffree(buf); return(NULL); }
static void speed_process (float * * data, int * samples) { double pitch = aud_get_double (CFGSECT, "pitch"); double speed = aud_get_double (CFGSECT, "speed"); /* Remove audio that has already been played from the output buffer. */ bufcut (& out, written); /* Copy the passed audio to the input buffer, scaled to adjust pitch. */ bufadd (& in, * data, * samples / curchans, 1.0 / pitch); /* If we are ending, add silence to the end of the input signal. */ if (ending) bufgrow (& in, in.len + width / 2); /* Calculate the spacing interval for input. */ int instep = round (outstep * speed / pitch); /* Run the speed change algorithm. */ int src = 0; int dst = 0; while (src + MAX (width, instep) <= in.len) { bufgrow (& out, dst + width); out.len = dst + width; for (int i = 0; i < width; i ++) for (int c = 0; c < curchans; c ++) OFFSET (out.mem, dst + i)[c] += OFFSET (in.mem, src + i)[c] * cosine[i]; src += instep; dst += outstep; } /* Remove processed audio from the input buffer. */ bufcut (& in, src); /* Trim silence from the beginning of the output buffer. */ if (trim > 0) { int cut = MIN (trim, dst); bufcut (& out, cut); dst -= cut; trim -= cut; } /* If we are ending, return all of the output buffer except the silence that * we trim from the end of it. */ if (ending) dst = out.len - width / 2; /* Return processed audio in the output buffer and mark it to be removed on * the next call. */ * data = out.mem; * samples = dst * curchans; written = dst; }
static void outplex(struct muth *muth, va_list args) { vavar(FILE *, sk); struct { struct ch { FILE *s; int id; } *b; size_t s, d; } outs; int i; struct ch ch; int type, rid; char *data; size_t dlen; bufinit(outs); while((ch.s = va_arg(args, FILE *)) != NULL) { ch.id = va_arg(args, int); bufadd(outs, ch); } data = NULL; while(1) { if(recvrec(sk, &type, &rid, &data, &dlen)) goto out; if(rid != 1) goto out; for(i = 0; i < outs.d; i++) { if(outs.b[i].id == type) { if(outs.b[i].s != NULL) { if(dlen == 0) { fclose(outs.b[i].s); outs.b[i].s = NULL; } else { if(fwrite(data, 1, dlen, outs.b[i].s) != dlen) goto out; } } break; } } free(data); data = NULL; } out: if(data != NULL) free(data); for(i = 0; i < outs.d; i++) { if(outs.b[i].s != NULL) fclose(outs.b[i].s); } buffree(outs); fclose(sk); }
static void bufcatkv(struct charbuf *dst, char *key, char *val) { size_t kl, vl; if((kl = strlen(key)) < 128) { bufadd(*dst, kl); } else { bufadd(*dst, ((kl & 0x7f000000) >> 24) | 0x80); bufadd(*dst, (kl & 0x00ff0000) >> 16); bufadd(*dst, (kl & 0x0000ff00) >> 8); bufadd(*dst, kl & 0x000000ff); } if((vl = strlen(val)) < 128) { bufadd(*dst, vl); } else { bufadd(*dst, ((vl & 0x7f000000) >> 24) | 0x80); bufadd(*dst, (vl & 0x00ff0000) >> 16); bufadd(*dst, (vl & 0x0000ff00) >> 8); bufadd(*dst, vl & 0x000000ff); } bufcat(*dst, key, kl); bufcat(*dst, val, vl); }
static char *connid(void) { static struct charbuf cur; int i; char *ret; for(i = 0; i < cur.d; i++) { if((++cur.b[i]) > 'Z') cur.b[i] = 'A'; else goto done; } bufadd(cur, 'A'); done: ret = memcpy(smalloc(cur.d + 1), cur.b, cur.d); ret[cur.d] = 0; return(ret); }
static struct hthead *parsereq(struct bufio *in) { struct hthead *req; struct charbuf method, url, ver; int c; req = NULL; bufinit(method); bufinit(url); bufinit(ver); while(1) { c = biogetc(in); if(c == ' ') { break; } else if((c == EOF) || (c < 32) || (c >= 128)) { goto fail; } else { bufadd(method, c); if(method.d >= 128) goto fail; } } while(1) { c = biogetc(in); if(c == ' ') { break; } else if((c == EOF) || (c < 32)) { goto fail; } else { bufadd(url, c); if(url.d >= 65536) goto fail; } } while(1) { c = biogetc(in); if(c == 10) { break; } else if(c == 13) { } else if((c == EOF) || (c < 32) || (c >= 128)) { goto fail; } else { bufadd(ver, c); if(ver.d >= 128) goto fail; } } bufadd(method, 0); bufadd(url, 0); bufadd(ver, 0); req = mkreq(method.b, url.b, ver.b); if(parseheadersb(req, in)) goto fail; trimx(req); goto out; fail: if(req != NULL) { freehthead(req); req = NULL; } out: buffree(method); buffree(url); buffree(ver); return(req); }
int main(int argc, char **argv, char **envp) { int c; char *file, *sp; struct charvbuf prog; int inpath, addfile, cd; int infd, outfd; FILE *in, *out; char **headers; pid_t child; int estat; environ = envp; signal(SIGPIPE, SIG_IGN); bufinit(prog); inpath = 0; addfile = 1; cd = 0; while((c = getopt(argc, argv, "cp:P:")) >= 0) { switch(c) { case 'c': cd = 1; break; case 'p': bufadd(prog, optarg); inpath = 1; break; case 'P': prog.d = 0; bufadd(prog, optarg); while(1) { if(optind >= argc) { flog(LOG_ERR, "callcgi: unterminated argument list for -P"); exit(1); } if(!strcmp(argv[optind], ";")) { optind++; break; } bufadd(prog, argv[optind++]); } if(prog.d == 0) { flog(LOG_ERR, "callcgi: -P option needs at least a program name"); exit(1); } inpath = 1; addfile = 0; break; default: usage(); exit(1); } } if(argc - optind < 3) { usage(); exit(1); } if(((file = getenv("REQ_X_ASH_FILE")) == NULL) && (prog.d == 0)) { flog(LOG_ERR, "callcgi: needs to be called with the X-Ash-File header"); exit(1); } if(cd) { /* This behavior is encouraged by the CGI specification (RFC 3875, 7.2), * but not strictly required, and I get the feeling it might break some * relative paths here or there, so it's not the default for now. */ if((sp = strrchr(file, '/')) != NULL) { *sp = 0; if(chdir(file)) { *sp = '/'; } else { file = sp + 1; } } } if(prog.d == 0) bufadd(prog, file); if(addfile && (file != NULL)) bufadd(prog, file); bufadd(prog, NULL); child = forkchild(inpath, prog.b, file, argv[optind], argv[optind + 1], argv[optind + 2], &infd, &outfd); in = fdopen(infd, "w"); passdata(stdin, in); /* Ignore errors, perhaps? */ fclose(in); out = fdopen(outfd, "r"); if((headers = parsecgiheaders(out)) == NULL) { flog(LOG_WARNING, "CGI handler returned invalid headers"); exit(1); } sendstatus(headers, stdout); sendheaders(headers, stdout); printf("\n"); if(passdata(out, stdout)) kill(child, SIGINT); fclose(out); if(waitpid(child, &estat, 0) == child) { if(WCOREDUMP(estat)) flog(LOG_WARNING, "CGI handler `%s' dumped core", prog.b[0]); if(WIFEXITED(estat) && !WEXITSTATUS(estat)) return(0); else return(1); } flog(LOG_WARNING, "could not wait for CGI handler: %s", strerror(errno)); return(1); }
struct hthead *parseresponseb(struct bufio *in) { struct hthead *req; int code; struct charbuf ver, msg; int c; req = NULL; bufinit(ver); bufinit(msg); code = 0; while(1) { c = biogetc(in); if(c == ' ') { break; } else if((c == EOF) || (c < 32) || (c >= 128)) { goto fail; } else { bufadd(ver, c); if(ver.d >= 128) goto fail; } } while(1) { c = biogetc(in); if(c == ' ') { break; } else if((c == EOF) || (c < '0') || (c > '9')) { goto fail; } else { code = (code * 10) + (c - '0'); if(code >= 10000) goto fail; } } while(1) { c = biogetc(in); if(c == 10) { break; } else if(c == 13) { } else if((c == EOF) || (c < 32)) { goto fail; } else { bufadd(msg, c); if(msg.d >= 512) goto fail; } } bufadd(msg, 0); bufadd(ver, 0); req = mkresp(code, msg.b, ver.b); if(parseheadersb(req, in)) goto fail; goto out; fail: if(req != NULL) { freehthead(req); req = NULL; } out: buffree(msg); buffree(ver); return(req); }
int parseheadersb(struct hthead *head, struct bufio *in) { int c, state; struct charbuf name, val; size_t tsz; bufinit(name); bufinit(val); state = 0; tsz = 0; while(1) { c = biogetc(in); if(++tsz >= 65536) goto fail; again: if(state == 0) { if(c == '\r') { } else if(c == '\n') { break; } else if(c == EOF) { goto fail; } else { state = 1; goto again; } } else if(state == 1) { if(c == ':') { trim(&name); bufadd(name, 0); state = 2; } else if(c == '\r') { } else if(c == '\n') { goto fail; } else if(c == EOF) { goto fail; } else { bufadd(name, c); } } else if(state == 2) { if(c == '\r') { } else if(c == '\n') { trim(&val); bufadd(val, 0); headappheader(head, name.b, val.b); buffree(name); buffree(val); state = 0; } else if(c == EOF) { goto fail; } else { bufadd(val, c); } } } return(0); fail: buffree(name); buffree(val); return(-1); }