#ifndef LIB_SLAPT
#define LIB_SLAPT 1
/*
 * Copyright (C) 2003-2025 Jason Woodward <woodwardj at jaos dot org>
 *
 * 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 2 of the License, or
 * 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 Library General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <unistd.h>
#include <getopt.h>
#include <curl/curl.h>
#include <curl/easy.h>
#include <regex.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <ctype.h>
#include <openssl/evp.h>
#include <libintl.h>
#include <locale.h>
#include <sys/statvfs.h>
#include <sys/mman.h>
#include <zlib.h>
#include <utime.h>
#include <math.h>

#ifdef SLAPT_HAS_GPGME
#endif

#define SLAPT_UPDATE_OPT 'u'
#define SLAPT_UPGRADE_OPT 'g'
#define SLAPT_INSTALL_OPT 'i'
#define SLAPT_INSTALL_DISK_SET_OPT 'D'
#define SLAPT_REMOVE_OPT 'r'
#define SLAPT_SHOW_OPT 's'
#define SLAPT_SEARCH_OPT 'e'
#define SLAPT_LIST_OPT 't'
#define SLAPT_INSTALLED_OPT 'd'
#define SLAPT_CLEAN_OPT 'c'
#define SLAPT_DOWNLOAD_ONLY_OPT 'o'
#define SLAPT_SIMULATE_OPT 'm'
#define SLAPT_VERSION_OPT 'v'
#define SLAPT_NO_PROMPT_OPT 'b'
#define SLAPT_PROMPT_OPT 'y'
#define SLAPT_REINSTALL_OPT 'n'
#define SLAPT_IGNORE_EXCLUDES_OPT 'x'
#define SLAPT_NO_MD5_OPT '5'
#define SLAPT_DIST_UPGRADE_OPT 'h'
#define SLAPT_HELP_OPT 'l'
#define SLAPT_IGNORE_DEP_OPT 'p'
#define SLAPT_NO_DEP_OPT 'q'
#define SLAPT_PRINT_URIS_OPT 'P'
#define SLAPT_SHOW_STATS_OPT 'S'
#define SLAPT_CONFIG_OPT 'C'
#define SLAPT_AUTOCLEAN_OPT 'a'
#define SLAPT_OBSOLETE_OPT 'O'
#define SLAPT_AVAILABLE_OPT 'A'
#define SLAPT_RETRY_OPT 'R'
#define SLAPT_NO_UPGRADE_OPT 'N'
#ifdef SLAPT_HAS_GPGME
#define SLAPT_ADD_KEYS_OPT 'k'
#define SLAPT_ALLOW_UNAUTH 'U'
#endif
#define SLAPT_FILELIST 'f'

#define SLAPT_DO_NOT_UNLINK_BAD_FILES 1
#define SLACKWARE_EXTRA_TESTING_PASTURE_WORKAROUND 1
/*
 * Copyright (C) 2003-2025 Jason Woodward <woodwardj at jaos dot org>
 *
 * 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 2 of the License, or
 * 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 Library General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#define SLAPT_MAX_REGEX_PARTS 10
#define SLAPT_SLACK_BASE_SET_REGEX "^./slackware/a$"

typedef enum {
    SLAPT_OK = 0,
    SLAPT_MD5_CHECKSUM_MISMATCH,
    SLAPT_MD5_CHECKSUM_MISSING,
#ifdef SLAPT_HAS_GPGME
    SLAPT_GPG_KEY_IMPORTED,
    SLAPT_GPG_KEY_NOT_IMPORTED,
    SLAPT_GPG_KEY_UNCHANGED,
    SLAPT_CHECKSUMS_VERIFIED,
    SLAPT_CHECKSUMS_MISSING_KEY,
    SLAPT_CHECKSUMS_NOT_VERIFIED,
    SLAPT_CHECKSUMS_NOT_VERIFIED_NULL_CONTEXT,
    SLAPT_CHECKSUMS_NOT_VERIFIED_READ_CHECKSUMS,
    SLAPT_CHECKSUMS_NOT_VERIFIED_READ_SIGNATURE,
    SLAPT_CHECKSUMS_NOT_VERIFIED_GPGME_KEY_REVOKED,
    SLAPT_CHECKSUMS_NOT_VERIFIED_GPGME_KEY_EXPIRED,
    SLAPT_CHECKSUMS_NOT_VERIFIED_GPGME_SIG_EXPIRED,
    SLAPT_CHECKSUMS_NOT_VERIFIED_GPGME_CRL_MISSING,
    SLAPT_CHECKSUMS_NOT_VERIFIED_GPGME_CRL_TOO_OLD,
    SLAPT_CHECKSUMS_NOT_VERIFIED_GPGME_BAD_POLICY,
    SLAPT_CHECKSUMS_NOT_VERIFIED_GPGME_SYS_ERROR,
#endif
    SLAPT_DOWNLOAD_INCOMPLETE
} slapt_code_t;

typedef enum {
    SLAPT_PRIORITY_DEFAULT = 0,
    SLAPT_PRIORITY_DEFAULT_PATCH,
    SLAPT_PRIORITY_OFFICIAL,
    SLAPT_PRIORITY_OFFICIAL_PATCH,
    SLAPT_PRIORITY_PREFERRED,
    SLAPT_PRIORITY_PREFERRED_PATCH,
    SLAPT_PRIORITY_CUSTOM,
    SLAPT_PRIORITY_CUSTOM_PATCH
} slapt_priority_t;

#define SLAPT_PRIORITY_DEFAULT_TOKEN "DEFAULT"
#define SLAPT_PRIORITY_PREFERRED_TOKEN "PREFERRED"
#define SLAPT_PRIORITY_OFFICIAL_TOKEN "OFFICIAL"
#define SLAPT_PRIORITY_CUSTOM_TOKEN "CUSTOM"

typedef struct slapt_regex {
    regmatch_t pmatch[SLAPT_MAX_REGEX_PARTS];
    regex_t regex;
    size_t nmatch;
    int reg_return;
} slapt_regex_t;

typedef int (*slapt_vector_t_cmp)(const void *, const void *);
typedef int (*slapt_vector_t_qsort_cmp)(const void *, const void *);
typedef void (*slapt_vector_t_free_function)(void *);
typedef struct slapt_vector_t {
    void **items;
    slapt_vector_t_free_function free_function;
    uint32_t size;
    uint32_t capacity;
    bool sorted;
} slapt_vector_t;
slapt_vector_t *slapt_vector_t_init(slapt_vector_t_free_function);
void slapt_vector_t_free(slapt_vector_t *);
void slapt_vector_t_add(slapt_vector_t *, void *);
void slapt_vector_t_remove(slapt_vector_t *v, const void *);
void slapt_vector_t_sort(slapt_vector_t *, slapt_vector_t_qsort_cmp);
int slapt_vector_t_index_of(const slapt_vector_t *, slapt_vector_t_cmp, void *);
slapt_vector_t *slapt_vector_t_search(const slapt_vector_t *, slapt_vector_t_cmp, void *);
#define slapt_vector_t_foreach(type, item, list) \
    __extension__ \
    type item;                                   \
    if (list) for (uint32_t item##__counter__ = 0; (item##__counter__ < list->size) && (item = list->items[item##__counter__]); item##__counter__++)

FILE *slapt_open_file(const char *file_name, const char *mode);
slapt_regex_t *slapt_regex_t_init(const char *regex_string);
void slapt_regex_t_execute(slapt_regex_t *regex_t, const char *string);
/* extract the string from the match, starts with 1 (not 0) */
char *slapt_regex_t_extract_match(const slapt_regex_t *r, const char *src, const int i);
void slapt_regex_t_free(slapt_regex_t *regex_t);
void slapt_create_dir_structure(const char *dir_name);
/* generate an md5sum of filehandle */
void slapt_gen_md5_sum_of_file(FILE *f, char *result_sum);

