auto commit 2
This commit is contained in:
5
Makefile
5
Makefile
@@ -12,7 +12,10 @@ CFLAGS ?= -Wall -O2 -Iinclude
|
|||||||
LIBS ?= -lcurl -ljansson
|
LIBS ?= -lcurl -ljansson
|
||||||
|
|
||||||
# Source and target
|
# Source and target
|
||||||
SRC = src/main.c
|
SRC = \
|
||||||
|
src/main.c \
|
||||||
|
src/info.c
|
||||||
|
|
||||||
BIN = neocities
|
BIN = neocities
|
||||||
|
|
||||||
# Detect Windows (MSYS2 / MinGW)
|
# Detect Windows (MSYS2 / MinGW)
|
||||||
|
|||||||
105
src/info.c
105
src/info.c
@@ -1,39 +1,63 @@
|
|||||||
#include "main.h"
|
#include "main.h" // Header local do projeto (declarações próprias: struct response, write_callback, etc.)
|
||||||
#include <stdio.h>
|
#include <stdio.h> // printf, fprintf
|
||||||
#include <stdlib.h>
|
#include <stdlib.h> // getenv, malloc, free
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h> // libcurl: HTTP/HTTPS client
|
||||||
#include <jansson.h>
|
#include <jansson.h> // Jansson: parsing e manipulação de JSON
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// Função responsável por buscar informações do site do usuário no Neocities
|
||||||
int fetch_neocities_info() {
|
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 *user = getenv("NEOCITIES_USER");
|
||||||
const char *pass = getenv("NEOCITIES_PASS");
|
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) {
|
if (!user || !pass) {
|
||||||
fprintf(stderr, "You're not logged!\n");
|
fprintf(stderr, "You're not logged!\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Buffer para "user:password", formato exigido por CURLOPT_USERPWD
|
||||||
char auth[256];
|
char auth[256];
|
||||||
snprintf(auth, sizeof(auth), "%s:%s", user, pass);
|
snprintf(auth, sizeof(auth), "%s:%s", user, pass);
|
||||||
|
|
||||||
|
// Inicializa um handle do libcurl
|
||||||
CURL *curl = curl_easy_init();
|
CURL *curl = curl_easy_init();
|
||||||
if (!curl) {
|
if (!curl) {
|
||||||
fprintf(stderr, "Erro ao inicializar cURL\n");
|
fprintf(stderr, "Erro ao inicializar cURL\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Monta a URL da API do Neocities para obter informações do site
|
||||||
char infourl[256];
|
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);
|
curl_easy_setopt(curl, CURLOPT_URL, infourl);
|
||||||
|
|
||||||
|
// Define autenticação HTTP Basic (user:pass)
|
||||||
curl_easy_setopt(curl, CURLOPT_USERPWD, auth);
|
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 };
|
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);
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
|
||||||
|
|
||||||
|
// Ponteiro passado para o write_callback (estado da resposta)
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resp);
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &resp);
|
||||||
|
|
||||||
|
// Executa a requisição HTTP de forma síncrona
|
||||||
CURLcode res = curl_easy_perform(curl);
|
CURLcode res = curl_easy_perform(curl);
|
||||||
if (res != CURLE_OK) {
|
if (res != CURLE_OK) {
|
||||||
fprintf(stderr, "Erro na requisição: %s\n", curl_easy_strerror(res));
|
fprintf(stderr, "Erro na requisição: %s\n", curl_easy_strerror(res));
|
||||||
@@ -41,51 +65,92 @@ int fetch_neocities_info() {
|
|||||||
free(resp.data);
|
free(resp.data);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Libera o handle do curl (a resposta já está em resp.data)
|
||||||
curl_easy_cleanup(curl);
|
curl_easy_cleanup(curl);
|
||||||
|
|
||||||
|
// Estrutura para capturar erros de parsing JSON
|
||||||
json_error_t error;
|
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) {
|
if (!obj) {
|
||||||
fprintf(stderr, "Erro ao parsear JSON: %s\n", error.text);
|
fprintf(stderr, "Erro ao parsear JSON: %s\n", error.text);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Obtém o campo "result" do JSON raiz
|
||||||
json_t *result_obj = json_object_get(obj, "result");
|
json_t *result_obj = json_object_get(obj, "result");
|
||||||
const char *result_str = json_string_value(result_obj);
|
const char *result_str = json_string_value(result_obj);
|
||||||
|
|
||||||
|
// Caso a API tenha retornado erro
|
||||||
if (strcmp(result_str, "error") == 0) {
|
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) {
|
if (strcmp(err_type, "invalid_auth") == 0) {
|
||||||
printf("Usuário ou senha incorretos!\n");
|
printf("Usuário ou senha incorretos!\n");
|
||||||
} else {
|
} else {
|
||||||
printf("Erro! %s\n", err_msg);
|
printf("Erro! %s\n", err_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Diminui o contador de referência do objeto JSON
|
||||||
json_decref(obj);
|
json_decref(obj);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Caso a requisição tenha sido bem-sucedida
|
||||||
if (strcmp(result_str, "success") == 0) {
|
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");
|
json_t *tags = json_object_get(info_obj, "tags");
|
||||||
|
|
||||||
printf("Tags: ");
|
printf("Tags: ");
|
||||||
size_t index;
|
size_t index;
|
||||||
json_t *tag;
|
json_t *tag;
|
||||||
|
|
||||||
|
// Itera sobre o array JSON "tags"
|
||||||
json_array_foreach(tags, index, tag) {
|
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");
|
printf("\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Libera o objeto JSON principal
|
||||||
json_decref(obj);
|
json_decref(obj);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
#ifndef INFO
|
#ifndef INFO
|
||||||
#define 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);
|
int fetch_neocities_info(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
// ^ Fim do include guard
|
||||||
|
|||||||
31
src/login.sh
Normal file → Executable file
31
src/login.sh
Normal file → Executable file
@@ -1,16 +1,27 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
BASHRC="$HOME/.bashrc"
|
CONFIG_DIR="$HOME/.config/neocities"
|
||||||
|
CONFIG_FILE="$CONFIG_DIR/credentials"
|
||||||
|
|
||||||
read -p "Username: " NEOCITIES_USER
|
mkdir -p "$CONFIG_DIR"
|
||||||
read -p "Password: " NEOCITIES_PASS
|
chmod 700 "$CONFIG_DIR"
|
||||||
|
|
||||||
# Remove linhas existentes se houver
|
read -p "Username: " USER
|
||||||
sed -i '/^NEOCITIES_USER=/d' "$BASHRC"
|
read -s -p "Password: " PASS
|
||||||
sed -i '/^NEOCITIES_PASS=/d' "$BASHRC"
|
echo
|
||||||
|
|
||||||
# Adiciona no final
|
read -p "Would you like to see the credentials on your screen to confirm? [Y/n]: " CHOICE
|
||||||
echo "NEOCITIES_USER=\"$NEOCITIES_USER\"" >> "$BASHRC"
|
case $CHOICE in
|
||||||
echo "NEOCITIES_PASS=\"$NEOCITIES_PASS\"" >> "$BASHRC"
|
y|Y) echo -e "Username: $USER\nPassword: $PASS" ;;
|
||||||
|
*) echo "" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
echo "Successfully logged in. Saved on $HOME/.bashrc"
|
cat > "$CONFIG_FILE" <<EOF
|
||||||
|
user = $USER
|
||||||
|
pass = $PASS
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod 600 "$CONFIG_FILE"
|
||||||
|
|
||||||
|
echo "Credentials saved in $CONFIG_FILE"
|
||||||
|
|||||||
60
src/main.c
60
src/main.c
@@ -1,57 +1,93 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h> // printf, fprintf
|
||||||
#include <stdlib.h>
|
#include <stdlib.h> // malloc, realloc, free
|
||||||
#include <string.h>
|
#include <string.h> // strcmp, memcpy
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h> // libcurl (necessário para callbacks e tipos)
|
||||||
|
|
||||||
#include "main.h"
|
#include "main.h" // Declarações globais do projeto (upload_func, etc.)
|
||||||
#include "info.h"
|
#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 {
|
struct response {
|
||||||
char *data;
|
char *data; // Buffer dinâmico com os dados recebidos
|
||||||
size_t len;
|
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) {
|
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;
|
struct response *resp = (struct response *)userdata;
|
||||||
|
|
||||||
|
// Tamanho real do bloco recebido
|
||||||
size_t chunk_size = size * nmemb;
|
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);
|
char *tmp = realloc(resp->data, resp->len + chunk_size + 1);
|
||||||
if (!tmp) {
|
if (!tmp) {
|
||||||
|
// Se realloc falhar, aborta a escrita
|
||||||
|
// Retornar 0 sinaliza erro ao libcurl
|
||||||
fprintf(stderr, "Erro de memória\n");
|
fprintf(stderr, "Erro de memória\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Atualiza o ponteiro com o novo buffer
|
||||||
resp->data = tmp;
|
resp->data = tmp;
|
||||||
|
|
||||||
|
// Copia o bloco recebido para o final do buffer atual
|
||||||
memcpy(resp->data + resp->len, data, chunk_size);
|
memcpy(resp->data + resp->len, data, chunk_size);
|
||||||
|
|
||||||
|
// Atualiza o tamanho total acumulado
|
||||||
resp->len += chunk_size;
|
resp->len += chunk_size;
|
||||||
|
|
||||||
|
// Garante que o buffer seja uma string C válida
|
||||||
resp->data[resp->len] = '\0';
|
resp->data[resp->len] = '\0';
|
||||||
|
|
||||||
|
// Retornar o número de bytes processados indica sucesso
|
||||||
return chunk_size;
|
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);
|
typedef int (*cmd_func_t)(void);
|
||||||
|
|
||||||
|
// Estrutura que associa:
|
||||||
|
// - nome do comando (string digitada no terminal)
|
||||||
|
// - função que implementa esse comando
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
cmd_func_t func;
|
cmd_func_t func;
|
||||||
} command_entry;
|
} command_entry;
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
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[] = {
|
command_entry commands[] = {
|
||||||
{"--info", fetch_neocities_info},
|
{"--info", fetch_neocities_info},
|
||||||
{"--upload", upload_func}
|
// {"--upload", upload_func}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Verifica se ao menos um argumento foi passado
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
printf("No command provided.\n");
|
printf("No command provided.\n");
|
||||||
return 0;
|
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) {
|
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();
|
return commands[i].func();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Se nenhum comando conhecido foi encontrado
|
||||||
printf("Unknown command.\n");
|
printf("Unknown command.\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
23
src/main.h
23
src/main.h
@@ -1,16 +1,31 @@
|
|||||||
#ifndef MAIN_H
|
#ifndef MAIN_H
|
||||||
#define MAIN_H
|
#define MAIN_H
|
||||||
|
// Include guard:
|
||||||
|
// Impede múltiplas inclusões deste header no mesmo processo de compilação.
|
||||||
|
|
||||||
#include <stddef.h> // para size_t
|
#include <stddef.h> // 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 *user;
|
||||||
extern const char *pass;
|
extern const char *pass;
|
||||||
|
|
||||||
|
// Estrutura usada para armazenar dados recebidos dinamicamente,
|
||||||
|
// geralmente como resposta de uma requisição HTTP.
|
||||||
struct response {
|
struct response {
|
||||||
char *data;
|
char *data; // Buffer dinâmico contendo os dados acumulados
|
||||||
size_t len;
|
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
|
#endif
|
||||||
|
// Fim do include guard
|
||||||
|
|||||||
Reference in New Issue
Block a user