251 lines
6.6 KiB
C++
251 lines
6.6 KiB
C++
/*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*/
|
|
module;
|
|
|
|
#include <cstdint>
|
|
#include <sqlite3.h>
|
|
#include <string.h>
|
|
#include <gio/gio.h>
|
|
#include <curl/curl.h>
|
|
#include <sqlite3.h>
|
|
|
|
export module katja.utils;
|
|
|
|
export namespace katja
|
|
{
|
|
enum class Info
|
|
{
|
|
// Error.
|
|
unknown,
|
|
// Installed in the same version.
|
|
installed,
|
|
// A different version is installed.
|
|
updating,
|
|
// Available, but not installed.
|
|
installing,
|
|
// Available.
|
|
available
|
|
};
|
|
|
|
struct JobData
|
|
{
|
|
sqlite3 *db;
|
|
CURL *curl;
|
|
|
|
virtual void package(Info info, const char *package_id, const char *summary) = 0;
|
|
virtual void files(char **) = 0;
|
|
virtual void details(char *package_id,
|
|
const char *group, const char *description, const char *homepage, int uncompressed) = 0;
|
|
virtual void set_percentage(double) = 0;
|
|
};
|
|
|
|
/**
|
|
* katja::get_file:
|
|
* @curl: curl easy handle.
|
|
* @source_url: source url.
|
|
* @dest: destination.
|
|
*
|
|
* Download the file.
|
|
*
|
|
* Returns: CURLE_OK (zero) on success, non-zero otherwise.
|
|
**/
|
|
CURLcode get_file(CURL **curl, char *source_url, char *dest)
|
|
{
|
|
char *dest_dir_name;
|
|
FILE *fout = nullptr;
|
|
CURLcode ret;
|
|
glong response_code;
|
|
|
|
if ((*curl == nullptr) && (!(*curl = curl_easy_init())))
|
|
{
|
|
return CURLE_BAD_FUNCTION_ARGUMENT;
|
|
}
|
|
|
|
curl_easy_setopt(*curl, CURLOPT_FOLLOWLOCATION, 1L);
|
|
curl_easy_setopt(*curl, CURLOPT_URL, source_url);
|
|
|
|
if (dest == nullptr)
|
|
{
|
|
curl_easy_setopt(*curl, CURLOPT_NOBODY, 1L);
|
|
curl_easy_setopt(*curl, CURLOPT_HEADER, 1L);
|
|
ret = curl_easy_perform(*curl);
|
|
curl_easy_getinfo(*curl, CURLINFO_RESPONSE_CODE, &response_code);
|
|
|
|
if (response_code != 200)
|
|
{
|
|
ret = CURLE_REMOTE_FILE_NOT_FOUND;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (g_file_test(dest, G_FILE_TEST_IS_DIR))
|
|
{
|
|
dest_dir_name = dest;
|
|
dest = g_strconcat(dest_dir_name, g_strrstr(source_url, "/"), nullptr);
|
|
g_free(dest_dir_name);
|
|
}
|
|
if ((fout = fopen(dest, "ab")) == nullptr)
|
|
{
|
|
return CURLE_WRITE_ERROR;
|
|
}
|
|
curl_easy_setopt(*curl, CURLOPT_WRITEDATA, fout);
|
|
ret = curl_easy_perform(*curl);
|
|
}
|
|
curl_easy_reset(*curl);
|
|
if (fout != nullptr)
|
|
{
|
|
fclose(fout);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* katja::split_package_name:
|
|
* Got the name of a package, without version-arch-release data.
|
|
**/
|
|
char **split_package_name(const char *pkg_filename)
|
|
{
|
|
char *pkg_full_name;
|
|
char **pkg_tokens;
|
|
|
|
g_return_val_if_fail(pkg_filename != nullptr, nullptr);
|
|
|
|
int len = strlen(pkg_filename);
|
|
if (len < 4)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
if (pkg_filename[len - 4] == '.')
|
|
{
|
|
pkg_tokens = static_cast<char **>(g_malloc_n (6, sizeof (char *)));
|
|
|
|
/* Full name without extension */
|
|
len -= 4;
|
|
pkg_full_name = g_strndup(pkg_filename, len);
|
|
pkg_tokens[3] = g_strdup(pkg_full_name);
|
|
|
|
/* The last 3 characters should be the file extension */
|
|
pkg_tokens[4] = g_strdup(pkg_filename + len + 1);
|
|
pkg_tokens[5] = nullptr;
|
|
}
|
|
else
|
|
{
|
|
pkg_tokens = static_cast<char **>(g_malloc_n (4, sizeof (char *)));
|
|
pkg_full_name = g_strdup(pkg_filename);
|
|
pkg_tokens[3] = nullptr;
|
|
}
|
|
|
|
/* Reverse all of the bytes in the package filename to get the name, version and the architecture */
|
|
g_strreverse (pkg_full_name);
|
|
char **reversed_tokens = g_strsplit(pkg_full_name, "-", 4);
|
|
pkg_tokens[0] = g_strreverse(reversed_tokens[3]); /* Name */
|
|
pkg_tokens[1] = g_strreverse(reversed_tokens[2]); /* Version */
|
|
pkg_tokens[2] = g_strreverse(reversed_tokens[1]); /* Architecture */
|
|
|
|
g_free(reversed_tokens[0]); /* Build number */
|
|
g_free(reversed_tokens);
|
|
g_free(pkg_full_name);
|
|
|
|
return pkg_tokens;
|
|
}
|
|
|
|
/**
|
|
* katja::is_installed:
|
|
* Checks if a package is already installed in the system.
|
|
*
|
|
* @pkg_fullname: Package name should be looked for.
|
|
*
|
|
* Returns: Package installation information.
|
|
**/
|
|
Info is_installed(const char *pkg_fullname)
|
|
{
|
|
GFileEnumerator *pkg_metadata_enumerator;
|
|
GFileInfo *pkg_metadata_file_info;
|
|
GFile *pkg_metadata_dir;
|
|
Info ret = Info::installing;
|
|
const char *it;
|
|
std::uint8_t dashes = 0;
|
|
ptrdiff_t pkg_name;
|
|
|
|
g_return_val_if_fail(pkg_fullname != nullptr, Info::unknown);
|
|
|
|
// We want to find the package name without version for the package we're
|
|
// looking for.
|
|
g_debug("Looking if %s is installed", pkg_fullname);
|
|
|
|
for (it = pkg_fullname + strlen(pkg_fullname); it != pkg_fullname; --it)
|
|
{
|
|
if (*it == '-')
|
|
{
|
|
if (dashes == 2)
|
|
{
|
|
break;
|
|
}
|
|
++dashes;
|
|
}
|
|
}
|
|
if (dashes < 2)
|
|
{
|
|
return Info::unknown;
|
|
}
|
|
pkg_name = it - pkg_fullname;
|
|
|
|
// Read the package metadata directory and comprare all installed packages
|
|
// with ones in the cache.
|
|
pkg_metadata_dir = g_file_new_for_path("/var/log/packages");
|
|
if (!(pkg_metadata_enumerator = g_file_enumerate_children(pkg_metadata_dir,
|
|
"standard::name",
|
|
G_FILE_QUERY_INFO_NONE,
|
|
nullptr,
|
|
nullptr)))
|
|
{
|
|
g_object_unref(pkg_metadata_dir);
|
|
return Info::unknown;
|
|
}
|
|
|
|
while ((pkg_metadata_file_info = g_file_enumerator_next_file(pkg_metadata_enumerator, nullptr, nullptr)))
|
|
{
|
|
const char *dir = g_file_info_get_name(pkg_metadata_file_info);
|
|
dashes = 0;
|
|
|
|
if (strcmp(dir, pkg_fullname) == 0)
|
|
{
|
|
ret = Info::installed;
|
|
}
|
|
else
|
|
{
|
|
for (it = dir + strlen(dir); it != dir; --it)
|
|
{
|
|
if (*it == '-')
|
|
{
|
|
if (dashes == 2)
|
|
{
|
|
break;
|
|
}
|
|
++dashes;
|
|
}
|
|
}
|
|
if (pkg_name == (it - dir) && strncmp(pkg_fullname, dir, pkg_name) == 0)
|
|
{
|
|
ret = Info::updating;
|
|
}
|
|
}
|
|
g_object_unref(pkg_metadata_file_info);
|
|
|
|
if (ret != Info::installing) /* If installed */
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
g_object_unref(pkg_metadata_enumerator);
|
|
g_object_unref(pkg_metadata_dir);
|
|
|
|
return ret;
|
|
}
|
|
|
|
}
|