From 5d071bcbfc40d45504dffd7f1840032b7984139d Mon Sep 17 00:00:00 2001 From: SyntaxError Date: Sun, 28 Dec 2025 03:24:48 -0300 Subject: [PATCH] auto commit 2 --- Makefile | 5 ++- neocities | Bin 16856 -> 16888 bytes src/info.c | 105 +++++++++++++++++++++++++++++++++++++++++---------- src/info.h | 8 +++- src/login.sh | 31 ++++++++++----- src/main.c | 60 +++++++++++++++++++++++------ src/main.h | 23 +++++++++-- 7 files changed, 184 insertions(+), 48 deletions(-) mode change 100644 => 100755 src/login.sh diff --git a/Makefile b/Makefile index 4bced34..758b6ee 100755 --- a/Makefile +++ b/Makefile @@ -12,7 +12,10 @@ CFLAGS ?= -Wall -O2 -Iinclude LIBS ?= -lcurl -ljansson # Source and target -SRC = src/main.c +SRC = \ + src/main.c \ + src/info.c + BIN = neocities # Detect Windows (MSYS2 / MinGW) diff --git a/neocities b/neocities index 2a1b3887c3de5a5facda74de09e3ac1bb2990df0..a252b481c3e8856a712a7b5c0429d9416042b805 100755 GIT binary patch delta 1464 zcmY*ZZERCj7(VB&+xoeFZnq7~XuG-sTkGzmL$K@CIpRf#xF3Fu1ZC2(EU;FV0ip?r zWtavR2d`xD7YsEag0iK?7$w-S;J_aSjR}hzOrnVwA#+m`bVIN2Ikz40Cg*wY`#jG% z@A`-R!DND? z<#O~{BO#kIzbNgCtU%=P2Lm-TCNrVz<4RKlSH6;RO3ebd)|F*Ad+ z{}oATO4+MfZo$Qh+S;fAx9?-LY|7k|(+ZW>;(iymAS+v26*)alm2H~;IJiVFjX^{V z3RMPpLG*@r$ZD-@7Z--QAV&8MBSvM=4zQt$nC%R#g*ty5Ik%suwT@=5V+H(ob5^Itx53^ZdOpO2siSs{<;%m@^AJasZJk3XBXw>~E#M_q9lRxOx(Y@b zL~s|osTsb-9uEAb?1GzIYbkiOSOs>RZ;az+jxTY1gX4P~zvOs>tbPJ;b5nI z&=+fT*!)Q Cy2>a3 delta 1519 zcmZ9Me@q)?7{}lDT4q~lp`~zbU~-f>rliOXJ0|k0>&Om=bBMz^#IZ<`Mnh$kZHd2P z>d?!qnLIJs5)&bqh|4m&R1G?_bT$gk#AvcOq7F1_Jf>mr$AS*@eD1x{sh8aMdEe*x zJkRs~==F~%or%)po9N!NxAWB8Z6NIFh8DVPZz|Jg84GRPeuvScdv99!gqwBF{TBIU z_Ua=~o;&s7Q-3dyKlFXsRA1sf!>V=X9!b95F0V+j`gkrOQuKF|BCDzzU7^o8rDM;U zq?m641Ih+;9!*9Z2)?P!dvLx_Om=pq9`5X#AEt!#CRXed)Os)nqd%{zDw0DG&-c;} zn9Z-G(_nQb=|}LTv#|J7Hnx(dBsry6kvy8reerb;T`}Km_DDgMtqwPF9!sL9es2ym z6zt?KTHsiLRHtRO%D*aYD_R2|ce7BV=8>nA!z@z2WYJoDCMK1QHyC=&0=b0+&tE}5 zbE|(c_hrV-DT^9~>6`TQFEZ(ub?#!Cn@)2?=aL!jU7fp-=0?-p4C`KhHq8|!m6tS7 zp2O9@gHG`~<&chy!ui6Ainr0HoI#{jUY4Q?mF`YSv8;SE?k0DeB1KbF>DKu+aPk6O z4?ez}yJCVz`BLwK2@58bVN9R@;4f7@j!h`0YA5y@YdfWUuGyIHx(QD6uA-kXLtBje zsp7=|-mqVi7x36IKF8P5lZj&2jawiflqQY{HMGyND;Rz(6bS_fg@6!fZ6RK7sJ}N% zEdAj~U#S0aArcmP!j*V+9S07EQe%gLp+R9+^ZkLA2V0uk_wQ+Men1Eh{mZl4-`+0t zr^YcY*c<8(^&A*1#Up?-rM0&eFQ{q{mO6b+RgL&_SVh~4^VLOFeFg0^ORD-YSUqKQ z0z?l_V*jxcy zp5JEjXZvj~jNve$dWI~CxOa=eShZEGh9&M+*uBmOIihpKV1zo+34&)zzZTz1JHICPitY!$h*5RmPcIVtELRZ1|{&L$h)<@+X;Scf*v*M zh75vzGoSS`&OErRd~qB{4q_#7yAH4&;&1|AJLe+PO}c+g--m(CJUyqafX=XWl;PK> zRX}0S#x#1BMYHhi9onasw^l*7*+8p#%7Y#2)G(Epb~1gM=^IQZnSR4`nW+Vqs(JT% z?5piR+4SGacR(qg(Vgt1wlVEsdPGzA36|w1Km0H2EykpnUSc}WG#l(bo|eD>>OI=n z-GP6lY`^(>-^1zlLB>Rwz6xW$lEjp6(U_R59W`(U4)!%vTGlSx=z)=jEsm`oJ$22R qD16&cY0msBC+v+oIBPt8b;Ss;gP^~{JnGZ)#^9vChWg=afB8RBEY~*x diff --git a/src/info.c b/src/info.c index cd3efde..f850ea0 100644 --- a/src/info.c +++ b/src/info.c @@ -1,39 +1,63 @@ -#include "main.h" -#include -#include -#include -#include +#include "main.h" // Header local do projeto (declarações próprias: struct response, write_callback, etc.) +#include // printf, fprintf +#include // getenv, malloc, free +#include // libcurl: HTTP/HTTPS client +#include // Jansson: parsing e manipulação de JSON +#include +// Função responsável por buscar informações do site do usuário no Neocities int fetch_neocities_info() { + + // Lê variáveis de ambiente com credenciais + // NEOCITIES_USER e NEOCITIES_PASS são usadas para autenticação HTTP Basic const char *user = getenv("NEOCITIES_USER"); const char *pass = getenv("NEOCITIES_PASS"); - const char *enc = getenv("NEOCITIES_PASS_ENC"); + // const char *enc = getenv("NEOCITIES_PASS_ENC"); // Não usado aqui (possível uso futuro) + + // Verificação básica: se usuário ou senha não existirem, aborta if (!user || !pass) { fprintf(stderr, "You're not logged!\n"); return 1; } + // Buffer para "user:password", formato exigido por CURLOPT_USERPWD char auth[256]; snprintf(auth, sizeof(auth), "%s:%s", user, pass); + // Inicializa um handle do libcurl CURL *curl = curl_easy_init(); if (!curl) { fprintf(stderr, "Erro ao inicializar cURL\n"); return 1; } + // Monta a URL da API do Neocities para obter informações do site char infourl[256]; - snprintf(infourl, sizeof(infourl), "https://neocities.org/api/info?sitename=%s", user); + snprintf( + infourl, + sizeof(infourl), + "https://neocities.org/api/info?sitename=%s", + user + ); + // Define a URL da requisição curl_easy_setopt(curl, CURLOPT_URL, infourl); + + // Define autenticação HTTP Basic (user:pass) curl_easy_setopt(curl, CURLOPT_USERPWD, auth); + // Estrutura usada para armazenar a resposta HTTP em memória + // resp.data será expandido pelo write_callback struct response resp = { .data = malloc(1), .len = 0 }; - resp.data[0] = '\0'; + resp.data[0] = '\0'; // Garante string vazia inicial + // Função chamada pelo libcurl sempre que dados são recebidos curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + + // Ponteiro passado para o write_callback (estado da resposta) curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resp); + // Executa a requisição HTTP de forma síncrona CURLcode res = curl_easy_perform(curl); if (res != CURLE_OK) { fprintf(stderr, "Erro na requisição: %s\n", curl_easy_strerror(res)); @@ -41,51 +65,92 @@ int fetch_neocities_info() { free(resp.data); return 1; } + + // Libera o handle do curl (a resposta já está em resp.data) curl_easy_cleanup(curl); + // Estrutura para capturar erros de parsing JSON json_error_t error; - json_t *obj = json_loads(resp.data, 0, &error); - free(resp.data); + // Converte a string JSON recebida em um objeto JSON manipulável + json_t *obj = json_loads(resp.data, 0, &error); + free(resp.data); // Não é mais necessária após o parsing + + // Caso o JSON seja inválido if (!obj) { fprintf(stderr, "Erro ao parsear JSON: %s\n", error.text); return 1; } + // Obtém o campo "result" do JSON raiz json_t *result_obj = json_object_get(obj, "result"); const char *result_str = json_string_value(result_obj); + // Caso a API tenha retornado erro if (strcmp(result_str, "error") == 0) { - const char *err_type = json_string_value(json_object_get(obj, "error_type")); - const char *err_msg = json_string_value(json_object_get(obj, "message")); + // Tipo de erro retornado pela API + const char *err_type = + json_string_value(json_object_get(obj, "error_type")); + + // Mensagem de erro legível + const char *err_msg = + json_string_value(json_object_get(obj, "message")); + + // Tratamento específico para erro de autenticação if (strcmp(err_type, "invalid_auth") == 0) { printf("Usuário ou senha incorretos!\n"); } else { printf("Erro! %s\n", err_msg); } + + // Diminui o contador de referência do objeto JSON json_decref(obj); return 1; } + // Caso a requisição tenha sido bem-sucedida if (strcmp(result_str, "success") == 0) { - json_t *info_obj = json_object_get(obj, "info"); - printf("\nSitename: %s\n", json_string_value(json_object_get(info_obj, "sitename"))); - printf("Hits: %d\n", (int)json_integer_value(json_object_get(info_obj, "hits"))); - printf("Created at: %s\n", json_string_value(json_object_get(info_obj, "created_at"))); - printf("Last updated: %s\n", json_string_value(json_object_get(info_obj, "last_updated"))); - printf("Domain: %s\n", json_string_value(json_object_get(info_obj, "domain"))); + // Objeto "info" contém os dados do site + json_t *info_obj = json_object_get(obj, "info"); + + // Impressão direta dos campos retornados + printf("\nSitename: %s\n", + json_string_value(json_object_get(info_obj, "sitename"))); + + printf("Hits: %d\n", + (int)json_integer_value(json_object_get(info_obj, "hits"))); + + printf("Created at: %s\n", + json_string_value(json_object_get(info_obj, "created_at"))); + + printf("Last updated: %s\n", + json_string_value(json_object_get(info_obj, "last_updated"))); + + printf("Domain: %s\n", + json_string_value(json_object_get(info_obj, "domain"))); + + // Array de tags associadas ao site json_t *tags = json_object_get(info_obj, "tags"); + printf("Tags: "); size_t index; json_t *tag; + + // Itera sobre o array JSON "tags" json_array_foreach(tags, index, tag) { - printf("#%s%s", json_string_value(tag), (index < json_array_size(tags) - 1) ? ", " : "."); + printf( + "#%s%s", + json_string_value(tag), + (index < json_array_size(tags) - 1) ? ", " : "." + ); } printf("\n\n"); } + // Libera o objeto JSON principal json_decref(obj); + return 0; -} \ No newline at end of file +} diff --git a/src/info.h b/src/info.h index 4096c3f..7cd9304 100644 --- a/src/info.h +++ b/src/info.h @@ -1,6 +1,12 @@ #ifndef INFO #define INFO +// ^ Guardas de inclusão (include guards) +// Evitam que este header seja processado mais de uma vez +// durante a compilação, o que causaria redefinições. +// Declaração da função que busca informações do Neocities. +// O `void` indica explicitamente que a função não recebe parâmetros. int fetch_neocities_info(void); -#endif \ No newline at end of file +#endif +// ^ Fim do include guard diff --git a/src/login.sh b/src/login.sh old mode 100644 new mode 100755 index dfba924..7c2da36 --- a/src/login.sh +++ b/src/login.sh @@ -1,16 +1,27 @@ #!/bin/bash +set -e -BASHRC="$HOME/.bashrc" +CONFIG_DIR="$HOME/.config/neocities" +CONFIG_FILE="$CONFIG_DIR/credentials" -read -p "Username: " NEOCITIES_USER -read -p "Password: " NEOCITIES_PASS +mkdir -p "$CONFIG_DIR" +chmod 700 "$CONFIG_DIR" -# Remove linhas existentes se houver -sed -i '/^NEOCITIES_USER=/d' "$BASHRC" -sed -i '/^NEOCITIES_PASS=/d' "$BASHRC" +read -p "Username: " USER +read -s -p "Password: " PASS +echo -# Adiciona no final -echo "NEOCITIES_USER=\"$NEOCITIES_USER\"" >> "$BASHRC" -echo "NEOCITIES_PASS=\"$NEOCITIES_PASS\"" >> "$BASHRC" +read -p "Would you like to see the credentials on your screen to confirm? [Y/n]: " CHOICE +case $CHOICE in + y|Y) echo -e "Username: $USER\nPassword: $PASS" ;; + *) echo "" ;; +esac -echo "Successfully logged in. Saved on $HOME/.bashrc" +cat > "$CONFIG_FILE" < -#include -#include -#include +#include // printf, fprintf +#include // malloc, realloc, free +#include // strcmp, memcpy +#include // libcurl (necessário para callbacks e tipos) -#include "main.h" -#include "info.h" +#include "main.h" // Declarações globais do projeto (upload_func, etc.) +#include "info.h" // Declaração de fetch_neocities_info() +// Estrutura usada para acumular a resposta HTTP em memória. +// É preenchida incrementalmente pelo write_callback. struct response { - char *data; - size_t len; + char *data; // Buffer dinâmico com os dados recebidos + size_t len; // Quantidade atual de bytes válidos em data }; +// Callback chamado pelo libcurl sempre que um novo bloco de dados chega. +// Não garante tamanho fixo nem chamada única. size_t write_callback(void *data, size_t size, size_t nmemb, void *userdata) { + + // userdata aponta para a struct response passada via CURLOPT_WRITEDATA struct response *resp = (struct response *)userdata; + + // Tamanho real do bloco recebido size_t chunk_size = size * nmemb; + // Realoca o buffer para caber os novos dados + '\0' char *tmp = realloc(resp->data, resp->len + chunk_size + 1); if (!tmp) { + // Se realloc falhar, aborta a escrita + // Retornar 0 sinaliza erro ao libcurl fprintf(stderr, "Erro de memória\n"); return 0; } + + // Atualiza o ponteiro com o novo buffer resp->data = tmp; + + // Copia o bloco recebido para o final do buffer atual memcpy(resp->data + resp->len, data, chunk_size); + + // Atualiza o tamanho total acumulado resp->len += chunk_size; + + // Garante que o buffer seja uma string C válida resp->data[resp->len] = '\0'; + + // Retornar o número de bytes processados indica sucesso return chunk_size; } +// Tipo de ponteiro para função que representa um comando CLI. +// Todas as funções de comando retornam int e não recebem argumentos. typedef int (*cmd_func_t)(void); +// Estrutura que associa: +// - nome do comando (string digitada no terminal) +// - função que implementa esse comando typedef struct { const char *name; cmd_func_t func; } command_entry; int main(int argc, char *argv[]) { + + // Tabela de comandos suportados pelo programa. + // Facilita adicionar novos comandos sem alterar a lógica principal. command_entry commands[] = { - {"--info", fetch_neocities_info}, - {"--upload", upload_func} + {"--info", fetch_neocities_info}, + // {"--upload", upload_func} }; + // Verifica se ao menos um argumento foi passado if (argc < 2) { printf("No command provided.\n"); return 0; } - for (size_t i = 0; i < sizeof(commands)/sizeof(commands[0]); i++) { + // Percorre a tabela de comandos procurando correspondência + for (size_t i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) { + + // Compara o argumento passado com o nome do comando if (strcmp(argv[1], commands[i].name) == 0) { + + // Executa a função associada ao comando + // e retorna imediatamente o código dela return commands[i].func(); } } + // Se nenhum comando conhecido foi encontrado printf("Unknown command.\n"); return 0; } - diff --git a/src/main.h b/src/main.h index f8ad691..053d496 100644 --- a/src/main.h +++ b/src/main.h @@ -1,16 +1,31 @@ #ifndef MAIN_H #define MAIN_H +// Include guard: +// Impede múltiplas inclusões deste header no mesmo processo de compilação. -#include // para size_t +#include // size_t +// Necessário para o tipo size_t, usado em tamanhos e contadores de memória. +// Declarações externas de variáveis globais. +// O `extern` indica que a definição real existe em outro arquivo .c. extern const char *user; extern const char *pass; +// Estrutura usada para armazenar dados recebidos dinamicamente, +// geralmente como resposta de uma requisição HTTP. struct response { - char *data; - size_t len; + char *data; // Buffer dinâmico contendo os dados acumulados + size_t len; // Quantidade de bytes válidos em data }; -size_t write_callback(void *ptr, size_t size, size_t nmemb, void *userdata); +// Protótipo da função de callback usada pelo libcurl. +// Essa função será chamada repetidamente conforme dados chegam. +size_t write_callback( + void *ptr, // Ponteiro para os dados recebidos + size_t size, // Tamanho de cada elemento + size_t nmemb, // Número de elementos + void *userdata // Ponteiro de contexto definido pelo usuário +); #endif +// Fim do include guard