PRIVATE int HTSC_putBlock (HTStream * me, const char * b, int l) { me->cur_size += l; /* ** If we get a buffer overflow and we are going to PUT or POST the document ** then ask the user whether it is OK to proceed buffering. Otherwise we ** must give up the request. In all other cases we stop if the buffer fills ** up. */ if (!me->ignore && me->max_size > 0 && me->cur_size > me->max_size) { HTMethod method = HTRequest_method(me->request); if (HTMethod_hasEntity(method)) { HTAlertCallback *cbf = HTAlert_find(HT_A_CONFIRM); if ((cbf && (*cbf)(me->request, HT_A_CONFIRM, HT_MSG_BIG_PUT, NULL, NULL, NULL))) me->ignore = YES; else me->give_up = YES; } else { me->give_up = YES; } } else if (!me->ensure) { HTParentAnchor * anchor = HTRequest_anchor(me->request); int cl = HTAnchor_length(anchor); if (cl > 0) HTChunk_ensure(me->chunk, cl); me->ensure = YES; } if (!me->give_up) { HTChunk_putb(me->chunk, b, l); return HT_OK; } return HT_ERROR; }
PRIVATE int HTML_write (HTStructured * me, const char * b, int l) { if (!me->started) { HTextImp_build(me->text, HTEXT_BEGIN); me->started = YES; } /* Look at what we got */ switch (me->sp[0]) { case HTML_TITLE: HTChunk_putb(me->title, b, l); /* Fall through */ default: HTextImp_addText(me->text, b, l); } return HT_OK; }
/* ** Searches for HTTP Request Line before going into transparent mode */ PRIVATE int HTTPReceive_put_block (HTStream * me, const char * b, int l) { if (!me->transparent) { const char *p=b; while (l>0 && *p!=CR && *p!=LF) l--, p++; HTChunk_putb(me->buffer, b, p-b); if (*p==CR || *p==LF) { int status = ParseRequest(me); HTChunk_clear(me->buffer); if (status != HT_OK) return status; me->transparent = YES; b=p; } } if (l > 0) { int status = PUTBLOCK(b, l); if (status == HT_LOADED) me->transparent = NO; return status; } return HT_OK; }
/* ** Header is terminated by CRCR, LFLF, CRLFLF, CRLFCRLF ** Folding is either of CF LWS, LF LWS, CRLF LWS */ PRIVATE int HTMIME_put_block (HTStream * me, const char * b, int l) { const char * start = b; const char * end = start; const char * value = HTChunk_size(me->value) > 0 ? b : NULL; int length = l; int status; while (!me->transparent) { if (me->EOLstate == EOL_FCR) { if (*b == CR) /* End of header */ me->EOLstate = EOL_END; else if (*b == LF) /* CRLF */ me->EOLstate = EOL_FLF; else if (isspace((int) *b)) /* Folding: CR SP */ me->EOLstate = EOL_FOLD; else /* New line */ me->EOLstate = EOL_LINE; } else if (me->EOLstate == EOL_FLF) { if (*b == CR) /* LF CR or CR LF CR */ me->EOLstate = EOL_SCR; else if (*b == LF) /* End of header */ me->EOLstate = EOL_END; else if (isspace((int) *b)) /* Folding: LF SP or CR LF SP */ me->EOLstate = EOL_FOLD; else /* New line */ me->EOLstate = EOL_LINE; } else if (me->EOLstate == EOL_SCR) { if (*b==CR || *b==LF) /* End of header */ me->EOLstate = EOL_END; else if (isspace((int) *b)) /* Folding: LF CR SP or CR LF CR SP */ me->EOLstate = EOL_FOLD; else /* New line */ me->EOLstate = EOL_LINE; } else if (*b == CR) me->EOLstate = EOL_FCR; else if (*b == LF) me->EOLstate = EOL_FLF; /* Line found */ else { if (!me->haveToken) { if (*b == ':' || isspace((int) *b)) { HTChunk_putb(me->token, start, end-start); HTChunk_putc(me->token, '\0'); me->haveToken = YES; } else { unsigned char ch = *(unsigned char *) b; ch = TOLOWER(ch); me->hash = (me->hash * 3 + ch) % MIME_HASH_SIZE; } } else if (value == NULL && *b != ':' && !isspace((int) *b)) value = b; end++; } switch (me->EOLstate) { case EOL_LINE: case EOL_END: { int ret = HT_ERROR; HTChunk_putb(me->value, value, end-value); HTChunk_putc(me->value, '\0'); ret = _stream2dispatchParsers(me); HTNet_addBytesRead(me->net, b-start); start=b, end=b; if (me->EOLstate == EOL_END) { /* EOL_END */ if (ret == HT_OK) { b++, l--; ret = pumpData(me); HTNet_addBytesRead(me->net, 1); if (me->mode & (HT_MIME_FOOTER | HT_MIME_CONT)) { HTHost_setConsumed(HTNet_host(me->net), length - l); return ret; } else { HTNet_setHeaderBytesRead(me->net, HTNet_bytesRead(me->net)); } } } else { /* EOL_LINE */ HTChunk_truncate(me->token,0); HTChunk_truncate(me->value,0); me->haveToken = NO; me->hash = 0; value = NULL; } me->EOLstate = EOL_BEGIN; if (ret != HT_OK && ret != HT_LOADED) return ret; break; } case EOL_FOLD: me->EOLstate = EOL_BEGIN; if (!me->haveToken) { HTChunk_putb(me->token, start, end-start); HTChunk_putc(me->token, '\0'); me->haveToken = YES; } else if (value) { HTChunk_putb(me->value, value, end-value); HTChunk_putc(me->value, ' '); } start=b, end=b; break; default: b++, l--; if (!l) { BOOL stop = NO; if (!me->haveToken) { /* If empty header then prepare to stop */ if (end-start) HTChunk_putb(me->token, start, end-start); else stop = YES; } else if (value) HTChunk_putb(me->value, value, end-value); HTHost_setConsumed(HTNet_host(me->net), length - l); return stop ? pumpData(me) : HT_OK; } } } if (length != l) HTHost_setConsumed(HTNet_host(me->net), length - l); /* ** Put the rest down the stream without touching the data but make sure ** that we get the correct content length of data. If we have a CL in ** the headers then this stream is responsible for the accountance. */ if (me->hasBody) { HTNet * net = me->net; /* Check if CL at all - thanks to [email protected] (John Wei) */ long cl = HTResponse_length(me->response); if (cl >= 0) { long bodyRead = HTNet_bytesRead(net) - HTNet_headerBytesRead(net); /* ** If we have more than we need then just take what belongs to us. */ if (bodyRead + l >= cl) { int consume = cl - bodyRead; if ((status = (*me->target->isa->put_block)(me->target, b, consume)) < 0) return status; else { HTAlertCallback * cbf = HTAlert_find(HT_PROG_DONE); HTNet_addBytesRead(net, consume); HTHost_setConsumed(HTNet_host(net), consume); if (cbf) (*cbf)(me->request, HT_PROG_DONE, HT_MSG_NULL, NULL, NULL, NULL); return HT_LOADED; } } else { if ((status = (*me->target->isa->put_block)(me->target, b, l)) < 0) return status; HTNet_addBytesRead(net, l); HTHost_setConsumed(HTNet_host(net), l); return status; } } return (*me->target->isa->put_block)(me->target, b, l); } else { HTAlertCallback * cbf = HTAlert_find(HT_PROG_DONE); if (cbf) (*cbf)(me->request, HT_PROG_DONE, HT_MSG_NULL, NULL, NULL, NULL); } return HT_LOADED; }
/* Append a string ** --------------- */ PUBLIC void HTChunk_puts (HTChunk * ch, const char * s) { HTChunk_putb(ch, s, (int) strlen(s)); }
/* CSParse_parseChunk - elemental parse engine for all pics nowIns. This passes * tokenized data into the handler functions in the CSParse_t.handlersOf. These * handlers are responsibel for placing the data in the appropriate target. * The text is broken into nowIns and passed a SubParser based on the current * nowIn which is one of: * NowIn_NEEDOPEN - get paren and go to NowIn_ENGINE, text is an error * NowIn_ENGINE - in a containing structure, text goes to engineOf_ * NowIn_NEEDCLOSE - get paren and go to NowIn_ENGINE, text is an error * NowIn_END - expect no more text or parens * NowIn_ERROR - */ PUBLIC CSDoMore_t CSParse_parseChunk (CSParse_t * pCSParse, const char * ptr, int len, void * pVoid) { int i; if (!len || !ptr) return CSDoMore_error; for (i = 0; i < len; i++) { pCSParse->offset++; if (pCSParse->quoteState) { if (pCSParse->quoteState == ptr[i]) { pCSParse->quoteState = 0; pCSParse->demark = ' '; } else HTChunk_putb(pCSParse->token, ptr+i, 1); continue; } if (ptr[i] == SQUOTE || ptr[i] == DQUOTE) { if (pCSParse->demark) { while ((pCSParse->nowIn = (*pCSParse->pParseContext->engineOf)(pCSParse, ' ', pVoid)) == NowIn_CHAIN); HTChunk_clear(pCSParse->token); pCSParse->demark = 0; } else if (HTChunk_size(pCSParse->token) && /* && warn(pCSParse, message_UNEXPECTED_CHARACTER, ptr[i])) */ callErrorHandler(pCSParse, ptr+i, ptr[i], StateRet_ERROR_BAD_CHAR) !=StateRet_OK) pCSParse->nowIn = NowIn_ERROR; pCSParse->quoteState = ptr[i]; pCSParse->pParseContext->observedQuotes = YES; continue; } switch (pCSParse->nowIn) { case NowIn_NEEDOPEN: if (ptr[i] == LPAREN) { pCSParse->nowIn = NowIn_ENGINE; continue; } if (isspace((int) ptr[i])) continue; /* if (warn(pCSParse, message_UNEXPECTED_CHARACTER, ptr[i])) pCSParse->nowIn = NowIn_ERROR; */ if (callErrorHandler(pCSParse, ptr+i, ptr[i], StateRet_ERROR_BAD_CHAR) !=StateRet_OK) pCSParse->nowIn = NowIn_ERROR; continue; case NowIn_ENGINE: if (isspace((int) ptr[i])) { if (HTChunk_size(pCSParse->token)) pCSParse->demark = ' '; continue; } if (ptr[i] == LPAREN || ptr[i] == RPAREN || pCSParse->demark) { /* parens override space demarkation */ if (ptr[i] == LPAREN) pCSParse->demark = LPAREN; if (ptr[i] == RPAREN) pCSParse->demark = RPAREN; /* call the engine as long as it wants re-entrance */ while ((pCSParse->nowIn = (*pCSParse->pParseContext->engineOf)(pCSParse, pCSParse->demark, pVoid)) == NowIn_CHAIN); HTChunk_clear(pCSParse->token); pCSParse->demark = 0; if (ptr[i] == LPAREN || ptr[i] == RPAREN) continue; /* continue with next token */ } HTChunk_putb(pCSParse->token, ptr+i, 1); continue; case NowIn_NEEDCLOSE: if (ptr[i] == RPAREN) { pCSParse->nowIn = NowIn_ENGINE; continue; } if (isspace((int) ptr[i])) continue; if (callErrorHandler(pCSParse, ptr+i, ptr[i], StateRet_ERROR_BAD_CHAR) !=StateRet_OK) pCSParse->nowIn = NowIn_ERROR; /* if (warn(pCSParse, message_UNEXPECTED_CHARACTER, ptr[i])) pCSParse->nowIn = NowIn_ERROR; */ continue; case NowIn_END: #if 0 /* enable this to tell the parser to check the remainder of the stream after the parsed object thinks it is done */ if (isspace(ptr[i])) continue; /* if (warn(pCSParse, message_UNEXPECTED_CHARACTER, ptr[i])) pCSParse->nowIn = NowIn_ERROR; */ if (callErrorHandler(pCSParse, ptr+i, ptr[i], StateRet_ERROR_BAD_CHAR) !=StateRet_OK) pCSParse->nowIn = NowIn_ERROR; continue; #else return CSDoMore_done; #endif case NowIn_MATCHCLOSE: if (ptr[i] == RPAREN) { if (!pCSParse->depth) pCSParse->nowIn = NowIn_ENGINE; else pCSParse->depth--; } if (ptr[i] == LPAREN) pCSParse->depth++; continue; case NowIn_ERROR: return CSDoMore_error; break; default: HTTRACE(PICS_TRACE, "PICS: Internal error in parser - bad nowIn:%d.\n" _ pCSParse->nowIn); return CSDoMore_error; } } /* check completion */ return pCSParse->nowIn == NowIn_END ? CSDoMore_done : CSDoMore_more; }
int main (int argc, char ** argv) { HTSQL * sql = NULL; char * sqlserver = DEFAULT_SQL_SERVER; char * sqldb = DEFAULT_SQL_DB; char * sqluser = DEFAULT_SQL_USER; char * sqlpw = DEFAULT_SQL_PW; char * cvsuser = DEFAULT_CVS_USER; time_t cvsdate = -1; FILE * fin = stdin; char * input_buffer[BUFSIZE]; HTChunk * loginfo = HTChunk_new(BUFSIZE); int arg = 0; BOOL create_db = YES; /* Initiate libwww */ HTLibInit(APP_NAME, APP_VERSION); /* Scan command line for parameters */ for (arg=1; arg<argc; arg++) { if (*argv[arg] == '-') { if (!strcmp(argv[arg], "-h") || !strcmp(argv[arg], "-?")) { VersionInfo(); Cleanup(0, sql, loginfo); } else if (!strcmp(argv[arg], "-v")) { HTSetTraceMessageMask("q"); } else if (!strcmp(argv[arg], "-nocreate")) { create_db = NO; } else if (!strncmp(argv[arg], "-sqldb", 5)) { sqldb = (arg+1 < argc && *argv[arg+1] != '-') ? argv[++arg] : DEFAULT_SQL_DB; } else if (!strncmp(argv[arg], "-sqlpassword", 5)) { sqlpw = (arg+1 < argc && *argv[arg+1] != '-') ? argv[++arg] : DEFAULT_SQL_PW; } else if (!strncmp(argv[arg], "-sqlserver", 5)) { sqlserver = (arg+1 < argc && *argv[arg+1] != '-') ? argv[++arg] : DEFAULT_SQL_SERVER; } else if (!strncmp(argv[arg], "-sqluser", 5)) { sqluser = (arg+1 < argc && *argv[arg+1] != '-') ? argv[++arg] : DEFAULT_SQL_USER; } else if (!strncmp(argv[arg], "-cvsuser", 5)) { cvsuser = (arg+1 < argc && *argv[arg+1] != '-') ? argv[++arg] : DEFAULT_CVS_USER; } else if (!strncmp(argv[arg], "-cvsdate", 5)) { cvsdate = (arg+1 < argc && *argv[arg+1] != '-') ? HTParseTime(argv[++arg], NULL, NO) : -1; } else { fprintf(stderr, "Bad Argument (%s)\n", argv[arg]); } } else { fprintf(stderr, "Bad Argument (%s)\n", argv[arg]); } } /* Get an SQL object */ if ((sql = HTSQL_new(sqlserver, sqluser, sqlpw, 0)) == NULL) Cleanup(-1, sql, loginfo); /* Connect to the SQL server */ if (HTSQL_connect(sql) != YES) Cleanup(-1, sql, loginfo); /* Select our database */ if (HTSQL_selectDB(sql, sqldb) != YES) Cleanup(-1, sql, loginfo); /* Create our tables */ if (create_db) createTables(sql, 0); /* Read the arguments from stdin */ for (;;) { int status = fread(input_buffer, 1, BUFSIZE, fin); if (status < 0) Cleanup(-1, sql, loginfo); if (status == 0) break; HTChunk_putb(loginfo, (const char *) input_buffer, status); } /* Parse the input chunk */ { char * ptr = HTChunk_data(loginfo); char * noop1 = HTNextField(&ptr); char * noop2 = HTNextField(&ptr); char * root = HTNextField(&ptr); char * operation = NULL; char * files = NULL; char * comment = NULL; int comment_id = -1; int user_id = -1; char * p, * q; #ifdef HT_REENTRANT char *lasts; /* For strtok_r */ #endif /* Find shared log message and get id */ if ((q = HTStrCaseStr(ptr, "\nLog Message:")) != NULL) { comment = q+14; *q = '\0'; } if ((comment_id = add_comment(sql, comment)) < 0) Cleanup(-1, sql, loginfo); /* Add/find user and get id */ if ((user_id = add_user(sql, cvsuser)) < 0) Cleanup(-1, sql, loginfo); /* For each operation, find the files involved */ while ((q = HTStrCaseStr(ptr, " Files:")) != NULL) { /* Find the operation */ files = q+9; for (p=q; p>HTChunk_data(loginfo) && *p && *p!='\n'; p--); p++; operation = HTNextField(&p); /* Find the next line */ if ((q = strchr(files, '\n')) != NULL) { *q++ = '\0'; ptr = q; } /* Create the query */ if (operation && files && comment) { char * file; int location_id = -1; #ifdef HT_REENTRANT if ((file = strtok_r(files, DELIMITERS, &lasts)) != NULL) { #else if ((file = strtok(files, DELIMITERS)) != NULL) { #endif /* HT_REENTRANT */ do { char * path = NULL; StrAllocMCopy(&path, root, "/", file, NULL); /* Add/find location and get id */ if ((location_id = add_location(sql, path)) < 0) { Cleanup(-1, sql, loginfo); break; } #if 0 fprintf(stderr, "location: `%s\', user: `%s\', operation: `%s\', comment: `%s\'\n", path, cvsuser, operation, comment); #endif /* Add log entry */ { char buf[16384]; char * query = HTSQL_printf(buf, 16384, "insert into %s values (%u,%u,%T,%S,%u)", DEFAULT_SQL_LOG_TABLE, location_id, user_id, cvsdate, operation, comment_id); if (HTSQL_query(sql, query) != YES) { Cleanup(-1, sql, loginfo); break; } } HT_FREE(path); #ifdef HT_REENTRANT } while ((file = (char *) strtok_r(NULL, DELIMITERS, &lasts)) != NULL); #else } while ((file = strtok(NULL, DELIMITERS)) != NULL); #endif /* HT_REENTRANT */ } } } } return 0; }