/* Ask the user to answer yes or no.
 * return 1 on yes, 0 on no, else -1.
 */
int slapt_ask_yes_no(const char *format, ...);
char *slapt_str_replace_chr(const char *string, const char find, const char replace);
void *slapt_malloc(size_t s);
void *slapt_calloc(size_t n, size_t s);

/* return human readable error */
const char *slapt_strerror(const slapt_code_t code);
/* return human readable priority */
const char *slapt_priority_to_str(slapt_priority_t priority);
bool slapt_disk_space_check(const char *path, double space_needed);

/* utils */
slapt_vector_t *slapt_parse_delimited_list(const char *line, char delim);
char *slapt_strip_whitespace(const char *s);

size_t slapt_strlcpy(char *, const char *, size_t);

/*
  generate the directory name for the package log directory,
  considering the root environment variable if set
  caller responsible for freeing the returned data
 */
char *slapt_gen_package_log_dir_name(void);
/* empty packages from cache dir */
void slapt_clean_pkg_dir(const char *dir_name);
/*
 * Copyright (C) 2003-2025 Jason Woodward <woodwardj at jaos dot org>
 *
 * 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 2 of the License, or
 * 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 Library General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#define SLAPT_SOURCE_TOKEN "SOURCE="
#define SLAPT_DISABLED_SOURCE_TOKEN "#DISABLED="
#define SLAPT_WORKINGDIR_TOKEN "WORKINGDIR="
#define SLAPT_WORKINGDIR_TOKEN_LEN 256
#define SLAPT_EXCLUDE_TOKEN "EXCLUDE="
#define SLAPT_SOURCE_ATTRIBUTE_REGEX "(:[A-Z_,]+)$"

typedef struct slapt_source {
    char *url;
    slapt_priority_t priority;
    bool disabled;
} slapt_source_t;

typedef struct slapt_config {
    char working_dir[SLAPT_WORKINGDIR_TOKEN_LEN];
    slapt_vector_t *sources;
    slapt_vector_t *exclude_list;
    int (*progress_cb)(void *, off_t, off_t, off_t, off_t);
    uint32_t retry;
    bool download_only;
    bool dist_upgrade;
    bool simulate;
    bool no_prompt;
    bool prompt;
    bool re_install;
    bool ignore_excludes;
    bool no_md5_check;
    bool ignore_dep;
    bool disable_dep_check;
    bool print_uris;
    bool dl_stats;
    bool remove_obsolete;
    bool no_upgrade;
    bool use_priority;
    bool gpgme_allow_unauth;
} slapt_config_t;

/* initialize slapt_config_t */
slapt_config_t *slapt_config_t_init(void);
/* read the configuration from file_name.  Returns (rc_config *) or NULL */
slapt_config_t *slapt_config_t_read(const char *file_name);
/* free rc_config structure */
void slapt_config_t_free(slapt_config_t *global_config);
int slapt_config_t_write(const slapt_config_t *global_config, const char *location);
bool slapt_is_interactive(const slapt_config_t *);

