From b50e57cc138fd19ed19da665daba54890995dca3 Mon Sep 17 00:00:00 2001 From: Nakidai Date: Thu, 26 Sep 2024 00:14:12 +0300 Subject: Now it will work --- Makefile | 5 +++ cptc.c | 10 ++++- cptc.h | 3 ++ downloadAvatar.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.c | 4 +- requestHandler.c | 90 ++++++++++++++++++++++++++++++++++++----- 6 files changed, 219 insertions(+), 13 deletions(-) create mode 100644 downloadAvatar.c diff --git a/Makefile b/Makefile index d2ea389..7ca6edb 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,13 @@ OBJS += cptc.o OBJS += main.o OBJS += requestHandler.o +OBJS += downloadAvatar.o +CFLAGS += $(shell curl-config --cflags) CFLAGS += -std=c11 + +LDFLAGS += $(shell curl-config --libs) +LDFLAGS += -lcpetpet RM = rm -f all: cptc diff --git a/cptc.c b/cptc.c index 60c1954..485c39f 100644 --- a/cptc.c +++ b/cptc.c @@ -1,11 +1,15 @@ +#include "cptc.h" + #include #include + #include #include #include #include -#include "cptc.h" +#include +#include #define error(text, status) \ @@ -22,8 +26,12 @@ void CPTC(const char *ip, in_port_t port) socklen_t peer_size; int fd, peerfd; + curl_easy_init(); + if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) error("socket()", 1); + if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int))) < 0) + error("setsockopt()", 1); addr = (struct sockaddr_in) { diff --git a/cptc.h b/cptc.h index aa14648..cfbffec 100644 --- a/cptc.h +++ b/cptc.h @@ -10,7 +10,10 @@ enum CPTC_Method CPTC_HEAD = 'H', }; +extern const char *CPTC_token; + void CPTC(const char *address, in_port_t port); void CPTC_requestHandler(int fd); +char *CPTC_downloadAvatar(long long uid, const char *download_path); #endif /* __CPTC_H__ */ diff --git a/downloadAvatar.c b/downloadAvatar.c new file mode 100644 index 0000000..45a39ac --- /dev/null +++ b/downloadAvatar.c @@ -0,0 +1,120 @@ +#define _POSIX_C_SOURCE 200112L + +#include "cptc.h" + +#include +#include +#include +#include + +#include +#include + + +static size_t write_function(void *contents, size_t size, size_t nmemb, void *userp) +{ + size_t realsize = size * nmemb; + struct {char *buf; size_t size;} *mem = userp; + + mem->buf = realloc(mem->buf, mem->size + realsize + 1); + if (!mem->buf) + { + perror("realloc()"); + return 0; + } + + memcpy(&(mem->buf[mem->size]), contents, realsize); + mem->size += realsize; + mem->buf[mem->size] = 0; + + return realsize; +} + +char *CPTC_downloadAvatar(long long uid, const char *filenamebuf) +{ + char *avatar, link[256], auth[128], *ret; + CURL *curl; + CURLcode res; + FILE *fp; + struct {char *buf; size_t size;} buffer; + buffer.buf = malloc(1); + buffer.size = 0; + + curl = curl_easy_init(); + if (curl) + { + snprintf(link, sizeof(link), "https://discord.com/api/v9/users/%lld", uid); + snprintf(auth, sizeof(auth), "Authorization: %s", CPTC_token); + + curl_easy_setopt(curl, CURLOPT_URL, link); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_function); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curl_slist_append(NULL, auth)); + + res = curl_easy_perform(curl); + if (res != CURLE_OK) + { + fprintf(stderr, "curl_easy_perform(): %s\n", curl_easy_strerror(res)); + curl_easy_cleanup(curl); + free(buffer.buf); + return NULL; + } + + curl_easy_cleanup(curl); + } else + { + free(buffer.buf); + return NULL; + } + avatar = strstr(buffer.buf, "avatar\":\"") + 9; + if (!(avatar - 9)) + { + fprintf(stderr, "User %lld has no avatar\n", uid); + free(buffer.buf); + return NULL; + } + *strchr(avatar, '"') = '\0'; + + fp = fopen(filenamebuf, "w"); + if (!fp) + { + perror("fopen()"); + free(buffer.buf); + return NULL; + } + + curl = curl_easy_init(); + if (curl) + { + snprintf(link, sizeof(link), "https://cdn.discordapp.com/avatars/%lld/%s.png", uid, avatar); + + curl_easy_setopt(curl, CURLOPT_URL, link); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curl_slist_append(NULL, auth)); + + res = curl_easy_perform(curl); + if (res != CURLE_OK) + { + fprintf(stderr, "curl_easy_perform(): %s\n", curl_easy_strerror(res)); + curl_easy_cleanup(curl); + fclose(fp); + free(buffer.buf); + return NULL; + } + + curl_easy_cleanup(curl); + } else + { + fclose(fp); + free(buffer.buf); + return NULL; + } + + fclose(fp); + ret = malloc(strlen(filenamebuf) + 1); + memcpy(ret, filenamebuf, strlen(filenamebuf) + 1); + free(buffer.buf); + return ret; +} diff --git a/main.c b/main.c index 7a63ebe..8099de2 100644 --- a/main.c +++ b/main.c @@ -1,8 +1,8 @@ +#include "cptc.h" + #include #include -#include "cptc.h" - int main(void) { diff --git a/requestHandler.c b/requestHandler.c index 5781218..94e0aec 100644 --- a/requestHandler.c +++ b/requestHandler.c @@ -1,19 +1,29 @@ +#define _POSIX_C_SOURCE 200112L + #include "cptc.h" +#include +#include #include #include #include +#include + #include #include +#include static const char *ok = "HTTP/1.0 200 OK\r\n"; static const char *notfound = "HTTP/1.0 404 Not found\r\n"; +static const char *forbidden = "HTTP/1.0 403 Forbidden\r\n"; +static const char *intserverror = "HTTP/1.0 500 Internal server error\r\n"; static const char *not_implemented = "HTTP/1.0 501 Not implemented\r\n"; static const char *content_length = "Content-Length: %d\r\n"; static const char *text_plain = "Content-Type: text/plain\r\n"; +static const char *image_gif = "Content-Type: image/gif\r\n"; static const char *end = "\r\n"; @@ -27,44 +37,104 @@ Paths:\n\ / Show this text\n\ /.* Return a gif that pets given UID\n"; +static bool isnumber(const char *s) +{ + for (const char *cp = s; *cp != '\0' && *cp != '.'; ++cp) + if (!isdigit(*cp)) + return false; + return true; +} + +static char *generate_filename(char *buf, size_t size, const char *ext) +{ + struct timespec tp; + clock_gettime(CLOCK_REALTIME, &tp); + snprintf(buf, size, "/tmp/%lld.%s", tp.tv_sec * 1000000000LL + tp.tv_nsec, ext); + return buf; +} + void CPTC_requestHandler(int fd) { enum CPTC_Method method; - char *path; - char *buffer = (char *)malloc(sizeof(*buffer) * 512); - ssize_t received = recv(fd, buffer, sizeof(*buffer) * 512, 0); + int ch; + char *path, chbuf; + char buffer[512], filenamebuf[64]; + ssize_t received = recv(fd, buffer, sizeof(buffer), 0); + FILE *fp; if (received == -1) { perror("recv()"); - goto end; + return; } method = buffer[0]; if (method != CPTC_GET && method != CPTC_HEAD) { send(fd, not_implemented, strlen(not_implemented), 0); - goto end; + return; } path = strchr(buffer, ' ') + 1; *strchr(path, ' ') = '\0'; puts(path); + if (strlen(path) == 1) { - send(fd, ok, strlen(ok), 0); char *length = malloc(sizeof(*length) * 32); snprintf(length, 32, content_length, strlen(root)); + send(fd, ok, strlen(ok), 0); send(fd, text_plain, strlen(text_plain), 0); send(fd, length, strlen(length), 0); send(fd, end, strlen(end), 0); send(fd, root, strlen(root), 0); free(length); - goto end; + return; } - send(fd, notfound, strlen(notfound), 0); + if (strchr(path, '.') && isnumber(path + 1)) + { + char *length = malloc(sizeof(*length) * 32); + + *strchr(path, '.') = '\0'; + generate_filename(filenamebuf, sizeof(filenamebuf), "png"); + char *in = CPTC_downloadAvatar(atoll(path + 1), filenamebuf); + if (!in) + { + send(fd, forbidden, strlen(forbidden), 0); + return; + } + generate_filename(filenamebuf, sizeof(filenamebuf), "gif"); + CPetPet(in, filenamebuf, 2); + printf("From %s to %s\n", in, filenamebuf); + + fp = fopen(filenamebuf, "rb"); + if (!fp) + { + perror("fopen()"); + send(fd, intserverror, strlen(intserverror), 0); + free(in); + free(length); + return; + } + fseek(fp, 0, SEEK_END); + snprintf(length, 32, content_length, ftell(fp)); + fseek(fp, 0, SEEK_SET); + + send(fd, ok, strlen(ok), 0); + send(fd, image_gif, strlen(image_gif), 0); + send(fd, length, strlen(length), 0); + send(fd, end, strlen(end), 0); + while ((ch = getc(fp)) >= 0) + { + chbuf = ch; + send(fd, &chbuf, 1, 0); + } + + fclose(fp); + free(in); + free(length); + } -end: - free(buffer); + send(fd, notfound, strlen(notfound), 0); } -- cgit 1.4.1