/*
 * UosSylph -- E-Mail client library
 * Copyright (C) 2020 ~ 2021 Uniontech Software Technology Co.,Ltd.
 *
 * Author:     shuiqucheng<shuiqucheng@uniontech.com>
 *
 * Maintainer: shuiqucheng<shuiqucheng@uniontech.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef __UOSUTILS_H__
#define __UOSUTILS_H__


#include "libsylph/utils.h"

#ifdef G_OS_UNIX
#define uos_syl_link syl_link
#else
#endif /* G_OS_UNIX */

#ifdef HAVE_U32_TYPEDEF
#undef uosu32 /* maybe there is a macro with this name */
typedef u32 uosu32;
#endif

typedef StrFindFunc UosStrFindFunc;

typedef stime_t uostime_t;

typedef GStatBuf UosGStatBuf;

#define UOSCHDIR_RETURN_IF_FAIL(dir) CHDIR_RETURN_IF_FAIL(dir)

#define UOSCHDIR_RETURN_VAL_IF_FAIL(dir, val) CHDIR_RETURN_VAL_IF_FAIL(dir, val)

#define UOSXalloca(ptr, size, iffail) Xalloca(ptr, size, iffail)

#define UOSXstrdup_a(ptr, str, iffail) Xstrdup_a(ptr, str, iffail)
#define UOSXstrndup_a(ptr, str, len, iffail) Xstrndup_a(ptr, str, len, iffail)

#define UOSXstrcat_a(ptr, str1, str2, iffail) Xstrcat_a(ptr, str1, str2, iffail)

#define UOSAUTORELEASE_STR(str, iffail) AUTORELEASE_STR(str, iffail)

#define UOSFILE_OP_ERROR(file, func) FILE_OP_ERROR(file, func)


typedef UIUpdateFunc UosUIUpdateFunc;
typedef EventLoopFunc UosEventLoopFunc;
typedef ProgressFunc UosProgressFunc;
typedef QueryPasswordFunc UosQueryPasswordFunc;
typedef LogFunc UosLogFunc;
typedef LogFlushFunc UosLogFlushFunc;

#define UOSStr(x) Str(x)
#define UOSXstr(x) Xstr(x)

#define UOSMSG_LEN MSG_LEN
#define UOSMSG_LEN_MIN MSG_LEN_MIN
#define UOSMSG_LEN_MAX MSG_LEN_MAX

void uos_list_free_strings(GList *list);
void uos_slist_free_strings(GSList *list);

void uos_hash_free_strings(GHashTable *table);
void uos_hash_free_value_mem(GHashTable *table);

gint uos_str_case_equal(gconstpointer v, gconstpointer v2);
guint uos_str_case_hash(gconstpointer key);

void uos_ptr_array_free_strings(GPtrArray *array);

gboolean uos_str_find(const gchar *haystack, const gchar *needle);
gboolean uos_str_case_find(const gchar *haystack, const gchar *needle);
gboolean uos_str_find_equal(const gchar *haystack, const gchar *needle);
gboolean uos_str_case_find_equal(const gchar *haystack, const gchar *needle);

gint uos_to_number(const gchar *nstr);
guint uos_to_unumber(const gchar *nstr);
gchar *uos_itos_buf(gchar *nstr, gint n);
gchar *uos_itos(gint n);
gchar *uos_utos_buf(gchar *nstr, guint n);
gchar *uos_to_human_readable_buf(gchar *buf, size_t bufsize, gint64 size);
gchar *uos_to_human_readable(gint64 size);

gint uos_strcmp2(const gchar *s1, const gchar *s2);
gint uos_path_cmp(const gchar *s1, const gchar *s2);
gboolean uos_is_path_parent(const gchar *parent, const gchar *child);

gchar *uos_strretchomp(gchar *str);
gchar *uos_strtailchomp(gchar *str, gchar tail_char);
gchar *uos_strcrchomp(gchar *str);