/* check that working_dir exists or make it if permissions allow */
void slapt_working_dir_init(const slapt_config_t *global_config);

/* create, destroy the source struct */
slapt_source_t *slapt_source_t_init(const char *s);
void slapt_source_t_free(slapt_source_t *src);
/*
 * Copyright (C) 2003-2025 Jason Woodward <woodwardj at jaos dot org>
 *
 * 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 2 of the License, or
 * 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 Library General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#define SLAPT_PKG_PARSE_REGEX "(.*{1,})\\-(.*[\\-].*[\\-].*)\\.[ti]+[gblxkz]+[ ]{0,}$"
#define SLAPT_PKG_NAMEVER "(.*{1,})\\-(.*[\\-].*[\\-].*)"
#define SLAPT_PKG_VER "(.*)[\\-](.*)[\\-](.*)"
#define SLAPT_PKG_NAME_PATTERN "^PACKAGE NAME:[ ]{1,}(.*{1,})\\-(.*[\\-].*[\\-].*)(\\.[ti]+[gblzkx]+)[ ]{0,}$"
#define SLAPT_PKG_MIRROR_PATTERN "^PACKAGE MIRROR:[ ]+(.*)$"
#define SLAPT_PKG_PRIORITY_PATTERN "^PACKAGE PRIORITY:[ ]+([0-9]{1,})$"
#define SLAPT_PKG_LOCATION_PATTERN "^PACKAGE LOCATION:[ ]+(.*)$"
#define SLAPT_PKG_SIZEC_PATTERN "^PACKAGE SIZE [(]+compressed[)]{1,}:[ ]{1,}([0-9]{1,}) K$"
#define SLAPT_PKG_SIZEU_PATTERN "^PACKAGE SIZE [(]+uncompressed[)]{1,}:[ ]{1,}([0-9]{1,}) K$"
#define SLAPT_PKG_LOG_SIZEC_PATTERN "^COMPRESSED PACKAGE SIZE:[ ]{1,}([0-9\\.]{1,})[ ]{0,}([GgMmKk])$"
#define SLAPT_PKG_LOG_SIZEU_PATTERN "^UNCOMPRESSED PACKAGE SIZE:[ ]{1,}([0-9\\.]{1,})[ ]{0,}([GgMmKk])$"
#define SLAPT_PKG_LOG_DIR "/var/log/packages"
#define SLAPT_PKG_LIB_DIR "/var/lib/pkgtools/packages"
#define SLAPT_ROOT_ENV_NAME "ROOT"
#define SLAPT_ROOT_ENV_LEN 255
#define SLAPT_PKG_LOG_PATTERN "^(.*{1,})\\-(.*[\\-].*[\\-].*)"
#define SLAPT_MD5SUM_REGEX "([a-zA-Z0-9]{1,})[ ]{1,}([a-zA-Z0-9\\/._+\\-]{1,})\\/(.*{1,})\\-(.*[\\-].*[\\-].*)\\.[ti]+[gblzkx]+$"
#define SLAPT_REQUIRED_REGEX "^[ ]{0,}([^ \\<\\=\\>]{1,})[ ]{0,}([\\<\\=\\>]+){0,}[ ]{0,}([a-zA-Z0-9\\+\\.\\_\\-]+){0,}[ ]{0,}$"
#define SLAPT_MD5_STR_LEN 32
#define SLAPT_PKG_LIST "PACKAGES.TXT"
#define SLAPT_PKG_LIST_GZ "PACKAGES.TXT.gz"
#define SLAPT_PKG_LIST_L "package_data"
#define SLAPT_PATCHES_LIST "patches/PACKAGES.TXT"
#define SLAPT_PATCHES_LIST_GZ "patches/PACKAGES.TXT.gz"
#define SLAPT_CHANGELOG_FILE "ChangeLog.txt"
#define SLAPT_CHANGELOG_FILE_GZ "ChangeLog.txt.gz"
#define SLAPT_PATCHDIR "patches/"
#define SLAPT_REMOVE_CMD "/sbin/removepkg "
#define SLAPT_INSTALL_CMD "/sbin/installpkg "
#define SLAPT_UPGRADE_CMD "/sbin/upgradepkg --reinstall "
#define SLAPT_CHECKSUM_FILE "CHECKSUMS.md5"
#define SLAPT_CHECKSUM_FILE_GZ "CHECKSUMS.md5.gz"
#define SLAPT_HEAD_FILE_EXT ".head"
#define SLAPT_MAX_MMAP_SIZE 1024
#define SLAPT_MAX_ZLIB_BUFFER 1024

typedef enum {
    DEP_OP_ANY = 0,
    DEP_OP_OR,
    DEP_OP_EQ,
    DEP_OP_GTE,
    DEP_OP_LTE,
    DEP_OP_GT,
    DEP_OP_LT,
} slapt_dependency_op;

typedef struct slapt_dependency {
    union {
        struct {
            char *name;
            char *version;
        };
        struct {
            slapt_vector_t* alternatives;
        };
    };
    slapt_dependency_op op;
} slapt_dependency_t;
slapt_dependency_t* slapt_dependency_t_init(void);
void slapt_dependency_t_free(slapt_dependency_t *);
slapt_dependency_t *slapt_dependency_t_parse_required(const char *);

typedef struct slapt_pkg {
    char *name;
    char *version;
    char *mirror;
    char *location;
    char *description;
    char *required;
    char *conflicts;
    char *suggests;
    char *file_ext;
    slapt_vector_t *dependencies;
    uint32_t size_c;
    uint32_t size_u;
    uint32_t priority;
    bool installed;
    char md5[SLAPT_MD5_STR_LEN + 1];
} slapt_pkg_t;

typedef struct {
    slapt_pkg_t *installed;
    slapt_pkg_t *upgrade;
} slapt_pkg_upgrade_t;

slapt_pkg_upgrade_t *slapt_pkg_upgrade_t_init(slapt_pkg_t *, slapt_pkg_t *);
void slapt_pkg_upgrade_t_free(slapt_pkg_upgrade_t *);

typedef struct {
    char *pkg;
    char *error;
} slapt_pkg_err_t;

slapt_pkg_err_t *slapt_pkg_err_t_init(char *, char *);
void slapt_pkg_err_t_free(slapt_pkg_err_t *);

/* returns an empty package structure */
slapt_pkg_t *slapt_pkg_t_init(void);
/* frees the package structure */
void slapt_pkg_t_free(slapt_pkg_t *pkg);
/* generate a short description, returns (char *) on success or NULL on error, caller responsible for freeing the returned data */
char *slapt_pkg_t_short_description(const slapt_pkg_t *);
/* clean package name from package description */
char *slapt_pkg_t_clean_description(const slapt_pkg_t *);
/* generate the download url for a package, caller responsible for freeing the returned data */
char *slapt_pkg_t_url(const slapt_pkg_t *pkg);
/* compare package versions,
  returns just like strcmp,
    > 0 if a is greater than b
    < 0 if a is less than b
    0 if a and b are equal
*/
int slapt_pkg_t_cmp_versions(const char *a, const char *b);
int slapt_pkg_t_cmp(const slapt_pkg_t *a, const slapt_pkg_t *b);
/* make a copy of a package (needs to be freed with free_pkg) */
slapt_pkg_t *slapt_pkg_t_copy(slapt_pkg_t *dst, const slapt_pkg_t *src);
/* retrieve the packages changelog entry, if any.  Returns NULL otherwise, Must be chdir'd to working_dir.  */
char *slapt_pkg_t_changelog(const slapt_pkg_t *pkg);
/* returns a string representation of the package */
char *slapt_pkg_t_string(const slapt_pkg_t *pkg);
/*
  get the package filelist, returns (char *) on success or NULL on error
  caller responsible for freeing the returned data
*/
char *slapt_pkg_t_filelist(const slapt_pkg_t *pkg);
/* used by qsort */
int slapt_pkg_t_qsort_cmp(const void *a, const void *b);

