about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNakidai <nakidai@disroot.org>2024-09-26 00:14:12 +0300
committerNakidai <nakidai@disroot.org>2024-09-26 00:14:59 +0300
commitb50e57cc138fd19ed19da665daba54890995dca3 (patch)
tree2c9d65b823fd1133aef19879eba7dcfce8b75e31
parent0caf047c3c1ecf34a47061951e838d05574dbd6c (diff)
downloadcptc-b50e57cc138fd19ed19da665daba54890995dca3.tar.gz
cptc-b50e57cc138fd19ed19da665daba54890995dca3.zip
Now it will work
-rw-r--r--Makefile5
-rw-r--r--cptc.c10
-rw-r--r--cptc.h3
-rw-r--r--downloadAvatar.c120
-rw-r--r--main.c4
-rw-r--r--requestHandler.c90
6 files changed, 219 insertions, 13 deletions
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 <stdio.h>
 #include <stdlib.h>
+
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <unistd.h>
 
-#include "cptc.h"
+#include <curl/curl.h>
+#include <curl/easy.h>
 
 
 #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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <curl/curl.h>
+#include <curl/easy.h>
+
+
+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 <fcntl.h>
 #include <unistd.h>
 
-#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 <ctype.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <time.h>
+
 #include <sys/socket.h>
 #include <sys/types.h>
 
+#include <cpetpet.h>
 
 
 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\
 /<UID>.*    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);
 }