Compare commits

..
29 changed files with 599 additions and 1283 deletions

2
.gitignore vendored
View file

@ -1,5 +1,3 @@
/bin
/obj
config.ini
/result

View file

@ -12,7 +12,7 @@ RUN apk add --no-cache \
WORKDIR /app
COPY . /app
RUN git clone https://git.bwaaa.space/beaker /tmp/beaker && \
RUN git clone https://git.bwaaa.monster/beaker /tmp/beaker && \
cd /tmp/beaker && \
make && make install && \
rm -rf /tmp/beaker

View file

@ -7,9 +7,8 @@ GIT_HASH := $(shell git rev-parse --short HEAD)
GIT_DATE := $(shell git log -1 --format='%ad' --date='format:%y.%m.%d')
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
GIT_REMOTE := $(shell git remote get-url origin)
GIT_TAG := $(shell git describe --tags --exact-match HEAD 2>/dev/null)
VERSION := $(if $(GIT_TAG),$(GIT_TAG),$(GIT_DATE)+$(GIT_HASH)_$(GIT_BRANCH))
VERSION := $(GIT_DATE)+$(GIT_HASH)_$(GIT_BRANCH)
CFLAGS := -Wall -Wextra -O2 -Isrc -DVERSION='"$(VERSION)"' -DGIT_REMOTE='"$(GIT_REMOTE)"'

View file