/*
  update the local package cache. Must be chdir'd to working_dir.
*/
int slapt_update_pkg_cache(const slapt_config_t *global_config);
/* write pkg data to disk */
void slapt_write_pkg_data(const char *source_url, FILE *d_file, const slapt_vector_t *pkgs);
/* parse the PACKAGES.TXT file */
slapt_vector_t *slapt_parse_packages_txt(FILE *);
/*
  return a list of available packages.  Must be chdir'd to
  rc_config->working_dir.  Otherwise, open a filehandle to the package data
  and pass it to slapt_parse_packages_txt();
*/
slapt_vector_t *slapt_get_available_pkgs(void);
/* retrieve list of installed pkgs */
slapt_vector_t *slapt_get_installed_pkgs(void);

/* retrieve the newest package from package list */
slapt_pkg_t *slapt_get_newest_pkg(const slapt_vector_t *, const char *);
/* get the exact package */
slapt_pkg_t *slapt_get_exact_pkg(const slapt_vector_t *list, const char *name, const char *version);
/* lookup package by details */
slapt_pkg_t *slapt_get_pkg_by_details(const slapt_vector_t *list, const char *name, const char *version, const char *location);
/* search package list with pattern */
slapt_vector_t *slapt_search_pkg_list(const slapt_vector_t *list, const char *pattern);

