feat: configure search engines in user settings

This commit is contained in:
frosty 2026-04-01 22:39:22 +03:00
parent 614bd26cb3
commit 8176078105
5 changed files with 233 additions and 4 deletions

View file

@ -290,6 +290,13 @@ static const SearchEngine *find_enabled_engine(const char *engine_id) {
return NULL; return NULL;
} }
static int engine_allowed_for_user(const SearchEngine *eng, char **user_ids,
int user_count, int has_pref) {
if (!has_pref)
return 1;
return user_engines_contains(eng->id, user_ids, user_count);
}
static char *build_search_href(const char *query, const char *engine_id, static char *build_search_href(const char *query, const char *engine_id,
int page) { int page) {
const char *safe_query = query ? query : ""; const char *safe_query = query ? query : "";
@ -350,6 +357,10 @@ int results_handler(UrlParams *params) {
int page = 1; int page = 1;
int btnI = 0; int btnI = 0;
char **user_engines = NULL;
int user_engine_count = 0;
int has_user_pref = (get_user_engines(&user_engines, &user_engine_count) == 0);
if (params) { if (params) {
for (int i = 0; i < params->count; i++) { for (int i = 0; i < params->count; i++) {
if (strcmp(params->params[i].key, "q") == 0) { if (strcmp(params->params[i].key, "q") == 0) {
@ -396,6 +407,11 @@ int results_handler(UrlParams *params) {
if (!raw_query || strlen(raw_query) == 0) { if (!raw_query || strlen(raw_query) == 0) {
send_redirect("/"); send_redirect("/");
if (has_user_pref) {
for (int i = 0; i < user_engine_count; i++)
free(user_engines[i]);
free(user_engines);
}
free_context(&ctx); free_context(&ctx);
return -1; return -1;
} }
@ -412,7 +428,9 @@ int results_handler(UrlParams *params) {
int enabled_engine_count = 0; int enabled_engine_count = 0;
for (int i = 0; i < ENGINE_COUNT; i++) { for (int i = 0; i < ENGINE_COUNT; i++) {
if (ENGINE_REGISTRY[i].enabled && if (ENGINE_REGISTRY[i].enabled &&
(!selected_engine || &ENGINE_REGISTRY[i] == selected_engine)) { (!selected_engine || &ENGINE_REGISTRY[i] == selected_engine) &&
engine_allowed_for_user(&ENGINE_REGISTRY[i], user_engines,
user_engine_count, has_user_pref)) {
enabled_engine_count++; enabled_engine_count++;
} }
} }
@ -439,7 +457,9 @@ int results_handler(UrlParams *params) {
int engine_idx = 0; int engine_idx = 0;
for (int i = 0; i < ENGINE_COUNT; i++) { for (int i = 0; i < ENGINE_COUNT; i++) {
if (ENGINE_REGISTRY[i].enabled && if (ENGINE_REGISTRY[i].enabled &&
(!selected_engine || &ENGINE_REGISTRY[i] == selected_engine)) { (!selected_engine || &ENGINE_REGISTRY[i] == selected_engine) &&
engine_allowed_for_user(&ENGINE_REGISTRY[i], user_engines,
user_engine_count, has_user_pref)) {
all_results[engine_idx] = NULL; all_results[engine_idx] = NULL;
jobs[engine_idx].engine = &ENGINE_REGISTRY[i]; jobs[engine_idx].engine = &ENGINE_REGISTRY[i];
jobs[engine_idx].query = raw_query; jobs[engine_idx].query = raw_query;
@ -488,6 +508,11 @@ int results_handler(UrlParams *params) {
snprintf(response, sizeof(response), "<h1>%s</h1>", rate_limit_msg); snprintf(response, sizeof(response), "<h1>%s</h1>", rate_limit_msg);
send_response(response); send_response(response);
free(request_cache_key); free(request_cache_key);
if (has_user_pref) {
for (int i = 0; i < user_engine_count; i++)
free(user_engines[i]);
free(user_engines);
}
free_context(&ctx); free_context(&ctx);
return -1; return -1;
} }
@ -499,7 +524,9 @@ int results_handler(UrlParams *params) {
int filter_engine_count = 0; int filter_engine_count = 0;
for (int i = 0; i < ENGINE_COUNT; i++) { for (int i = 0; i < ENGINE_COUNT; i++) {
if (ENGINE_REGISTRY[i].enabled) if (ENGINE_REGISTRY[i].enabled &&
engine_allowed_for_user(&ENGINE_REGISTRY[i], user_engines,
user_engine_count, has_user_pref))
filter_engine_count++; filter_engine_count++;
} }
@ -516,7 +543,9 @@ int results_handler(UrlParams *params) {
free(all_href); free(all_href);
for (int i = 0; i < ENGINE_COUNT; i++) { for (int i = 0; i < ENGINE_COUNT; i++) {
if (!ENGINE_REGISTRY[i].enabled) if (!ENGINE_REGISTRY[i].enabled ||
!engine_allowed_for_user(&ENGINE_REGISTRY[i], user_engines,
user_engine_count, has_user_pref))
continue; continue;
char *filter_href = char *filter_href =
@ -575,6 +604,11 @@ int results_handler(UrlParams *params) {
} }
} }
free(request_cache_key); free(request_cache_key);
if (has_user_pref) {
for (int i = 0; i < user_engine_count; i++)
free(user_engines[i]);
free(user_engines);
}
free_context(&ctx); free_context(&ctx);
if (redirect_url) { if (redirect_url) {
send_redirect(redirect_url); send_redirect(redirect_url);
@ -594,6 +628,11 @@ int results_handler(UrlParams *params) {
} }
} }
free(request_cache_key); free(request_cache_key);
if (has_user_pref) {
for (int i = 0; i < user_engine_count; i++)
free(user_engines[i]);
free(user_engines);
}
free_context(&ctx); free_context(&ctx);
char no_results_html[128]; char no_results_html[128];
snprintf(no_results_html, sizeof(no_results_html), "<h1>%s</h1>", no_results_msg); snprintf(no_results_html, sizeof(no_results_html), "<h1>%s</h1>", no_results_msg);
@ -696,6 +735,11 @@ int results_handler(UrlParams *params) {
} }
} }
free(request_cache_key); free(request_cache_key);
if (has_user_pref) {
for (int i = 0; i < user_engine_count; i++)
free(user_engines[i]);
free(user_engines);
}
free_context(&ctx); free_context(&ctx);
return 0; return 0;
} }
@ -822,6 +866,11 @@ int results_handler(UrlParams *params) {
} }
} }
free(locale); free(locale);
if (has_user_pref) {
for (int i = 0; i < user_engine_count; i++)
free(user_engines[i]);
free(user_engines);
}
free_context(&ctx); free_context(&ctx);
return 0; return 0;

View file

@ -1,4 +1,5 @@
#include "Settings.h" #include "Settings.h"
#include "../Scraping/Scraping.h"
#include "../Utility/Utility.h" #include "../Utility/Utility.h"
#include <beaker.h> #include <beaker.h>
#include <stdlib.h> #include <stdlib.h>
@ -29,6 +30,48 @@ int settings_handler(UrlParams *params) {
inner_counts[i] = 2; inner_counts[i] = 2;
} }
char **user_engines = NULL;
int user_engine_count = 0;
int has_user_pref = (get_user_engines(&user_engines, &user_engine_count) == 0);
int enabled_count = 0;
for (int i = 0; i < ENGINE_COUNT; i++) {
if (ENGINE_REGISTRY[i].enabled)
enabled_count++;
}
char ***engine_data = NULL;
int *engine_inner = NULL;
if (enabled_count > 0) {
engine_data = malloc(sizeof(char **) * enabled_count);
engine_inner = malloc(sizeof(int) * enabled_count);
int idx = 0;
for (int i = 0; i < ENGINE_COUNT; i++) {
if (!ENGINE_REGISTRY[i].enabled)
continue;
int is_selected = !has_user_pref;
if (has_user_pref) {
for (int j = 0; j < user_engine_count; j++) {
if (strcmp(user_engines[j], ENGINE_REGISTRY[i].id) == 0) {
is_selected = 1;
break;
}
}
}
engine_data[idx] = malloc(sizeof(char *) * 3);
engine_data[idx][0] = (char *)ENGINE_REGISTRY[i].id;
engine_data[idx][1] = (char *)ENGINE_REGISTRY[i].name;
engine_data[idx][2] = is_selected ? "checked" : "";
engine_inner[idx] = 3;
idx++;
}
}
TemplateContext ctx = new_context(); TemplateContext ctx = new_context();
beaker_set_locale(&ctx, locale); beaker_set_locale(&ctx, locale);
context_set(&ctx, "query", query); context_set(&ctx, "query", query);
@ -36,9 +79,26 @@ int settings_handler(UrlParams *params) {
context_set(&ctx, "locale", locale); context_set(&ctx, "locale", locale);
context_set_array_of_arrays(&ctx, "locales", locale_data, locale_count, inner_counts); context_set_array_of_arrays(&ctx, "locales", locale_data, locale_count, inner_counts);
if (enabled_count > 0) {
context_set_array_of_arrays(&ctx, "enabled_engines", engine_data,
enabled_count, engine_inner);
context_set(&ctx, "has_enabled_engines", "1");
}
for (int i = 0; i < locale_count; i++) { for (int i = 0; i < locale_count; i++) {
free(locale_data[i]); free(locale_data[i]);
} }
if (engine_data) {
for (int i = 0; i < enabled_count; i++)
free(engine_data[i]);
free(engine_data);
}
free(engine_inner);
if (has_user_pref) {
for (int i = 0; i < user_engine_count; i++)
free(user_engines[i]);
free(user_engines);
}
char *rendered_html = render_template("settings.html", &ctx); char *rendered_html = render_template("settings.html", &ctx);
send_response(rendered_html); send_response(rendered_html);

View file

@ -1,11 +1,18 @@
#include "SettingsSave.h" #include "SettingsSave.h"
#include "../Scraping/Scraping.h"
#include "../Utility/Utility.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#define MAX_ENGINE_IDS ENGINE_COUNT
int settings_save_handler(UrlParams *params) { int settings_save_handler(UrlParams *params) {
const char *theme = ""; const char *theme = "";
const char *locale = ""; const char *locale = "";
const char *query = ""; const char *query = "";
int engines_present = 0;
char selected_ids[ENGINE_COUNT][32];
int selected_count = 0;
if (params) { if (params) {
for (int i = 0; i < params->count; i++) { for (int i = 0; i < params->count; i++) {
@ -15,6 +22,19 @@ int settings_save_handler(UrlParams *params) {
locale = params->params[i].value; locale = params->params[i].value;
} else if (strcmp(params->params[i].key, "q") == 0) { } else if (strcmp(params->params[i].key, "q") == 0) {
query = params->params[i].value; query = params->params[i].value;
} else if (strcmp(params->params[i].key, "engines_present") == 0) {
engines_present = 1;
} else if (strncmp(params->params[i].key, "engine_", 7) == 0 &&
strcmp(params->params[i].value, "1") == 0) {
const char *engine_id = params->params[i].key + 7;
if (engine_id[0] != '\0' && is_engine_id_enabled(engine_id) &&
selected_count < ENGINE_COUNT) {
strncpy(selected_ids[selected_count], engine_id,
sizeof(selected_ids[selected_count]) - 1);
selected_ids[selected_count][sizeof(selected_ids[selected_count]) - 1] =
'\0';
selected_count++;
}
} }
} }
} }
@ -26,6 +46,18 @@ int settings_save_handler(UrlParams *params) {
set_cookie("locale", locale, "Fri, 31 Dec 2038 23:59:59 GMT", "/", false, false); set_cookie("locale", locale, "Fri, 31 Dec 2038 23:59:59 GMT", "/", false, false);
} }
if (engines_present) {
char cookie_value[512];
cookie_value[0] = '\0';
for (int i = 0; i < selected_count; i++) {
if (i > 0)
strcat(cookie_value, ",");
strcat(cookie_value, selected_ids[i]);
}
set_cookie("engines", cookie_value, "Fri, 31 Dec 2038 23:59:59 GMT", "/",
false, false);
}
char redirect_url[512]; char redirect_url[512];
snprintf(redirect_url, sizeof(redirect_url), "/settings?q=%s", query); snprintf(redirect_url, sizeof(redirect_url), "/settings?q=%s", query);
send_redirect(redirect_url); send_redirect(redirect_url);

View file

@ -1,4 +1,5 @@
#include "Utility.h" #include "Utility.h"
#include "../Scraping/Scraping.h"
#include <beaker.h> #include <beaker.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -34,6 +35,89 @@ char *get_locale(const char *default_locale) {
return strdup(default_locale); return strdup(default_locale);
} }
static int engine_id_casecmp(const char *a, const char *b) {
while (*a && *b) {
char la = *a;
char lb = *b;
if (la >= 'A' && la <= 'Z') la = la - 'A' + 'a';
if (lb >= 'A' && lb <= 'Z') lb = lb - 'A' + 'a';
if (la != lb) return 0;
a++;
b++;
}
return *a == *b;
}
int is_engine_id_enabled(const char *engine_id) {
if (!engine_id) return 0;
for (int i = 0; i < ENGINE_COUNT; i++) {
if (ENGINE_REGISTRY[i].enabled &&
engine_id_casecmp(ENGINE_REGISTRY[i].id, engine_id)) {
return 1;
}
}
return 0;
}
int get_user_engines(char ***out_ids, int *out_count) {
*out_ids = NULL;
*out_count = 0;
char *cookie = get_cookie("engines");
if (!cookie || cookie[0] == '\0') {
free(cookie);
return -1;
}
char **ids = NULL;
int count = 0;
char *copy = strdup(cookie);
if (!copy) {
free(cookie);
return -1;
}
char *saveptr;
char *token = strtok_r(copy, ",", &saveptr);
while (token) {
while (*token == ' ' || *token == '\t')
token++;
if (token[0] != '\0' && is_engine_id_enabled(token)) {
char **new_ids = realloc(ids, sizeof(char *) * (count + 1));
if (new_ids) {
ids = new_ids;
ids[count] = strdup(token);
count++;
}
}
token = strtok_r(NULL, ",", &saveptr);
}
free(copy);
free(cookie);
if (count == 0) {
free(ids);
return -1;
}
*out_ids = ids;
*out_count = count;
return 0;
}
int user_engines_contains(const char *engine_id, char **ids, int count) {
if (!engine_id || !ids) return 0;
for (int i = 0; i < count; i++) {
if (engine_id_casecmp(ids[i], engine_id))
return 1;
}
return 0;
}
int add_link_to_collection(const char *href, const char *label, int add_link_to_collection(const char *href, const char *label,
const char *class_name, char ****collection, const char *class_name, char ****collection,
int **inner_counts, int current_count) { int **inner_counts, int current_count) {

View file

@ -9,6 +9,10 @@ int hex_to_int(char c);
char *get_theme(const char *default_theme); char *get_theme(const char *default_theme);
char *get_locale(const char *default_locale); char *get_locale(const char *default_locale);
int is_engine_id_enabled(const char *engine_id);
int get_user_engines(char ***out_ids, int *out_count);
int user_engines_contains(const char *engine_id, char **ids, int count);
int add_link_to_collection(const char *href, const char *label, int add_link_to_collection(const char *href, const char *label,
const char *class_name, char ****collection, const char *class_name, char ****collection,
int **inner_counts, int current_count); int **inner_counts, int current_count);