#include #include #include #include #include #include #include #include "cmoe.h" static uint32_t* items_len; static COUNTER counter; static char* DATFILE = "dat.sp"; static char* TOKEN = "fumiama"; #define ADD_HEADER_PARAM(buf, offset, h, p) sprintf(buf + offset, (h), (p)) #define HEADER(content_type) HTTP200 SERVER_STRING CACHE_CTRL CONTENT_TYPE(content_type) #define headers(content_len, content_type) (_headers(content_len, HEADER(content_type), sizeof(HEADER(content_type))-1)) static void _headers(uint32_t content_len, const char* h, size_t hlen) { char buf[64]; size_t offset = ADD_HEADER_PARAM(buf, 0, CONTENT_LEN "\r\n", content_len); if(offset <= 0) { write(1, "\0\0\0\0", 4); exit(EXIT_FAILURE); } content_len += offset+hlen; struct iovec iov[3] = {{&content_len, sizeof(uint32_t)}, {h, hlen}, {buf, offset}}; writev(1, &iov, 3); } static void http_error(ERRCODE code, char* msg) { uint32_t len = strlen(msg) + typel[code]; char* str = malloc(len); sprintf(str, types[code], msg); struct iovec iov[2] = {{&len, sizeof(uint32_t)}, {str, len}}; writev(1, &iov, 2); free(str); exit(EXIT_FAILURE); } static char* get_arg(const char* query) { int len = 0; while(query[len] && query[len] != '&') len++; if(len <= 0) return NULL; char* name = malloc(len+1); memcpy(name, query, len); name[len] = 0; return name; } static int del_user(FILE* fp, SIMPLE_PB* spb) { COUNTER *d = (COUNTER *)spb->target; uint32_t next = ftell(fp); uint32_t this = next - spb->real_len; fseek(fp, 0, SEEK_END); uint32_t end = ftell(fp); if(next == end) return ftruncate(fileno(fp), end - spb->real_len); uint32_t cap = end - next; char *data = malloc(cap); if(data) { fseek(fp, next, SEEK_SET); if(fread(data, cap, 1, fp) == 1) { if(!ftruncate(fileno(fp), end - spb->real_len)){ fseek(fp, this, SEEK_SET); if(fwrite(data, cap, 1, fp) == 1) { free(data); fflush(fp); return 0; } } } free(data); } return 2; } static int add_user(char* name, uint32_t count, FILE* fp) { counter.count = count; strncpy(counter.name, name, COUNTER_NAME_LEN-1); fseek(fp, 0, SEEK_END); return !set_pb(fp, items_len, sizeof(COUNTER), &counter); } static uint32_t get_content_len(int isbig, uint16_t* len_type, char* cntstr) { uint32_t len = sizeof(svg_small) // small & big has the same len + sizeof(svg_tail) - 1; for(int i = 0; cntstr[i]; i++) { len += len_type[cntstr[i] - '0'] + (sizeof(img_slot_front) + sizeof(img_slot_rear) - 2); if(i > 0) len++; if(i > 2-isbig) len++; } return len; } #define has_next(fp, ch) ((ch=getc(fp)),(feof(fp)?0:(ungetc(ch,fp),1))) #define set_type(name, t, l) if(!strcmp(theme, name)) {\ theme_type = t;\ len_type = l;\ } static void return_count(char* name, char* theme) { FILE* fp = fopen(DATFILE, "rb+"); if(!fp) fp = fopen(DATFILE, "wb+"); if(fp) { flock(fileno(fp), LOCK_EX); int ch, exist = 0, user_exist = 0; while(has_next(fp, ch)) { SIMPLE_PB *spb = get_pb(fp); COUNTER *d = (COUNTER *)spb->target; if (!strcmp(name, d->name)) { if(del_user(fp, spb)) http_error(HTTP500, "Unable to Delete Old Data."); else { if (add_user(d->name, d->count + 1, fp)) http_error(HTTP500, "Add User Error."); else { fclose(fp); char cntstrbuf[11]; sprintf(cntstrbuf, "%010u", d->count); free(spb); char* cntstr = cntstrbuf; for(int i = 0; i < 10; i++) if(cntstrbuf[i] != '0') { if(i > 2) cntstr = cntstrbuf+i-2; break; } int isbig = 0; char** theme_type = mb; uint16_t* len_type = mbl; if(theme) { set_type("mbh", mbh, mbhl) else set_type("r34", r34, r34l) else set_type("gb", gb, gbl) else set_type("gbh", gbh, gbhl) isbig = (theme_type == gb || theme_type == gbh); } int w, h; char *head; if(isbig) { w = W_BIG; h = H_BIG; head = svg_big; } else { w = W_SMALL; h = H_SMALL; head = svg_small; } headers(get_content_len(isbig, len_type, cntstr), image/svg+xml); printf(head, w*(10+cntstrbuf-cntstr)); for(int i = 0; cntstr[i]; i++) { printf(img_slot_front, w * i, w, h); int n = cntstr[i] - '0'; fwrite(theme_type[n], len_type[n], 1, stdout); printf(img_slot_rear); } printf(svg_tail); } return; } } else free(spb); } fclose(fp); http_error(HTTP404, "No Such User."); } else http_error(HTTP500, "Open File Error."); } static int name_exist(char* name) { FILE* fp = fopen(DATFILE, "rb+"); if(!fp) fp = fopen(DATFILE, "wb+"); if(fp) { int ch, exist = 0; flock(fileno(fp), LOCK_EX); while(has_next(fp, ch)) { SIMPLE_PB *spb = get_pb(fp); COUNTER *d = (COUNTER *)spb->target; if (!strcmp(name, d->name)) { free(spb); fclose(fp); return 1; } else free(spb); } fclose(fp); return 0; } else http_error(HTTP500, "Open File Error."); } #define QS (argv[2]) // Usage: cmoe method query_string int main(int argc, char **argv) { if(argc == 3) { char* str = getenv("DATFILE"); if(str != NULL) DATFILE = str; str = getenv("TOKEN"); if(str != NULL) TOKEN = str; char* name = strstr(QS, "name="); items_len = align_struct(sizeof(COUNTER), 2, &counter.name, &counter.count); if(!items_len) http_error(HTTP500, "Align Struct Error."); else if(name) { name = get_arg(name + 5); if(name) { char* theme = strstr(QS, "theme="); if(theme) { theme = get_arg(theme + 6); } char* reg = strstr(QS, "reg="); if(reg) { reg = get_arg(reg + 4); if(reg) { if(strcmp(reg, TOKEN)) http_error(HTTP400, "Token Error."); else if(!name_exist(name)) { FILE* fp = fopen(DATFILE, "ab+"); if(fp) { flock(fileno(fp), LOCK_EX); add_user(name, 0, fp); fclose(fp); char* msg = "

Success.\r\n"; headers(strlen(msg), text/html); write(1, msg, strlen(msg)); } else http_error(HTTP500, "Open File Error."); } else http_error(HTTP400, "Name Exist."); } else http_error(HTTP400, "Null Register Token."); } else return_count(name, theme); } else http_error(HTTP400, "Null Name Argument."); } else http_error(HTTP400, "Name Argument Notfound."); } else http_error(HTTP500, "Argument Count Error."); return 0; }