/* install package by calling installpkg, returns 0 on success, -1 on error */
int slapt_install_pkg(const slapt_config_t *, const slapt_pkg_t *);
/* upgrade package by calling upgradepkg, returns 0 on success, -1 on error */
int slapt_upgrade_pkg(const slapt_config_t *global_config, const slapt_pkg_t *pkg);
/* remove package by calling removepkg, returns 0 on success, -1 on error */
int slapt_remove_pkg(const slapt_config_t *, const slapt_pkg_t *);

/* get a list of obsolete packages */
slapt_vector_t *slapt_get_obsolete_pkgs(const slapt_config_t *global_config, const slapt_vector_t *avail_pkgs, const slapt_vector_t *installed_pkgs);

/* generate the filename from the url, caller responsible for freeing the returned data */
char *slapt_gen_filename_from_url(const char *url, const char *file);
/* generate the package file name, caller responsible for freeing the returned data */
char *slapt_gen_pkg_file_name(const slapt_config_t *global_config, const slapt_pkg_t *pkg);
/* exclude pkg based on pkg name, returns 1 if package is present in the exclude list, 0 if not present */
bool slapt_is_excluded(const slapt_config_t *, const slapt_pkg_t *);
/* package is already downloaded and cached, md5sum if applicable is ok, returns slapt_code_t.  */
slapt_code_t slapt_verify_downloaded_pkg(const slapt_config_t *global_config, const slapt_pkg_t *pkg);
/* fill in the md5sum of the package */
void slapt_get_md5sums(const slapt_vector_t *pkgs, FILE *checksum_file);
/* find out the pkg file size (post download) */
size_t slapt_get_pkg_file_size(const slapt_config_t *global_config, const slapt_pkg_t *pkg);