@ -11,7 +11,7 @@ Create a config.ini, there is an example included in the root. Or if you install
## Dependencies
- libxml2
- libcurl (may be replaced in the future with curl-impersonate)
- beaker [(source)](https://git.bwaaa.space/beaker/)
- beaker [(source)](https://git.bwaaa.monster/beaker/)
## First Setup
Depending on your system, you may first need to install libcurl and libxml2.
@ -47,32 +47,6 @@ On Alpine, `shadow` is needed for the user creation process during the install.
# xbps-install -S libxml2-devel libcurl-devel
```
### NixOS
Add the flake to your inputs and import the module. That is all you need.
Here's an example of using the modules in a flake:
```nix
# flake.nix
{
inputs = {
omnisearch = {
url = "git+https://git.bwaaa.monster/omnisearch";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = { self, nixpkgs, omnisearch, ... }: {
nixosConfigurations.mySystem = nixpkgs.lib.nixosSystem {
modules = [
omnisearch.nixosModules.default
{
services.omnisearch.enable = true;
}
];
};
};
}
```
### macOS (Homebrew)
```
$ brew install libxml2 curl openssl pkg-config
@ -87,7 +61,7 @@ On macOS the build uses `pkg-config` to discover `libxml2`, `libcurl` and OpenSS
Install libbeaker:
```
$ git clone https://git.bwaaa.space/beaker
$ git clone https://git.bwaaa.monster/beaker
$ cd beaker
$ make
# make install
@ -97,7 +71,7 @@ On macOS `beaker` installs to `/usr/local/` by default and installs `libbeaker.d
And then install omnisearch:
```
$ git clone https://git.bwaaa.space/omnisearch
$ git clone https://git.bwaaa.monster/omnisearch
$ cd omnisearch
$ make
# make install-<init>
@ -115,7 +89,7 @@ You need Docker or Podman and Docker Compose installed on your system.
Run the container:
```
$ git clone https://git.bwaaa.space/omnisearch
$ git clone https://git.bwaaa.monster/omnisearch
$ cd omnisearch
$ docker compose up -d --build
```
@ -139,6 +113,6 @@ $ git merge origin/master
If there are conflicts in the files you modified, resolve them manually. You should also make the changes to the cloned repository, and then run the install command again if you installed omnisearch. Changes made directly to the configuration/assets folder will be overwritten on reinstall.
## Contribution
Generate a patch with ```git format-patch HEAD~1``` and email to [frostinator33@airmail.cc](mailto:frostinator33@airmail.cc), beginning the subject line with [PATCH omnisearch]
Generate a patch with ```git format-patch HEAD~1``` and email to [gabriel@bwaaa.monster](mailto:gabriel@bwaaa.monster), beginning the subject line with [PATCH omnisearch]
*If you are sending a revised version of a previous patch, please use [PATCH omnisearch v2, v3, etc].*

View file

@ -31,11 +31,8 @@ port = 8087
[engines]
# Use * for all engines, or specify comma-separated list (e.g., ddg,yahoo)
# Use *,-engine to exclude specific engines (e.g., *,-startpage)
# Available engines: ddg, startpage, yahoo, mojeek, yacy
# Available engines: ddg, startpage, yahoo, mojeek
engines="*"
# YaCy instance to use for the yacy engine (optional, default: http://127.0.0.1:8090)
# Requires "yacy" to be in the engines list above.
#yacy_instance = http://127.0.0.1:8090
[rate_limit]
# Rate limit searches per interval

43
flake.lock generated
View file

@ -1,43 +0,0 @@
{
"nodes": {
"beaker-src": {
"flake": false,
"locked": {
"lastModified": 1790704008,
"narHash": "sha256-Al/BE7uVRSmUGF/t1m0pWxF9jNgzdCVUrc5ZHkcPiQg=",
"ref": "refs/heads/master",
"rev": "10be7f581fb828e74f064ea7ad4fb0534ee8540a",
"revCount": 46,
"shallow": false,
"type": "git",
"url": "https://git.bwaaa.space/beaker"
},
"original": {
"shallow": false,
"type": "git",
"url": "https://git.bwaaa.space/beaker"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1791456040,
"narHash": "sha256-gRZ/s8WQJ2CsXdhcDVQH34qxuL0MuMCOs3aBiK1Prsw=",
"rev": "e7439b6b14ad3cc35d05608ebca9bce01a25f5f8",
"type": "tarball",
"url": "https://releases.nixos.org/nixos/unstable/nixos-26.11pre1087755.e7439b6b14ad/nixexprs.tar.zst?lastModified=1791456040&rev=e7439b6b14ad3cc35d05608ebca9bce01a25f5f8"
},
"original": {
"type": "tarball",
"url": "https://channels.nixos.org/nixos-unstable/nixexprs.tar.zst"
}
},
"root": {
"inputs": {
"beaker-src": "beaker-src",
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

View file

@ -1,76 +0,0 @@
{
inputs = {
nixpkgs.url = "https://channels.nixos.org/nixos-unstable/nixexprs.tar.zst";
beaker-src = {
url = "git+https://git.bwaaa.space/beaker?shallow=0";
flake = false;
};
};
outputs =
{
self,
nixpkgs,
beaker-src,
}:
let
supportedSystems = [
"x86_64-linux"
"aarch64-linux"
];
forAllSystems = nixpkgs.lib.genAttrs supportedSystems;
in
{
formatter = forAllSystems (system: nixpkgs.legacyPackages.${system}.nixfmt);
packages = forAllSystems (
system:
let
pkgs = import nixpkgs { inherit system; };
beaker = pkgs.stdenv.mkDerivation {
pname = "beaker";
version = "git";
src = beaker-src;
makeFlags = [
"INSTALL_PREFIX=$(out)/"
"LDCONFIG=true"
];
};
in
{
default = pkgs.stdenv.mkDerivation {
pname = "omnisearch";
version = "git";
src = ./.;
buildInputs = [
pkgs.libxml2.dev
pkgs.curl.dev
pkgs.openssl
beaker
];
preBuild = ''
makeFlagsArray+=(
"PREFIX=$out"
"CFLAGS=-Wall -Wextra -O2 -Isrc -I${pkgs.libxml2.dev}/include/libxml2 -I${beaker}/include/beaker.h"
"LIBS=-lbeaker -lcurl -lxml2 -lpthread -lm -lssl -lcrypto"
)
'';
installPhase = ''
mkdir -p $out/bin $out/share/omnisearch
install -Dm755 bin/omnisearch $out/bin/omnisearch
cp -r templates static locales -t $out/share/omnisearch/
'';
meta = {
description = "Lightweight metasearch engine in C";
platforms = pkgs.lib.platforms.linux;
};
};
}
);
nixosModules.default = import ./module.nix self;
};
}

View file

@ -21,8 +21,6 @@ display_language_label = "Display Language"
language_desc = "Choose your preferred language."
engines_label = "Search Engines"
engines_desc = "Choose which search engines to use. Only engines enabled on the server are shown."
default_engine_label = "Default Search Engine"
all_engines_option = "All enabled engines"
save_settings_button = "Save Settings"
no_results = "No results found"
error_images = "Error fetching images"

View file

@ -21,8 +21,6 @@ display_language_label = "Display Language"
language_desc = "Choose your preferred language."
engines_label = "Search Engines"
engines_desc = "Choose which search engines to use. Only engines enabled on the server are shown."
default_engine_label = "Default Search Engine"
all_engines_option = "All enabled engines"
save_settings_button = "Save Settings"
no_results = "No results found"
error_images = "Error fetching images"

View file

@ -1,36 +0,0 @@
[Meta]
Id = "fi_fi"
Name = "Suomi"
Direction = "ltr"
[Keys]
search_placeholder = "Hae netistä..."
search_button = "Hae"
surprise_me_button = "Kokeilen onneani"
all_tab = "Kaikki"
images_tab = "Kuvat"
settings_tab = "Asetukset"
settings_title = "Asetukset"
theme_label = "Ulkonäkö"
theme_desc = "Valitse haluamasi väriteema."
theme_system = "Järjestelmä"
theme_light = "Vaalea"
theme_dark = "Tumma"
language_label = "Kieli"
display_language_label = "Näyttökieli"
language_desc = "Valitse haluamasi kieli."
engines_label = "Hakukoneet"
engines_desc = "Valitse mitä hakukoneita käytetään. Vain palvelimella käyttöön otetut hakukoneet näytetään."
default_engine_label = "Oletushakukone"
all_engines_option = "Kaikki valitut hakukoneet"
save_settings_button = "Tallenna asetukset"
no_results = "Ei tuloksia"
error_images = "Virhe kuvien haussa"
rate_limit = "Hidasta hieman! Sinulta on tullut liian monta hakupyyntöä!"
warning_fetch_error = "pyyntö epäonnistui ennen kuin OmniSearch ehti lukea hakutuloksia."
warning_parse_mismatch = "palautti hakutulokset muodossa jota OmniSearch ei osaa jäsentää."
warning_blocked = "palautti captchan tai muun estosivun hakutulosten sijaan."
read_more = "Lue Lisää"
view_cached = "Välimuistissa"
view_image = "Kuva"
visit_site = "Sivu"

View file

@ -1,142 +0,0 @@
self:
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.omnisearch;
pkg = cfg.package;
finalConfigFile =
if cfg.configFile != null then
cfg.configFile
else
pkgs.writeText "omnisearch.ini" ''
[server]
host = ${cfg.settings.server.host}
port = ${toString cfg.settings.server.port}
domain = ${cfg.settings.server.domain}
${lib.optionalString (cfg.settings.server.locale != null) "locale = ${cfg.settings.server.locale}"}
[proxy]
${lib.optionalString (cfg.settings.proxy.proxy != null) "proxy = \"${cfg.settings.proxy.proxy}\""}
${lib.optionalString (
cfg.settings.proxy.list_file != null
) "list_file = ${cfg.settings.proxy.list_file}"}
max_retries = ${toString cfg.settings.proxy.max_retries}
randomize_username = ${lib.boolToString cfg.settings.proxy.randomize_username}
randomize_password = ${lib.boolToString cfg.settings.proxy.randomize_password}
[cache]
dir = ${cfg.settings.cache.dir}
ttl_search = ${toString cfg.settings.cache.ttl_search}
ttl_infobox = ${toString cfg.settings.cache.ttl_infobox}
'';
in
{
options.services.omnisearch = {
enable = lib.mkEnableOption "OmniSearch metasearch engine";
package = lib.mkOption {
type = lib.types.package;
default = self.packages.${pkgs.stdenv.hostPlatform.system}.default;
description = "The omnisearch package to use.";
};
configFile = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
description = "Path to a custom config.ini. Overrides 'settings'.";
};
settings = {
server = {
host = lib.mkOption {
type = lib.types.str;
default = "0.0.0.0";
};
port = lib.mkOption {
type = lib.types.port;
default = 8087;
};
domain = lib.mkOption {
type = lib.types.str;
default = "http://localhost:${toString cfg.settings.server.port}";
};
locale = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
};
};
proxy = {
proxy = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
};
list_file = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
};
max_retries = lib.mkOption {
type = lib.types.int;
default = 3;
};
randomize_username = lib.mkOption {
type = lib.types.bool;
default = true;
};
randomize_password = lib.mkOption {
type = lib.types.bool;
default = true;
};
};
cache = {
dir = lib.mkOption {
type = lib.types.str;
default = "/var/cache/omnisearch";
};
ttl_search = lib.mkOption {
type = lib.types.int;
default = 3600;
};
ttl_infobox = lib.mkOption {
type = lib.types.int;
default = 86400;
};
};
};
};
config = lib.mkIf cfg.enable {
systemd.services.omnisearch = {
description = "OmniSearch Service";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = "${pkg}/bin/omnisearch";
WorkingDirectory = "/var/lib/omnisearch";
StateDirectory = "omnisearch";
CacheDirectory = "omnisearch";
BindReadOnlyPaths = [
"${pkg}/share/omnisearch/templates:/var/lib/omnisearch/templates"
"${pkg}/share/omnisearch/static:/var/lib/omnisearch/static"
"${pkg}/share/omnisearch/locales:/var/lib/omnisearch/locales"
"${finalConfigFile}:/var/lib/omnisearch/config.ini"
];
DynamicUser = true;
ProtectSystem = "strict";
ProtectHome = true;
PrivateTmp = true;
Restart = "always";
};
};
};
}

View file

@ -1,189 +1,120 @@
#include "Config.h"
#include <errno.h>
#include <limits.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
typedef enum {
CONFIG_STRING,
CONFIG_INTEGER,
CONFIG_BOOLEAN,
} ConfigValueType;
typedef struct {
const char *section;
const char *key;
ConfigValueType type;
size_t offset;
size_t size;
} ConfigOption;
#define STRING_OPTION(section_name, key_name, field) \
{section_name, key_name, CONFIG_STRING, offsetof(Config, field), \
sizeof(((Config *)0)->field)}
#define INTEGER_OPTION(section_name, key_name, field) \
{section_name, key_name, CONFIG_INTEGER, offsetof(Config, field), 0}
#define BOOLEAN_OPTION(section_name, key_name, field) \
{section_name, key_name, CONFIG_BOOLEAN, offsetof(Config, field), 0}
static const ConfigOption CONFIG_OPTIONS[] = {
STRING_OPTION("server", "host", host),
INTEGER_OPTION("server", "port", port),
STRING_OPTION("server", "locale", default_locale),
STRING_OPTION("proxy", "proxy", proxy),
STRING_OPTION("proxy", "list_file", proxy_list_file),
INTEGER_OPTION("proxy", "max_retries", max_proxy_retries),
BOOLEAN_OPTION("proxy", "randomize_username", randomize_username),
BOOLEAN_OPTION("proxy", "randomize_password", randomize_password),
STRING_OPTION("cache", "dir", cache_dir),
INTEGER_OPTION("cache", "ttl_search", cache_ttl_search),
INTEGER_OPTION("cache", "ttl_infobox", cache_ttl_infobox),
INTEGER_OPTION("cache", "ttl_image", cache_ttl_image),
STRING_OPTION("engines", "engines", engines),
STRING_OPTION("engines", "yacy_instance", yacy_instance),
INTEGER_OPTION("rate_limit", "search_requests", rate_limit_search_requests),
INTEGER_OPTION("rate_limit", "search_interval", rate_limit_search_interval),
INTEGER_OPTION("rate_limit", "images_requests", rate_limit_images_requests),
INTEGER_OPTION("rate_limit", "images_interval", rate_limit_images_interval),
};
void config_set_defaults(Config *config) {
if (!config) {
return;
}
*config = (Config){
.host = DEFAULT_HOST,
.port = DEFAULT_PORT,
.default_locale = "en_gb",
.max_proxy_retries = DEFAULT_MAX_PROXY_RETRIES,
.cache_dir = DEFAULT_CACHE_DIR,
.cache_ttl_search = DEFAULT_CACHE_TTL_SEARCH,
.cache_ttl_infobox = DEFAULT_CACHE_TTL_INFOBOX,
.cache_ttl_image = DEFAULT_CACHE_TTL_IMAGE,
};
}
static char *trim(char *value) {
while (*value == ' ' || *value == '\t') {
value++;
}
char *end = value + strlen(value);
while (end > value && (end[-1] == ' ' || end[-1] == '\t')) {
end--;
}
*end = '\0';
return value;
}
static char *unquote(char *value) {
size_t length = strlen(value);
if (length >= 2 && (value[0] == '"' || value[0] == '\'') &&
value[length - 1] == value[0]) {
value[length - 1] = '\0';
return value + 1;
}
return value;
}
static int parse_integer(const char *value, int *result) {
char *end;
errno = 0;
long parsed = strtol(value, &end, 10);
if (value == end || *end != '\0' || errno == ERANGE || parsed < INT_MIN ||
parsed > INT_MAX) {
return -1;
}
*result = (int)parsed;
return 0;
}
static int parse_boolean(const char *value, int *result) {
if (strcmp(value, "1") == 0 || strcasecmp(value, "true") == 0 ||
strcasecmp(value, "yes") == 0 || strcasecmp(value, "on") == 0) {
*result = 1;
return 0;
}
if (strcmp(value, "0") == 0 || strcasecmp(value, "false") == 0 ||
strcasecmp(value, "no") == 0 || strcasecmp(value, "off") == 0) {
*result = 0;
return 0;
}
return -1;
}
static void set_option(Config *config, const char *section, const char *key,
const char *value) {
size_t option_count = sizeof(CONFIG_OPTIONS) / sizeof(CONFIG_OPTIONS[0]);
for (size_t i = 0; i < option_count; i++) {
const ConfigOption *option = &CONFIG_OPTIONS[i];
if (strcmp(section, option->section) != 0 ||
strcmp(key, option->key) != 0) {
continue;
}
void *destination = (char *)config + option->offset;
if (option->type == CONFIG_STRING) {
snprintf(destination, option->size, "%s", value);
} else if (option->type == CONFIG_INTEGER) {
parse_integer(value, destination);
} else {
parse_boolean(value, destination);
}
return;
}
}
int load_config(const char *filename, Config *config) {
if (!filename || !config) {
return -1;
}
FILE *file = fopen(filename, "r");
if (!file) {
return -1;
}
char line[1024];
char line[512];
char section[64] = "";
while (fgets(line, sizeof(line), file)) {
line[strcspn(line, "\r\n")] = '\0';
char *content = trim(line);
line[strcspn(line, "\r\n")] = 0;
if (*content == '\0' || *content == '#' || *content == ';') {
if (line[0] == '\0' || line[0] == '#' || line[0] == ';') {
continue;
}
if (*content == '[') {
char *end = strchr(content + 1, ']');
if (line[0] == '[') {
char *end = strchr(line, ']');
if (end) {
*end = '\0';
snprintf(section, sizeof(section), "%s", trim(content + 1));
snprintf(section, sizeof(section), "%.*s", (int)(sizeof(section) - 1),
line + 1);
section[sizeof(section) - 1] = '\0';
}
continue;
}
char *delimiter = strchr(content, '=');
if (!delimiter) {
continue;
}
char *delimiter = strchr(line, '=');
if (delimiter) {
*delimiter = '\0';
char *key = trim(content);
char *value = unquote(trim(delimiter + 1));
set_option(config, section, key, value);
char *key = line;
char *value = delimiter + 1;
while (*key == ' ' || *key == '\t')
key++;
while (*value == ' ' || *value == '\t')
value++;
char *key_end = key + strlen(key) - 1;
while (key_end > key && (*key_end == ' ' || *key_end == '\t')) {
*key_end = '\0';
key_end--;
}
int result = ferror(file) ? -1 : 0;
char *value_end = value + strlen(value) - 1;
while (value_end > value && (*value_end == ' ' || *value_end == '\t' ||
*value_end == '"' || *value_end == '\'')) {
*value_end = '\0';
value_end--;
}
while (*value == ' ' || *value == '\t')
value++;
while (*value == '"' || *value == '\'')
value++;
if (strcmp(section, "server") == 0) {
if (strcmp(key, "host") == 0) {
strncpy(config->host, value, sizeof(config->host) - 1);
config->host[sizeof(config->host) - 1] = '\0';
} else if (strcmp(key, "port") == 0) {
config->port = atoi(value);
} else if (strcmp(key, "locale") == 0) {
strncpy(config->default_locale, value,
sizeof(config->default_locale) - 1);
config->default_locale[sizeof(config->default_locale) - 1] = '\0';
}
} else if (strcmp(section, "proxy") == 0) {
if (strcmp(key, "proxy") == 0) {
strncpy(config->proxy, value, sizeof(config->proxy) - 1);
config->proxy[sizeof(config->proxy) - 1] = '\0';
} else if (strcmp(key, "list_file") == 0) {
strncpy(config->proxy_list_file, value,
sizeof(config->proxy_list_file) - 1);
config->proxy_list_file[sizeof(config->proxy_list_file) - 1] = '\0';
} else if (strcmp(key, "max_retries") == 0) {
config->max_proxy_retries = atoi(value);
} else if (strcmp(key, "randomize_username") == 0) {
config->randomize_username = atoi(value);
} else if (strcmp(key, "randomize_password") == 0) {
config->randomize_password = atoi(value);
}
} else if (strcmp(section, "cache") == 0) {
if (strcmp(key, "dir") == 0) {
strncpy(config->cache_dir, value, sizeof(config->cache_dir) - 1);
config->cache_dir[sizeof(config->cache_dir) - 1] = '\0';
} else if (strcmp(key, "ttl_search") == 0) {
config->cache_ttl_search = atoi(value);
} else if (strcmp(key, "ttl_infobox") == 0) {
config->cache_ttl_infobox = atoi(value);
} else if (strcmp(key, "ttl_image") == 0) {
config->cache_ttl_image = atoi(value);
}
} else if (strcmp(section, "engines") == 0) {
if (strcmp(key, "engines") == 0) {
strncpy(config->engines, value, sizeof(config->engines) - 1);
config->engines[sizeof(config->engines) - 1] = '\0';
}
} else if (strcmp(section, "rate_limit") == 0) {
if (strcmp(key, "search_requests") == 0) {
config->rate_limit_search_requests = atoi(value);
} else if (strcmp(key, "search_interval") == 0) {
config->rate_limit_search_interval = atoi(value);
} else if (strcmp(key, "images_requests") == 0) {
config->rate_limit_images_requests = atoi(value);
} else if (strcmp(key, "images_interval") == 0) {
config->rate_limit_images_interval = atoi(value);
}
}
}
}
fclose(file);
return result;
return 0;
}

View file

@ -8,7 +8,6 @@
#define DEFAULT_CACHE_TTL_INFOBOX 86400
#define DEFAULT_CACHE_TTL_IMAGE 604800
#define DEFAULT_MAX_PROXY_RETRIES 3
#define DEFAULT_YACY_INSTANCE "http://127.0.0.1:8090"
#define BUFFER_SIZE_SMALL 256
#define BUFFER_SIZE_MEDIUM 512
@ -47,14 +46,12 @@ typedef struct {
int cache_ttl_infobox;
int cache_ttl_image;
char engines[512];
char yacy_instance[512];
int rate_limit_search_requests;
int rate_limit_search_interval;
int rate_limit_images_requests;
int rate_limit_images_interval;
} Config;
void config_set_defaults(Config *config);
int load_config(const char *filename, Config *config);
#endif

View file

@ -12,7 +12,6 @@
#include "Routes/Home.h"
#include "Routes/ImageProxy.h"
#include "Routes/Images.h"
#include "Routes/Info.h"
#include "Routes/Search.h"
#include "Routes/Settings.h"
#include "Routes/SettingsSave.h"
@ -66,8 +65,23 @@ int main() {
curl_global_init(CURL_GLOBAL_DEFAULT);
Config cfg;
config_set_defaults(&cfg);
Config cfg = {.host = DEFAULT_HOST,
.port = DEFAULT_PORT,
.default_locale = "en_gb",
.proxy = "",
.proxy_list_file = "",
.max_proxy_retries = DEFAULT_MAX_PROXY_RETRIES,
.randomize_username = 0,
.randomize_password = 0,
.cache_dir = DEFAULT_CACHE_DIR,
.cache_ttl_search = DEFAULT_CACHE_TTL_SEARCH,
.cache_ttl_infobox = DEFAULT_CACHE_TTL_INFOBOX,
.cache_ttl_image = DEFAULT_CACHE_TTL_IMAGE,
.engines = "",
.rate_limit_search_requests = 0,
.rate_limit_search_interval = 0,
.rate_limit_images_requests = 0,
.rate_limit_images_interval = 0};
if (load_config("config.ini", &cfg) != 0) {
fprintf(stderr, "[WARN] Could not load config file, using defaults\n");
@ -87,23 +101,6 @@ int main() {
}
apply_engines_config(cfg.engines);
configure_yacy_engine(cfg.yacy_instance);
if (cfg.yacy_instance[0] != '\0') {
int yacy_enabled = 0;
for (int i = 0; i < ENGINE_COUNT; i++) {
if (strcmp(ENGINE_REGISTRY[i].id, "yacy") == 0) {
yacy_enabled = ENGINE_REGISTRY[i].enabled;
break;
}
}
if (!yacy_enabled) {
fprintf(
stderr,
"[INFO] YaCy instance configured but the yacy engine is not "
"enabled (add it to the engines list, e.g. engines=\"*,yacy\")\n");
}
}
if (cache_init(cfg.cache_dir) != 0) {
fprintf(stderr,
@ -139,7 +136,6 @@ int main() {
set_handler("/search", results_handler);
set_handler("/images", images_handler);
set_handler("/proxy", image_proxy_handler);
set_handler("/info", info_handler);
set_handler("/settings", settings_handler);
set_handler("/save_settings", settings_save_handler);

View file

@ -76,12 +76,14 @@ int images_handler(UrlParams *params) {
if (!error_images_msg)
error_images_msg = "Error fetching images";
StringMatrix pagination;
string_matrix_build_pagination(page, images_href_builder, (void *)raw_query,
&pagination);
if (pagination.count > 0) {
context_set_array_of_arrays(&ctx, "pagination_links", pagination.rows,
pagination.count, pagination.field_counts);
char ***pager_matrix = NULL;
int *pager_inner_counts = NULL;
int pager_count =
build_pagination(page, images_href_builder, (void *)raw_query,
&pager_matrix, &pager_inner_counts);
if (pager_count > 0) {
context_set_array_of_arrays(&ctx, "pagination_links", pager_matrix,
pager_count, pager_inner_counts);
}
char *display_query = url_decode_query(raw_query);
@ -89,9 +91,8 @@ int images_handler(UrlParams *params) {
if (!raw_query || strlen(raw_query) == 0) {
send_redirect("/");
string_matrix_free(&pagination);
if (display_query)
free(display_query);
free(locale);
free_context(&ctx);
return -1;
}
@ -127,9 +128,7 @@ int images_handler(UrlParams *params) {
snprintf(response, sizeof(response), "<h1>%s</h1>", rate_limit_msg);
send_response(response);
free(request_cache_key);
string_matrix_free(&pagination);
free(display_query);
free(locale);
free_context(&ctx);
return -1;
}
@ -148,37 +147,37 @@ int images_handler(UrlParams *params) {
snprintf(error_html, sizeof(error_html), "<h1>%s</h1>", error_images_msg);
send_response(error_html);
free(request_cache_key);
string_matrix_free(&pagination);
free(display_query);
free(locale);
free_context(&ctx);
return -1;
}
StringMatrix images;
string_matrix_init(&images);
char ***image_matrix = malloc(sizeof(char **) * result_count);
int *inner_counts = malloc(sizeof(int) * result_count);
for (int i = 0; i < result_count; i++) {
const char *values[IMAGE_RESULT_FIELDS] = {
results[i].thumbnail_url,
results[i].title,
results[i].page_url,
results[i].full_url,
};
if (string_matrix_append(&images, values, IMAGE_RESULT_FIELDS) != 0) {
string_matrix_free(&images);
string_matrix_free(&pagination);
if (!image_matrix || !inner_counts) {
if (image_matrix)
free(image_matrix);
if (inner_counts)
free(inner_counts);
free_image_results(results, result_count);
free(request_cache_key);
free(display_query);
free(locale);
free_context(&ctx);
return -1;
}
for (int i = 0; i < result_count; i++) {
image_matrix[i] = malloc(sizeof(char *) * IMAGE_RESULT_FIELDS);
image_matrix[i][0] = strdup(results[i].thumbnail_url);
image_matrix[i][1] = strdup(results[i].title);
image_matrix[i][2] = strdup(results[i].page_url);
image_matrix[i][3] = strdup(results[i].full_url);
inner_counts[i] = IMAGE_RESULT_FIELDS;
}
context_set_array_of_arrays(&ctx, "images", images.rows, images.count,
images.field_counts);
context_set_array_of_arrays(&ctx, "images", image_matrix, result_count,
inner_counts);
char *rendered = render_template("images.html", &ctx);
if (rendered) {
@ -188,13 +187,27 @@ int images_handler(UrlParams *params) {
send_response("<h1>Error rendering image results</h1>");
}
string_matrix_free(&images);
string_matrix_free(&pagination);
for (int i = 0; i < result_count; i++) {
for (int j = 0; j < IMAGE_RESULT_FIELDS; j++)
free(image_matrix[i][j]);
free(image_matrix[i]);
}
free(image_matrix);
free(inner_counts);
if (pager_count > 0) {
for (int i = 0; i < pager_count; i++) {
for (int j = 0; j < LINK_FIELD_COUNT; j++)
free(pager_matrix[i][j]);
free(pager_matrix[i]);
}
free(pager_matrix);
free(pager_inner_counts);
}
free_image_results(results, result_count);
free(request_cache_key);
free(display_query);
free(locale);
free_context(&ctx);
return 0;

View file

@ -1,69 +0,0 @@
#include "Info.h"
#include "../Config.h"
#include "../Scraping/Scraping.h"
#include "../Utility/Utility.h"
#include <beaker.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
static int append_json(char *buf, size_t size, size_t *used, const char *format,
...) {
if (*used >= size) {
return -1;
}
va_list args;
va_start(args, format);
int written = vsnprintf(buf + *used, size - *used, format, args);
va_end(args);
if (written < 0 || (size_t)written >= size - *used) {
return -1;
}
*used += (size_t)written;
return 0;
}
int info_handler(UrlParams *params) {
(void)params;
extern Config global_config;
char json[INITIAL_BUFFER_SIZE];
size_t used = 0;
if (append_json(json, sizeof(json), &used, "{\"version\":\"%s\",", VERSION) !=
0 ||
append_json(json, sizeof(json), &used, "\"git_remote\":\"%s\",",
GIT_REMOTE) != 0 ||
append_json(json, sizeof(json), &used, "\"locale\":\"%s\",",
global_config.default_locale) != 0 ||
append_json(json, sizeof(json), &used, "\"engines\":[") != 0) {
send_response("Failed to build instance info");
return -1;
}
int first = 1;
for (int i = 0; i < ENGINE_COUNT; i++) {
if (!ENGINE_REGISTRY[i].enabled) {
continue;
}
if (append_json(json, sizeof(json), &used,
"%s{\"id\":\"%s\",\"name\":\"%s\"}", first ? "" : ",",
ENGINE_REGISTRY[i].id, ENGINE_REGISTRY[i].name) != 0) {
send_response("Failed to build instance info");
return -1;
}
first = 0;
}
if (append_json(json, sizeof(json), &used, "]}") != 0) {
send_response("Failed to build instance info");
return -1;
}
serve_data(json, used, "application/json");
return 0;
}

View file

@ -1,8 +0,0 @@
#ifndef INFO_H
#define INFO_H
#include <beaker.h>
int info_handler(UrlParams *params);
#endif

View file

@ -140,8 +140,7 @@ static InfoBox fetch_currency_wrapper(char *query) {
return fetch_currency_data(query);
}
char *get_base_url(const char *input) {
if (!input)
return NULL;
if (!input) return NULL;
const char *start = input;
@ -158,8 +157,7 @@ char *get_base_url(const char *input) {
size_t len = end - start;
char *domain = (char *)malloc(len + 1);
if (!domain)
return NULL;
if (!domain) return NULL;
strncpy(domain, start, len);
domain[len] = '\0';
@ -251,65 +249,88 @@ static void *infobox_thread_func(void *arg) {
return NULL;
}
static int add_infobox_to_collection(InfoBox *infobox,
StringMatrix *collection) {
const char *values[INFOBOX_FIELD_COUNT] = {
infobox->title, infobox->thumbnail_url, infobox->extract,
infobox->url, infobox->url,
};
return string_matrix_append(collection, values, INFOBOX_FIELD_COUNT);
static int add_infobox_to_collection(InfoBox *infobox, char ****collection,
int **inner_counts, int current_count) {
*collection =
(char ***)realloc(*collection, sizeof(char **) * (current_count + 1));
*inner_counts =
(int *)realloc(*inner_counts, sizeof(int) * (current_count + 1));
(*collection)[current_count] =
(char **)malloc(sizeof(char *) * INFOBOX_FIELD_COUNT);
(*collection)[current_count][0] =
infobox->title ? strdup(infobox->title) : NULL;
(*collection)[current_count][1] =
infobox->thumbnail_url ? strdup(infobox->thumbnail_url) : NULL;
(*collection)[current_count][2] =
infobox->extract ? strdup(infobox->extract) : NULL;
(*collection)[current_count][3] = infobox->url ? strdup(infobox->url) : NULL;
(*collection)[current_count][4] = infobox->url ? strdup(infobox->url) : NULL;
(*inner_counts)[current_count] = INFOBOX_FIELD_COUNT;
return current_count + 1;
}
static int add_warning_to_collection(const char *engine_name,
const char *warning_message,
StringMatrix *collection) {
const char *values[] = {engine_name, warning_message};
return string_matrix_append(collection, values, 2);
char ****collection, int **inner_counts,
int current_count) {
char ***new_collection =
(char ***)malloc(sizeof(char **) * (current_count + 1));
int *new_inner_counts =
(int *)malloc(sizeof(int) * (current_count + 1));
if (!new_collection || !new_inner_counts) {
free(new_collection);
free(new_inner_counts);
return current_count;
}
static void free_user_engine_list(char **user_engines, int user_engine_count) {
for (int i = 0; i < user_engine_count; i++)
free(user_engines[i]);
free(user_engines);
if (*collection && current_count > 0) {
memcpy(new_collection, *collection, sizeof(char **) * current_count);
}
if (*inner_counts && current_count > 0) {
memcpy(new_inner_counts, *inner_counts, sizeof(int) * current_count);
}
static void free_search_results(SearchResult **all_results, ScrapeJob *jobs,
int job_count) {
for (int i = 0; i < job_count; i++) {
for (int j = 0; all_results[i] && j < jobs[i].results_count; j++) {
free(all_results[i][j].url);
free(all_results[i][j].title);
free(all_results[i][j].snippet);
}
free(all_results[i]);
}
free(*collection);
free(*inner_counts);
*collection = new_collection;
*inner_counts = new_inner_counts;
(*collection)[current_count] = (char **)malloc(sizeof(char *) * 2);
if (!(*collection)[current_count])
return current_count;
(*collection)[current_count][0] = strdup(engine_name ? engine_name : "");
(*collection)[current_count][1] =
strdup(warning_message ? warning_message : "");
if (!(*collection)[current_count][0] || !(*collection)[current_count][1]) {
free((*collection)[current_count][0]);
free((*collection)[current_count][1]);
free((*collection)[current_count]);
return current_count;
}
static void free_infobox_results(InfoBoxThreadData *data) {
for (int i = 0; i < HANDLER_COUNT; i++) {
free_infobox(&data[i].result);
}
(*inner_counts)[current_count] = 2;
return current_count + 1;
}
static const char *warning_message_for_job(const ScrapeJob *job,
const char *locale) {
static const char *warning_message_for_job(const ScrapeJob *job, const char *locale) {
switch (job->status) {
case SCRAPE_STATUS_FETCH_ERROR: {
const char *msg = beaker_get_locale_value(locale, "warning_fetch_error");
return msg ? msg
: "request failed before OmniSearch could read search results.";
return msg ? msg : "request failed before OmniSearch could read search results.";
}
case SCRAPE_STATUS_PARSE_MISMATCH: {
const char *msg = beaker_get_locale_value(locale, "warning_parse_mismatch");
return msg ? msg
: "returned search results in a format OmniSearch could not "
"parse.";
return msg ? msg : "returned search results in a format OmniSearch could not parse.";
}
case SCRAPE_STATUS_BLOCKED: {
const char *msg = beaker_get_locale_value(locale, "warning_blocked");
return msg ? msg
: "returned a captcha or another blocking page instead of "
"search results.";
return msg ? msg : "returned a captcha or another blocking page instead of search results.";
}
default:
return NULL;
@ -363,8 +384,8 @@ static int engine_allowed_for_user(const SearchEngine *eng, char **user_ids,
static char *build_search_href(const char *query, const char *engine_id,
int page) {
const char *safe_query = query ? query : "";
int use_engine =
engine_id && engine_id[0] != '\0' && !engine_id_matches(engine_id, "all");
int use_engine = engine_id && engine_id[0] != '\0' &&
!engine_id_matches(engine_id, "all");
size_t needed = strlen("/search?q=") + strlen(safe_query) + 1;
if (use_engine)
@ -416,18 +437,13 @@ int results_handler(UrlParams *params) {
extern Config global_config;
TemplateContext ctx = new_context();
char *raw_query = "";
char selected_engine_id[32];
char *default_engine = get_default_search_engine();
snprintf(selected_engine_id, sizeof(selected_engine_id), "%s",
default_engine);
free(default_engine);
const char *selected_engine_id = "all";
int page = 1;
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);
int has_user_pref = (get_user_engines(&user_engines, &user_engine_count) == 0);
if (params) {
for (int i = 0; i < params->count; i++) {
@ -438,8 +454,7 @@ int results_handler(UrlParams *params) {
if (parsed > 1)
page = parsed;
} else if (strcmp(params->params[i].key, "engine") == 0) {
snprintf(selected_engine_id, sizeof(selected_engine_id), "%s",
params->params[i].value);
selected_engine_id = params->params[i].value;
} else if (strcmp(params->params[i].key, "btnI") == 0) {
btnI = atoi(params->params[i].value);
}
@ -456,11 +471,9 @@ int results_handler(UrlParams *params) {
beaker_set_locale(&ctx, locale);
const char *rate_limit_msg = beaker_get_locale_value(locale, "rate_limit");
if (!rate_limit_msg)
rate_limit_msg = "Slow down! Too many searches from you!";
if (!rate_limit_msg) rate_limit_msg = "Slow down! Too many searches from you!";
const char *no_results_msg = beaker_get_locale_value(locale, "no_results");
if (!no_results_msg)
no_results_msg = "No results found";
if (!no_results_msg) no_results_msg = "No results found";
char page_str[16];
snprintf(page_str, sizeof(page_str), "%d", page);
@ -478,24 +491,18 @@ int results_handler(UrlParams *params) {
if (!raw_query || strlen(raw_query) == 0) {
send_redirect("/");
free(locale);
free_user_engine_list(user_engines, user_engine_count);
if (has_user_pref) {
for (int i = 0; i < user_engine_count; i++)
free(user_engines[i]);
free(user_engines);
}
free_context(&ctx);
return -1;
}
const SearchEngine *selected_engine = find_enabled_engine(selected_engine_id);
if (selected_engine &&
!engine_allowed_for_user(selected_engine, user_engines, user_engine_count,
has_user_pref)) {
selected_engine = NULL;
}
if (selected_engine) {
snprintf(selected_engine_id, sizeof(selected_engine_id), "%s",
selected_engine->id);
} else {
snprintf(selected_engine_id, sizeof(selected_engine_id), "all");
}
if (!selected_engine)
selected_engine_id = "all";
context_set(&ctx, "selected_engine", selected_engine_id);
char *search_href = build_search_href(raw_query, selected_engine_id, 1);
@ -521,6 +528,13 @@ int results_handler(UrlParams *params) {
infobox_data[i].result = (InfoBox){NULL};
}
if (page == 1) {
for (int i = 0; i < HANDLER_COUNT; i++) {
pthread_create(&infobox_threads[i], NULL, infobox_thread_func,
&infobox_data[i]);
}
}
ScrapeJob jobs[ENGINE_COUNT];
SearchResult *all_results[ENGINE_COUNT];
@ -578,8 +592,11 @@ int results_handler(UrlParams *params) {
snprintf(response, sizeof(response), "<h1>%s</h1>", rate_limit_msg);
send_response(response);
free(request_cache_key);
free(locale);
free_user_engine_list(user_engines, user_engine_count);
if (has_user_pref) {
for (int i = 0; i < user_engine_count; i++)
free(user_engines[i]);
free(user_engines);
}
free_context(&ctx);
return -1;
}
@ -598,14 +615,15 @@ int results_handler(UrlParams *params) {
}
if (filter_engine_count > 1) {
StringMatrix filter_matrix;
string_matrix_init(&filter_matrix);
char ***filter_matrix = NULL;
int *filter_inner_counts = NULL;
int filter_count = 0;
char *all_href = build_search_href(raw_query, "all", 1);
const char *all_values[LINK_FIELD_COUNT] = {
all_href, "All",
selected_engine ? "engine-filter" : "engine-filter active"};
string_matrix_append(&filter_matrix, all_values, LINK_FIELD_COUNT);
filter_count = add_link_to_collection(
all_href, "All",
selected_engine ? "engine-filter" : "engine-filter active",
&filter_matrix, &filter_inner_counts, filter_count);
free(all_href);
for (int i = 0; i < ENGINE_COUNT; i++) {
@ -621,24 +639,22 @@ int results_handler(UrlParams *params) {
? "engine-filter active"
: "engine-filter";
const char *filter_values[LINK_FIELD_COUNT] = {
filter_href, ENGINE_REGISTRY[i].name, filter_class};
string_matrix_append(&filter_matrix, filter_values, LINK_FIELD_COUNT);
filter_count = add_link_to_collection(filter_href, ENGINE_REGISTRY[i].name,
filter_class, &filter_matrix,
&filter_inner_counts, filter_count);
free(filter_href);
}
if (filter_matrix.count > 0) {
context_set_array_of_arrays(&ctx, "engine_filters", filter_matrix.rows,
filter_matrix.count,
filter_matrix.field_counts);
if (filter_count > 0) {
context_set_array_of_arrays(&ctx, "engine_filters", filter_matrix,
filter_count, filter_inner_counts);
for (int i = 0; i < filter_count; i++) {
for (int j = 0; j < LINK_FIELD_COUNT; j++)
free(filter_matrix[i][j]);
free(filter_matrix[i]);
}
string_matrix_free(&filter_matrix);
}
if (page == 1) {
for (int i = 0; i < HANDLER_COUNT; i++) {
pthread_create(&infobox_threads[i], NULL, infobox_thread_func,
&infobox_data[i]);
free(filter_matrix);
free(filter_inner_counts);
}
}
@ -656,12 +672,27 @@ int results_handler(UrlParams *params) {
for (int i = 0; i < engine_idx; i++) {
if (jobs[i].results_count > 0 && all_results[i][0].url) {
char *redirect_url = strdup(all_results[i][0].url);
free_search_results(all_results, jobs, engine_idx);
if (page == 1)
free_infobox_results(infobox_data);
for (int j = 0; j < enabled_engine_count; j++) {
for (int k = 0; k < jobs[j].results_count; k++) {
free(all_results[j][k].url);
free(all_results[j][k].title);
free(all_results[j][k].snippet);
}
free(all_results[j]);
}
if (page == 1) {
for (int j = 0; j < HANDLER_COUNT; j++) {
if (infobox_data[j].success) {
free_infobox(&infobox_data[j].result);
}
}
}
free(request_cache_key);
free(locale);
free_user_engine_list(user_engines, user_engine_count);
if (has_user_pref) {
for (int i = 0; i < user_engine_count; i++)
free(user_engines[i]);
free(user_engines);
}
free_context(&ctx);
if (redirect_url) {
send_redirect(redirect_url);
@ -670,37 +701,54 @@ int results_handler(UrlParams *params) {
return 0;
}
}
free_search_results(all_results, jobs, engine_idx);
if (page == 1)
free_infobox_results(infobox_data);
for (int i = 0; i < enabled_engine_count; i++) {
free(all_results[i]);
}
if (page == 1) {
for (int i = 0; i < HANDLER_COUNT; i++) {
if (infobox_data[i].success) {
free_infobox(&infobox_data[i].result);
}
}
}
free(request_cache_key);
free(locale);
free_user_engine_list(user_engines, user_engine_count);
if (has_user_pref) {
for (int i = 0; i < user_engine_count; i++)
free(user_engines[i]);
free(user_engines);
}
free_context(&ctx);
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);
send_response(no_results_html);
return 0;
}
StringMatrix infobox_matrix;
string_matrix_init(&infobox_matrix);
char ***infobox_matrix = NULL;
int *infobox_inner_counts = NULL;
int infobox_count = 0;
if (page == 1) {
for (int i = 0; i < HANDLER_COUNT; i++) {
if (infobox_data[i].success) {
add_infobox_to_collection(&infobox_data[i].result, &infobox_matrix);
infobox_count =
add_infobox_to_collection(&infobox_data[i].result, &infobox_matrix,
&infobox_inner_counts, infobox_count);
}
}
}
if (infobox_matrix.count > 0) {
context_set_array_of_arrays(&ctx, "infoboxes", infobox_matrix.rows,
infobox_matrix.count,
infobox_matrix.field_counts);
if (infobox_count > 0) {
context_set_array_of_arrays(&ctx, "infoboxes", infobox_matrix,
infobox_count, infobox_inner_counts);
for (int i = 0; i < infobox_count; i++) {
for (int j = 0; j < INFOBOX_FIELD_COUNT; j++)
free(infobox_matrix[i][j]);
free(infobox_matrix[i]);
}
free(infobox_matrix);
free(infobox_inner_counts);
}
string_matrix_free(&infobox_matrix);
int warning_count = 0;
for (int i = 0; i < enabled_engine_count; i++) {
@ -709,33 +757,35 @@ int results_handler(UrlParams *params) {
}
if (warning_count > 0) {
StringMatrix warning_matrix;
string_matrix_init(&warning_matrix);
char ***warning_matrix = NULL;
int *warning_inner_counts = NULL;
int warning_index = 0;
for (int i = 0; i < enabled_engine_count; i++) {
const char *warning_message = warning_message_for_job(&jobs[i], locale);
if (!warning_message)
continue;
if (jobs[i].http_status >= 400) {
char warning_with_status[BUFFER_SIZE_LARGE];
snprintf(warning_with_status, sizeof(warning_with_status),
"%s (HTTP %ld)", warning_message, jobs[i].http_status);
add_warning_to_collection(jobs[i].engine->name, warning_with_status,
&warning_matrix);
} else {
add_warning_to_collection(jobs[i].engine->name, warning_message,
&warning_matrix);
}
warning_index = add_warning_to_collection(
jobs[i].engine->name, warning_message, &warning_matrix,
&warning_inner_counts, warning_index);
}
if (warning_matrix.count > 0) {
context_set_array_of_arrays(&ctx, "engine_warnings", warning_matrix.rows,
warning_matrix.count,
warning_matrix.field_counts);
if (warning_index > 0) {
context_set_array_of_arrays(&ctx, "engine_warnings", warning_matrix,
warning_index, warning_inner_counts);
}
string_matrix_free(&warning_matrix);
if (warning_matrix) {
for (int i = 0; i < warning_index; i++) {
free(warning_matrix[i][0]);
free(warning_matrix[i][1]);
free(warning_matrix[i]);
}
free(warning_matrix);
}
if (warning_inner_counts)
free(warning_inner_counts);
}
int total_results = 0;
@ -744,8 +794,33 @@ int results_handler(UrlParams *params) {
}
if (total_results > 0) {
StringMatrix results_matrix;
string_matrix_init(&results_matrix);
char ***results_matrix = (char ***)malloc(sizeof(char **) * total_results);
int *results_inner_counts = (int *)malloc(sizeof(int) * total_results);
if (!results_matrix || !results_inner_counts) {
char *html = render_template("results.html", &ctx);
if (html) {
send_response(html);
free(html);
}
for (int i = 0; i < enabled_engine_count; i++)
free(all_results[i]);
if (page == 1) {
for (int i = 0; i < HANDLER_COUNT; i++) {
if (infobox_data[i].success) {
free_infobox(&infobox_data[i].result);
}
}
}
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);
return 0;
}
int unique_count = 0;
UrlHashTable url_table;
url_hash_init(&url_table);
@ -762,45 +837,61 @@ int results_handler(UrlParams *params) {
url_hash_insert(&url_table, display_url);
results_matrix[unique_count] =
(char **)malloc(sizeof(char *) * RESULT_FIELD_COUNT);
if (!results_matrix[unique_count]) {
free(all_results[i][j].url);
free(all_results[i][j].title);
free(all_results[i][j].snippet);
continue;
}
char *pretty_url = pretty_display_url(display_url);
char *base_url = get_base_url(display_url);
const char *values[RESULT_FIELD_COUNT] = {
display_url,
pretty_url,
all_results[i][j].title ? all_results[i][j].title : "Untitled",
all_results[i][j].snippet ? all_results[i][j].snippet : "",
base_url,
"",
};
int append_result =
string_matrix_append(&results_matrix, values, RESULT_FIELD_COUNT);
results_matrix[unique_count][0] = strdup(display_url);
results_matrix[unique_count][1] = strdup(pretty_url);
results_matrix[unique_count][2] = all_results[i][j].title
? strdup(all_results[i][j].title)
: strdup("Untitled");
results_matrix[unique_count][3] =
all_results[i][j].snippet ? strdup(all_results[i][j].snippet)
: strdup("");
results_matrix[unique_count][4] = strdup(base_url ? base_url : "");
results_matrix[unique_count][5] = strdup("");
results_inner_counts[unique_count] = RESULT_FIELD_COUNT;
free(pretty_url);
free(base_url);
free(all_results[i][j].url);
free(all_results[i][j].title);
free(all_results[i][j].snippet);
if (append_result != 0) {
continue;
}
unique_count++;
}
free(all_results[i]);
}
context_set_array_of_arrays(&ctx, "results", results_matrix.rows,
results_matrix.count,
results_matrix.field_counts);
context_set_array_of_arrays(&ctx, "results", results_matrix, unique_count,
results_inner_counts);
StringMatrix pager_matrix;
SearchHrefData href_data = {.query = raw_query,
.engine_id = selected_engine_id};
int pagination_result = string_matrix_build_pagination(
page, search_href_builder, &href_data, &pager_matrix);
char ***pager_matrix = NULL;
int *pager_inner_counts = NULL;
SearchHrefData href_data = { .query = raw_query, .engine_id = selected_engine_id };
int pager_count = build_pagination(page, search_href_builder,
&href_data, &pager_matrix,
&pager_inner_counts);
if (pagination_result == 0 && pager_matrix.count > 0) {
context_set_array_of_arrays(&ctx, "pagination_links", pager_matrix.rows,
pager_matrix.count,
pager_matrix.field_counts);
if (pager_count > 0) {
context_set_array_of_arrays(&ctx, "pagination_links", pager_matrix,
pager_count, pager_inner_counts);
for (int i = 0; i < pager_count; i++) {
for (int j = 0; j < LINK_FIELD_COUNT; j++)
free(pager_matrix[i][j]);
free(pager_matrix[i]);
}
free(pager_matrix);
free(pager_inner_counts);
}
char *html = render_template("results.html", &ctx);
@ -809,8 +900,13 @@ int results_handler(UrlParams *params) {
free(html);
}
string_matrix_free(&pager_matrix);
string_matrix_free(&results_matrix);
for (int i = 0; i < unique_count; i++) {
for (int j = 0; j < RESULT_FIELD_COUNT; j++)
free(results_matrix[i][j]);
free(results_matrix[i]);
}
free(results_matrix);
free(results_inner_counts);
url_hash_free(&url_table);
} else {
char *html = render_template("results.html", &ctx);
@ -819,15 +915,26 @@ int results_handler(UrlParams *params) {
free(html);
}
free_search_results(all_results, jobs, engine_idx);
for (int i = 0; i < enabled_engine_count; i++) {
free(all_results[i]);
}
}
free(request_cache_key);
if (page == 1)
free_infobox_results(infobox_data);
if (page == 1) {
for (int i = 0; i < HANDLER_COUNT; i++) {
if (infobox_data[i].success) {
free_infobox(&infobox_data[i].result);
}
}
}
free(locale);
free_user_engine_list(user_engines, user_engine_count);
if (has_user_pref) {
for (int i = 0; i < user_engine_count; i++)
free(user_engines[i]);
free(user_engines);
}
free_context(&ctx);
return 0;

View file

@ -34,14 +34,6 @@ int settings_handler(UrlParams *params) {
int user_engine_count = 0;
int has_user_pref =
(get_user_engines(&user_engines, &user_engine_count) == 0);
char *default_engine = get_default_search_engine();
if (strcmp(default_engine, "all") != 0 && has_user_pref &&
!user_engines_contains(default_engine, user_engines,
user_engine_count)) {
free(default_engine);
default_engine = strdup("all");
}
int enabled_count = 0;
for (int i = 0; i < ENGINE_COUNT; i++) {
@ -71,13 +63,11 @@ int settings_handler(UrlParams *params) {
}
}
engine_data[idx] = malloc(sizeof(char *) * 4);
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_data[idx][3] =
strcmp(default_engine, ENGINE_REGISTRY[i].id) == 0 ? "selected" : "";
engine_inner[idx] = 4;
engine_inner[idx] = 3;
idx++;
}
@ -88,7 +78,6 @@ int settings_handler(UrlParams *params) {
context_set(&ctx, "query", query);
context_set(&ctx, "theme", theme);
context_set(&ctx, "locale", locale);
context_set(&ctx, "default_engine", default_engine);
context_set_array_of_arrays(&ctx, "locales", locale_data, locale_count,
inner_counts);
@ -143,7 +132,6 @@ int settings_handler(UrlParams *params) {
send_response(rendered_html);
free(rendered_html);
free(default_engine);
free(theme);
free(locale);
free_context(&ctx);

View file

@ -10,8 +10,6 @@ int settings_save_handler(UrlParams *params) {
const char *theme = "";
const char *locale = "";
const char *query = "";
const char *default_engine = "all";
int default_engine_present = 0;
int engines_present = 0;
char selected_ids[ENGINE_COUNT][32];
int selected_count = 0;
@ -24,9 +22,6 @@ int settings_save_handler(UrlParams *params) {
locale = params->params[i].value;
} else if (strcmp(params->params[i].key, "q") == 0) {
query = params->params[i].value;
} else if (strcmp(params->params[i].key, "default_engine") == 0) {
default_engine = params->params[i].value;
default_engine_present = 1;
} else if (strcmp(params->params[i].key, "engines_present") == 0) {
engines_present = 1;
} else if (strncmp(params->params[i].key, "engine_", 7) == 0 &&
@ -63,31 +58,6 @@ int settings_save_handler(UrlParams *params) {
false, false);
}
if (default_engine_present) {
const char *validated_default = "all";
for (int i = 0; i < ENGINE_COUNT; i++) {
if (!ENGINE_REGISTRY[i].enabled ||
strcmp(default_engine, ENGINE_REGISTRY[i].id) != 0)
continue;
int selected = !engines_present;
for (int j = 0; j < selected_count; j++) {
if (strcmp(selected_ids[j], ENGINE_REGISTRY[i].id) == 0) {
selected = 1;
break;
}
}
if (selected)
validated_default = ENGINE_REGISTRY[i].id;
break;
}
set_cookie("default_engine", validated_default,
"Fri, 31 Dec 2038 23:59:59 GMT", "/", false, false);
}
char redirect_url[512];
snprintf(redirect_url, sizeof(redirect_url), "/settings?q=%s", query);
send_redirect(redirect_url);

Some files were not shown because too many files have changed in this diff Show more