const gchar *uos_strcasestr(const gchar *haystack,
                        const gchar *needle);

gpointer uos_my_memmem(gconstpointer haystack, size_t haystacklen, gconstpointer needle,
                   size_t needlelen);

gchar *uos_strncpy2(gchar *dest, const gchar *src, size_t n);

gboolean uos_str_has_suffix_case(const gchar *str, const gchar *suffix);

gint uos_str_find_format_times(const gchar *haystack, gchar ch);

gboolean uos_is_next_nonascii(const gchar *s);
gint uos_get_next_word_len(const gchar *s);

gint uos_subject_compare(const gchar *s1, const gchar *s2);
gint uos_subject_compare_for_sort(const gchar *s1, const gchar *s2);
void uos_trim_subject_for_compare(gchar *str);
void uos_trim_subject_for_sort(gchar *str);
void uos_trim_subject(gchar *str);
void uos_eliminate_parenthesis(gchar *str, gchar op, gchar cl);
void uos_extract_parenthesis(gchar *str, gchar op, gchar cl);
void uos_extract_parenthesis_with_escape(gchar *str, gchar op, gchar cl);

void uos_extract_parenthesis_with_skip_quote(gchar *str, gchar quote_chr, gchar op, gchar cl);

void uos_eliminate_quote(gchar *str, gchar quote_chr);
void uos_extract_quote(gchar *str, gchar quote_chr);
void uos_extract_quote_with_escape(gchar *str, gchar quote_chr);
void uos_eliminate_address_comment(gchar *str);
gchar *uos_strchr_with_skip_quote(const gchar *str, gint quote_chr, gint c);
gchar *uos_strrchr_with_skip_quote(const gchar *str, gint quote_chr, gint c);
void uos_extract_address(gchar *str);
void uos_extract_list_id_str(gchar *str);

gchar *uos_extract_addresses(const gchar *str);

gchar *uos_normalize_address_field(const gchar *str);

gboolean uos_address_equal(const gchar *addr1, const gchar *addr2);

GSList *uos_address_list_append_orig(GSList *addr_list, const gchar *str);
GSList *uos_address_list_append(GSList *addr_list, const gchar *str);
GSList *uos_references_list_prepend(GSList *msgid_list, const gchar *str);
GSList *uos_references_list_append(GSList *msgid_list, const gchar *str);
GSList *uos_newsgroup_list_append(GSList *group_list, const gchar *str);

GList *uos_add_history(GList *list, const gchar *str);

/* modify string */
void uos_remove_return(gchar *str);
void uos_remove_space(gchar *str);
void uos_unfold_line(gchar *str);
void uos_subst_char(gchar *str, gchar orig, gchar subst);
void uos_subst_chars(gchar *str, gchar *orig, gchar subst);
void uos_subst_null(gchar *str, gint len, gchar subst);
void uos_subst_control(gchar *str, gchar subst);
void uos_subst_for_filename(gchar *str);

gchar *uos_get_alt_filename(const gchar *filename, gint count);

gboolean uos_is_header_line(const gchar *str);
gboolean uos_is_ascii_str(const gchar *str);

gint uos_get_quote_level(const gchar *str);
gint uos_check_line_length(const gchar *str, gint max_chars, gint *line);

gchar *uos_strstr_with_skip_quote(const gchar *haystack, const gchar *needle);
gchar *uos_strcasestr_with_skip_quote(const gchar *haystack, const gchar *needle);
gchar *uos_strchr_parenthesis_close(const gchar *str, gchar op, gchar cl);

gchar **uos_strsplit_parenthesis(const gchar *str, gchar op, gchar cl, gint max_tokens);
gchar **uos_strsplit_with_quote(const gchar *str, const gchar *delim, gint max_tokens);
gchar **uos_strsplit_csv(const gchar *str, gchar delim, gint max_tokens);

gchar *uos_strconcat_csv(gchar delim, const gchar *field1, ...);