/*
  resolve dependencies
  returns 0 on success, -1 on error setting conflict_err and missing_err
  (usually called with transaction->conflict_err and transaction->missing_err)
*/
int slapt_get_pkg_dependencies(const slapt_config_t *global_config,
                               const slapt_vector_t *avail_pkgs,
                               const slapt_vector_t *installed_pkgs,
                               const slapt_pkg_t *pkg,
                               slapt_vector_t *deps,
                               slapt_vector_t *conflict_err,
                               slapt_vector_t *missing_err);
/* return list of package conflicts */
slapt_vector_t *slapt_get_pkg_conflicts(const slapt_vector_t *avail_pkgs, const slapt_vector_t *installed_pkgs, const slapt_pkg_t *pkg);
/* return list of packages required by */
slapt_vector_t *slapt_is_required_by(const slapt_config_t *global_config,
                                     const slapt_vector_t *avail,
                                     const slapt_vector_t *installed_pkgs,
                                     slapt_vector_t *pkgs_to_install,
                                     slapt_vector_t *pkgs_to_remove,
                                     const slapt_pkg_t *pkg);

/*
  clean out old outdated packages in the cache that are no longer available
  in the current source lists (ie are not downloadable)
*/
void slapt_purge_old_cached_pkgs(const slapt_config_t *global_config, const char *dir_name, slapt_vector_t *avail_pkgs);

/*
  download the PACKAGES.TXT and CHECKSUMS.md5 files
  compressed is set if the compressed version was downloaded.
*/
slapt_vector_t *slapt_get_pkg_source_packages(const slapt_config_t *global_config, const char *url, bool *compressed);
slapt_vector_t *slapt_get_pkg_source_patches(const slapt_config_t *global_config, const char *url, bool *compressed);
FILE *slapt_get_pkg_source_checksums(const slapt_config_t *global_config, const char *url, bool *compressed);
bool slapt_get_pkg_source_changelog(const slapt_config_t *global_config, const char *url, bool *compressed);
/*
 * Copyright (C) 2003-2025 Jason Woodward <woodwardj at jaos dot org>
 *
 * 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 2 of the License, or
 * 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 Library General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#define SLAPT_NO_SSL_VERIFYPEER "SLAPT_NO_SSL_VERIFYPEER"

#include <curl/curl.h>

#ifdef CURLINFO_FILETIME_T
  typedef curl_off_t SLAPT_DOWNLOAD_FILE_TIME_T;
#else
  typedef long SLAPT_DOWNLOAD_FILE_TIME_T;
#endif

/* download data to file, resuming from bytes and preserving filetime.  returns curl code */
int slapt_download_data(FILE *fh, const char *url, size_t bytes, SLAPT_DOWNLOAD_FILE_TIME_T *filetime, const slapt_config_t *global_config);

