1
0
mirror of https://github.com/fumiama/CMoe-Counter.git synced 2024-11-30 16:24:28 +01:00
CMoe-Counter/cmoe.c

267 lines
8.0 KiB
C
Raw Normal View History

2021-06-10 06:03:29 +02:00
#include <simple_protobuf.h>
2021-06-07 15:18:19 +02:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
2021-06-10 06:03:29 +02:00
#include <sys/file.h>
2022-03-02 10:08:10 +01:00
#include <sys/uio.h>
2021-06-07 15:18:19 +02:00
#include <unistd.h>
#include "cmoe.h"
static uint32_t* items_len;
2022-11-23 07:45:39 +01:00
static counter_t counter;
2021-06-07 15:18:19 +02:00
2022-11-23 08:22:53 +01:00
static char* datfile = "dat.sp";
static char* token = "fumiama";
2022-05-20 09:13:49 +02:00
2023-03-04 10:55:25 +01:00
static FILE* fp;
2022-03-05 07:14:28 +01:00
#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))
2023-03-07 14:29:29 +01:00
static int _headers(uint32_t content_len, const char* h, size_t hlen) {
2022-03-05 07:14:28 +01:00
char buf[64];
size_t offset = ADD_HEADER_PARAM(buf, 0, CONTENT_LEN "\r\n", content_len);
2023-03-07 14:29:29 +01:00
if(offset <= 0) return -1;
2022-03-05 07:14:28 +01:00
content_len += offset+hlen;
2023-03-04 10:55:25 +01:00
struct iovec iov[3] = {{&content_len, sizeof(uint32_t)}, {(void*)h, hlen}, {(void*)buf, offset}};
2023-03-07 14:29:29 +01:00
return writev(1, (const struct iovec *)&iov, 3) <= 0;
2021-06-07 15:18:19 +02:00
}
2023-03-07 14:29:29 +01:00
static inline void http_error(errcode_enum_t code, char* msg) {
2021-09-11 18:05:52 +02:00
uint32_t len = strlen(msg) + typel[code];
2023-03-07 14:29:29 +01:00
char str[len];
2021-09-11 18:05:52 +02:00
sprintf(str, types[code], msg);
2023-03-04 10:55:25 +01:00
struct iovec iov[2] = {{(void*)&len, sizeof(uint32_t)}, {(void*)str, len}};
writev(1, (const struct iovec *)&iov, 2);
2021-06-07 15:18:19 +02:00
}
2023-03-07 14:29:29 +01:00
// get_arg used malloc but has never freed
2021-06-08 07:11:58 +02:00
static char* get_arg(const char* query) {
2021-06-07 18:17:42 +02:00
int len = 0;
2021-06-07 15:18:19 +02:00
while(query[len] && query[len] != '&') len++;
2022-03-02 10:08:10 +01:00
if(len <= 0) return NULL;
char* name = malloc(len+1);
memcpy(name, query, len);
name[len] = 0;
return name;
2021-06-07 15:18:19 +02:00
}
static int del_user(FILE* fp, SIMPLE_PB* spb) {
2022-11-23 07:45:39 +01:00
counter_t *d = (counter_t *)spb->target;
2021-06-07 15:18:19 +02:00
uint32_t next = ftell(fp);
uint32_t this = next - spb->real_len;
fseek(fp, 0, SEEK_END);
uint32_t end = ftell(fp);
2022-03-02 10:08:10 +01:00
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;
2021-06-07 15:18:19 +02:00
}
}
}
2022-03-02 10:08:10 +01:00
free(data);
2021-06-07 15:18:19 +02:00
}
2021-06-10 06:03:29 +02:00
return 2;
2021-06-07 15:18:19 +02:00
}
2023-03-07 14:29:29 +01:00
static inline int add_user(char* name, uint32_t count, FILE* fp) {
2021-06-07 15:18:19 +02:00
counter.count = count;
strncpy(counter.name, name, COUNTER_NAME_LEN-1);
fseek(fp, 0, SEEK_END);
2022-11-23 07:45:39 +01:00
return !set_pb(fp, items_len, sizeof(counter_t), &counter);
2021-06-07 15:18:19 +02:00
}
2023-03-07 14:29:29 +01:00
static inline uint32_t get_content_len(int isbig, uint16_t* len_type, char* cntstr) {
2022-03-02 12:22:14 +01:00
uint32_t len = sizeof(svg_small) // small & big has the same len
2021-06-07 15:18:19 +02:00
+ sizeof(svg_tail) - 1;
2022-03-02 10:36:24 +01:00
for(int i = 0; cntstr[i]; i++) {
2022-03-02 10:58:19 +01:00
len += len_type[cntstr[i] - '0'] + (sizeof(img_slot_front) + sizeof(img_slot_rear) - 2);
2022-03-02 12:22:14 +01:00
if(i > 0) len++;
if(i > 2-isbig) len++;
2021-06-07 15:18:19 +02:00
}
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)) {\
2023-03-04 10:55:25 +01:00
theme_type = (char**)t;\
len_type = (uint16_t*)l;\
2021-06-07 15:18:19 +02:00
}
2023-03-04 10:55:25 +01:00
static void return_count(FILE* fp, char* name, char* theme) {
2022-11-23 07:39:37 +01:00
int ch, exist = 0, user_exist = 0;
2022-11-23 07:45:39 +01:00
char buf[sizeof(SIMPLE_PB)+sizeof(counter_t)];
2022-11-23 07:39:37 +01:00
while(has_next(fp, ch)) {
SIMPLE_PB *spb = read_pb_into(fp, (SIMPLE_PB*)buf);
2022-11-23 07:45:39 +01:00
counter_t *d = (counter_t *)spb->target;
2022-11-23 07:39:37 +01:00
if (strcmp(name, d->name)) continue;
if(del_user(fp, spb)) {
http_error(HTTP500, "Unable to Delete Old Data.");
return;
}
if (add_user(d->name, d->count + 1, fp)) {
http_error(HTTP500, "Add User Error.");
return;
2021-06-07 15:18:19 +02:00
}
2022-11-23 07:39:37 +01:00
char cntstrbuf[11];
sprintf(cntstrbuf, "%010u", d->count);
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;
2023-03-04 10:55:25 +01:00
char** theme_type = (char**)mb;
uint16_t* len_type = (uint16_t*)mbl;
2022-11-23 07:39:37 +01:00
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)
2023-03-04 10:55:25 +01:00
isbig = (theme_type == (char**)gb || theme_type == (char**)gbh);
2022-11-23 07:39:37 +01:00
}
int w, h;
char *head;
if(isbig) {
w = W_BIG;
h = H_BIG;
2023-03-04 10:55:25 +01:00
head = (char*)svg_big;
2022-11-23 07:39:37 +01:00
}
else {
w = W_SMALL;
h = H_SMALL;
2023-03-04 10:55:25 +01:00
head = (char*)svg_small;
2022-11-23 07:39:37 +01:00
}
2023-03-08 09:38:48 +01:00
if(headers(get_content_len(isbig, len_type, cntstr), "image/svg+xml")) {
2023-03-07 14:29:29 +01:00
write(1, "\0\0\0\0", 4);
return;
}
2022-11-23 07:39:37 +01:00
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;
}
http_error(HTTP404, "No Such User.");
2021-06-07 15:18:19 +02:00
}
2023-03-04 10:55:25 +01:00
static int name_exist(FILE* fp, char* name) {
2022-11-23 07:39:37 +01:00
int ch, exist = 0;
2022-11-23 07:45:39 +01:00
char buf[sizeof(SIMPLE_PB)+sizeof(counter_t)];
2022-11-23 07:39:37 +01:00
while(has_next(fp, ch)) {
SIMPLE_PB *spb = read_pb_into(fp, (SIMPLE_PB*)buf);
2022-11-23 07:45:39 +01:00
counter_t *d = (counter_t *)spb->target;
2023-03-04 10:55:25 +01:00
if (!strcmp(name, d->name)) return 1;
2022-11-23 07:39:37 +01:00
}
return 0;
2021-06-07 15:18:19 +02:00
}
2023-03-04 10:55:25 +01:00
#define create_or_open(fp, filename) ((fp = fopen(filename, "rb+"))?(fp):(fp = fopen(filename, "wb+")))
2023-05-30 15:27:51 +02:00
#define flease(fp) { \
fflush(fp); \
flock(fileno(fp), LOCK_UN); \
fclose(fp); fp = NULL; \
}
2021-06-07 15:18:19 +02:00
#define QS (argv[2])
2022-03-02 10:18:50 +01:00
// Usage: cmoe method query_string
2021-06-07 15:18:19 +02:00
int main(int argc, char **argv) {
2022-11-23 07:39:37 +01:00
if(argc != 3) {
http_error(HTTP500, "Argument Count Error.");
2023-03-04 10:55:25 +01:00
return -1;
2022-11-23 07:39:37 +01:00
}
char* str = getenv("DATFILE");
2022-11-23 08:22:53 +01:00
if(str != NULL) datfile = str;
2022-11-23 07:39:37 +01:00
str = getenv("TOKEN");
2022-11-23 08:22:53 +01:00
if(str != NULL) token = str;
2022-11-23 07:39:37 +01:00
char* name = strstr(QS, "name=");
2022-11-23 07:45:39 +01:00
items_len = align_struct(sizeof(counter_t), 2, &counter.name, &counter.count);
2022-11-23 07:39:37 +01:00
if(!items_len) {
http_error(HTTP500, "Align Struct Error.");
return 2;
}
if(!name) {
http_error(HTTP400, "Name Argument Notfound.");
return 3;
}
name = get_arg(name + 5);
if(!name) {
http_error(HTTP400, "Null Name Argument.");
return 4;
}
char* theme = strstr(QS, "theme=");
if(theme) {
theme = get_arg(theme + 6);
}
char* reg = strstr(QS, "reg=");
if (!reg) {
2023-03-04 10:55:25 +01:00
if(!create_or_open(fp, datfile)) {
http_error(HTTP500, "Open File Error.");
return -2;
}
if(flock(fileno(fp), LOCK_EX)) {
http_error(HTTP500, "Lock File Error.");
return -3;
}
return_count(fp, name, theme);
2023-05-30 15:27:51 +02:00
flease(fp);
2022-11-23 07:39:37 +01:00
return 0;
}
reg = get_arg(reg + 4);
if (!reg) {
http_error(HTTP400, "Null Register Token.");
return 5;
}
2022-11-23 08:22:53 +01:00
if(strcmp(reg, token)) {
2022-11-23 07:39:37 +01:00
http_error(HTTP400, "Token Error.");
return 6;
}
2023-03-04 10:55:25 +01:00
if(!create_or_open(fp, datfile)) {
http_error(HTTP500, "Open File Error.");
return -4;
}
if(flock(fileno(fp), LOCK_EX)) {
http_error(HTTP500, "Lock File Error.");
return -5;
}
if(name_exist(fp, name)) {
2023-05-30 15:27:51 +02:00
flease(fp);
2022-11-23 07:39:37 +01:00
http_error(HTTP400, "Name Exist.");
return 7;
}
2023-05-30 15:27:51 +02:00
flease(fp);
2023-03-04 10:55:25 +01:00
fp = fopen(datfile, "ab+");
2022-11-23 07:39:37 +01:00
if (!fp) {
http_error(HTTP500, "Open File Error.");
2023-03-04 10:55:25 +01:00
return -6;
}
if(flock(fileno(fp), LOCK_EX)) {
http_error(HTTP500, "Lock File Error.");
return -7;
2022-11-23 07:39:37 +01:00
}
add_user(name, 0, fp);
2023-05-30 15:27:51 +02:00
flease(fp);
2022-11-23 07:39:37 +01:00
char* msg = "<P>Success.\r\n";
2023-03-08 09:38:48 +01:00
if(headers(strlen(msg), "text/html")) {
2023-03-07 14:29:29 +01:00
write(1, "\0\0\0\0", 4);
return 8;
}
2022-11-23 07:39:37 +01:00
return write(1, msg, strlen(msg)) <= 0;
2021-06-07 15:18:19 +02:00
}
2023-03-04 10:55:25 +01:00
static void __attribute__((destructor)) defer_close_fp() {
2023-05-30 15:27:51 +02:00
if(fp) flease(fp);
2023-03-04 10:55:25 +01:00
}