gchar *uos_get_abbrev_newsgroup_name(const gchar *group, gint len);
gchar *uos_trim_string(const gchar *str, gint len);
gchar *uos_trim_string_before(const gchar *str, gint len);

GList *uos_uri_list_extract_filenames(const gchar *uri_list);
gboolean uos_is_uri_string(const gchar *str);
gchar *uos_get_uri_path(const gchar *uri);
gint uos_get_uri_len(const gchar *str);
void uos_decode_uri(gchar *decoded_uri, const gchar *encoded_uri);
void uos_decode_xdigit_encoded_str(gchar *decoded, const gchar *encoded);
gchar *uos_encode_uri(const gchar *filename);
gchar *uos_uriencode_for_filename(const gchar *filename);
gchar *uos_uriencode_for_mailto(const gchar *mailto);
gint uos_scan_mailto_url(const gchar *mailto, gchar **to, gchar **cc, gchar **bcc, gchar **subject,
                     gchar **inreplyto, gchar **body);

void uos_set_startup_dir(void);
void uos_set_rc_dir(const gchar *dir);

/* return static strings */
const gchar *uos_get_startup_dir(void);
const gchar *uos_get_home_dir(void);
const gchar *uos_get_document_dir(void);
const gchar *uos_get_rc_dir(void);
const gchar *uos_get_old_rc_dir(void);
const gchar *uos_get_mail_base_dir(void);
gchar *uos_get_news_cache_dir(void);
gchar *uos_get_imap_cache_dir(void);
gchar *uos_get_pop_cache_dir(void);
gchar *uos_get_mime_tmp_dir(void);
const gchar *uos_get_template_dir(void);
gchar *uos_get_tmp_dir(void);
gchar *uos_get_tmp_file(void);
const gchar *uos_get_domain_name(void);

off_t uos_get_file_size(const gchar *file);
off_t uos_get_file_size_as_crlf(const gchar *file);
off_t uos_get_left_file_size(FILE *fp);

gint uos_get_last_empty_line_size(FILE *fp, off_t size);

gboolean uos_file_exist(const gchar *file, gboolean allow_fifo);
gboolean uos_is_dir_exist(const gchar *dir);
gboolean uos_is_file_entry_exist(const gchar *file);
gboolean uos_dirent_is_regular_file(struct dirent *d);
gboolean uos_dirent_is_directory(struct dirent *d);

#define uos_is_file_exist(file) is_file_exist(file)
#define uos_is_file_or_fifo_exist(file) is_file_or_fifo_exist(file)

gint uos_change_dir(const gchar *dir);
gint uos_make_dir(const gchar *dir);
gint uos_make_dir_hier(const gchar *dir);
gint uos_remove_all_files(const gchar *dir);
gint uos_remove_numbered_files(const gchar *dir, guint first, guint last);
gint uos_remove_all_numbered_files(const gchar *dir);
gint uos_remove_expired_files(const gchar *dir, guint hours);
gint uos_remove_dir_recursive(const gchar *dir);
gint uos_rename_force(const gchar *oldpath, const gchar *newpath);
gint uos_copy_file(const gchar *src, const gchar *dest, gboolean keep_backup);
gint uos_copy_file_import(const gchar *src, const gchar *dest, const gchar *uosmessageid, gboolean keep_backup);
gint uos_copy_dir(const gchar *src, const gchar *dest);
gint uos_move_file(const gchar *src, const gchar *dest, gboolean overwrite);

gint uos_append_file_part(FILE *fp, off_t offset, size_t length, FILE *dest_fp);
gint uos_copy_file_part(FILE *fp, off_t offset, size_t length, const gchar *dest);

gint uos_copy_file_stream(FILE *fp, FILE *dest_fp);

gchar *uos_canonicalize_str(const gchar *str);
gint uos_canonicalize_file(const gchar *src, const gchar *dest);
gint uos_canonicalize_file_replace(const gchar *file);
FILE *uos_canonicalize_file_stream(FILE *fp, gint *length);
gint uos_uncanonicalize_file(const gchar *src, const gchar *dest);
gint uos_uncanonicalize_file_replace(const gchar *file);