/* retrieves the head data for the url, returns (char *) or NULL on error */
char *slapt_head_request(const char *url);

/* this fills FILE with data from url, used for PACKAGES.TXT and CHECKSUMS Returns error on failure.  */
const char *slapt_get_mirror_data_from_source(FILE *fh, const slapt_config_t *global_config, const char *base_url, const char *filename);

/* download pkg, calls download_data.  returns error on failure.  */
const char *slapt_download_pkg(const slapt_config_t *global_config, const slapt_pkg_t *pkg, const char *note);

/* this is the default progress callback if global_config->progress_cb == NULL */
int slapt_progress_callback(void *clientp, off_t dltotal, off_t dlnow, off_t ultotal, off_t ulnow);

/* generate the head cache filename, caller responsible for freeing the returned data */
char *slapt_gen_head_cache_filename(const char *filename_from_url);
/* do a head request on the mirror data to find out if it's new returns (char *) or NULL */
char *slapt_head_mirror_data(const char *wurl, const char *file);
/* clear head cache storage file */
void slapt_clear_head_cache(const char *cache_filename);
/* cache the head request */
void slapt_write_head_cache(const char *cache, const char *cache_filename);
/* read the cached head request, returns (char *) or NULL */
char *slapt_read_head_cache(const char *cache_filename);

struct slapt_progress_data {
    size_t bytes;
    time_t start;
};

struct slapt_progress_data *slapt_init_progress_data(void);
void slapt_free_progress_data(struct slapt_progress_data *d);
/*
 * Copyright (C) 2003-2025 Jason Woodward <woodwardj at jaos dot org>
 *
 * 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 2 of the License, or
 * 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 Library General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/*
  this defines the max length of the transaction summary lines, hopefully
  someday this will be replaced with a more dynamic solution.
*/
#define MAX_LINE_LEN 80

enum slapt_action {
    SLAPT_ACTION_USAGE = 0,
    SLAPT_ACTION_UPDATE,
    SLAPT_ACTION_INSTALL,
    SLAPT_ACTION_REMOVE,
    SLAPT_ACTION_SHOW,
    SLAPT_ACTION_SEARCH,
    SLAPT_ACTION_UPGRADE,
    SLAPT_ACTION_LIST,
    SLAPT_ACTION_INSTALLED,
    SLAPT_ACTION_CLEAN,
    SLAPT_ACTION_SHOWVERSION,
    SLAPT_ACTION_AUTOCLEAN,
    SLAPT_ACTION_AVAILABLE,
    SLAPT_ACTION_INSTALL_DISK_SET,
    SLAPT_ACTION_FILELIST,
#ifdef SLAPT_HAS_GPGME
    SLAPT_ACTION_ADD_KEYS,
#endif
    SLAPT_ACTION_END
};

typedef struct slapt_queue {
    union {
        slapt_pkg_t *i;
        slapt_pkg_upgrade_t *u;
    } pkg;
    enum slapt_action type;
} slapt_queue_i;
slapt_queue_i *slapt_queue_i_init(slapt_pkg_t *, slapt_pkg_upgrade_t *);
void slapt_queue_i_free(slapt_queue_i *);

typedef struct slapt_transaction {
    slapt_vector_t *install_pkgs;
    slapt_vector_t *upgrade_pkgs;
    slapt_vector_t *reinstall_pkgs;
    slapt_vector_t *remove_pkgs;
    slapt_vector_t *exclude_pkgs;
    slapt_vector_t *suggests;
    slapt_vector_t *conflict_err;
    slapt_vector_t *missing_err;
    slapt_vector_t *queue;
} slapt_transaction_t;

