/* arfnet2-search: Fast file indexer and search Copyright (C) 2023 arf20 (Ángel Ruiz Fernandez) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . main.c: Program entry point */ #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "index.h" static char *index_format_template = NULL; static index_t g_index = NULL; static const char *result_html_template = "
\n" "%s""%s
\n" "%s
%s%s

\n" "
\n"; static const char * sizestr(size_t size) { static char buf[32]; if (size < 1024) snprintf(buf, 32, "%ld B", size); else if (size < 1024LL * 1024LL) snprintf(buf, 32, "%.2f KiB", (float)size/1024.f); else if (size < 1024LL * 1024LL * 1024LL) snprintf(buf, 32, "%.2f MiB", (float)size/(1024.f*1024.f)); else if (size < 1024LL * 1024LL * 1024LL * 1024LL) snprintf(buf, 32, "%.2f GiB", (float)size/(1024.f*1024.f*1024.f)); else if (size < 1024LL * 1024LL * 1024LL * 1024LL * 1024LL) snprintf(buf, 32, "%.2f TiB", (float)size/(1024.f*1024.f*1024.f*1024.f)); return buf; } static const char * generate_results_html(results_t *results) { static char buff[65535], timebuf[256], urlbuf[4096]; char *pos = buff; for (int i = 0; i < results->size; i++) { const node_data_t *data = results->results[i]; struct tm *tm_mtim = gmtime(&data->stat.st_mtim.tv_sec); strftime(timebuf, 256, "%Y-%m-%d %H:%M:%S", tm_mtim); snprintf(urlbuf, 4096, "%s%s", subdir, data->path); pos += snprintf(pos, 65535 - (pos - buff), result_html_template, data->name, data->mime ? data->mime : "", urlbuf, data->path, sizestr(data->stat.st_size), timebuf ); } return buff; } enum MHD_Result answer_to_connection( void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **ptr ) { char buff[BUFF_SIZE]; const struct sockaddr_in **coninfo = (const struct sockaddr_in**)MHD_get_connection_info( connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS); time_t time_now = time(NULL); struct tm *tm_now = gmtime(&time_now); static char timestr[256]; strftime(timestr, 256, "%Y-%m-%d %H:%M:%S", tm_now); printf("[%s] [webserver] %s %s %s: ", timestr, inet_ntoa((*coninfo)->sin_addr), method, url); struct MHD_Response *response; int ret; if (strcmp(method, "GET") == 0 && strcmp(url, "/") == 0) { snprintf(buff, BUFF_SIZE, index_format_template, "", ""); response = MHD_create_response_from_buffer(strlen(buff), (void*)buff, MHD_RESPMEM_PERSISTENT); printf("%d\n", 200); ret = MHD_queue_response(connection, MHD_HTTP_OK, response); MHD_destroy_response(response); } else if (strcmp(method, "GET") == 0 && strcmp(url, "/query") == 0) { const char *query = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "query"); results_t *results = NULL; if (g_index) results = index_lookup(g_index, LOOKUP_SUBSTR, query); if (results) snprintf(buff, BUFF_SIZE, index_format_template, query, generate_results_html(results)); else snprintf(buff, BUFF_SIZE, index_format_template, query, "indexing in progress... try again later"); response = MHD_create_response_from_buffer(strlen(buff), (void*)buff, MHD_RESPMEM_PERSISTENT); if (results) results_destroy(results); printf("%d\n", 200); ret = MHD_queue_response(connection, MHD_HTTP_OK, response); MHD_destroy_response(response); } else { response = MHD_create_response_from_buffer(0, (void*)NULL, 0); printf("%d\n", 418); ret = MHD_queue_response(connection, 418, response); MHD_destroy_response(response); } return ret; } int main() { printf("ARFNET search (C) 2025 licence GPLv3\n"); if (config_load(CONFIG_PATH) < 0) return 1; /* read index template file */ FILE *tf = fopen(tmpl_path, "r"); if (!tf) { fprintf(stderr, "error opening index template file: %s\n", strerror(errno)); return 1; } fseek(tf, 0, SEEK_END); size_t tfs = ftell(tf); rewind(tf); index_format_template = malloc(tfs + 1); fread(index_format_template, 1, tfs, tf); fclose(tf); index_format_template[tfs] = '\0'; /* start server */ struct MHD_Daemon *daemon; daemon = MHD_start_daemon( MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_EPOLL, port, NULL, NULL, &answer_to_connection, NULL, MHD_OPTION_END); if (!daemon) { fprintf(stderr, "error starting libmicrohttpd daemon\n"); return 1; } /* begin indexing */ if (index_init() < 0) return 1; time_t time_now = time(NULL); struct tm *tm_now = gmtime(&time_now); static char timestr[256]; strftime(timestr, 256, "%Y-%m-%d %H:%M:%S", tm_now); printf("[%s] [index] indexeding started...\n", timestr); g_index = index_new(INIT_MAP_CAPACITY, root, 1); time_now = time(NULL); tm_now = gmtime(&time_now); strftime(timestr, 256, "%Y-%m-%d %H:%M:%S", tm_now); printf("[%s] [index] indexed finished\n", timestr); while (1) { sleep(1000); } }