gchar *uos_normalize_newlines(const gchar *str);
gchar *uos_strchomp_all(const gchar *str);

FILE *uos_get_outgoing_rfc2822_file(FILE *fp);
gchar *uos_get_outgoing_rfc2822_str(FILE *fp);
gchar *uos_generate_mime_boundary(const gchar *prefix);

gint uos_change_file_mode_rw(FILE *fp, const gchar *file);
FILE *uos_my_tmpfile(void);
FILE *uos_str_open_as_stream(const gchar *str);
gint uos_str_write_to_file(const gchar *str, const gchar *file);
gchar *uos_file_read_to_str(const gchar *file);
gchar *uos_file_read_stream_to_str(FILE *fp);

/* process execution */
gint uos_execute_async(gchar *const argv[]);
gint uos_execute_sync(gchar *const argv[]);
gint uos_execute_command_line(const gchar *cmdline, gboolean async);
gint uos_execute_command_line_async_wait(const gchar *cmdline);

gint uos_execute_open_file(const gchar *file, const gchar *content_type);
gint uos_execute_print_file(const gchar *file);
gchar *uos_get_command_output(const gchar *cmdline);

/* open URI with external browser */
gint uos_open_uri(const gchar *uri, const gchar *cmdline);

/* play sound */
gint uos_play_sound(const gchar *file, gboolean async);

/* time functions */
stime_t uos_remote_tzoffset_sec(const gchar *zone);
stime_t uos_tzoffset_sec(stime_t *now);
gchar *uos_tzoffset_buf(gchar *buf, stime_t *now);
gchar *uos_tzoffset(stime_t *now);
void uos_get_rfc822_date(gchar *buf, gint len);

size_t uos_my_strftime(gchar *s, size_t max, const gchar *format, const struct tm *tm);

/* UI hints */
void uos_set_ui_update_func(UIUpdateFunc func);
void uos_ui_update(void);

void uos_set_event_loop_func(EventLoopFunc func);
void uos_event_loop_iterate(void);

void uos_set_progress_func(ProgressFunc func);
void uos_progress_show(gint cur, gint total);

/* user input */
void uos_set_input_query_password_func(QueryPasswordFunc func);

gchar *uos_input_query_password(const gchar *server, const gchar *user);

/* logging */
void uos_set_log_file(const gchar *filename);
void uos_close_log_file(void);
void uos_set_log_verbosity(gboolean verbose);
gboolean uos_get_debug_mode(void);
void uos_set_debug_mode(gboolean enable);

void uos_set_log_ui_func(LogFunc print_func, LogFunc message_func, LogFunc warning_func,
                     LogFunc error_func);
void uos_set_log_ui_func_full(LogFunc print_func, LogFunc message_func, LogFunc warning_func,
                          LogFunc error_func, LogFlushFunc flush_func);

void uos_set_log_show_status_func(LogFunc status_func);

void uos_debug_print(const gchar *format, ...);
void uos_status_print(const gchar *format, ...);

void uos_log_write(const gchar *str, const gchar *prefix);

void uos_log_print(const gchar *format, ...);
void uos_log_message(const gchar *format, ...);
void uos_log_warning(const gchar *format, ...);
void uos_log_error(const gchar *format, ...);

void uos_log_flush(void);
unsigned long uos_max_strlen(const char *buf, unsigned long max_size);

typedef AesDecryptFunc UosAesDecryptFunc;
typedef Base64DecryptFunc UosBase64DecryptFunc;

void uos_set_log_print_qt_func(UosLogFunc func);
void uos_set_aesdecrypt_func(UosAesDecryptFunc func);
void uos_set_base64decrypt_func(UosBase64DecryptFunc func);
void uos_set_is_network_online(gboolean (*func)(void));
void uos_set_debugprint(gboolean trigger);


#endif /* __UOSUTILS_H__ */