/* fill in transaction structure with defaults */
slapt_transaction_t *slapt_transaction_t_init(void);
/* free the transaction structure and it's members */
void slapt_transaction_t_free(slapt_transaction_t *);
/* download and install/remove/upgrade packages as defined in the transaction, returns 0 on success */
int slapt_transaction_t_run(const slapt_config_t *, slapt_transaction_t *);

/* add package for installation to transaction */
void slapt_transaction_t_add_install(slapt_transaction_t *, const slapt_pkg_t *pkg);
/* add package for removal to transaction */
void slapt_transaction_t_add_remove(slapt_transaction_t *, const slapt_pkg_t *pkg);
/* add package to upgrade to transaction */
void slapt_transaction_t_add_upgrade(slapt_transaction_t *, const slapt_pkg_t *installed_pkg, const slapt_pkg_t *upgrade_pkg);
/* add package to reinstall to transaction */
void slapt_transaction_t_add_reinstall(slapt_transaction_t *, const slapt_pkg_t *installed_pkg, const slapt_pkg_t *upgrade_pkg);
/* add package to exclude to transaction */
void slapt_transaction_t_add_exclude(slapt_transaction_t *, const slapt_pkg_t *pkg);
/* remove package from transaction, returns modified transaction */
slapt_transaction_t *slapt_transaction_t_remove(slapt_transaction_t *trxn, const slapt_pkg_t *pkg);

/* search transaction by package name.  returns true if found, false otherwise */
bool slapt_transaction_t_search(const slapt_transaction_t *, const char *pkg_name);
/* search transaction by package attributes, returns true if found, false otherwise */
bool slapt_transaction_t_search_by_pkg(const slapt_transaction_t *trxn, const slapt_pkg_t *pkg);
/* searches the upgrade list of the transaction for the present of the package, returns true if found, false if not found */
bool slapt_transaction_t_search_upgrade(const slapt_transaction_t *trxn, const slapt_pkg_t *pkg);

/* add dependencies for package to transaction, returns -1 on error, 0 otherwise */
int slapt_transaction_t_add_dependencies(const slapt_config_t *global_config,
                            slapt_transaction_t *trxn,
                            const slapt_vector_t *avail_pkgs,
                            const slapt_vector_t *installed_pkgs,
                            const slapt_pkg_t *pkg);

/* check to see if a package has a conflict already present in the transaction, returns conflicted package or NULL if none */
slapt_vector_t *slapt_transaction_t_find_conflicts(const slapt_transaction_t *trxn,
                                    const slapt_vector_t *avail_pkgs,
                                    const slapt_vector_t *installed_pkgs,
                                    const slapt_pkg_t *pkg);

/* generate a list of suggestions based on the current packages in the transaction */
void slapt_transaction_t_suggestions(slapt_transaction_t *trxn);
/*
 * Copyright (C) 2003-2025 Jason Woodward <woodwardj at jaos dot org>
 *
 * 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 2 of the License, or
 * 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 Library General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

/* http://www.gnupg.org/documentation/manuals/gpgme/Largefile-Support-_0028LFS_0029.html#Largefile-Support-_0028LFS_0029
   we now need to define _FILE_OFFSET_BITS prior to including gpgme.h
   */
#define _FILE_OFFSET_BITS 64
#include <gpgme.h>

#define SLAPT_GPG_KEY "GPG-KEY"
#define SLAPT_CHECKSUM_ASC_FILE "CHECKSUMS.md5.asc"
#define SLAPT_CHECKSUM_ASC_FILE_GZ "CHECKSUMS.md5.gz.asc"

/* retrieve the signature of the CHECKSUMS.md5 file */
FILE *slapt_get_pkg_source_checksums_signature(const slapt_config_t *global_config, const char *url, bool *compressed);
/* retrieve the package sources GPG-KEY */
FILE *slapt_get_pkg_source_gpg_key(const slapt_config_t *global_config, const char *url, bool *compressed);
/* Add the GPG-KEY to the local keyring */
slapt_code_t slapt_add_pkg_source_gpg_key(FILE *key);
/* Verify the signature is valid for the checksum file */
slapt_code_t slapt_gpg_verify_checksums(FILE *checksums, FILE *signature);
#endif
