Merge upstream/master into merge/upstream-full
All checks were successful
CI Code / Check coding style (pull_request) Successful in 32s
CI Code / Check spelling (pull_request) Successful in 15s
CI Code / Linux (debian) (pull_request) Successful in 6m43s
CI Code / Linux (ubuntu) (pull_request) Successful in 6m49s
CI Code / Linux (arch) (pull_request) Successful in 8m52s
CI Code / Code Coverage (pull_request) Successful in 7m19s

Merge profanity-im/profanity master (373 commits) into cproof fork.

Source changes (manual merge):
- src/command/: cmd_defs, cmd_funcs, cmd_ac — upstream g_new0, auto_gchar,
  launch_editor callback; keep our XEP-0308 LMC, force-encryption, CWE-134
- src/config/: preferences, tlscerts, account — upstream UNIQUE dedup,
  dynamic pad capacity; keep our db_history_result_t, scroll logic
- src/database.*: upstream g_new0 memory mgmt; keep our return types,
  add null-check fix for msg->timestamp
- src/omemo/, src/pgp/: upstream _gpgme_key_get_email, g_new0;
  keep our replace_id in omemo_on_message_send
- src/tools/: editor, http_upload, bookmark_ignore — upstream launch_editor
  callback API
- src/ui/: console, window, chatwin, mucwin, inputwin, buffer —
  upstream win_warn_needed/sent dedup, PAD_MIN_HEIGHT dynamic pads;
  keep our y_start_pos scroll, _truncate_datetime_suffix
- src/xmpp/: message, stanza, presence, roster_list, iq, session —
  upstream connection_get_available_resources; keep our LMC stanza logic
- src/common.c: fix format-security (cons_show)

Build system:
- Makefile.am: updated test paths to subdirectory structure, added
  test_cmd_ac, test_forced_encryption
- Restored autotools files deleted by upstream meson migration:
  bootstrap.sh, autogen.sh, m4/ax_valgrind_check.m4, configure-debug

Tests:
- Unit tests: upstream unittests.c base + our forced_encryption tests
  (482 passed, 0 failed across all 4 configurations)
- Functional tests: kept our version (93 passed, 0 failed)
  upstream version requires stbbr_for_xmlns not yet in our stabber fork
- Updated test stubs: stub_xmpp.c, stub_omemo.c from upstream

Compile fixes:
- src/common.c: cons_show(errmsg) -> cons_show("%s", errmsg)
- src/database.c: null-check before msg->timestamp access
- src/ui/console.c: size_t -> (int) cast for format width
- src/config/tlscerts.c: %d -> %zu for size_t
This commit is contained in:
2026-04-11 13:12:23 +03:00
301 changed files with 10361 additions and 9361 deletions

View File

@@ -3,35 +3,9 @@
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2018 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2018 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -267,13 +241,7 @@ _chat_log_chat(const char* const login, const char* const other, const char* msg
g_string_free(other_str, TRUE);
}
if (timestamp == NULL) {
timestamp = g_date_time_new_now_local();
} else {
g_date_time_ref(timestamp);
}
auto_gchar gchar* date_fmt = g_date_time_format_iso8601(timestamp);
auto_gchar gchar* date_fmt = prof_date_time_format_iso8601(timestamp);
FILE* chatlogp = fopen(dated_log->filename, "a");
g_chmod(dated_log->filename, S_IRUSR | S_IWUSR);
if (chatlogp) {
@@ -304,8 +272,6 @@ _chat_log_chat(const char* const login, const char* const other, const char* msg
log_error("Error closing file %s, errno = %d", dated_log->filename, errno);
}
}
g_date_time_unref(timestamp);
}
void
@@ -373,9 +339,7 @@ _groupchat_log_chat(const gchar* const login, const gchar* const room, const gch
g_hash_table_replace(logs, strdup(room), dated_log);
}
GDateTime* dt_tmp = g_date_time_new_now_local();
auto_gchar gchar* date_fmt = g_date_time_format_iso8601(dt_tmp);
auto_gchar gchar* date_fmt = prof_date_time_format_iso8601(NULL);
FILE* grpchatlogp = fopen(dated_log->filename, "a");
g_chmod(dated_log->filename, S_IRUSR | S_IWUSR);
@@ -392,8 +356,6 @@ _groupchat_log_chat(const gchar* const login, const gchar* const room, const gch
log_error("Error closing file %s, errno = %d", dated_log->filename, errno);
}
}
g_date_time_unref(dt_tmp);
}
static char*
@@ -418,7 +380,7 @@ _create_chatlog(const char* const other, const char* const login)
GDateTime* now = g_date_time_new_now_local();
auto_char char* filename = _get_log_filename(other, login, now, FALSE);
struct dated_chat_log* new_log = malloc(sizeof(struct dated_chat_log));
struct dated_chat_log* new_log = g_new0(struct dated_chat_log, 1);
new_log->filename = strdup(filename);
new_log->date = now;
@@ -431,7 +393,7 @@ _create_groupchat_log(const char* const room, const char* const login)
GDateTime* now = g_date_time_new_now_local();
auto_char char* filename = _get_log_filename(room, login, now, TRUE);
struct dated_chat_log* new_log = malloc(sizeof(struct dated_chat_log));
struct dated_chat_log* new_log = g_new0(struct dated_chat_log, 1);
new_log->filename = strdup(filename);
new_log->date = now;

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef CHATLOG_H

View File

@@ -3,35 +3,9 @@
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2019 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2019 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -69,6 +43,7 @@
static char* _sub_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _notify_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _theme_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _spellcheck_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _autoaway_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _autoconnect_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _account_autocomplete(ProfWin* window, const char* const input, gboolean previous);
@@ -134,6 +109,7 @@ static char* _lastactivity_autocomplete(ProfWin* window, const char* const input
static char* _intype_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _mood_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _strophe_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _stamp_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _adhoc_cmd_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _vcard_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _force_encryption_autocomplete(ProfWin* window, const char* const input, gboolean previous);
@@ -164,6 +140,7 @@ static Autocomplete autoconnect_ac;
static Autocomplete wintitle_ac;
static Autocomplete theme_ac;
static Autocomplete theme_load_ac;
static Autocomplete spellcheck_ac;
static Autocomplete account_ac;
static Autocomplete account_set_ac;
static Autocomplete account_clear_ac;
@@ -287,6 +264,8 @@ static Autocomplete mood_type_ac;
static Autocomplete strophe_ac;
static Autocomplete strophe_sm_ac;
static Autocomplete strophe_verbosity_ac;
static Autocomplete stamp_ac;
static Autocomplete stamp_unset_ac;
static Autocomplete adhoc_cmd_ac;
static Autocomplete lastactivity_ac;
static Autocomplete vcard_ac;
@@ -300,6 +279,8 @@ static Autocomplete vcard_address_type_ac;
static Autocomplete force_encryption_ac;
static Autocomplete force_encryption_policy_ac;
static char* last_filepath_input = NULL;
static Autocomplete* all_acs[] = {
&commands_ac,
&who_room_ac,
@@ -322,6 +303,7 @@ static Autocomplete* all_acs[] = {
&autoconnect_ac,
&wintitle_ac,
&theme_ac,
&spellcheck_ac,
&account_ac,
&account_set_ac,
&account_clear_ac,
@@ -441,6 +423,8 @@ static Autocomplete* all_acs[] = {
&strophe_ac,
&strophe_sm_ac,
&strophe_verbosity_ac,
&stamp_ac,
&stamp_unset_ac,
&adhoc_cmd_ac,
&lastactivity_ac,
&vcard_ac,
@@ -587,6 +571,11 @@ cmd_ac_init(void)
autocomplete_add(theme_ac, "colours");
autocomplete_add(theme_ac, "properties");
autocomplete_add(spellcheck_ac, "on");
autocomplete_add(spellcheck_ac, "off");
autocomplete_add(spellcheck_ac, "list");
autocomplete_add(spellcheck_ac, "lang");
autocomplete_add(disco_ac, "info");
autocomplete_add(disco_ac, "items");
@@ -858,8 +847,9 @@ cmd_ac_init(void)
autocomplete_add(tls_property_ac, "force");
autocomplete_add(tls_property_ac, "allow");
autocomplete_add(tls_property_ac, "trust");
autocomplete_add(tls_property_ac, "legacy");
autocomplete_add(tls_property_ac, "direct");
autocomplete_add(tls_property_ac, "disable");
autocomplete_add(tls_property_ac, "legacy");
autocomplete_add(auth_property_ac, "default");
autocomplete_add(auth_property_ac, "legacy");
@@ -1185,6 +1175,13 @@ cmd_ac_init(void)
autocomplete_add(strophe_verbosity_ac, "2");
autocomplete_add(strophe_verbosity_ac, "3");
autocomplete_add(stamp_ac, "outgoing");
autocomplete_add(stamp_ac, "incoming");
autocomplete_add(stamp_ac, "unset");
autocomplete_add(stamp_unset_ac, "outgoing");
autocomplete_add(stamp_unset_ac, "incoming");
autocomplete_add(mood_ac, "set");
autocomplete_add(mood_ac, "clear");
autocomplete_add(mood_ac, "on");
@@ -1414,6 +1411,7 @@ cmd_ac_init(void)
g_hash_table_insert(ac_funcs, "/status", _status_autocomplete);
g_hash_table_insert(ac_funcs, "/statusbar", _statusbar_autocomplete);
g_hash_table_insert(ac_funcs, "/strophe", _strophe_autocomplete);
g_hash_table_insert(ac_funcs, "/stamp", _stamp_autocomplete);
g_hash_table_insert(ac_funcs, "/sub", _sub_autocomplete);
g_hash_table_insert(ac_funcs, "/subject", _subject_autocomplete);
g_hash_table_insert(ac_funcs, "/theme", _theme_autocomplete);
@@ -1557,6 +1555,10 @@ cmd_ac_remove_form_fields(DataForm* form)
char*
cmd_ac_complete(ProfWin* window, const char* const input, gboolean previous)
{
if (!input) {
return NULL;
}
char* found = NULL;
// autocomplete command
if ((strncmp(input, "/", 1) == 0) && (!strchr(input, ' '))) {
@@ -1660,65 +1662,74 @@ cmd_ac_uninit(void)
autocomplete_free(plugins_unload_ac);
autocomplete_free(plugins_reload_ac);
autocomplete_free(script_show_ac);
g_free(last_filepath_input);
last_filepath_input = NULL;
g_hash_table_destroy(ac_funcs);
ac_funcs = NULL;
}
static void
_filepath_item_free(char** ptr)
_filepath_item_free(gchar** ptr)
{
char* item = *ptr;
free(item);
gchar* item = *ptr;
g_free(item);
}
char*
cmd_ac_complete_filepath(const char* const input, char* const startstr, gboolean previous)
{
unsigned int output_off = 0;
char* tmp = NULL;
// strip command
char* inpcp = (char*)input + strlen(startstr);
while (*inpcp == ' ') {
inpcp++;
char* inpcp_ptr = (char*)input + strlen(startstr);
while (*inpcp_ptr == ' ') {
inpcp_ptr++;
}
inpcp = strdup(inpcp);
// strip quotes
if (*inpcp == '"') {
tmp = strrchr(inpcp + 1, '"');
if (tmp) {
*tmp = '\0';
}
tmp = strdup(inpcp + 1);
free(inpcp);
inpcp = tmp;
tmp = NULL;
}
// expand ~ to $HOME
if (inpcp[0] == '~' && inpcp[1] == '/') {
char* home = getenv("HOME");
if (!home) {
free(inpcp);
return NULL;
}
tmp = g_strdup_printf("%s/%sfoo", home, inpcp + 2);
output_off = strlen(home) + 1;
} else {
tmp = g_strdup_printf("%sfoo", inpcp);
}
free(inpcp);
if (!tmp) {
auto_gchar gchar* inpcp = g_strdup(inpcp_ptr);
if (!inpcp) {
return NULL;
}
char* foofile = strdup(basename(tmp));
char* directory = strdup(dirname(tmp));
g_free(tmp);
// strip quotes
if (inpcp[0] == '"') {
char* last_quote = strrchr(inpcp + 1, '"');
if (last_quote) {
*last_quote = '\0';
}
gchar* unquoted = g_strdup(inpcp + 1);
g_free(inpcp);
inpcp = unquoted;
}
GArray* files = g_array_new(TRUE, FALSE, sizeof(char*));
auto_gchar gchar* expanded = get_expanded_path(inpcp);
if (!expanded) {
return NULL;
}
auto_gchar gchar* foofile = g_path_get_basename(expanded);
auto_gchar gchar* directory = g_path_get_dirname(expanded);
// If the input is already a known completion, don't update to allow cycling
if (last_filepath_input && (g_strcmp0(inpcp, last_filepath_input) == 0 || autocomplete_contains(filepath_ac, inpcp))) {
return autocomplete_param_with_ac(input, startstr, filepath_ac, TRUE, previous);
}
// If the input ends with a slash, the basename will be "." or "/"
// In that case, we are looking for all files in that directory
gboolean find_all = FALSE;
size_t inpcp_len = strlen(inpcp);
if (inpcp_len == 0 || inpcp[inpcp_len - 1] == '/') {
find_all = TRUE;
}
char* last_slash = strrchr(inpcp, '/');
auto_gchar gchar* user_dir_part = NULL;
if (last_slash) {
user_dir_part = g_strndup(inpcp, last_slash - inpcp + 1);
} else {
user_dir_part = g_strdup("");
}
GArray* files = g_array_new(TRUE, FALSE, sizeof(gchar*));
g_array_set_clear_func(files, (GDestroyNotify)_filepath_item_free);
DIR* d = opendir(directory);
@@ -1726,47 +1737,48 @@ cmd_ac_complete_filepath(const char* const input, char* const startstr, gboolean
struct dirent* dir;
while ((dir = readdir(d)) != NULL) {
if (strcmp(dir->d_name, ".") == 0) {
continue;
} else if (strcmp(dir->d_name, "..") == 0) {
continue;
} else if (*(dir->d_name) == '.' && *foofile != '.') {
// only show hidden files on explicit request
if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) {
continue;
}
char* acstring = NULL;
if (output_off) {
tmp = g_strdup_printf("%s/%s", directory, dir->d_name);
if (tmp) {
acstring = g_strdup_printf("~/%s", tmp + output_off);
g_free(tmp);
}
} else if (strcmp(directory, "/") == 0) {
acstring = g_strdup_printf("/%s", dir->d_name);
} else {
acstring = g_strdup_printf("%s/%s", directory, dir->d_name);
}
if (!acstring) {
g_array_free(files, TRUE);
free(foofile);
free(directory);
return NULL;
// check if it matches prefix
if (!find_all && !g_str_has_prefix(dir->d_name, foofile)) {
continue;
}
g_array_append_val(files, acstring);
// only show hidden files on explicit request
if (dir->d_name[0] == '.' && (find_all || foofile[0] != '.')) {
continue;
}
gchar* acstring = g_strdup_printf("%s%s", user_dir_part, dir->d_name);
if (acstring) {
g_array_append_val(files, acstring);
}
}
closedir(d);
}
free(directory);
free(foofile);
autocomplete_update(filepath_ac, (char**)files->data);
g_array_free(files, TRUE);
g_free(last_filepath_input);
last_filepath_input = g_strdup(inpcp);
return autocomplete_param_with_ac(input, startstr, filepath_ac, TRUE, previous);
}
static char*
_spellcheck_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/spellcheck", spellcheck_ac, TRUE, previous);
return result;
}
static char*
_cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previous)
{
@@ -1779,13 +1791,18 @@ _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previ
"/history", "/vercheck", "/privileges", "/wrap",
"/carbons", "/slashguard", "/mam", "/silence" };
for (int i = 0; i < ARRAY_SIZE(boolean_choices); i++) {
for (size_t i = 0; i < ARRAY_SIZE(boolean_choices); i++) {
result = autocomplete_param_with_func(input, boolean_choices[i], prefs_autocomplete_boolean_choice, previous, NULL);
if (result) {
return result;
}
}
result = _spellcheck_autocomplete(window, input, previous);
if (result) {
return result;
}
// autocomplete nickname in chat rooms
if (window->type == WIN_MUC) {
ProfMucWin* mucwin = (ProfMucWin*)window;
@@ -1796,7 +1813,7 @@ _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previ
// Remove quote character before and after names when doing autocomplete
char* unquoted = strip_arg_quotes(input);
for (int i = 0; i < ARRAY_SIZE(nick_choices); i++) {
for (size_t i = 0; i < ARRAY_SIZE(nick_choices); i++) {
result = autocomplete_param_with_ac(unquoted, nick_choices[i], nick_ac, TRUE, previous);
if (result) {
free(unquoted);
@@ -1811,7 +1828,7 @@ _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previ
gchar* contact_choices[] = { "/msg", "/info" };
// Remove quote character before and after names when doing autocomplete
char* unquoted = strip_arg_quotes(input);
for (int i = 0; i < ARRAY_SIZE(contact_choices); i++) {
for (size_t i = 0; i < ARRAY_SIZE(contact_choices); i++) {
result = autocomplete_param_with_func(unquoted, contact_choices[i], roster_contact_autocomplete, previous, NULL);
if (result) {
free(unquoted);
@@ -1826,7 +1843,7 @@ _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previ
free(unquoted);
gchar* resource_choices[] = { "/caps", "/ping" };
for (int i = 0; i < ARRAY_SIZE(resource_choices); i++) {
for (size_t i = 0; i < ARRAY_SIZE(resource_choices); i++) {
result = autocomplete_param_with_func(input, resource_choices[i], roster_fulljid_autocomplete, previous, NULL);
if (result) {
return result;
@@ -1835,7 +1852,7 @@ _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previ
}
gchar* invite_choices[] = { "/join" };
for (int i = 0; i < ARRAY_SIZE(invite_choices); i++) {
for (size_t i = 0; i < ARRAY_SIZE(invite_choices); i++) {
result = autocomplete_param_with_func(input, invite_choices[i], muc_invites_find, previous, NULL);
if (result) {
return result;
@@ -1855,7 +1872,7 @@ _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previ
{ "/inputwin", winpos_ac },
};
for (int i = 0; i < ARRAY_SIZE(ac_cmds); i++) {
for (size_t i = 0; i < ARRAY_SIZE(ac_cmds); i++) {
result = autocomplete_param_with_ac(input, ac_cmds[i].cmd, ac_cmds[i].completer, TRUE, previous);
if (result) {
return result;
@@ -1875,7 +1892,8 @@ _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previ
}
parsed[i] = '\0';
char* (*ac_func)(ProfWin*, const char* const, gboolean) = g_hash_table_lookup(ac_funcs, parsed);
char* (*ac_func)(ProfWin*, const char* const, gboolean) = (char* (*)(ProfWin*, const char* const, gboolean))g_hash_table_lookup(ac_funcs, parsed);
if (ac_func) {
result = ac_func(window, input, previous);
if (result) {
@@ -1944,7 +1962,7 @@ _who_autocomplete(ProfWin* window, const char* const input, gboolean previous)
"/who chat", "/who away", "/who xa", "/who dnd", "/who available",
"/who unavailable" };
for (int i = 0; i < ARRAY_SIZE(group_commands); i++) {
for (size_t i = 0; i < ARRAY_SIZE(group_commands); i++) {
result = autocomplete_param_with_func(input, group_commands[i], roster_group_autocomplete, previous, NULL);
if (result) {
return result;
@@ -2266,7 +2284,7 @@ _notify_autocomplete(ProfWin* window, const char* const input, gboolean previous
gchar* boolean_choices1[] = { "/notify room current", "/notify chat current", "/notify typing current",
"/notify room text", "/notify chat text", "/notify room offline" };
for (int i = 0; i < ARRAY_SIZE(boolean_choices1); i++) {
for (size_t i = 0; i < ARRAY_SIZE(boolean_choices1); i++) {
result = autocomplete_param_with_func(input, boolean_choices1[i], prefs_autocomplete_boolean_choice, previous, NULL);
if (result) {
return result;
@@ -2299,7 +2317,7 @@ _notify_autocomplete(ProfWin* window, const char* const input, gboolean previous
}
gchar* boolean_choices2[] = { "/notify invite", "/notify sub", "/notify mention", "/notify trigger" };
for (int i = 0; i < ARRAY_SIZE(boolean_choices2); i++) {
for (size_t i = 0; i < ARRAY_SIZE(boolean_choices2); i++) {
result = autocomplete_param_with_func(input, boolean_choices2[i], prefs_autocomplete_boolean_choice, previous, NULL);
if (result) {
return result;
@@ -3745,7 +3763,7 @@ _account_autocomplete(ProfWin* window, const char* const input, gboolean previou
"/account disable", "/account rename", "/account clear", "/account remove",
"/account default set" };
for (int i = 0; i < ARRAY_SIZE(account_choice); i++) {
for (size_t i = 0; i < ARRAY_SIZE(account_choice); i++) {
found = autocomplete_param_with_func(input, account_choice[i], accounts_find_all, previous, NULL);
if (found) {
return found;
@@ -4262,6 +4280,20 @@ _strophe_autocomplete(ProfWin* window, const char* const input, gboolean previou
return autocomplete_param_with_ac(input, "/strophe", strophe_ac, FALSE, previous);
}
static char*
_stamp_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/stamp unset", stamp_unset_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/stamp", stamp_ac, TRUE, previous);
return result;
}
static char*
_adhoc_cmd_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
@@ -4286,7 +4318,7 @@ _vcard_autocomplete(ProfWin* window, const char* const input, gboolean previous)
gboolean is_num = TRUE;
if (num_args >= 2) {
for (int i = 0; i < strlen(args[1]); i++) {
for (size_t i = 0; i < strlen(args[1]); i++) {
if (!isdigit((int)args[1][i])) {
is_num = FALSE;
break;

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef COMMAND_CMD_AC_H

View File

@@ -3,35 +3,9 @@
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2019 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2019 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -105,6 +79,9 @@ static gboolean _cmd_has_tag(Command* pcmd, const char* const tag);
* Command list
*/
#define CMD_TLS_DIRECT "Use direct TLS for the connection. It means TLS handshake is started right after TCP connection is established."
#define CMD_TLS_LEGACY "Alternative keyword for 'direct', which was created when one still thought that 'STARTTLS' is the future."
// clang-format off
static const struct cmd_t command_defs[] = {
{ CMD_PREAMBLE("/help",
@@ -147,7 +124,7 @@ static const struct cmd_t command_defs[] = {
CMD_TAG_CONNECTION)
CMD_SYN(
"/connect [<account>]",
"/connect <account> [server <server>] [port <port>] [tls force|allow|trust|legacy|disable] [auth default|legacy]",
"/connect <account> [server <server>] [port <port>] [tls force|allow|trust|direct|disable|legacy] [auth default|legacy]",
"/connect <server>")
CMD_DESC(
"Login to a chat service. "
@@ -162,8 +139,9 @@ static const struct cmd_t command_defs[] = {
{ "tls force", "Force TLS connection, and fail if one cannot be established, this is default behaviour." },
{ "tls allow", "Use TLS for the connection if it is available." },
{ "tls trust", "Force TLS connection and trust server's certificate." },
{ "tls legacy", "Use legacy TLS for the connection. It means server doesn't support STARTTLS and TLS is forced just after TCP connection is established." },
{ "tls direct", CMD_TLS_DIRECT },
{ "tls disable", "Disable TLS for the connection." },
{ "tls legacy", CMD_TLS_LEGACY },
{ "auth default", "Default authentication process." },
{ "auth legacy", "Allow legacy authentication." })
CMD_EXAMPLES(
@@ -404,15 +382,17 @@ static const struct cmd_t command_defs[] = {
CMD_DESC(
"Manage blocked users (XEP-0191), calling with no arguments shows the current list of blocked users. "
"To blog a certain user in a MUC use the following as jid: room@conference.example.org/spammy-user"
"It is also possible to block and report (XEP-0377) a user with the report-abuse and report-spam commands.")
"It is also possible to block and report (XEP-0377) a user with the report-abuse and report-spam commands. "
"For spam reporting, please include the content of the spam message as evidence for the service operator.")
CMD_ARGS(
{ "add [<jid>]", "Block the specified Jabber ID. If in a chat window and no jid is specified, the current recipient will be blocked." },
{ "remove <jid>", "Remove the specified Jabber ID from the blocked list." },
{ "report-abuse <jid> [<message>]", "Report the jid as abuse with an optional message to the service operator." },
{ "report-spam <jid> [<message>]", "Report the jid as spam with an optional message to the service operator." })
{ "report-abuse <jid> [<message>]", "Report a user for abuse with an optional description of the behavior." },
{ "report-spam <jid> [<message>]", "Report a user for spam, including the actual spam message as evidence." })
CMD_EXAMPLES(
"/blocked add hel@helheim.edda",
"/blocked report-spam hel@helheim.edda Very annoying guy",
"/blocked report-abuse hel@helheim.edda Harassing me in MUC",
"/blocked report-spam spambot@example.com \"You won a free prize!\"",
"/blocked add profanity@rooms.dismail.de/spammy-user")
},
@@ -1472,6 +1452,23 @@ static const struct cmd_t command_defs[] = {
{ "on|off", "Enable or disable splash logo." })
},
{ CMD_PREAMBLE("/spellcheck",
parse_args, 1, 2, &cons_spellcheck_setting)
CMD_MAINFUNC(cmd_spellcheck)
CMD_TAGS(
CMD_TAG_UI)
CMD_SYN(
"/spellcheck on|off",
"/spellcheck list",
"/spellcheck lang <locale>")
CMD_DESC(
"Enable or disable spellchecking, or set the language.")
CMD_ARGS(
{ "on|off", "Enable or disable spellchecking." },
{ "list", "List available dictionaries recognized by Enchant." },
{ "lang <locale>", "Set the spellcheck language (en_US)." })
},
{ CMD_PREAMBLE("/autoconnect",
parse_args, 1, 2, &cons_autoconnect_setting)
CMD_MAINFUNC(cmd_autoconnect)
@@ -2071,7 +2068,7 @@ static const struct cmd_t command_defs[] = {
"/account set <account> pgpkeyid <pgpkeyid>",
"/account set <account> startscript <script>",
"/account set <account> clientid \"<name> <version>\"",
"/account set <account> tls force|allow|trust|legacy|disable",
"/account set <account> tls force|allow|trust|direct|disable|legacy",
"/account set <account> auth default|legacy",
"/account set <account> theme <theme>",
"/account set <account> session_alarm <max_sessions>",
@@ -2117,8 +2114,9 @@ static const struct cmd_t command_defs[] = {
{ "set <account> tls force", "Force TLS connection, and fail if one cannot be established, this is default behaviour." },
{ "set <account> tls allow", "Use TLS for the connection if it is available." },
{ "set <account> tls trust", "Force TLS connection and trust server's certificate." },
{ "set <account> tls legacy", "Use legacy TLS for the connection. It means server doesn't support STARTTLS and TLS is forced just after TCP connection is established." },
{ "set <account> tls direct", CMD_TLS_DIRECT },
{ "set <account> tls disable", "Disable TLS for the connection." },
{ "set <account> tls legacy", CMD_TLS_LEGACY },
{ "set <account> auth default", "Use default authentication process." },
{ "set <account> auth legacy", "Allow legacy authentication." },
{ "set <account> theme <theme>", "Set the UI theme for the account." },
@@ -2145,6 +2143,7 @@ static const struct cmd_t command_defs[] = {
"/account set me status dnd",
"/account set me dnd -1",
"/account set me clientid \"Profanity 0.42 (Dev)\"",
"/account set me eval_password \"pass \\\"Test Accounts/my user\\\"\"",
"/account rename me chattyme",
"/account clear me pgpkeyid")
},
@@ -2328,13 +2327,18 @@ static const struct cmd_t command_defs[] = {
"/omemo clear_device_list",
"/omemo qrcode")
CMD_DESC(
"OMEMO commands to manage keys, and perform encryption during chat sessions.")
"OMEMO commands to manage keys, and perform encryption during chat sessions.\n"
"The title bar will show the OMEMO session status:\n"
"[OMEMO][trusted] - All active devices for the contact are trusted.\n"
"[OMEMO][untrusted] - One or more active devices for the contact are untrusted.\n")
CMD_ARGS(
{ "gen", "Generate OMEMO cryptographic materials for current account." },
{ "start [<contact>]", "Start an OMEMO session with contact, or current recipient if omitted." },
{ "end", "End the current OMEMO session." },
{ "log on|off", "Enable or disable plaintext logging of OMEMO encrypted messages." },
{ "log redact", "Log OMEMO encrypted messages, but replace the contents with [redacted]." },
{ "trust [<contact>] <fp>", "Trust a fingerprint for a contact, or current recipient if omitted. If all active devices are trusted, the title bar will show [trusted]. Otherwise, it will show [untrusted]." },
{ "untrust [<contact>] <fp>","Untrust a fingerprint for a contact, or current recipient if omitted." },
{ "fingerprint [<contact>]", "Show contact's fingerprints, or current recipient's if omitted." },
{ "char <char>", "Set the character to be displayed next to OMEMO encrypted messages." },
{ "trustmode manual", "Set the global OMEMO trust mode to manual, OMEMO keys has to be trusted manually." },
@@ -2353,6 +2357,15 @@ static const struct cmd_t command_defs[] = {
"/omemo char *")
},
{ CMD_PREAMBLE("/changes",
parse_args, 0, 0, NULL)
CMD_MAINFUNC(cmd_changes)
CMD_SYN(
"/changes")
CMD_DESC(
"Show changes from saved configuration file.")
},
{ CMD_PREAMBLE("/save",
parse_args, 0, 0, NULL)
CMD_MAINFUNC(cmd_save)
@@ -2411,7 +2424,7 @@ static const struct cmd_t command_defs[] = {
"/stamp unset outgoing|incoming")
CMD_DESC("Set chat window stamp. "
"The format of line in the chat window is: \"<timestamp> <encryption sign> <stamp> <message>\" "
"where <stamp> is \"me:\" for incoming messages or \"username@server/resource\" for outgoing messages. "
"where <stamp> is \"me:\" for outgoing messages or \"username@server/resource\" for incoming messages. "
"This command allows to change <stamp> value.")
CMD_ARGS({ "outgoing", "Set outgoing stamp" },
{ "incoming", "Set incoming stamp"},
@@ -2651,7 +2664,7 @@ static const struct cmd_t command_defs[] = {
CMD_TAGS(
CMD_TAG_CONNECTION)
CMD_SYN(
"/register <username> <server> [port <port>] [tls force|allow|trust|legacy|disable]")
"/register <username> <server> [port <port>] [tls force|allow|trust|direct|disable|legacy]")
CMD_DESC(
"Register an account on a server.")
CMD_ARGS(
@@ -2661,8 +2674,9 @@ static const struct cmd_t command_defs[] = {
{ "tls force", "Force TLS connection, and fail if one cannot be established. This is the default behavior." },
{ "tls allow", "Use TLS for the connection if it is available." },
{ "tls trust", "Force TLS connection and trust the server's certificate." },
{ "tls legacy", "Use legacy TLS for the connection. This forces TLS just after the TCP connection is established. Use when a server doesn't support STARTTLS." },
{ "tls disable", "Disable TLS for the connection." })
{ "tls direct", CMD_TLS_DIRECT },
{ "tls disable", "Disable TLS for the connection." },
{ "tls legacy", CMD_TLS_LEGACY })
CMD_EXAMPLES(
"/register odin valhalla.edda ",
"/register freyr vanaheimr.edda port 5678",
@@ -2808,7 +2822,7 @@ _cmd_index(const Command* cmd)
g_string_free(index_source, TRUE);
GString* index = g_string_new("");
for (int i = 0; i < g_strv_length(tokens); i++) {
for (guint i = 0; i < g_strv_length(tokens); i++) {
index = g_string_append(index, tokens[i]);
index = g_string_append(index, " ");
}
@@ -2985,16 +2999,11 @@ command_docgen(void)
cmds = g_list_insert_sorted(cmds, (gpointer)pcmd, (GCompareFunc)_cmp_command);
}
FILE* toc_fragment = fopen("toc_fragment.html", "w");
if (!toc_fragment) {
log_error("command_docgen(): unable to open toc_fragment.html for writing: %s", g_strerror(errno));
g_list_free(cmds);
return;
}
FILE* main_fragment = fopen("main_fragment.html", "w");
if (!main_fragment) {
log_error("command_docgen(): unable to open main_fragment.html for writing: %s", g_strerror(errno));
fclose(toc_fragment);
auto_FILE FILE* toc_fragment = fopen("toc_fragment.html", "w");
auto_FILE FILE* main_fragment = fopen("main_fragment.html", "w");
if (!toc_fragment || !main_fragment) {
log_error("command_docgen(): unable to open html files: %s", g_strerror(errno));
g_list_free(cmds);
return;
}
@@ -3065,8 +3074,6 @@ command_docgen(void)
fputs("</ul></ul>\n", toc_fragment);
fclose(toc_fragment);
fclose(main_fragment);
printf("\nProcessed %u commands.\n\n", g_list_length(cmds));
g_list_free(cmds);
}

View File

@@ -3,35 +3,9 @@
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2019 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2019 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef COMMAND_CMD_DEFS_H

File diff suppressed because it is too large Load Diff

View File

@@ -3,35 +3,9 @@
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2019 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2019 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef COMMAND_CMD_FUNCS_H
@@ -129,6 +103,7 @@ gboolean cmd_bookmark_ignore(ProfWin* window, const char* const command, gchar**
gboolean cmd_roster(ProfWin* window, const char* const command, gchar** args);
gboolean cmd_software(ProfWin* window, const char* const command, gchar** args);
gboolean cmd_splash(ProfWin* window, const char* const command, gchar** args);
gboolean cmd_spellcheck(ProfWin* window, const char* const command, gchar** args);
gboolean cmd_states(ProfWin* window, const char* const command, gchar** args);
gboolean cmd_status_get(ProfWin* window, const char* const command, gchar** args);
gboolean cmd_status_set(ProfWin* window, const char* const command, gchar** args);
@@ -234,6 +209,7 @@ gboolean cmd_omemo_policy(ProfWin* window, const char* const command, gchar** ar
gboolean cmd_omemo_clear_device_list(ProfWin* window, const char* const command, gchar** args);
gboolean cmd_omemo_qrcode(ProfWin* window, const char* const command, gchar** args);
gboolean cmd_changes(ProfWin* window, const char* const command, gchar** args);
gboolean cmd_save(ProfWin* window, const char* const command, gchar** args);
gboolean cmd_reload(ProfWin* window, const char* const command, gchar** args);

View File

@@ -3,35 +3,9 @@
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2019 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2019 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -64,6 +38,7 @@
#include "log.h"
#include "common.h"
#include "config/files.h"
#include "ui/ui.h"
#ifdef HAVE_GIT_VERSION
#include "gitversion.h"
@@ -161,20 +136,27 @@ auto_close_FILE(FILE** fd)
log_error("%s", g_strerror(errno));
}
void
auto_free_gerror(GError** err)
{
if (err == NULL)
return;
PROF_GERROR_FREE(*err);
}
static gboolean
_load_keyfile(prof_keyfile_t* keyfile)
{
GError* error = NULL;
auto_gerror GError* error = NULL;
keyfile->keyfile = g_key_file_new();
if (g_key_file_load_from_file(keyfile->keyfile, keyfile->filename, G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, &error)) {
return TRUE;
} else if (error->code != G_FILE_ERROR_NOENT) {
} else if (error && error->code != G_FILE_ERROR_NOENT) {
log_warning("[Keyfile] error loading %s: %s", keyfile->filename, error->message);
g_error_free(error);
} else {
log_warning("[Keyfile] no such file: %s", keyfile->filename);
g_error_free(error);
}
return FALSE;
}
@@ -212,10 +194,9 @@ load_custom_keyfile(prof_keyfile_t* keyfile, gchar* filename)
gboolean
save_keyfile(prof_keyfile_t* keyfile)
{
GError* error = NULL;
auto_gerror GError* error = NULL;
if (!g_key_file_save_to_file(keyfile->keyfile, keyfile->filename, &error)) {
log_error("[Keyfile]: saving file %s failed! %s", keyfile->filename, error->message);
g_error_free(error);
log_error("[Keyfile]: saving file %s failed! %s", STR_MAYBE_NULL(keyfile->filename), PROF_GERROR_MESSAGE(error));
return FALSE;
}
g_chmod(keyfile->filename, S_IRUSR | S_IWUSR);
@@ -254,11 +235,8 @@ copy_file(const char* const sourcepath, const char* const targetpath, const gboo
{
GFile* source = g_file_new_for_path(sourcepath);
GFile* dest = g_file_new_for_path(targetpath);
GError* error = NULL;
GFileCopyFlags flags = overwrite_existing ? G_FILE_COPY_OVERWRITE : G_FILE_COPY_NONE;
gboolean success = g_file_copy(source, dest, flags, NULL, NULL, NULL, &error);
if (error != NULL)
g_error_free(error);
gboolean success = g_file_copy(source, dest, flags, NULL, NULL, NULL, NULL);
g_object_unref(source);
g_object_unref(dest);
return success;
@@ -358,6 +336,66 @@ strtoi_range(const char* str, int* saveptr, int min, int max, gchar** err_msg)
return TRUE;
}
gboolean
string_matches_one_of(const char* what, const char* is, gboolean is_can_be_null, const char* first, ...)
{
gboolean ret = FALSE;
va_list ap;
const char* cur = first;
if (!is)
return is_can_be_null;
va_start(ap, first);
while (cur != NULL) {
if (g_strcmp0(is, cur) == 0) {
ret = TRUE;
break;
}
cur = va_arg(ap, const char*);
}
va_end(ap);
if (!ret && what) {
cons_show("Invalid %s: '%s'", what, is);
char errmsg[256] = { 0 };
size_t sz = 0;
int s = snprintf(errmsg, sizeof(errmsg) - sz, "%s must be one of:", what);
if (s < 0 || s + sz >= sizeof(errmsg))
return ret;
sz += s;
cur = first;
va_start(ap, first);
while (cur != NULL) {
const char* next = va_arg(ap, const char*);
if (next) {
s = snprintf(errmsg + sz, sizeof(errmsg) - sz, " '%s',", cur);
} else {
/* remove last ',' */
sz--;
errmsg[sz] = '\0';
s = snprintf(errmsg + sz, sizeof(errmsg) - sz, " or '%s'.", cur);
}
if (s < 0 || s + sz >= sizeof(errmsg)) {
log_debug("Error message too long or some other error occurred (%d).", s);
s = -1;
break;
}
sz += s;
cur = next;
}
va_end(ap);
if (s > 0)
cons_show("%s", errmsg);
}
return ret;
}
gboolean
valid_tls_policy_option(const char* is)
{
return string_matches_one_of("TLS policy", is, TRUE, "force", "allow", "trust", "disable", "legacy", "direct", NULL);
}
int
utf8_display_len(const char* const str)
{
@@ -380,6 +418,33 @@ utf8_display_len(const char* const str)
return len;
}
/**
* Removes illegal XML 1.0 characters from a string.
*
* This function creates a new string that excludes characters in the range
* U+0000 to U+001F, except for U+0009 (TAB), U+000A (LF), and U+000D (CR).
*/
gchar*
str_xml_sanitize(const char* const str)
{
if (str == NULL) {
return NULL;
}
GString* sanitized = g_string_new_len(NULL, strlen(str));
const char* curr = str;
while (*curr != '\0') {
gunichar c = g_utf8_get_char(curr);
if ((c >= 0x20) || (c == 0x09) || (c == 0x0A) || (c == 0x0D)) {
g_string_append_unichar(sanitized, c);
}
curr = g_utf8_next_char(curr);
}
return g_string_free(sanitized, FALSE);
}
char*
release_get_latest(void)
{
@@ -407,11 +472,15 @@ release_get_latest(void)
}
gboolean
release_is_new(char* found_version)
release_is_new(const char* const curr_version, const char* const found_version)
{
if (!curr_version || !found_version) {
return FALSE;
}
int curr_maj, curr_min, curr_patch, found_maj, found_min, found_patch;
int parse_curr = sscanf(PACKAGE_VERSION, "%d.%d.%d", &curr_maj, &curr_min,
int parse_curr = sscanf(curr_version, "%d.%d.%d", &curr_maj, &curr_min,
&curr_patch);
int parse_found = sscanf(found_version, "%d.%d.%d", &found_maj, &found_min,
&found_patch);
@@ -474,23 +543,32 @@ _get_file_or_linked(gchar* loc)
char*
strip_arg_quotes(const char* const input)
{
char* unquoted = strdup(input);
if (input == NULL) {
return NULL;
}
// Remove starting quote if it exists
if (strchr(unquoted, '"')) {
if (strchr(unquoted, ' ') + 1 == strchr(unquoted, '"')) {
memmove(strchr(unquoted, '"'), strchr(unquoted, '"') + 1, strchr(unquoted, '\0') - strchr(unquoted, '"'));
// Unescape and strip quotes
GString* unescaped = g_string_new("");
for (const char* p = input; *p; p++) {
if (*p == '\\' && (*(p + 1) != '\0')) {
p++;
g_string_append_c(unescaped, *p);
} else if (*p == '"') {
// Only strip if it's the first char or preceded by a space
if (p == input || *(p - 1) == ' ') {
continue;
}
// Or if it's the last char
if (*(p + 1) == '\0') {
continue;
}
g_string_append_c(unescaped, *p);
} else {
g_string_append_c(unescaped, *p);
}
}
// Remove ending quote if it exists
if (strchr(unquoted, '"')) {
if (strchr(unquoted, '\0') - 1 == strchr(unquoted, '"')) {
memmove(strchr(unquoted, '"'), strchr(unquoted, '"') + 1, strchr(unquoted, '\0') - strchr(unquoted, '"'));
}
}
return unquoted;
return g_string_free(unescaped, FALSE);
}
gboolean
@@ -514,36 +592,48 @@ is_notify_enabled(void)
GSList*
prof_occurrences(const char* const needle, const char* const haystack, int offset, gboolean whole_word, GSList** result)
{
if (needle == NULL || haystack == NULL) {
if (needle == NULL || haystack == NULL || *needle == '\0') {
return *result;
}
do {
gchar* haystack_curr = g_utf8_offset_to_pointer(haystack, offset);
if (g_str_has_prefix(haystack_curr, needle)) {
size_t needle_len = strlen(needle);
gchar* p = g_utf8_offset_to_pointer(haystack, offset);
GSList* matches = NULL;
while (p) {
if (g_str_has_prefix(p, needle)) {
if (whole_word) {
gunichar before = 0;
gchar* haystack_before_ch = g_utf8_find_prev_char(haystack, haystack_curr);
gchar* haystack_before_ch = g_utf8_find_prev_char(haystack, p);
if (haystack_before_ch) {
before = g_utf8_get_char(haystack_before_ch);
}
gunichar after = 0;
gchar* haystack_after_ch = haystack_curr + strlen(needle);
if (haystack_after_ch[0] != '\0') {
gchar* haystack_after_ch = p + needle_len;
if (*haystack_after_ch != '\0') {
after = g_utf8_get_char(haystack_after_ch);
}
if (!g_unichar_isalnum(before) && !g_unichar_isalnum(after)) {
*result = g_slist_append(*result, GINT_TO_POINTER(offset));
matches = g_slist_prepend(matches, GINT_TO_POINTER(offset));
}
} else {
*result = g_slist_append(*result, GINT_TO_POINTER(offset));
matches = g_slist_prepend(matches, GINT_TO_POINTER(offset));
}
}
if (*p == '\0') {
break;
}
p = g_utf8_next_char(p);
offset++;
} while (g_strcmp0(g_utf8_offset_to_pointer(haystack, offset), "\0") != 0);
}
if (matches) {
*result = g_slist_concat(*result, g_slist_reverse(matches));
}
return *result;
}
@@ -599,15 +689,15 @@ get_file_paths_recursive(const char* path, GSList** contents)
}
}
char*
gchar*
get_random_string(int length)
{
GRand* prng;
char* rand;
char alphabet[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
gchar* rand;
gchar alphabet[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
int endrange = sizeof(alphabet) - 1;
rand = calloc(length + 1, sizeof(char));
rand = g_malloc0(length + 1);
prng = g_rand_new();
@@ -634,7 +724,7 @@ get_mentions(gboolean whole_word, gboolean case_sensitive, const char* const mes
gboolean
call_external(gchar** argv)
{
GError* spawn_error;
auto_gerror GError* spawn_error = NULL;
gboolean is_successful;
GSpawnFlags flags = G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL;
@@ -647,9 +737,7 @@ call_external(gchar** argv)
&spawn_error);
if (!is_successful) {
auto_gchar gchar* cmd = g_strjoinv(" ", argv);
log_error("Spawning '%s' failed with error '%s'", cmd, spawn_error ? spawn_error->message : "Unknown, spawn_error is NULL");
g_error_free(spawn_error);
log_error("Spawning '%s' failed with error '%s'", cmd, PROF_GERROR_MESSAGE(spawn_error));
}
return is_successful;
@@ -711,7 +799,7 @@ _unique_filename(const char* filename)
return unique;
}
static bool
static gboolean
_has_directory_suffix(const char* path)
{
return (g_str_has_suffix(path, ".")
@@ -809,6 +897,20 @@ unique_filename_from_url(const char* url, const char* path)
return unique_filename;
}
/* This returns a timestamp formatted in ISO8601 format.
* Either it returns the current time if `dt` is NULL, or
* it returns the formatted time value passed in `dt`.
*/
gchar*
prof_date_time_format_iso8601(GDateTime* dt)
{
GDateTime* dt_ = (dt == NULL) ? g_date_time_new_now_local() : dt;
gchar* ret = g_date_time_format_iso8601(dt_);
if (dt == NULL)
g_date_time_unref(dt_);
return ret;
}
/* build profanity version string.
* example: 0.13.1dev.master.69d8c1f9
*/

View File

@@ -4,36 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* @file common.h
*
* @brief Common utilities for the project.
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef COMMON_H
@@ -112,12 +83,22 @@ void auto_close_gfd(gint* fd);
void auto_close_FILE(FILE** fd);
void auto_free_gerror(GError** err);
#define auto_gerror __attribute__((__cleanup__(auto_free_gerror)))
#if defined(__OpenBSD__)
#define STR_MAYBE_NULL(p) (p) ?: "(null)"
#else
#define STR_MAYBE_NULL(p) (p)
#endif
#define PROF_GERROR_MESSAGE(err) (err) ? (err)->message : "error message missing"
#define PROF_GERROR_FREE(err) \
do { \
if (err) \
g_error_free(err); \
} while (0)
typedef struct prof_keyfile_t
{
gchar* filename;
@@ -180,9 +161,13 @@ gboolean copy_file(const char* const src, const char* const target, const gboole
char* str_replace(const char* string, const char* substr, const char* replacement);
gboolean strtoi_range(const char* str, int* saveptr, int min, int max, char** err_msg);
int utf8_display_len(const char* const str);
gchar* str_xml_sanitize(const char* const str);
gboolean string_matches_one_of(const char* what, const char* is, gboolean is_can_be_null, const char* first, ...) __attribute__((sentinel));
gboolean valid_tls_policy_option(const char* is);
char* release_get_latest(void);
gboolean release_is_new(char* found_version);
gboolean release_is_new(const char* const curr_version, const char* const found_version);
char* strip_arg_quotes(const char* const input);
gboolean is_notify_enabled(void);
@@ -195,7 +180,7 @@ int is_regular_file(const char* path);
int is_dir(const char* path);
void get_file_paths_recursive(const char* directory, GSList** contents);
char* get_random_string(int length);
gchar* get_random_string(int length);
gboolean call_external(gchar** argv);
gchar** format_call_external_argv(const char* template, const char* url, const char* filename);
@@ -205,6 +190,8 @@ gchar* get_expanded_path(const char* path);
char* basename_from_url(const char* url);
gchar* prof_date_time_format_iso8601(GDateTime* dt);
gchar* prof_get_version(void);
void prof_add_shutdown_routine(void (*routine)(void));

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -39,6 +13,7 @@
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <sys/wait.h>
#include <glib.h>
@@ -59,7 +34,7 @@ account_new(gchar* name, gchar* jid, gchar* password, gchar* eval_password, gboo
gchar* startscript, gchar* theme, gchar* tls_policy, gchar* auth_policy,
gchar* client, int max_sessions)
{
ProfAccount* new_account = calloc(1, sizeof(ProfAccount));
ProfAccount* new_account = g_new0(ProfAccount, 1);
new_account->name = name;
@@ -144,13 +119,13 @@ account_new(gchar* name, gchar* jid, gchar* password, gchar* eval_password, gboo
return new_account;
}
char*
gchar*
account_create_connect_jid(ProfAccount* account)
{
if (account->resource) {
return create_fulljid(account->jid, account->resource);
} else {
return strdup(account->jid);
return g_strdup(account->jid);
}
}
@@ -160,53 +135,41 @@ account_eval_password(ProfAccount* account)
assert(account != NULL);
assert(account->eval_password != NULL);
errno = 0;
gchar* stdout_buf = NULL;
GError* error = NULL;
gint exit_status = 0;
gchar** argv = NULL;
FILE* stream = popen(account->eval_password, "r");
if (stream == NULL) {
const char* errmsg = strerror(errno);
if (errmsg) {
log_error("Could not execute `eval_password` command (%s).",
errmsg);
} else {
log_error("Failed to allocate memory for `eval_password` command.");
if (!g_shell_parse_argv(account->eval_password, NULL, &argv, &error)) {
log_error("Failed to parse `eval_password` command: %s", error->message);
g_error_free(error);
return FALSE;
}
if (!g_spawn_sync(NULL, argv, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_CHILD_INHERITS_STDIN, NULL, NULL, &stdout_buf, NULL, &exit_status, &error)) {
log_error("Failed to execute `eval_password` command: %s", error->message);
g_strfreev(argv);
g_error_free(error);
return FALSE;
}
g_strfreev(argv);
if (WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == 0) {
account->password = stdout_buf;
g_strstrip(account->password);
if (account->password[0] == '\0') {
log_error("Empty password returned by `eval_password` command.");
g_free(account->password);
account->password = NULL;
return FALSE;
}
return TRUE;
} else {
log_error("`eval_password` command failed with status %d", exit_status);
g_free(stdout_buf);
return FALSE;
}
account->password = g_malloc(READ_BUF_SIZE);
if (!account->password) {
log_error("Failed to allocate enough memory to read `eval_password` "
"output.");
return FALSE;
}
account->password = fgets(account->password, READ_BUF_SIZE, stream);
if (!account->password) {
log_error("Failed to read password from stream.");
return FALSE;
}
int exit_status = pclose(stream);
if (exit_status > 0) {
log_error("Command for `eval_password` returned error status (%d).",
exit_status);
return FALSE;
} else if (exit_status < 0) {
log_error("Failed to close stream for `eval_password` command output "
"(%s).",
strerror(errno));
return FALSE;
};
// Remove leading and trailing whitespace from output.
g_strstrip(account->password);
if (!account->password) {
log_error("Empty password returned by `eval_password` command.");
return FALSE;
}
return TRUE;
}
void

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef CONFIG_ACCOUNT_H
@@ -84,7 +58,7 @@ ProfAccount* account_new(gchar* name, gchar* jid, gchar* password, gchar* eval_p
GList* ox_enabled, GList* pgp_enabled, gchar* pgp_keyid,
gchar* startscript, gchar* theme, gchar* tls_policy, gchar* auth_policy,
gchar* client, int max_sessions);
char* account_create_connect_jid(ProfAccount* account);
gchar* account_create_connect_jid(ProfAccount* account);
gboolean account_eval_password(ProfAccount* account);
void account_free(ProfAccount* account);
void account_set_server(ProfAccount* account, const char* server);

View File

@@ -3,35 +3,9 @@
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2019 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2019 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -59,7 +33,73 @@ static GKeyFile* accounts;
static Autocomplete all_ac;
static Autocomplete enabled_ac;
static void _save_accounts(void);
static gchar*
_sanitize_account_name(const char* const name)
{
if (!name) {
return NULL;
}
gchar* sanitized = g_strdup(name);
gchar* p = sanitized;
while (*p) {
if (*p == '[' || *p == ']' || *p == '=') {
*p = '_';
}
p++;
}
return sanitized;
}
static gboolean
_accounts_has_group(const char* account_name)
{
if (!account_name || !accounts)
return FALSE;
auto_gchar gchar* sanitized = _sanitize_account_name(account_name);
return g_key_file_has_group(accounts, sanitized);
}
static void
_accounts_save(const char* account_name)
{
prof_keyfile_t current;
if (!load_data_keyfile(&current, FILE_ACCOUNTS)) {
log_error("Could not load accounts");
return;
}
auto_gchar gchar* sanitized = _sanitize_account_name(account_name);
if (_accounts_has_group(sanitized)) {
// Remove keys from file that are no longer in memory
gsize nkeys_disk;
auto_gcharv gchar** keys_disk = g_key_file_get_keys(current.keyfile, sanitized, &nkeys_disk, NULL);
if (keys_disk) {
for (gsize j = 0; j < nkeys_disk; ++j) {
if (!g_key_file_has_key(accounts_prof_keyfile.keyfile, sanitized, keys_disk[j], NULL)) {
g_key_file_remove_key(current.keyfile, sanitized, keys_disk[j], NULL);
}
}
}
gsize nkeys;
auto_gcharv gchar** keys = g_key_file_get_keys(accounts_prof_keyfile.keyfile, sanitized, &nkeys, NULL);
if (keys) {
for (gsize j = 0; j < nkeys; ++j) {
auto_gchar gchar* new_value = g_key_file_get_value(accounts_prof_keyfile.keyfile, sanitized, keys[j], NULL);
g_key_file_set_value(current.keyfile, sanitized, keys[j], new_value);
}
}
} else {
g_key_file_remove_group(current.keyfile, sanitized, NULL);
}
save_keyfile(&current);
free_keyfile(&current);
}
static void
_accounts_close(void)
@@ -79,7 +119,9 @@ accounts_load(void)
all_ac = autocomplete_new();
enabled_ac = autocomplete_new();
load_data_keyfile(&accounts_prof_keyfile, FILE_ACCOUNTS);
if (!load_data_keyfile(&accounts_prof_keyfile, FILE_ACCOUNTS)) {
log_error("Could not load accounts");
}
accounts = accounts_prof_keyfile.keyfile;
// create the logins searchable list for autocompletion
@@ -132,54 +174,58 @@ accounts_add(const char* account_name, const char* altdomain, const int port, co
}
}
if (g_key_file_has_group(accounts, account_name)) {
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
if (_accounts_has_group(sanitized_account_name)) {
log_error("Can't add account \"%s\", it already exists.", account_name);
return;
}
g_key_file_set_boolean(accounts, account_name, "enabled", TRUE);
g_key_file_set_string(accounts, account_name, "jid", barejid);
g_key_file_set_string(accounts, account_name, "resource", resource);
g_key_file_set_boolean(accounts, sanitized_account_name, "enabled", TRUE);
g_key_file_set_string(accounts, sanitized_account_name, "jid", barejid);
g_key_file_set_string(accounts, sanitized_account_name, "resource", resource);
if (altdomain) {
g_key_file_set_string(accounts, account_name, "server", altdomain);
g_key_file_set_string(accounts, sanitized_account_name, "server", altdomain);
}
if (port != 0) {
g_key_file_set_integer(accounts, account_name, "port", port);
g_key_file_set_integer(accounts, sanitized_account_name, "port", port);
}
if (tls_policy) {
g_key_file_set_string(accounts, account_name, "tls.policy", tls_policy);
g_key_file_set_string(accounts, sanitized_account_name, "tls.policy", tls_policy);
}
if (auth_policy) {
g_key_file_set_string(accounts, account_name, "auth.policy", auth_policy);
g_key_file_set_string(accounts, sanitized_account_name, "auth.policy", auth_policy);
}
auto_jid Jid* jidp = jid_create(barejid);
if (jidp->localpart == NULL) {
g_key_file_set_string(accounts, account_name, "muc.nick", jidp->domainpart);
g_key_file_set_string(accounts, sanitized_account_name, "muc.nick", jidp->domainpart);
} else {
g_key_file_set_string(accounts, account_name, "muc.nick", jidp->localpart);
g_key_file_set_string(accounts, sanitized_account_name, "muc.nick", jidp->localpart);
}
g_key_file_set_string(accounts, account_name, "presence.last", "online");
g_key_file_set_string(accounts, account_name, "presence.login", "online");
g_key_file_set_integer(accounts, account_name, "priority.online", 0);
g_key_file_set_integer(accounts, account_name, "priority.chat", 0);
g_key_file_set_integer(accounts, account_name, "priority.away", 0);
g_key_file_set_integer(accounts, account_name, "priority.xa", 0);
g_key_file_set_integer(accounts, account_name, "priority.dnd", 0);
g_key_file_set_string(accounts, sanitized_account_name, "presence.last", "online");
g_key_file_set_string(accounts, sanitized_account_name, "presence.login", "online");
g_key_file_set_integer(accounts, sanitized_account_name, "priority.online", 0);
g_key_file_set_integer(accounts, sanitized_account_name, "priority.chat", 0);
g_key_file_set_integer(accounts, sanitized_account_name, "priority.away", 0);
g_key_file_set_integer(accounts, sanitized_account_name, "priority.xa", 0);
g_key_file_set_integer(accounts, sanitized_account_name, "priority.dnd", 0);
_save_accounts();
autocomplete_add(all_ac, account_name);
autocomplete_add(enabled_ac, account_name);
_accounts_save(account_name);
autocomplete_add(all_ac, sanitized_account_name);
autocomplete_add(enabled_ac, sanitized_account_name);
}
int
gboolean
accounts_remove(const char* account_name)
{
int r = g_key_file_remove_group(accounts, account_name, NULL);
_save_accounts();
autocomplete_remove(all_ac, account_name);
autocomplete_remove(enabled_ac, account_name);
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
gboolean r = g_key_file_remove_group(accounts, sanitized_account_name, NULL);
_accounts_save(account_name);
autocomplete_remove(all_ac, sanitized_account_name);
autocomplete_remove(enabled_ac, sanitized_account_name);
return r;
}
@@ -189,167 +235,123 @@ accounts_get_list(void)
return g_key_file_get_groups(accounts, NULL);
}
ProfAccount*
accounts_get_account(const char* const name)
static GList*
_g_strv_to_glist(gchar** in, gsize length)
{
if (!g_key_file_has_group(accounts, name)) {
if (in == NULL)
return NULL;
GList* out = NULL;
for (gsize i = 0; i < length; i++) {
out = g_list_append(out, in[i]);
}
g_free(in);
return out;
}
static GList*
_accounts_get_glist(const gchar* sanitized_account_name,
const gchar* key)
{
gsize length = 0;
gchar** list = g_key_file_get_string_list(accounts, sanitized_account_name, key, &length, NULL);
return _g_strv_to_glist(list, length);
}
ProfAccount*
accounts_get_account(const char* const account_name)
{
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
if (!_accounts_has_group(sanitized_account_name)) {
return NULL;
} else {
gchar* jid = g_key_file_get_string(accounts, name, "jid", NULL);
gchar* jid = g_key_file_get_string(accounts, sanitized_account_name, "jid", NULL);
// fix accounts that have no jid property by setting to name
// fix accounts that have no jid property by setting to account_name
if (jid == NULL) {
g_key_file_set_string(accounts, name, "jid", name);
_save_accounts();
g_key_file_set_string(accounts, sanitized_account_name, "jid", account_name);
_accounts_save(account_name);
}
gchar* password = g_key_file_get_string(accounts, name, "password", NULL);
gchar* eval_password = g_key_file_get_string(accounts, name, "eval_password", NULL);
gboolean enabled = g_key_file_get_boolean(accounts, name, "enabled", NULL);
gchar* password = g_key_file_get_string(accounts, sanitized_account_name, "password", NULL);
gchar* eval_password = g_key_file_get_string(accounts, sanitized_account_name, "eval_password", NULL);
gboolean enabled = g_key_file_get_boolean(accounts, sanitized_account_name, "enabled", NULL);
gchar* server = g_key_file_get_string(accounts, name, "server", NULL);
gchar* resource = g_key_file_get_string(accounts, name, "resource", NULL);
int port = g_key_file_get_integer(accounts, name, "port", NULL);
gchar* server = g_key_file_get_string(accounts, sanitized_account_name, "server", NULL);
gchar* resource = g_key_file_get_string(accounts, sanitized_account_name, "resource", NULL);
int port = g_key_file_get_integer(accounts, sanitized_account_name, "port", NULL);
gchar* last_presence = g_key_file_get_string(accounts, name, "presence.last", NULL);
gchar* login_presence = g_key_file_get_string(accounts, name, "presence.login", NULL);
gchar* last_presence = g_key_file_get_string(accounts, sanitized_account_name, "presence.last", NULL);
gchar* login_presence = g_key_file_get_string(accounts, sanitized_account_name, "presence.login", NULL);
int priority_online = g_key_file_get_integer(accounts, name, "priority.online", NULL);
int priority_chat = g_key_file_get_integer(accounts, name, "priority.chat", NULL);
int priority_away = g_key_file_get_integer(accounts, name, "priority.away", NULL);
int priority_xa = g_key_file_get_integer(accounts, name, "priority.xa", NULL);
int priority_dnd = g_key_file_get_integer(accounts, name, "priority.dnd", NULL);
int priority_online = g_key_file_get_integer(accounts, sanitized_account_name, "priority.online", NULL);
int priority_chat = g_key_file_get_integer(accounts, sanitized_account_name, "priority.chat", NULL);
int priority_away = g_key_file_get_integer(accounts, sanitized_account_name, "priority.away", NULL);
int priority_xa = g_key_file_get_integer(accounts, sanitized_account_name, "priority.xa", NULL);
int priority_dnd = g_key_file_get_integer(accounts, sanitized_account_name, "priority.dnd", NULL);
gchar* muc_service = NULL;
if (g_key_file_has_key(accounts, name, "muc.service", NULL)) {
muc_service = g_key_file_get_string(accounts, name, "muc.service", NULL);
if (g_key_file_has_key(accounts, sanitized_account_name, "muc.service", NULL)) {
muc_service = g_key_file_get_string(accounts, sanitized_account_name, "muc.service", NULL);
} else {
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status == JABBER_CONNECTED) {
const char* conf_jid = connection_jid_for_feature(XMPP_FEATURE_MUC);
if (conf_jid) {
muc_service = strdup(conf_jid);
muc_service = g_strdup(conf_jid);
}
}
}
gchar* muc_nick = g_key_file_get_string(accounts, name, "muc.nick", NULL);
gchar* muc_nick = g_key_file_get_string(accounts, sanitized_account_name, "muc.nick", NULL);
gchar* otr_policy = NULL;
if (g_key_file_has_key(accounts, name, "otr.policy", NULL)) {
otr_policy = g_key_file_get_string(accounts, name, "otr.policy", NULL);
}
gchar* otr_policy = g_key_file_get_string(accounts, sanitized_account_name, "otr.policy", NULL);
GList* otr_manual = _accounts_get_glist(sanitized_account_name, "otr.manual");
GList* otr_opportunistic = _accounts_get_glist(sanitized_account_name, "otr.opportunistic");
GList* otr_always = _accounts_get_glist(sanitized_account_name, "otr.always");
gsize length;
GList* otr_manual = NULL;
auto_gcharv gchar** manual = g_key_file_get_string_list(accounts, name, "otr.manual", &length, NULL);
if (manual) {
for (int i = 0; i < length; i++) {
otr_manual = g_list_append(otr_manual, strdup(manual[i]));
}
}
gchar* omemo_policy = g_key_file_get_string(accounts, sanitized_account_name, "omemo.policy", NULL);
GList* omemo_enabled = _accounts_get_glist(sanitized_account_name, "omemo.enabled");
GList* omemo_disabled = _accounts_get_glist(sanitized_account_name, "omemo.disabled");
GList* otr_opportunistic = NULL;
auto_gcharv gchar** opportunistic = g_key_file_get_string_list(accounts, name, "otr.opportunistic", &length, NULL);
if (opportunistic) {
for (int i = 0; i < length; i++) {
otr_opportunistic = g_list_append(otr_opportunistic, strdup(opportunistic[i]));
}
}
GList* ox_enabled = _accounts_get_glist(sanitized_account_name, "ox.enabled");
GList* otr_always = NULL;
auto_gcharv gchar** always = g_key_file_get_string_list(accounts, name, "otr.always", &length, NULL);
if (always) {
for (int i = 0; i < length; i++) {
otr_always = g_list_append(otr_always, strdup(always[i]));
}
}
GList* pgp_enabled = _accounts_get_glist(sanitized_account_name, "pgp.enabled");
gchar* omemo_policy = NULL;
if (g_key_file_has_key(accounts, name, "omemo.policy", NULL)) {
omemo_policy = g_key_file_get_string(accounts, name, "omemo.policy", NULL);
}
gchar* pgp_keyid = g_key_file_get_string(accounts, sanitized_account_name, "pgp.keyid", NULL);
GList* omemo_enabled = NULL;
auto_gcharv gchar** omemo_enabled_list = g_key_file_get_string_list(accounts, name, "omemo.enabled", &length, NULL);
if (omemo_enabled_list) {
for (int i = 0; i < length; i++) {
omemo_enabled = g_list_append(omemo_enabled, strdup(omemo_enabled_list[i]));
}
}
gchar* startscript = g_key_file_get_string(accounts, sanitized_account_name, "script.start", NULL);
GList* omemo_disabled = NULL;
auto_gcharv gchar** omemo_disabled_list = g_key_file_get_string_list(accounts, name, "omemo.disabled", &length, NULL);
if (omemo_disabled_list) {
for (int i = 0; i < length; i++) {
omemo_disabled = g_list_append(omemo_disabled, strdup(omemo_disabled_list[i]));
}
}
gchar* client = g_key_file_get_string(accounts, sanitized_account_name, "client.account_name", NULL);
GList* ox_enabled = NULL;
auto_gcharv gchar** ox_enabled_list = g_key_file_get_string_list(accounts, name, "ox.enabled", &length, NULL);
if (ox_enabled_list) {
for (int i = 0; i < length; i++) {
ox_enabled = g_list_append(ox_enabled, strdup(ox_enabled_list[i]));
}
}
gchar* theme = g_key_file_get_string(accounts, sanitized_account_name, "theme", NULL);
GList* pgp_enabled = NULL;
auto_gcharv gchar** pgp_enabled_list = g_key_file_get_string_list(accounts, name, "pgp.enabled", &length, NULL);
if (pgp_enabled_list) {
for (int i = 0; i < length; i++) {
pgp_enabled = g_list_append(pgp_enabled, strdup(pgp_enabled_list[i]));
}
}
gchar* pgp_keyid = NULL;
if (g_key_file_has_key(accounts, name, "pgp.keyid", NULL)) {
pgp_keyid = g_key_file_get_string(accounts, name, "pgp.keyid", NULL);
}
gchar* startscript = NULL;
if (g_key_file_has_key(accounts, name, "script.start", NULL)) {
startscript = g_key_file_get_string(accounts, name, "script.start", NULL);
}
gchar* client = NULL;
if (g_key_file_has_key(accounts, name, "client.name", NULL)) {
client = g_key_file_get_string(accounts, name, "client.name", NULL);
}
gchar* theme = NULL;
if (g_key_file_has_key(accounts, name, "theme", NULL)) {
theme = g_key_file_get_string(accounts, name, "theme", NULL);
}
gchar* tls_policy = g_key_file_get_string(accounts, name, "tls.policy", NULL);
if (tls_policy && ((g_strcmp0(tls_policy, "force") != 0) && (g_strcmp0(tls_policy, "allow") != 0) && (g_strcmp0(tls_policy, "trust") != 0) && (g_strcmp0(tls_policy, "disable") != 0) && (g_strcmp0(tls_policy, "legacy") != 0))) {
gchar* tls_policy = g_key_file_get_string(accounts, sanitized_account_name, "tls.policy", NULL);
if (tls_policy && !valid_tls_policy_option(tls_policy)) {
g_free(tls_policy);
tls_policy = NULL;
}
gchar* auth_policy = g_key_file_get_string(accounts, name, "auth.policy", NULL);
gchar* auth_policy = g_key_file_get_string(accounts, sanitized_account_name, "auth.policy", NULL);
int max_sessions = g_key_file_get_integer(accounts, name, "max.sessions", 0);
int max_sessions = g_key_file_get_integer(accounts, sanitized_account_name, "max.sessions", 0);
ProfAccount* new_account = account_new(g_strdup(name), jid, password, eval_password, enabled,
server, port, resource, last_presence, login_presence,
priority_online, priority_chat, priority_away, priority_xa,
priority_dnd, muc_service, muc_nick, otr_policy, otr_manual,
otr_opportunistic, otr_always, omemo_policy, omemo_enabled,
omemo_disabled, ox_enabled, pgp_enabled, pgp_keyid,
startscript, theme, tls_policy, auth_policy, client, max_sessions);
return new_account;
return account_new(g_strdup(account_name), jid, password, eval_password, enabled,
server, port, resource, last_presence, login_presence,
priority_online, priority_chat, priority_away, priority_xa,
priority_dnd, muc_service, muc_nick, otr_policy, otr_manual,
otr_opportunistic, otr_always, omemo_policy, omemo_enabled,
omemo_disabled, ox_enabled, pgp_enabled, pgp_keyid,
startscript, theme, tls_policy, auth_policy, client, max_sessions);
}
}
gboolean
accounts_enable(const char* const name)
accounts_enable(const char* const account_name)
{
if (g_key_file_has_group(accounts, name)) {
g_key_file_set_boolean(accounts, name, "enabled", TRUE);
_save_accounts();
autocomplete_add(enabled_ac, name);
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
if (_accounts_has_group(sanitized_account_name)) {
g_key_file_set_boolean(accounts, sanitized_account_name, "enabled", TRUE);
_accounts_save(account_name);
autocomplete_add(enabled_ac, sanitized_account_name);
return TRUE;
} else {
return FALSE;
@@ -357,12 +359,13 @@ accounts_enable(const char* const name)
}
gboolean
accounts_disable(const char* const name)
accounts_disable(const char* const account_name)
{
if (g_key_file_has_group(accounts, name)) {
g_key_file_set_boolean(accounts, name, "enabled", FALSE);
_save_accounts();
autocomplete_remove(enabled_ac, name);
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
if (_accounts_has_group(sanitized_account_name)) {
g_key_file_set_boolean(accounts, sanitized_account_name, "enabled", FALSE);
_accounts_save(account_name);
autocomplete_remove(enabled_ac, sanitized_account_name);
return TRUE;
} else {
return FALSE;
@@ -372,63 +375,33 @@ accounts_disable(const char* const name)
gboolean
accounts_rename(const char* const account_name, const char* const new_name)
{
if (g_key_file_has_group(accounts, new_name)) {
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
auto_gchar gchar* sanitized_new_account_name = _sanitize_account_name(new_name);
if (_accounts_has_group(sanitized_new_account_name)) {
return FALSE;
}
if (!g_key_file_has_group(accounts, account_name)) {
if (!_accounts_has_group(sanitized_account_name)) {
return FALSE;
}
// treat all properties as strings for copy
gchar* string_keys[] = {
"enabled",
"jid",
"server",
"port",
"resource",
"password",
"eval_password",
"presence.last",
"presence.laststatus",
"presence.login",
"priority.online",
"priority.chat",
"priority.away",
"priority.xa",
"priority.dnd",
"muc.service",
"muc.nick",
"otr.policy",
"otr.manual",
"otr.opportunistic",
"otr.always",
"omemo.policy",
"omemo.enabled",
"omemo.disabled",
"ox.enabled",
"pgp.enabled",
"pgp.keyid",
"last.activity",
"script.start",
"tls.policy"
};
for (int i = 0; i < ARRAY_SIZE(string_keys); i++) {
auto_gchar gchar* value = g_key_file_get_string(accounts, account_name, string_keys[i], NULL);
if (value) {
g_key_file_set_string(accounts, new_name, string_keys[i], value);
}
gsize nkeys;
auto_gcharv gchar** keys = g_key_file_get_keys(accounts, sanitized_account_name, &nkeys, NULL);
for (gsize i = 0; i < nkeys; i++) {
auto_gchar gchar* new_value = g_key_file_get_value(accounts, sanitized_account_name, keys[i], NULL);
g_key_file_set_value(accounts, sanitized_new_account_name, keys[i], new_value);
}
g_key_file_remove_group(accounts, account_name, NULL);
_save_accounts();
g_key_file_remove_group(accounts, sanitized_account_name, NULL);
_accounts_save(account_name);
_accounts_save(new_name);
autocomplete_remove(all_ac, account_name);
autocomplete_add(all_ac, new_name);
if (g_key_file_get_boolean(accounts, new_name, "enabled", NULL)) {
autocomplete_remove(enabled_ac, account_name);
autocomplete_add(enabled_ac, new_name);
autocomplete_remove(all_ac, sanitized_account_name);
autocomplete_remove(enabled_ac, sanitized_account_name);
autocomplete_add(all_ac, sanitized_new_account_name);
if (g_key_file_get_boolean(accounts, sanitized_new_account_name, "enabled", NULL)) {
autocomplete_add(enabled_ac, sanitized_new_account_name);
}
return TRUE;
@@ -437,7 +410,7 @@ accounts_rename(const char* const account_name, const char* const new_name)
gboolean
accounts_account_exists(const char* const account_name)
{
return g_key_file_has_group(accounts, account_name);
return _accounts_has_group(account_name);
}
void
@@ -445,19 +418,20 @@ accounts_set_jid(const char* const account_name, const char* const value)
{
auto_jid Jid* jid = jid_create(value);
if (jid) {
if (accounts_account_exists(account_name)) {
g_key_file_set_string(accounts, account_name, "jid", jid->barejid);
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
if (_accounts_has_group(sanitized_account_name)) {
g_key_file_set_string(accounts, sanitized_account_name, "jid", jid->barejid);
if (jid->resourcepart) {
g_key_file_set_string(accounts, account_name, "resource", jid->resourcepart);
g_key_file_set_string(accounts, sanitized_account_name, "resource", jid->resourcepart);
}
if (jid->localpart == NULL) {
g_key_file_set_string(accounts, account_name, "muc.nick", jid->domainpart);
g_key_file_set_string(accounts, sanitized_account_name, "muc.nick", jid->domainpart);
} else {
g_key_file_set_string(accounts, account_name, "muc.nick", jid->localpart);
g_key_file_set_string(accounts, sanitized_account_name, "muc.nick", jid->localpart);
}
_save_accounts();
_accounts_save(account_name);
}
}
}
@@ -465,9 +439,10 @@ accounts_set_jid(const char* const account_name, const char* const value)
void
accounts_set_server(const char* const account_name, const char* const value)
{
if (accounts_account_exists(account_name)) {
g_key_file_set_string(accounts, account_name, "server", value);
_save_accounts();
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
if (_accounts_has_group(sanitized_account_name)) {
g_key_file_set_string(accounts, sanitized_account_name, "server", value);
_accounts_save(account_name);
}
}
@@ -475,35 +450,41 @@ void
accounts_set_port(const char* const account_name, const int value)
{
if (value != 0) {
g_key_file_set_integer(accounts, account_name, "port", value);
_save_accounts();
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
if (_accounts_has_group(sanitized_account_name)) {
g_key_file_set_integer(accounts, sanitized_account_name, "port", value);
_accounts_save(account_name);
}
}
}
static void
_accounts_set_string_option(const char* account_name, const char* const option, const char* const value)
{
if (accounts_account_exists(account_name)) {
g_key_file_set_string(accounts, account_name, option, value ?: "");
_save_accounts();
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
if (_accounts_has_group(sanitized_account_name)) {
g_key_file_set_string(accounts, sanitized_account_name, option, value ?: "");
_accounts_save(account_name);
}
}
static void
_accounts_set_int_option(const char* account_name, const char* const option, int value)
{
if (accounts_account_exists(account_name)) {
g_key_file_set_integer(accounts, account_name, option, value);
_save_accounts();
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
if (_accounts_has_group(sanitized_account_name)) {
g_key_file_set_integer(accounts, sanitized_account_name, option, value);
_accounts_save(account_name);
}
}
static void
_accounts_clear_string_option(const char* account_name, const char* const option)
{
if (accounts_account_exists(account_name)) {
g_key_file_remove_key(accounts, account_name, option, NULL);
_save_accounts();
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
if (_accounts_has_group(sanitized_account_name)) {
g_key_file_remove_key(accounts, sanitized_account_name, option, NULL);
_accounts_save(account_name);
}
}
@@ -630,83 +611,88 @@ accounts_clear_max_sessions(const char* const account_name)
void
accounts_add_otr_policy(const char* const account_name, const char* const contact_jid, const char* const policy)
{
if (accounts_account_exists(account_name)) {
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
if (_accounts_has_group(sanitized_account_name)) {
GString* key = g_string_new("otr.");
g_string_append(key, policy);
conf_string_list_add(accounts, account_name, key->str, contact_jid);
conf_string_list_add(accounts, sanitized_account_name, key->str, contact_jid);
g_string_free(key, TRUE);
// check for and remove from other lists
if (strcmp(policy, "manual") == 0) {
conf_string_list_remove(accounts, account_name, "otr.opportunistic", contact_jid);
conf_string_list_remove(accounts, account_name, "otr.always", contact_jid);
conf_string_list_remove(accounts, sanitized_account_name, "otr.opportunistic", contact_jid);
conf_string_list_remove(accounts, sanitized_account_name, "otr.always", contact_jid);
}
if (strcmp(policy, "opportunistic") == 0) {
conf_string_list_remove(accounts, account_name, "otr.manual", contact_jid);
conf_string_list_remove(accounts, account_name, "otr.always", contact_jid);
conf_string_list_remove(accounts, sanitized_account_name, "otr.manual", contact_jid);
conf_string_list_remove(accounts, sanitized_account_name, "otr.always", contact_jid);
}
if (strcmp(policy, "always") == 0) {
conf_string_list_remove(accounts, account_name, "otr.opportunistic", contact_jid);
conf_string_list_remove(accounts, account_name, "otr.manual", contact_jid);
conf_string_list_remove(accounts, sanitized_account_name, "otr.opportunistic", contact_jid);
conf_string_list_remove(accounts, sanitized_account_name, "otr.manual", contact_jid);
}
_save_accounts();
_accounts_save(account_name);
}
}
void
accounts_add_omemo_state(const char* const account_name, const char* const contact_jid, gboolean enabled)
{
if (accounts_account_exists(account_name)) {
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
if (_accounts_has_group(sanitized_account_name)) {
if (enabled) {
conf_string_list_add(accounts, account_name, "omemo.enabled", contact_jid);
conf_string_list_remove(accounts, account_name, "omemo.disabled", contact_jid);
conf_string_list_add(accounts, sanitized_account_name, "omemo.enabled", contact_jid);
conf_string_list_remove(accounts, sanitized_account_name, "omemo.disabled", contact_jid);
} else {
conf_string_list_add(accounts, account_name, "omemo.disabled", contact_jid);
conf_string_list_remove(accounts, account_name, "omemo.enabled", contact_jid);
conf_string_list_add(accounts, sanitized_account_name, "omemo.disabled", contact_jid);
conf_string_list_remove(accounts, sanitized_account_name, "omemo.enabled", contact_jid);
}
_save_accounts();
_accounts_save(account_name);
}
}
void
accounts_add_ox_state(const char* const account_name, const char* const contact_jid, gboolean enabled)
{
if (accounts_account_exists(account_name)) {
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
if (_accounts_has_group(sanitized_account_name)) {
if (enabled) {
conf_string_list_add(accounts, account_name, "ox.enabled", contact_jid);
conf_string_list_add(accounts, sanitized_account_name, "ox.enabled", contact_jid);
} else {
conf_string_list_remove(accounts, account_name, "ox.enabled", contact_jid);
conf_string_list_remove(accounts, sanitized_account_name, "ox.enabled", contact_jid);
}
_save_accounts();
_accounts_save(account_name);
}
}
void
accounts_add_pgp_state(const char* const account_name, const char* const contact_jid, gboolean enabled)
{
if (accounts_account_exists(account_name)) {
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
if (_accounts_has_group(sanitized_account_name)) {
if (enabled) {
conf_string_list_add(accounts, account_name, "pgp.enabled", contact_jid);
conf_string_list_remove(accounts, account_name, "pgp.disabled", contact_jid);
conf_string_list_add(accounts, sanitized_account_name, "pgp.enabled", contact_jid);
conf_string_list_remove(accounts, sanitized_account_name, "pgp.disabled", contact_jid);
} else {
conf_string_list_add(accounts, account_name, "pgp.disabled", contact_jid);
conf_string_list_remove(accounts, account_name, "pgp.enabled", contact_jid);
conf_string_list_add(accounts, sanitized_account_name, "pgp.disabled", contact_jid);
conf_string_list_remove(accounts, sanitized_account_name, "pgp.enabled", contact_jid);
}
_save_accounts();
_accounts_save(account_name);
}
}
void
accounts_clear_omemo_state(const char* const account_name, const char* const contact_jid)
{
if (accounts_account_exists(account_name)) {
conf_string_list_remove(accounts, account_name, "omemo.enabled", contact_jid);
conf_string_list_remove(accounts, account_name, "omemo.disabled", contact_jid);
_save_accounts();
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
if (_accounts_has_group(sanitized_account_name)) {
conf_string_list_remove(accounts, sanitized_account_name, "omemo.enabled", contact_jid);
conf_string_list_remove(accounts, sanitized_account_name, "omemo.disabled", contact_jid);
_accounts_save(account_name);
}
}
@@ -779,7 +765,8 @@ accounts_set_priority_dnd(const char* const account_name, const gint value)
void
accounts_set_priority_all(const char* const account_name, const gint value)
{
if (accounts_account_exists(account_name)) {
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
if (_accounts_has_group(sanitized_account_name)) {
accounts_set_priority_online(account_name, value);
accounts_set_priority_chat(account_name, value);
accounts_set_priority_away(account_name, value);
@@ -793,22 +780,23 @@ accounts_get_priority_for_presence_type(const char* const account_name,
resource_presence_t presence_type)
{
gint result;
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
switch (presence_type) {
case (RESOURCE_ONLINE):
result = g_key_file_get_integer(accounts, account_name, "priority.online", NULL);
result = g_key_file_get_integer(accounts, sanitized_account_name, "priority.online", NULL);
break;
case (RESOURCE_CHAT):
result = g_key_file_get_integer(accounts, account_name, "priority.chat", NULL);
result = g_key_file_get_integer(accounts, sanitized_account_name, "priority.chat", NULL);
break;
case (RESOURCE_AWAY):
result = g_key_file_get_integer(accounts, account_name, "priority.away", NULL);
result = g_key_file_get_integer(accounts, sanitized_account_name, "priority.away", NULL);
break;
case (RESOURCE_XA):
result = g_key_file_get_integer(accounts, account_name, "priority.xa", NULL);
result = g_key_file_get_integer(accounts, sanitized_account_name, "priority.xa", NULL);
break;
default:
result = g_key_file_get_integer(accounts, account_name, "priority.dnd", NULL);
result = g_key_file_get_integer(accounts, sanitized_account_name, "priority.dnd", NULL);
break;
}
@@ -833,7 +821,8 @@ accounts_set_last_status(const char* const account_name, const char* const value
void
accounts_set_last_activity(const char* const account_name)
{
if (accounts_account_exists(account_name)) {
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
if (_accounts_has_group(sanitized_account_name)) {
GDateTime* nowdt = g_date_time_new_now_utc();
GTimeVal nowtv;
gboolean res = g_date_time_to_timeval(nowdt, &nowtv);
@@ -841,8 +830,8 @@ accounts_set_last_activity(const char* const account_name)
if (res) {
auto_char char* timestr = g_time_val_to_iso8601(&nowtv);
g_key_file_set_string(accounts, account_name, "last.activity", timestr);
_save_accounts();
g_key_file_set_string(accounts, sanitized_account_name, "last.activity", timestr);
_accounts_save(account_name);
}
}
}
@@ -850,8 +839,9 @@ accounts_set_last_activity(const char* const account_name)
gchar*
accounts_get_last_activity(const char* const account_name)
{
if (accounts_account_exists(account_name)) {
return g_key_file_get_string(accounts, account_name, "last.activity", NULL);
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
if (_accounts_has_group(sanitized_account_name)) {
return g_key_file_get_string(accounts, sanitized_account_name, "last.activity", NULL);
} else {
return NULL;
}
@@ -860,27 +850,30 @@ accounts_get_last_activity(const char* const account_name)
gchar*
accounts_get_resource(const char* const account_name)
{
if (!accounts_account_exists(account_name)) {
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
if (!_accounts_has_group(sanitized_account_name)) {
return NULL;
}
return g_key_file_get_string(accounts, account_name, "resource", NULL);
return g_key_file_get_string(accounts, sanitized_account_name, "resource", NULL);
}
int
accounts_get_max_sessions(const char* const account_name)
{
if (!accounts_account_exists(account_name)) {
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
if (!_accounts_has_group(sanitized_account_name)) {
return 0;
}
return g_key_file_get_integer(accounts, account_name, "max.sessions", 0);
return g_key_file_get_integer(accounts, sanitized_account_name, "max.sessions", 0);
}
void
accounts_set_login_presence(const char* const account_name, const char* const value)
{
if (accounts_account_exists(account_name)) {
g_key_file_set_string(accounts, account_name, "presence.login", value);
_save_accounts();
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
if (_accounts_has_group(sanitized_account_name)) {
g_key_file_set_string(accounts, sanitized_account_name, "presence.login", value);
_accounts_save(account_name);
}
}
@@ -888,7 +881,8 @@ resource_presence_t
accounts_get_last_presence(const char* const account_name)
{
resource_presence_t result;
auto_gchar gchar* setting = g_key_file_get_string(accounts, account_name, "presence.last", NULL);
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
auto_gchar gchar* setting = g_key_file_get_string(accounts, sanitized_account_name, "presence.last", NULL);
if (setting == NULL || (strcmp(setting, "online") == 0)) {
result = RESOURCE_ONLINE;
@@ -912,14 +906,16 @@ accounts_get_last_presence(const char* const account_name)
char*
accounts_get_last_status(const char* const account_name)
{
return g_key_file_get_string(accounts, account_name, "presence.laststatus", NULL);
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
return g_key_file_get_string(accounts, sanitized_account_name, "presence.laststatus", NULL);
}
resource_presence_t
accounts_get_login_presence(const char* const account_name)
{
resource_presence_t result;
auto_gchar gchar* setting = g_key_file_get_string(accounts, account_name, "presence.login", NULL);
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
auto_gchar gchar* setting = g_key_file_get_string(accounts, sanitized_account_name, "presence.login", NULL);
if (setting == NULL || (strcmp(setting, "online") == 0)) {
result = RESOURCE_ONLINE;
@@ -944,7 +940,8 @@ accounts_get_login_presence(const char* const account_name)
char*
accounts_get_login_status(const char* const account_name)
{
auto_gchar gchar* setting = g_key_file_get_string(accounts, account_name, "presence.login", NULL);
auto_gchar gchar* sanitized_account_name = _sanitize_account_name(account_name);
auto_gchar gchar* setting = g_key_file_get_string(accounts, sanitized_account_name, "presence.login", NULL);
gchar* status = NULL;
if (g_strcmp0(setting, "last") == 0) {
@@ -953,9 +950,3 @@ accounts_get_login_status(const char* const account_name)
return status;
}
static void
_save_accounts(void)
{
save_keyfile(&accounts_prof_keyfile);
}

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef CONFIG_ACCOUNTS_H
@@ -48,7 +22,7 @@ char* accounts_find_enabled(const char* const prefix, gboolean previous, void* c
void accounts_reset_all_search(void);
void accounts_reset_enabled_search(void);
void accounts_add(const char* jid, const char* altdomain, const int port, const char* const tls_policy, const char* const auth_policy);
int accounts_remove(const char* jid);
gboolean accounts_remove(const char* jid);
gchar** accounts_get_list(void);
ProfAccount* accounts_get_account(const char* const name);
gboolean accounts_enable(const char* const name);

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2022 Steffen Jaeckel <jaeckel-floss@eyet-services.de>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -53,8 +27,7 @@ _cafile_name(void)
if (!create_dir(certs_dir)) {
return NULL;
}
gchar* filename = g_strdup_printf("%s/CAfile.pem", certs_dir);
return filename;
return g_strdup_printf("%s/CAfile.pem", certs_dir);
}
void
@@ -70,21 +43,25 @@ cafile_add(const TLSCertificate* cert)
auto_gchar gchar* contents = NULL;
auto_gchar gchar* new_contents = NULL;
gsize length;
GError* glib_error = NULL;
auto_gerror GError* glib_error = NULL;
if (g_file_test(cafile, G_FILE_TEST_EXISTS)) {
if (!g_file_get_contents(cafile, &contents, &length, &glib_error)) {
log_error("[CAfile] could not read from %s: %s", cafile, glib_error ? glib_error->message : "No GLib error given");
log_error("[CAfile] could not read from %s: %s", cafile, PROF_GERROR_MESSAGE(glib_error));
return;
}
if (strstr(contents, cert->fingerprint)) {
log_debug("[CAfile] fingerprint %s already stored", cert->fingerprint);
return;
}
if (strstr(contents, cert->fingerprint_sha1)) {
log_debug("[CAfile] fingerprint %s already stored", cert->fingerprint_sha1);
return;
}
}
const char* header = "# Profanity CAfile\n# DO NOT EDIT - this file is automatically generated";
new_contents = g_strdup_printf("%s\n\n# %s\n%s", contents ? contents : header, cert->fingerprint, cert->pem);
new_contents = g_strdup_printf("%s\n# %s\n%s", contents ? contents : header, cert->fingerprint, cert->pem);
if (!g_file_set_contents(cafile, new_contents, -1, &glib_error))
log_error("[CAfile] could not write to %s: %s", cafile, glib_error ? glib_error->message : "No GLib error given");
log_error("[CAfile] could not write to %s: %s", cafile, PROF_GERROR_MESSAGE(glib_error));
}
gchar*

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2022 Steffen Jaeckel <jaeckel-floss@eyet-services.de>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef CONFIG_CAFILE_H

View File

@@ -3,35 +3,9 @@
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2019 Aurelien Aptel <aurelien.aptel@gmail.com>
* Copyright (C) 2019 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2019 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -344,7 +318,7 @@ color_distance(const struct color_def* a, const struct color_def* b)
static int
find_closest_col(int h, int s, int l)
{
struct color_def a = { h, s, l };
struct color_def a = { h, s, l, NULL };
int min = 0;
int dmin = color_distance(&a, &color_names[0]);
@@ -369,7 +343,7 @@ find_col(const char* col_name, int n)
* blue.
*/
if (n >= sizeof(name)) {
if (n >= (int)sizeof(name)) {
/* truncate */
log_error("Color: <%s,%d> bigger than %zu", col_name, n, sizeof(name));
n = sizeof(name) - 1;

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2019 Aurelien Aptel <aurelien.aptel@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef _COLOR_H_

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -66,9 +40,7 @@ conf_string_list_add(GKeyFile* keyfile, const char* const group, const char* con
// Add item to the existing list
const gchar** new_list = g_new(const gchar*, length + 2);
for (gsize i = 0; i < length; ++i) {
new_list[i] = list[i];
}
memcpy(new_list, list, sizeof(list[0]) * length);
new_list[length] = item;
new_list[length + 1] = NULL;
@@ -89,33 +61,28 @@ conf_string_list_remove(GKeyFile* keyfile, const char* const group, const char*
return FALSE;
}
GList* glist = NULL;
gsize new_length = 0;
const gchar** new_list = g_new(const gchar*, length + 1);
gboolean deleted = FALSE;
for (int i = 0; i < length; i++) {
for (gsize i = 0; i < length; i++) {
if (strcmp(list[i], item) == 0) {
deleted = TRUE;
continue;
}
glist = g_list_append(glist, strdup(list[i]));
new_list[new_length++] = list[i];
}
new_list[new_length] = NULL;
if (deleted) {
if (g_list_length(glist) == 0) {
if (new_length == 0) {
g_key_file_remove_key(keyfile, group, key, NULL);
} else {
const gchar* new_list[g_list_length(glist) + 1];
int i = 0;
for (GList* curr = glist; curr; curr = g_list_next(curr)) {
new_list[i++] = curr->data;
}
new_list[i] = NULL;
g_key_file_set_string_list(keyfile, group, key, new_list, g_list_length(glist));
g_key_file_set_string_list(keyfile, group, key, new_list, new_length);
}
}
g_list_free_full(glist, g_free);
g_free(new_list);
return deleted;
}

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef CONFIG_CONFLISTS_H

View File

@@ -3,35 +3,9 @@
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2020 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2020 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"

View File

@@ -3,35 +3,9 @@
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2018 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2018 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef CONFIG_FILES_H

View File

@@ -3,35 +3,9 @@
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2019 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2019 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -49,6 +23,7 @@
#include "tools/autocomplete.h"
#include "config/files.h"
#include "config/conflists.h"
#include "ui/ui.h"
// preference groups refer to the sections in .profrc or theme files
// for example [ui] but not [colours] which is handled in theme.c
@@ -66,6 +41,7 @@
#define PREF_GROUP_MUC "muc"
#define PREF_GROUP_PLUGINS "plugins"
#define PREF_GROUP_EXECUTABLES "executables"
#define PREF_GROUP_SPELLCHECK "spellcheck"
#define INPBLOCK_DEFAULT 1000
@@ -77,10 +53,10 @@ static Autocomplete boolean_choice_ac;
static Autocomplete room_trigger_ac;
static void _save_prefs(void);
static const char* _get_group(preference_t pref);
static const char* _get_key(preference_t pref);
static const gchar* _get_group(preference_t pref);
static const gchar* _get_key(preference_t pref);
static gboolean _get_default_boolean(preference_t pref);
static char* _get_default_string(preference_t pref);
static gchar* _get_default_string(preference_t pref);
static void
_prefs_load(void)
@@ -89,7 +65,7 @@ _prefs_load(void)
log_maxsize = g_key_file_get_integer(prefs, PREF_GROUP_LOGGING, "maxsize", &err);
if (err) {
log_maxsize = 0;
g_error_free(err);
PROF_GERROR_FREE(err);
}
// move pre 0.5.0 autoaway.time to autoaway.awaytime
@@ -109,7 +85,7 @@ _prefs_load(void)
// migrate pre 0.5.0 time settings
if (g_key_file_has_key(prefs, PREF_GROUP_UI, "time", NULL)) {
auto_gchar gchar* time = g_key_file_get_string(prefs, PREF_GROUP_UI, "time", NULL);
char* val = time ? time : "off";
gchar* val = time ? time : "off";
g_key_file_set_string(prefs, PREF_GROUP_UI, "time.console", val);
g_key_file_set_string(prefs, PREF_GROUP_UI, "time.chat", val);
g_key_file_set_string(prefs, PREF_GROUP_UI, "time.muc", val);
@@ -178,7 +154,7 @@ _prefs_load(void)
if (values && !g_key_file_has_key(prefs, PREF_GROUP_EXECUTABLES, "url.open.cmd", NULL)) {
// First value in array is `require_save` option -- we ignore that
// one as there is no such option anymore.
char* executable = values[1];
gchar* executable = values[1];
g_key_file_set_string(prefs, PREF_GROUP_EXECUTABLES, "url.open.cmd", executable);
g_key_file_set_comment(prefs, PREF_GROUP_EXECUTABLES, "url.open.cmd", " Migrated from url.open.cmd[DEF]. `require_save` option has been removed in v0.10 and was discarded.", NULL);
@@ -252,7 +228,7 @@ _prefs_load(void)
gsize len = 0;
auto_gcharv gchar** triggers = g_key_file_get_string_list(prefs, PREF_GROUP_NOTIFICATIONS, "room.trigger.list", &len, NULL);
for (int i = 0; i < len; i++) {
for (gsize i = 0; i < len; i++) {
autocomplete_add(room_trigger_ac, triggers[i]);
}
}
@@ -274,7 +250,7 @@ prefs_reload(void)
}
void
prefs_load(const char* config_file)
prefs_load(const gchar* config_file)
{
if (config_file == NULL) {
load_config_keyfile(&prefs_prof_keyfile, FILE_PROFRC);
@@ -286,6 +262,77 @@ prefs_load(const char* config_file)
_prefs_load();
}
static void
prefs_changes_print(const gchar* key, const gchar* newval, const gchar* oldval, gboolean* banner_shown)
{
#define PREFS_CHANGES_FORMAT_STRING "%-32s | %-20s | %-20s"
if (!*banner_shown) {
cons_show(PREFS_CHANGES_FORMAT_STRING, "Key", "New value", "Old value");
*banner_shown = TRUE;
}
cons_show(PREFS_CHANGES_FORMAT_STRING, key, newval, oldval);
#undef PREFS_CHANGES_FORMAT_STRING
}
void
prefs_changes(void)
{
const gchar* undef = "";
prof_keyfile_t saved;
if (!load_custom_keyfile(&saved, g_strdup(prefs_prof_keyfile.filename)))
return;
gsize ngroups, nsavedgroups, g;
auto_gcharv gchar** groups = g_key_file_get_groups(prefs_prof_keyfile.keyfile, &ngroups);
gboolean banner_shown = FALSE;
for (g = 0; g < ngroups; ++g) {
gsize nkeys, k;
gboolean saved_has_group = g_key_file_has_group(saved.keyfile, groups[g]);
auto_gcharv gchar** keys = g_key_file_get_keys(prefs_prof_keyfile.keyfile, groups[g], &nkeys, NULL);
for (k = 0; k < nkeys; ++k) {
auto_gerror GError* err = NULL;
auto_gchar gchar* full_key = g_strdup_printf("%s.%s", groups[g], keys[k]);
auto_gchar gchar* new_value = g_key_file_get_value(prefs_prof_keyfile.keyfile, groups[g], keys[k], &err);
if (err || !new_value) {
cons_show_error("%s: New value (%s) error: %s", full_key, STR_MAYBE_NULL(new_value), PROF_GERROR_MESSAGE(err));
continue;
}
if (!saved_has_group
|| !g_key_file_has_key(saved.keyfile, groups[g], keys[k], NULL)) {
prefs_changes_print(full_key, new_value, undef, &banner_shown);
continue;
}
auto_gchar gchar* old_value = g_key_file_get_value(saved.keyfile, groups[g], keys[k], &err);
if (err || !old_value) {
cons_show_error("%s: Old value (%s) error: %s", full_key, STR_MAYBE_NULL(old_value), PROF_GERROR_MESSAGE(err));
continue;
}
if (!g_str_equal(old_value, new_value)) {
prefs_changes_print(full_key, new_value, old_value, &banner_shown);
}
}
}
auto_gcharv gchar** savedgroups = g_key_file_get_groups(saved.keyfile, &nsavedgroups);
for (g = 0; g < nsavedgroups; ++g) {
gsize nkeys, k;
auto_gcharv gchar** keys = g_key_file_get_keys(saved.keyfile, savedgroups[g], &nkeys, NULL);
for (k = 0; k < nkeys; ++k) {
if (g_key_file_has_key(prefs_prof_keyfile.keyfile, savedgroups[g], keys[k], NULL))
continue;
auto_gerror GError* err = NULL;
auto_gchar gchar* full_key = g_strdup_printf("%s.%s", groups[g], keys[k]);
auto_gchar gchar* old_value = g_key_file_get_value(saved.keyfile, groups[g], keys[k], &err);
if (err || !old_value) {
cons_show_error("%s: Old value (%s) error: %s", full_key, STR_MAYBE_NULL(old_value), PROF_GERROR_MESSAGE(err));
continue;
}
prefs_changes_print(full_key, undef, old_value, &banner_shown);
}
}
free_keyfile(&saved);
if (!banner_shown)
cons_show("No changes to saved preferences.");
}
void
prefs_save(void)
{
@@ -302,7 +349,7 @@ prefs_close(void)
}
gchar*
prefs_autocomplete_boolean_choice(const char* const prefix, gboolean previous, void* context)
prefs_autocomplete_boolean_choice(const gchar* const prefix, gboolean previous, void* context)
{
return autocomplete_complete(boolean_choice_ac, prefix, TRUE, previous);
}
@@ -314,7 +361,7 @@ prefs_reset_boolean_choice(void)
}
gchar*
prefs_autocomplete_room_trigger(const char* const prefix, gboolean previous, void* context)
prefs_autocomplete_room_trigger(const gchar* const prefix, gboolean previous, void* context)
{
return autocomplete_complete(room_trigger_ac, prefix, TRUE, previous);
}
@@ -340,7 +387,7 @@ prefs_do_chat_notify(gboolean current_win)
}
GList*
prefs_message_get_triggers(const char* const message)
prefs_message_get_triggers(const gchar* const message)
{
GList* result = NULL;
@@ -348,7 +395,7 @@ prefs_message_get_triggers(const char* const message)
gsize len = 0;
auto_gcharv gchar** triggers = g_key_file_get_string_list(prefs, PREF_GROUP_NOTIFICATIONS, "room.trigger.list", &len, NULL);
for (int i = 0; i < len; i++) {
for (gsize i = 0; i < len; i++) {
auto_gchar gchar* trigger_lower = g_utf8_strdown(triggers[i], -1);
if (g_strrstr(message_lower, trigger_lower)) {
result = g_list_append(result, strdup(triggers[i]));
@@ -359,8 +406,8 @@ prefs_message_get_triggers(const char* const message)
}
gboolean
prefs_do_room_notify(gboolean current_win, const char* const roomjid, const char* const mynick,
const char* const theirnick, const char* const message, gboolean mention, gboolean trigger_found)
prefs_do_room_notify(gboolean current_win, const gchar* const roomjid, const gchar* const mynick,
const gchar* const theirnick, const gchar* const message, gboolean mention, gboolean trigger_found)
{
if (g_strcmp0(mynick, theirnick) == 0) {
return FALSE;
@@ -409,7 +456,7 @@ prefs_do_room_notify(gboolean current_win, const char* const roomjid, const char
}
gboolean
prefs_do_room_notify_mention(const char* const roomjid, int unread, gboolean mention, gboolean trigger)
prefs_do_room_notify_mention(const gchar* const roomjid, int unread, gboolean mention, gboolean trigger)
{
gboolean notify_room = FALSE;
if (g_key_file_has_key(prefs, roomjid, "notify", NULL)) {
@@ -445,61 +492,61 @@ prefs_do_room_notify_mention(const char* const roomjid, int unread, gboolean men
}
void
prefs_set_room_notify(const char* const roomjid, gboolean value)
prefs_set_room_notify(const gchar* const roomjid, gboolean value)
{
g_key_file_set_boolean(prefs, roomjid, "notify", value);
}
void
prefs_set_room_notify_mention(const char* const roomjid, gboolean value)
prefs_set_room_notify_mention(const gchar* const roomjid, gboolean value)
{
g_key_file_set_boolean(prefs, roomjid, "notify.mention", value);
}
void
prefs_set_room_notify_trigger(const char* const roomjid, gboolean value)
prefs_set_room_notify_trigger(const gchar* const roomjid, gboolean value)
{
g_key_file_set_boolean(prefs, roomjid, "notify.trigger", value);
}
gboolean
prefs_has_room_notify(const char* const roomjid)
prefs_has_room_notify(const gchar* const roomjid)
{
return g_key_file_has_key(prefs, roomjid, "notify", NULL);
}
gboolean
prefs_has_room_notify_mention(const char* const roomjid)
prefs_has_room_notify_mention(const gchar* const roomjid)
{
return g_key_file_has_key(prefs, roomjid, "notify.mention", NULL);
}
gboolean
prefs_has_room_notify_trigger(const char* const roomjid)
prefs_has_room_notify_trigger(const gchar* const roomjid)
{
return g_key_file_has_key(prefs, roomjid, "notify.trigger", NULL);
}
gboolean
prefs_get_room_notify(const char* const roomjid)
prefs_get_room_notify(const gchar* const roomjid)
{
return g_key_file_get_boolean(prefs, roomjid, "notify", NULL);
}
gboolean
prefs_get_room_notify_mention(const char* const roomjid)
prefs_get_room_notify_mention(const gchar* const roomjid)
{
return g_key_file_get_boolean(prefs, roomjid, "notify.mention", NULL);
}
gboolean
prefs_get_room_notify_trigger(const char* const roomjid)
prefs_get_room_notify_trigger(const gchar* const roomjid)
{
return g_key_file_get_boolean(prefs, roomjid, "notify.trigger", NULL);
}
gboolean
prefs_reset_room_notify(const char* const roomjid)
prefs_reset_room_notify(const gchar* const roomjid)
{
if (g_key_file_has_group(prefs, roomjid)) {
g_key_file_remove_group(prefs, roomjid, NULL);
@@ -512,8 +559,8 @@ prefs_reset_room_notify(const char* const roomjid)
gboolean
prefs_get_boolean(preference_t pref)
{
const char* group = _get_group(pref);
const char* key = _get_key(pref);
const gchar* group = _get_group(pref);
const gchar* key = _get_key(pref);
gboolean def = _get_default_boolean(pref);
if (!g_key_file_has_key(prefs, group, key, NULL)) {
@@ -526,8 +573,8 @@ prefs_get_boolean(preference_t pref)
void
prefs_set_boolean(preference_t pref, gboolean value)
{
const char* group = _get_group(pref);
const char* key = _get_key(pref);
const gchar* group = _get_group(pref);
const gchar* key = _get_key(pref);
g_key_file_set_boolean(prefs, group, key, value);
}
@@ -542,9 +589,9 @@ prefs_set_boolean(preference_t pref, gboolean value)
gchar*
prefs_get_string(preference_t pref)
{
const char* group = _get_group(pref);
const char* key = _get_key(pref);
char* def = _get_default_string(pref);
const gchar* group = _get_group(pref);
const gchar* key = _get_key(pref);
gchar* def = _get_default_string(pref);
gchar* result = g_key_file_get_string(prefs, group, key, NULL);
@@ -571,9 +618,9 @@ prefs_get_string(preference_t pref)
gchar*
prefs_get_string_with_locale(preference_t pref, gchar* locale)
{
const char* group = _get_group(pref);
const char* key = _get_key(pref);
char* def = _get_default_string(pref);
const gchar* group = _get_group(pref);
const gchar* key = _get_key(pref);
gchar* def = _get_default_string(pref);
gchar* result = g_key_file_get_locale_string(prefs, group, key, locale, NULL);
@@ -602,8 +649,8 @@ prefs_get_string_with_locale(preference_t pref, gchar* locale)
void
prefs_set_string(preference_t pref, const gchar* new_value)
{
const char* group = _get_group(pref);
const char* key = _get_key(pref);
const gchar* group = _get_group(pref);
const gchar* key = _get_key(pref);
if (new_value == NULL) {
g_key_file_remove_key(prefs, group, key, NULL);
} else {
@@ -612,10 +659,10 @@ prefs_set_string(preference_t pref, const gchar* new_value)
}
void
prefs_set_string_with_option(preference_t pref, char* option, char* value)
prefs_set_string_with_option(preference_t pref, gchar* option, gchar* value)
{
const char* group = _get_group(pref);
const char* key = _get_key(pref);
const gchar* group = _get_group(pref);
const gchar* key = _get_key(pref);
if (value == NULL) {
g_key_file_remove_key(prefs, group, key, NULL);
} else {
@@ -624,10 +671,10 @@ prefs_set_string_with_option(preference_t pref, char* option, char* value)
}
void
prefs_set_string_list_with_option(preference_t pref, char* option, const gchar* const* values)
prefs_set_string_list_with_option(preference_t pref, gchar* option, const gchar* const* values)
{
const char* group = _get_group(pref);
const char* key = _get_key(pref);
const gchar* group = _get_group(pref);
const gchar* key = _get_key(pref);
if (values == NULL || *values == NULL) {
if (g_strcmp0(option, "*") == 0) {
g_key_file_set_string_list(prefs, group, key, NULL, 0);
@@ -647,11 +694,11 @@ prefs_set_string_list_with_option(preference_t pref, char* option, const gchar*
}
}
char*
gchar*
prefs_get_tls_certpath(void)
{
const char* group = _get_group(PREF_TLS_CERTPATH);
const char* key = _get_key(PREF_TLS_CERTPATH);
const gchar* group = _get_group(PREF_TLS_CERTPATH);
const gchar* key = _get_key(PREF_TLS_CERTPATH);
auto_gchar gchar* setting = g_key_file_get_string(prefs, group, key, NULL);
@@ -679,7 +726,7 @@ prefs_get_tls_certpath(void)
return NULL;
}
char* result = strdup(setting);
gchar* result = g_strdup(setting);
return result;
}
@@ -883,14 +930,14 @@ prefs_get_plugins(void)
}
void
prefs_add_plugin(const char* const name)
prefs_add_plugin(const gchar* const name)
{
conf_string_list_add(prefs, PREF_GROUP_PLUGINS, "load", name);
_save_prefs();
}
void
prefs_remove_plugin(const char* const name)
prefs_remove_plugin(const gchar* const name)
{
conf_string_list_remove(prefs, PREF_GROUP_PLUGINS, "load", name);
_save_prefs();
@@ -924,7 +971,7 @@ prefs_get_occupants_char(void)
}
void
prefs_set_occupants_char(char* ch)
prefs_set_occupants_char(gchar* ch)
{
if (g_utf8_strlen(ch, 4) == 1) {
g_key_file_set_string(prefs, PREF_GROUP_UI, "occupants.char", ch);
@@ -969,7 +1016,7 @@ prefs_get_occupants_header_char(void)
}
void
prefs_set_occupants_header_char(char* ch)
prefs_set_occupants_header_char(gchar* ch)
{
if (g_utf8_strlen(ch, 4) == 1) {
g_key_file_set_string(prefs, PREF_GROUP_UI, "occupants.header.char", ch);
@@ -1003,7 +1050,7 @@ prefs_get_roster_size(void)
}
static gchar*
_prefs_get_encryption_char(const char* const ch, const char* const pref_group, const char* const key)
_prefs_get_encryption_char(const gchar* const ch, const gchar* const pref_group, const gchar* const key)
{
gchar* result = NULL;
@@ -1018,7 +1065,7 @@ _prefs_get_encryption_char(const char* const ch, const char* const pref_group, c
}
static gboolean
_prefs_set_encryption_char(const char* const ch, const char* const pref_group, const char* const key)
_prefs_set_encryption_char(const gchar* const ch, const gchar* const pref_group, const gchar* const key)
{
if (g_utf8_strlen(ch, 4) == 1) {
g_key_file_set_string(prefs, pref_group, key, ch);
@@ -1036,7 +1083,7 @@ prefs_get_otr_char(void)
}
gboolean
prefs_set_otr_char(char* ch)
prefs_set_otr_char(gchar* ch)
{
return _prefs_set_encryption_char(ch, PREF_GROUP_OTR, "otr.char");
}
@@ -1048,7 +1095,7 @@ prefs_get_pgp_char(void)
}
gboolean
prefs_set_pgp_char(char* ch)
prefs_set_pgp_char(gchar* ch)
{
return _prefs_set_encryption_char(ch, PREF_GROUP_PGP, "pgp.char");
}
@@ -1060,7 +1107,7 @@ prefs_get_ox_char(void)
}
gboolean
prefs_set_ox_char(char* ch)
prefs_set_ox_char(gchar* ch)
{
return _prefs_set_encryption_char(ch, PREF_GROUP_OX, "ox.char");
}
@@ -1072,7 +1119,7 @@ prefs_get_omemo_char(void)
}
gboolean
prefs_set_omemo_char(char* ch)
prefs_set_omemo_char(gchar* ch)
{
return _prefs_set_encryption_char(ch, PREF_GROUP_OMEMO, "omemo.char");
}
@@ -1084,7 +1131,7 @@ prefs_get_roster_header_char(void)
}
void
prefs_set_roster_header_char(char* ch)
prefs_set_roster_header_char(gchar* ch)
{
if (g_utf8_strlen(ch, 4) == 1) {
g_key_file_set_string(prefs, PREF_GROUP_UI, "roster.header.char", ch);
@@ -1106,7 +1153,7 @@ prefs_get_roster_contact_char(void)
}
void
prefs_set_roster_contact_char(char* ch)
prefs_set_roster_contact_char(gchar* ch)
{
if (g_utf8_strlen(ch, 4) == 1) {
g_key_file_set_string(prefs, PREF_GROUP_UI, "roster.contact.char", ch);
@@ -1128,7 +1175,7 @@ prefs_get_roster_resource_char(void)
}
void
prefs_set_roster_resource_char(char* ch)
prefs_set_roster_resource_char(gchar* ch)
{
if (g_utf8_strlen(ch, 4) == 1) {
g_key_file_set_string(prefs, PREF_GROUP_UI, "roster.resource.char", ch);
@@ -1150,7 +1197,7 @@ prefs_get_roster_private_char(void)
}
void
prefs_set_roster_private_char(char* ch)
prefs_set_roster_private_char(gchar* ch)
{
if (g_utf8_strlen(ch, 4) == 1) {
g_key_file_set_string(prefs, PREF_GROUP_UI, "roster.private.char", ch);
@@ -1172,7 +1219,7 @@ prefs_get_roster_room_char(void)
}
void
prefs_set_roster_room_char(char* ch)
prefs_set_roster_room_char(gchar* ch)
{
if (g_utf8_strlen(ch, 4) == 1) {
g_key_file_set_string(prefs, PREF_GROUP_UI, "roster.rooms.char", ch);
@@ -1194,7 +1241,7 @@ prefs_get_roster_room_private_char(void)
}
void
prefs_set_roster_room_private_char(char* ch)
prefs_set_roster_room_private_char(gchar* ch)
{
if (g_utf8_strlen(ch, 4) == 1) {
g_key_file_set_string(prefs, PREF_GROUP_UI, "roster.rooms.private.char", ch);
@@ -1281,7 +1328,7 @@ prefs_get_correction_char(void)
}
void
prefs_set_correction_char(char* ch)
prefs_set_correction_char(gchar* ch)
{
if (g_utf8_strlen(ch, 4) == 1) {
g_key_file_set_string(prefs, PREF_GROUP_UI, "correction.char", ch);
@@ -1291,7 +1338,7 @@ prefs_set_correction_char(char* ch)
}
gboolean
prefs_add_room_notify_trigger(const char* const text)
prefs_add_room_notify_trigger(const gchar* const text)
{
gboolean res = conf_string_list_add(prefs, PREF_GROUP_NOTIFICATIONS, "room.trigger.list", text);
@@ -1303,7 +1350,7 @@ prefs_add_room_notify_trigger(const char* const text)
}
gboolean
prefs_remove_room_notify_trigger(const char* const text)
prefs_remove_room_notify_trigger(const gchar* const text)
{
gboolean res = conf_string_list_remove(prefs, PREF_GROUP_NOTIFICATIONS, "room.trigger.list", text);
_save_prefs();
@@ -1322,7 +1369,7 @@ prefs_get_room_notify_triggers(void)
gsize len = 0;
auto_gcharv gchar** triggers = g_key_file_get_string_list(prefs, PREF_GROUP_NOTIFICATIONS, "room.trigger.list", &len, NULL);
for (int i = 0; i < len; i++) {
for (gsize i = 0; i < len; i++) {
result = g_list_append(result, strdup(triggers[i]));
}
@@ -1332,7 +1379,7 @@ prefs_get_room_notify_triggers(void)
ProfWinPlacement*
prefs_create_profwin_placement(int titlebar, int mainwin, int statusbar, int inputwin)
{
ProfWinPlacement* placement = malloc(sizeof(ProfWinPlacement));
ProfWinPlacement* placement = g_new0(ProfWinPlacement, 1);
placement->titlebar_pos = titlebar;
placement->mainwin_pos = mainwin;
placement->statusbar_pos = statusbar;
@@ -1623,7 +1670,7 @@ prefs_inputwin_pos_down(void)
}
gboolean
prefs_add_alias(const char* const name, const char* const value)
prefs_add_alias(const gchar* const name, const gchar* const value)
{
if (g_key_file_has_key(prefs, PREF_GROUP_ALIAS, name, NULL)) {
return FALSE;
@@ -1634,13 +1681,13 @@ prefs_add_alias(const char* const name, const char* const value)
}
gchar*
prefs_get_alias(const char* const name)
prefs_get_alias(const gchar* const name)
{
return g_key_file_get_string(prefs, PREF_GROUP_ALIAS, name, NULL);
}
gboolean
prefs_remove_alias(const char* const name)
prefs_remove_alias(const gchar* const name)
{
if (!g_key_file_has_key(prefs, PREF_GROUP_ALIAS, name, NULL)) {
return FALSE;
@@ -1669,14 +1716,14 @@ prefs_get_aliases(void)
gsize len;
auto_gcharv gchar** keys = g_key_file_get_keys(prefs, PREF_GROUP_ALIAS, &len, NULL);
for (int i = 0; i < len; i++) {
char* name = keys[i];
for (gsize i = 0; i < len; i++) {
gchar* name = keys[i];
auto_gchar gchar* value = g_key_file_get_string(prefs, PREF_GROUP_ALIAS, name, NULL);
if (value) {
ProfAlias* alias = malloc(sizeof(struct prof_alias_t));
alias->name = strdup(name);
alias->value = strdup(value);
ProfAlias* alias = g_new0(struct prof_alias_t, 1);
alias->name = g_strdup(name);
alias->value = g_strdup(value);
result = g_list_insert_sorted(result, alias, (GCompareFunc)_alias_cmp);
}
@@ -1689,9 +1736,9 @@ prefs_get_aliases(void)
void
_free_alias(ProfAlias* alias)
{
FREE_SET_NULL(alias->name);
FREE_SET_NULL(alias->value);
FREE_SET_NULL(alias);
GFREE_SET_NULL(alias->name);
GFREE_SET_NULL(alias->value);
GFREE_SET_NULL(alias);
}
void
@@ -1709,7 +1756,7 @@ _save_prefs(void)
// get the preference group for a specific preference
// for example the PREF_BEEP setting ("beep" in .profrc, see _get_key) belongs
// to the [ui] section.
static const char*
static const gchar*
_get_group(preference_t pref)
{
switch (pref) {
@@ -1865,6 +1912,9 @@ _get_group(preference_t pref)
return PREF_GROUP_OMEMO;
case PREF_OX_LOG:
return PREF_GROUP_OX;
case PREF_SPELLCHECK_ENABLE:
case PREF_SPELLCHECK_LANG:
return PREF_GROUP_SPELLCHECK;
default:
return NULL;
}
@@ -1872,7 +1922,7 @@ _get_group(preference_t pref)
// get the key used in .profrc for the preference
// for example the PREF_AUTOAWAY_MODE maps to "autoaway.mode" in .profrc
static const char*
static const gchar*
_get_key(preference_t pref)
{
switch (pref) {
@@ -2156,6 +2206,10 @@ _get_key(preference_t pref)
return "force-encryption.enabled";
case PREF_FORCE_ENCRYPTION_MODE:
return "force-encryption.policy";
case PREF_SPELLCHECK_ENABLE:
return "enabled";
case PREF_SPELLCHECK_LANG:
return "lang";
default:
return NULL;
}
@@ -2209,6 +2263,7 @@ _get_default_boolean(preference_t pref)
case PREF_STROPHE_SM_ENABLED:
case PREF_STROPHE_SM_RESEND:
return TRUE;
case PREF_SPELLCHECK_ENABLE:
case PREF_PGP_PUBKEY_AUTOIMPORT:
case PREF_FORCE_ENCRYPTION:
default:
@@ -2218,7 +2273,7 @@ _get_default_boolean(preference_t pref)
// the default setting for a string type preference
// if it is not specified in .profrc
static char*
static gchar*
_get_default_string(preference_t pref)
{
switch (pref) {
@@ -2319,6 +2374,8 @@ _get_default_string(preference_t pref)
return "on";
case PREF_FORCE_ENCRYPTION_MODE:
return "resend-to-confirm";
case PREF_SPELLCHECK_LANG:
return "en_US";
default:
return NULL;
}

View File

@@ -3,35 +3,9 @@
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2019 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2019 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef CONFIG_PREFERENCES_H
@@ -188,7 +162,9 @@ typedef enum {
PREF_VCARD_PHOTO_CMD,
PREF_STATUSBAR_TABMODE,
PREF_FORCE_ENCRYPTION,
PREF_FORCE_ENCRYPTION_MODE
PREF_FORCE_ENCRYPTION_MODE,
PREF_SPELLCHECK_ENABLE,
PREF_SPELLCHECK_LANG,
} preference_t;
typedef struct prof_alias_t
@@ -205,15 +181,16 @@ typedef struct prof_winplacement_t
int inputwin_pos;
} ProfWinPlacement;
void prefs_load(const char* config_file);
void prefs_load(const gchar* config_file);
void prefs_changes(void);
void prefs_save(void);
void prefs_close(void);
void prefs_reload(void);
gchar* prefs_autocomplete_boolean_choice(const char* const prefix, gboolean previous, void* context);
gchar* prefs_autocomplete_boolean_choice(const gchar* const prefix, gboolean previous, void* context);
void prefs_reset_boolean_choice(void);
gchar* prefs_autocomplete_room_trigger(const char* const prefix, gboolean previous, void* context);
gchar* prefs_autocomplete_room_trigger(const gchar* const prefix, gboolean previous, void* context);
void prefs_reset_room_trigger_ac(void);
gint prefs_get_gone(void);
@@ -250,42 +227,42 @@ gint prefs_get_autoxa_time(void);
void prefs_set_autoxa_time(gint value);
gchar** prefs_get_plugins(void);
void prefs_add_plugin(const char* const name);
void prefs_remove_plugin(const char* const name);
void prefs_add_plugin(const gchar* const name);
void prefs_remove_plugin(const gchar* const name);
gchar* prefs_get_otr_char(void);
gboolean prefs_set_otr_char(char* ch);
gboolean prefs_set_otr_char(gchar* ch);
gchar* prefs_get_pgp_char(void);
gboolean prefs_set_pgp_char(char* ch);
gboolean prefs_set_pgp_char(gchar* ch);
gchar* prefs_get_omemo_char(void);
gboolean prefs_set_omemo_char(char* ch);
gboolean prefs_set_omemo_char(gchar* ch);
// XEP-0373: OpenPGP for XMPP
char* prefs_get_ox_char(void);
gboolean prefs_set_ox_char(char* ch);
gboolean prefs_set_ox_char(gchar* ch);
gchar* prefs_get_roster_header_char(void);
void prefs_set_roster_header_char(char* ch);
void prefs_set_roster_header_char(gchar* ch);
void prefs_clear_roster_header_char(void);
gchar* prefs_get_roster_contact_char(void);
void prefs_set_roster_contact_char(char* ch);
void prefs_set_roster_contact_char(gchar* ch);
void prefs_clear_roster_contact_char(void);
gchar* prefs_get_roster_resource_char(void);
void prefs_set_roster_resource_char(char* ch);
void prefs_set_roster_resource_char(gchar* ch);
void prefs_clear_roster_resource_char(void);
gchar* prefs_get_roster_private_char(void);
void prefs_set_roster_private_char(char* ch);
void prefs_set_roster_private_char(gchar* ch);
void prefs_clear_roster_private_char(void);
gchar* prefs_get_roster_room_char(void);
void prefs_set_roster_room_char(char* ch);
void prefs_set_roster_room_char(gchar* ch);
void prefs_clear_roster_room_char(void);
gchar* prefs_get_roster_room_private_char(void);
void prefs_set_roster_room_private_char(char* ch);
void prefs_set_roster_room_private_char(gchar* ch);
void prefs_clear_roster_room_private_char(void);
gchar* prefs_get_occupants_char(void);
void prefs_set_occupants_char(char* ch);
void prefs_set_occupants_char(gchar* ch);
void prefs_clear_occupants_char(void);
gchar* prefs_get_occupants_header_char(void);
void prefs_set_occupants_header_char(char* ch);
void prefs_set_occupants_header_char(gchar* ch);
void prefs_clear_occupants_header_char(void);
gint prefs_get_roster_contact_indent(void);
@@ -298,21 +275,21 @@ gint prefs_get_occupants_indent(void);
void prefs_set_occupants_indent(gint value);
gchar* prefs_get_correction_char(void);
void prefs_set_correction_char(char* ch);
void prefs_set_correction_char(gchar* ch);
void prefs_add_login(const char* jid);
void prefs_add_login(const gchar* jid);
void prefs_set_tray_timer(gint value);
gint prefs_get_tray_timer(void);
gboolean prefs_add_alias(const char* const name, const char* const value);
gboolean prefs_remove_alias(const char* const name);
gchar* prefs_get_alias(const char* const name);
gboolean prefs_add_alias(const gchar* const name, const gchar* const value);
gboolean prefs_remove_alias(const gchar* const name);
gchar* prefs_get_alias(const gchar* const name);
GList* prefs_get_aliases(void);
void prefs_free_aliases(GList* aliases);
gboolean prefs_add_room_notify_trigger(const char* const text);
gboolean prefs_remove_room_notify_trigger(const char* const text);
gboolean prefs_add_room_notify_trigger(const gchar* const text);
gboolean prefs_remove_room_notify_trigger(const gchar* const text);
GList* prefs_get_room_notify_triggers(void);
ProfWinPlacement* prefs_get_win_placement(void);

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef CONFIG_SCRIPTS_H

View File

@@ -3,35 +3,9 @@
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2019 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2019 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -117,6 +91,7 @@ theme_init(const char* const theme_name)
g_hash_table_insert(defaults, strdup("mention"), strdup("yellow"));
g_hash_table_insert(defaults, strdup("trigger"), strdup("yellow"));
g_hash_table_insert(defaults, strdup("input.text"), strdup("default"));
g_hash_table_insert(defaults, strdup("input.misspelled"), strdup("red"));
g_hash_table_insert(defaults, strdup("main.time"), strdup("default"));
g_hash_table_insert(defaults, strdup("titlebar.text"), strdup("white"));
g_hash_table_insert(defaults, strdup("titlebar.brackets"), strdup("cyan"));
@@ -533,7 +508,7 @@ _theme_find(const char* const theme_name)
g_string_append(path, "/");
g_string_append(path, theme_name);
if (!g_file_test(path->str, G_FILE_TEST_EXISTS)) {
g_string_free(path, true);
g_string_free(path, TRUE);
path = NULL;
}
}
@@ -667,25 +642,17 @@ _theme_prep_fgnd(char* setting, GString* lookup_str, gboolean* bold)
}
}
char*
gchar*
theme_get_string(char* str)
{
gchar* res = g_key_file_get_string(theme, "colours", str, NULL);
if (!res) {
return strdup(g_hash_table_lookup(defaults, str));
return g_strdup(g_hash_table_lookup(defaults, str));
} else {
return res;
}
}
void
theme_free_string(char* str)
{
if (str) {
g_free(str);
}
}
int
theme_hash_attrs(const char* str)
{
@@ -748,6 +715,9 @@ theme_attrs(theme_item_t attrs)
case THEME_INPUT_TEXT:
_theme_prep_fgnd("input.text", lookup_str, &bold);
break;
case THEME_INPUT_MISSPELLED:
_theme_prep_fgnd("input.misspelled", lookup_str, &bold);
break;
case THEME_TIME:
_theme_prep_fgnd("main.time", lookup_str, &bold);
break;

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef CONFIG_THEME_H
@@ -53,6 +27,7 @@ typedef enum {
THEME_MENTION,
THEME_TRIGGER,
THEME_INPUT_TEXT,
THEME_INPUT_MISSPELLED,
THEME_TIME,
THEME_TITLE_TEXT,
THEME_TITLE_BRACKET,
@@ -152,7 +127,6 @@ void theme_close(void);
int theme_hash_attrs(const char* str);
int theme_attrs(theme_item_t attrs);
char* theme_get_string(char* str);
void theme_free_string(char* str);
theme_item_t theme_main_presence_attrs(const char* const presence);
theme_item_t theme_roster_unread_presence_attrs(const char* const presence);
theme_item_t theme_roster_active_presence_attrs(const char* const presence);

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -54,7 +28,7 @@ static void _save_tlscerts(void);
static Autocomplete certs_ac;
static char* current_fp;
static gchar* current_fp;
static void
_tlscerts_close(void)
@@ -62,7 +36,7 @@ _tlscerts_close(void)
free_keyfile(&tlscerts_prof_keyfile);
tlscerts = NULL;
free(current_fp);
g_free(current_fp);
current_fp = NULL;
autocomplete_free(certs_ac);
@@ -82,7 +56,7 @@ tlscerts_init(void)
gsize len = 0;
auto_gcharv gchar** groups = g_key_file_get_groups(tlscerts, &len);
for (int i = 0; i < g_strv_length(groups); i++) {
for (guint i = 0; i < g_strv_length(groups); i++) {
autocomplete_add(certs_ac, groups[i]);
}
@@ -90,33 +64,116 @@ tlscerts_init(void)
}
void
tlscerts_set_current(const char* const fp)
tlscerts_set_current(const TLSCertificate* cert)
{
if (current_fp) {
free(current_fp);
g_free(current_fp);
}
current_fp = strdup(fp);
current_fp = g_strdup(cert->fingerprint);
}
char*
tlscerts_get_current(void)
gboolean
tlscerts_current_fingerprint_equals(const TLSCertificate* cert)
{
return current_fp;
return g_strcmp0(current_fp, cert->fingerprint) == 0;
}
void
tlscerts_clear_current(void)
{
if (current_fp) {
free(current_fp);
g_free(current_fp);
current_fp = NULL;
}
}
gboolean
tlscerts_exists(const char* const fingerprint)
tlscerts_exists(const TLSCertificate* cert)
{
return g_key_file_has_group(tlscerts, fingerprint);
return g_key_file_has_group(tlscerts, cert->fingerprint);
}
#define _name_to_tlscert_name(in, cert, which) \
do { \
_name_to_tlscert_name_(in, &cert->which, #which); \
} while (0)
static void
_name_to_tlscert_name_(const char* in, tls_cert_name_t* out, const char* name);
static TLSCertificate*
_tlscerts_new(gchar* fingerprint_sha1, int version, gchar* serialnumber, gchar* subjectname,
gchar* issuername, gchar* notbefore, gchar* notafter,
gchar* key_alg, gchar* signature_alg, gchar* pem,
gchar* fingerprint_sha256, gchar* pubkey_fingerprint)
{
TLSCertificate* cert = g_new0(TLSCertificate, 1);
if (fingerprint_sha256 && fingerprint_sha1) {
cert->fingerprint_sha256 = fingerprint_sha256;
cert->fingerprint_sha1 = fingerprint_sha1;
cert->fingerprint = cert->fingerprint_sha256;
} else {
if (fingerprint_sha256) {
size_t s = strlen(fingerprint_sha256);
switch (s) {
case 40:
cert->fingerprint_sha1 = fingerprint_sha256;
cert->fingerprint = cert->fingerprint_sha1;
break;
case 64:
cert->fingerprint_sha256 = fingerprint_sha256;
cert->fingerprint = cert->fingerprint_sha256;
break;
default:
log_error("fingerprint_sha256 of length %zu unexpected: %s", s, fingerprint_sha256);
}
} else {
cert->fingerprint_sha1 = fingerprint_sha1;
cert->fingerprint = cert->fingerprint_sha1;
}
}
cert->version = version;
cert->serialnumber = serialnumber;
cert->subjectname = subjectname;
cert->issuername = issuername;
cert->notbefore = notbefore;
cert->notafter = notafter;
cert->key_alg = key_alg;
cert->signature_alg = signature_alg;
cert->pem = pem;
cert->pubkey_fingerprint = pubkey_fingerprint;
/* Do this check after assigning all values, in order to not leak them,
* even though the situation is most likely already FUBAR */
if (!fingerprint_sha256 && !fingerprint_sha1) {
log_error("No TLSCertificate w/o fingerprint");
tlscerts_free(cert);
return NULL;
}
_name_to_tlscert_name(subjectname, cert, subject);
_name_to_tlscert_name(issuername, cert, issuer);
return cert;
}
static TLSCertificate*
_get_TLSCertificate(const gchar* fingerprint)
{
int version = g_key_file_get_integer(tlscerts, fingerprint, "version", NULL);
gchar* serialnumber = g_key_file_get_string(tlscerts, fingerprint, "serialnumber", NULL);
gchar* subjectname = g_key_file_get_string(tlscerts, fingerprint, "subjectname", NULL);
gchar* issuername = g_key_file_get_string(tlscerts, fingerprint, "issuername", NULL);
gchar* notbefore = g_key_file_get_string(tlscerts, fingerprint, "start", NULL);
gchar* notafter = g_key_file_get_string(tlscerts, fingerprint, "end", NULL);
gchar* keyalg = g_key_file_get_string(tlscerts, fingerprint, "keyalg", NULL);
gchar* signaturealg = g_key_file_get_string(tlscerts, fingerprint, "signaturealg", NULL);
gchar* fingerprint_sha1 = g_key_file_get_string(tlscerts, fingerprint, "fingerprint_sha1", NULL);
gchar* pubkey_fingerprint = g_key_file_get_string(tlscerts, fingerprint, "pubkey_fingerprint", NULL);
return _tlscerts_new(fingerprint_sha1, version, serialnumber, subjectname, issuername, notbefore,
notafter, keyalg, signaturealg, NULL, g_strdup(fingerprint), pubkey_fingerprint);
}
GList*
@@ -126,125 +183,89 @@ tlscerts_list(void)
gsize len = 0;
auto_gcharv gchar** groups = g_key_file_get_groups(tlscerts, &len);
for (int i = 0; i < g_strv_length(groups); i++) {
char* fingerprint = strdup(groups[i]);
int version = g_key_file_get_integer(tlscerts, fingerprint, "version", NULL);
auto_gchar gchar* serialnumber = g_key_file_get_string(tlscerts, fingerprint, "serialnumber", NULL);
auto_gchar gchar* subjectname = g_key_file_get_string(tlscerts, fingerprint, "subjectname", NULL);
auto_gchar gchar* issuername = g_key_file_get_string(tlscerts, fingerprint, "issuername", NULL);
auto_gchar gchar* notbefore = g_key_file_get_string(tlscerts, fingerprint, "start", NULL);
auto_gchar gchar* notafter = g_key_file_get_string(tlscerts, fingerprint, "end", NULL);
auto_gchar gchar* keyalg = g_key_file_get_string(tlscerts, fingerprint, "keyalg", NULL);
auto_gchar gchar* signaturealg = g_key_file_get_string(tlscerts, fingerprint, "signaturealg", NULL);
TLSCertificate* cert = tlscerts_new(fingerprint, version, serialnumber, subjectname, issuername, notbefore,
notafter, keyalg, signaturealg, NULL);
res = g_list_append(res, cert);
for (gsize i = 0; i < len; i++) {
res = g_list_append(res, _get_TLSCertificate(groups[i]));
}
return res;
}
TLSCertificate*
tlscerts_new(const char* const fingerprint, int version, const char* const serialnumber, const char* const subjectname,
const char* const issuername, const char* const notbefore, const char* const notafter,
const char* const key_alg, const char* const signature_alg, const char* const pem)
static void
_name_to_tlscert_name_(const char* in, tls_cert_name_t* out, const char* name)
{
TLSCertificate* cert = calloc(1, sizeof(TLSCertificate));
if (fingerprint) {
cert->fingerprint = strdup(fingerprint);
}
cert->version = version;
if (serialnumber) {
cert->serialnumber = strdup(serialnumber);
}
if (subjectname) {
cert->subjectname = strdup(subjectname);
}
if (issuername) {
cert->issuername = strdup(issuername);
}
if (notbefore) {
cert->notbefore = strdup(notbefore);
}
if (notafter) {
cert->notafter = strdup(notafter);
}
if (key_alg) {
cert->key_alg = strdup(key_alg);
}
if (signature_alg) {
cert->signature_alg = strdup(signature_alg);
}
if (pem) {
cert->pem = strdup(pem);
}
auto_gcharv gchar** fields = g_strsplit(subjectname, "/", 0);
for (int i = 0; i < g_strv_length(fields); i++) {
auto_gcharv gchar** fields = g_strsplit(in, "/", 0);
const guint fields_num = g_strv_length(fields);
for (guint i = 0; i < fields_num; i++) {
auto_gcharv gchar** keyval = g_strsplit(fields[i], "=", 2);
if (g_strv_length(keyval) == 2) {
#define tls_cert_name_set(which) \
do { \
if (out->which) { \
log_warning("%s." #which " already set, skip %s", name, keyval[1]); \
continue; \
} \
out->which = g_strdup(keyval[1]); \
} while (0)
if ((g_strcmp0(keyval[0], "C") == 0) || (g_strcmp0(keyval[0], "countryName") == 0)) {
cert->subject_country = strdup(keyval[1]);
tls_cert_name_set(country);
}
if ((g_strcmp0(keyval[0], "ST") == 0) || (g_strcmp0(keyval[0], "stateOrProvinceName") == 0)) {
cert->subject_state = strdup(keyval[1]);
tls_cert_name_set(state);
}
if (g_strcmp0(keyval[0], "dnQualifier") == 0) {
cert->subject_distinguishedname = strdup(keyval[1]);
tls_cert_name_set(distinguishedname);
}
if (g_strcmp0(keyval[0], "serialnumber") == 0) {
cert->subject_serialnumber = strdup(keyval[1]);
tls_cert_name_set(serialnumber);
}
if ((g_strcmp0(keyval[0], "CN") == 0) || (g_strcmp0(keyval[0], "commonName") == 0)) {
cert->subject_commonname = strdup(keyval[1]);
tls_cert_name_set(commonname);
}
if ((g_strcmp0(keyval[0], "O") == 0) || (g_strcmp0(keyval[0], "organizationName") == 0)) {
cert->subject_organisation = strdup(keyval[1]);
tls_cert_name_set(organisation);
}
if ((g_strcmp0(keyval[0], "OU") == 0) || (g_strcmp0(keyval[0], "organizationalUnitName") == 0)) {
cert->subject_organisation_unit = strdup(keyval[1]);
tls_cert_name_set(organisation_unit);
}
if (g_strcmp0(keyval[0], "emailAddress") == 0) {
cert->subject_email = strdup(keyval[1]);
tls_cert_name_set(email);
}
#undef tls_cert_name_set
}
}
}
auto_gcharv gchar** fields2 = g_strsplit(issuername, "/", 0);
for (int i = 0; i < g_strv_length(fields2); i++) {
auto_gcharv gchar** keyval = g_strsplit(fields2[i], "=", 2);
if (g_strv_length(keyval) == 2) {
if ((g_strcmp0(keyval[0], "C") == 0) || (g_strcmp0(keyval[0], "countryName") == 0)) {
cert->issuer_country = strdup(keyval[1]);
}
if ((g_strcmp0(keyval[0], "ST") == 0) || (g_strcmp0(keyval[0], "stateOrProvinceName") == 0)) {
cert->issuer_state = strdup(keyval[1]);
}
if (g_strcmp0(keyval[0], "dnQualifier") == 0) {
cert->issuer_distinguishedname = strdup(keyval[1]);
}
if (g_strcmp0(keyval[0], "serialnumber") == 0) {
cert->issuer_serialnumber = strdup(keyval[1]);
}
if ((g_strcmp0(keyval[0], "CN") == 0) || (g_strcmp0(keyval[0], "commonName") == 0)) {
cert->issuer_commonname = strdup(keyval[1]);
}
if ((g_strcmp0(keyval[0], "O") == 0) || (g_strcmp0(keyval[0], "organizationName") == 0)) {
cert->issuer_organisation = strdup(keyval[1]);
}
if ((g_strcmp0(keyval[0], "OU") == 0) || (g_strcmp0(keyval[0], "organizationalUnitName") == 0)) {
cert->issuer_organisation_unit = strdup(keyval[1]);
}
if (g_strcmp0(keyval[0], "emailAddress") == 0) {
cert->issuer_email = strdup(keyval[1]);
}
}
}
static gchar*
_checked_g_strdup(const char* in)
{
if (in == NULL)
return NULL;
return g_strdup(in);
}
return cert;
TLSCertificate*
tlscerts_new(const char* fingerprint_sha1, int version, const char* serialnumber, const char* subjectname,
const char* issuername, const char* notbefore, const char* notafter,
const char* key_alg, const char* signature_alg, const char* pem,
const char* fingerprint_sha256, const char* pubkey_fingerprint)
{
return _tlscerts_new(_checked_g_strdup(fingerprint_sha1), version, _checked_g_strdup(serialnumber), _checked_g_strdup(subjectname),
_checked_g_strdup(issuername), _checked_g_strdup(notbefore), _checked_g_strdup(notafter),
_checked_g_strdup(key_alg), _checked_g_strdup(signature_alg), _checked_g_strdup(pem),
_checked_g_strdup(fingerprint_sha256), _checked_g_strdup(pubkey_fingerprint));
}
static void
_checked_g_key_file_set_string(GKeyFile* key_file,
const gchar* group_name,
const gchar* key,
const gchar* string)
{
if (string == NULL)
return;
g_key_file_set_string(key_file, group_name, key, string);
}
void
@@ -261,33 +282,21 @@ tlscerts_add(const TLSCertificate* cert)
autocomplete_add(certs_ac, cert->fingerprint);
g_key_file_set_integer(tlscerts, cert->fingerprint, "version", cert->version);
if (cert->serialnumber) {
g_key_file_set_string(tlscerts, cert->fingerprint, "serialnumber", cert->serialnumber);
}
if (cert->subjectname) {
g_key_file_set_string(tlscerts, cert->fingerprint, "subjectname", cert->subjectname);
}
if (cert->issuername) {
g_key_file_set_string(tlscerts, cert->fingerprint, "issuername", cert->issuername);
}
if (cert->notbefore) {
g_key_file_set_string(tlscerts, cert->fingerprint, "start", cert->notbefore);
}
if (cert->notafter) {
g_key_file_set_string(tlscerts, cert->fingerprint, "end", cert->notafter);
}
if (cert->key_alg) {
g_key_file_set_string(tlscerts, cert->fingerprint, "keyalg", cert->key_alg);
}
if (cert->signature_alg) {
g_key_file_set_string(tlscerts, cert->fingerprint, "signaturealg", cert->signature_alg);
}
_checked_g_key_file_set_string(tlscerts, cert->fingerprint, "serialnumber", cert->serialnumber);
_checked_g_key_file_set_string(tlscerts, cert->fingerprint, "subjectname", cert->subjectname);
_checked_g_key_file_set_string(tlscerts, cert->fingerprint, "issuername", cert->issuername);
_checked_g_key_file_set_string(tlscerts, cert->fingerprint, "start", cert->notbefore);
_checked_g_key_file_set_string(tlscerts, cert->fingerprint, "end", cert->notafter);
_checked_g_key_file_set_string(tlscerts, cert->fingerprint, "keyalg", cert->key_alg);
_checked_g_key_file_set_string(tlscerts, cert->fingerprint, "signaturealg", cert->signature_alg);
_checked_g_key_file_set_string(tlscerts, cert->fingerprint, "fingerprint_sha1", cert->fingerprint_sha1);
_checked_g_key_file_set_string(tlscerts, cert->fingerprint, "pubkey_fingerprint", cert->pubkey_fingerprint);
_save_tlscerts();
}
gboolean
tlscerts_revoke(const char* const fingerprint)
tlscerts_revoke(const char* fingerprint)
{
gboolean result = g_key_file_remove_group(tlscerts, fingerprint, NULL);
if (result) {
@@ -300,28 +309,24 @@ tlscerts_revoke(const char* const fingerprint)
}
TLSCertificate*
tlscerts_get_trusted(const char* const fingerprint)
tlscerts_get_trusted(const gchar* fingerprint)
{
if (!g_key_file_has_group(tlscerts, fingerprint)) {
gsize len = 0;
auto_gcharv gchar** groups = g_key_file_get_groups(tlscerts, &len);
for (gsize i = 0; i < len; i++) {
auto_gchar gchar* fingerprint_sha1 = g_key_file_get_string(tlscerts, groups[i], "fingerprint_sha1", NULL);
if (g_strcmp0(fingerprint, fingerprint_sha1) == 0) {
return _get_TLSCertificate(fingerprint_sha1);
}
}
return NULL;
}
int version = g_key_file_get_integer(tlscerts, fingerprint, "version", NULL);
auto_gchar gchar* serialnumber = g_key_file_get_string(tlscerts, fingerprint, "serialnumber", NULL);
auto_gchar gchar* subjectname = g_key_file_get_string(tlscerts, fingerprint, "subjectname", NULL);
auto_gchar gchar* issuername = g_key_file_get_string(tlscerts, fingerprint, "issuername", NULL);
auto_gchar gchar* notbefore = g_key_file_get_string(tlscerts, fingerprint, "start", NULL);
auto_gchar gchar* notafter = g_key_file_get_string(tlscerts, fingerprint, "end", NULL);
auto_gchar gchar* keyalg = g_key_file_get_string(tlscerts, fingerprint, "keyalg", NULL);
auto_gchar gchar* signaturealg = g_key_file_get_string(tlscerts, fingerprint, "signaturealg", NULL);
TLSCertificate* cert = tlscerts_new(fingerprint, version, serialnumber, subjectname, issuername, notbefore,
notafter, keyalg, signaturealg, NULL);
return cert;
return _get_TLSCertificate(fingerprint);
}
char*
tlscerts_complete(const char* const prefix, gboolean previous, void* context)
tlscerts_complete(const char* prefix, gboolean previous, void* context)
{
return autocomplete_complete(certs_ac, prefix, TRUE, previous);
}
@@ -332,40 +337,37 @@ tlscerts_reset_ac(void)
autocomplete_reset(certs_ac);
}
static void
_tls_cert_name_free(tls_cert_name_t* name)
{
g_free(name->country);
g_free(name->state);
g_free(name->distinguishedname);
g_free(name->serialnumber);
g_free(name->commonname);
g_free(name->organisation);
g_free(name->organisation_unit);
g_free(name->email);
}
void
tlscerts_free(TLSCertificate* cert)
{
if (cert) {
free(cert->serialnumber);
_tls_cert_name_free(&cert->subject);
_tls_cert_name_free(&cert->issuer);
free(cert->subjectname);
free(cert->subject_country);
free(cert->subject_state);
free(cert->subject_distinguishedname);
free(cert->subject_serialnumber);
free(cert->subject_commonname);
free(cert->subject_organisation);
free(cert->subject_organisation_unit);
free(cert->subject_email);
free(cert->issuername);
free(cert->issuer_country);
free(cert->issuer_state);
free(cert->issuer_distinguishedname);
free(cert->issuer_serialnumber);
free(cert->issuer_commonname);
free(cert->issuer_organisation);
free(cert->issuer_organisation_unit);
free(cert->issuer_email);
free(cert->notbefore);
free(cert->notafter);
free(cert->fingerprint);
free(cert->key_alg);
free(cert->signature_alg);
free(cert->pem);
g_free(cert->pubkey_fingerprint);
g_free(cert->pem);
g_free(cert->signature_alg);
g_free(cert->key_alg);
g_free(cert->notafter);
g_free(cert->notbefore);
g_free(cert->issuername);
g_free(cert->subjectname);
g_free(cert->serialnumber);
g_free(cert->fingerprint_sha1);
g_free(cert->fingerprint_sha256);
free(cert);
}

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef CONFIG_TLSCERTS_H
@@ -38,61 +12,63 @@
#include <glib.h>
typedef struct tls_cert_name_t
{
gchar* country;
gchar* state;
gchar* distinguishedname;
gchar* serialnumber;
gchar* commonname;
gchar* organisation;
gchar* organisation_unit;
gchar* email;
} tls_cert_name_t;
typedef struct tls_cert_t
{
int version;
char* serialnumber;
char* subjectname;
char* subject_country;
char* subject_state;
char* subject_distinguishedname;
char* subject_serialnumber;
char* subject_commonname;
char* subject_organisation;
char* subject_organisation_unit;
char* subject_email;
char* issuername;
char* issuer_country;
char* issuer_state;
char* issuer_distinguishedname;
char* issuer_serialnumber;
char* issuer_commonname;
char* issuer_organisation;
char* issuer_organisation_unit;
char* issuer_email;
char* notbefore;
char* notafter;
char* fingerprint;
char* key_alg;
char* signature_alg;
char* pem;
const gchar* fingerprint;
gchar* serialnumber;
gchar* subjectname;
tls_cert_name_t subject;
gchar* issuername;
tls_cert_name_t issuer;
gchar* notbefore;
gchar* notafter;
gchar* fingerprint_sha1;
gchar* fingerprint_sha256;
gchar* key_alg;
gchar* signature_alg;
gchar* pem;
gchar* pubkey_fingerprint;
} TLSCertificate;
void tlscerts_init(void);
TLSCertificate* tlscerts_new(const char* const fingerprint, int version, const char* const serialnumber, const char* const subjectname,
const char* const issuername, const char* const notbefore, const char* const notafter,
const char* const key_alg, const char* const signature_alg, const char* const pem);
TLSCertificate* tlscerts_new(const char* fingerprint_sha1, int version, const char* serialnumber, const char* subjectname,
const char* issuername, const char* notbefore, const char* notafter,
const char* key_alg, const char* signature_alg, const char* pem,
const char* fingerprint_sha256, const char* pubkey_fingerprint);
void tlscerts_set_current(const char* const fp);
void tlscerts_set_current(const TLSCertificate* cert);
char* tlscerts_get_current(void);
gboolean tlscerts_current_fingerprint_equals(const TLSCertificate* cert);
void tlscerts_clear_current(void);
gboolean tlscerts_exists(const char* const fingerprint);
gboolean tlscerts_exists(const TLSCertificate* cert);
void tlscerts_add(const TLSCertificate* cert);
gboolean tlscerts_revoke(const char* const fingerprint);
gboolean tlscerts_revoke(const char* fingerprint);
TLSCertificate* tlscerts_get_trusted(const char* const fingerprint);
TLSCertificate* tlscerts_get_trusted(const char* fingerprint);
void tlscerts_free(TLSCertificate* cert);
GList* tlscerts_list(void);
char* tlscerts_complete(const char* const prefix, gboolean previous, void* context);
char* tlscerts_complete(const char* prefix, gboolean previous, void* context);
void tlscerts_reset_ac(void);

View File

@@ -2,35 +2,9 @@
* database.c
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2020 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2020 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -61,9 +35,10 @@ static prof_msg_type_t _get_message_type_type(const char* const type);
static prof_enc_t _get_message_enc_type(const char* const encstr);
static int _get_db_version(void);
static gboolean _migrate_to_v2(void);
static gboolean _migrate_to_v3(void);
static gboolean _check_available_space_for_db_migration(char* path_to_db);
static const int latest_version = 2;
static const int latest_version = 3;
// Helper: close DB handle (if any), warn on busy, and shutdown SQLite
static void
@@ -167,22 +142,22 @@ log_database_init(ProfAccount* account)
// replace_id is the ID from XEP-0308: Last Message Correction
// replaces_db_id is ID (primary key) of the original message that LMC message corrects/replaces
// replaced_by_db_id is ID (primary key) of the last correcting (LMC) message for the original message
const char* query = "CREATE TABLE IF NOT EXISTS `ChatLogs` ("
"`id` INTEGER PRIMARY KEY AUTOINCREMENT, "
"`from_jid` TEXT NOT NULL, "
"`to_jid` TEXT NOT NULL, "
"`from_resource` TEXT, "
"`to_resource` TEXT, "
"`message` TEXT, "
"`timestamp` TEXT, "
"`type` TEXT, "
"`stanza_id` TEXT, "
"`archive_id` TEXT, "
"`encryption` TEXT, "
"`marked_read` INTEGER, "
"`replace_id` TEXT, "
"`replaces_db_id` INTEGER, "
"`replaced_by_db_id` INTEGER)";
char* query = "CREATE TABLE IF NOT EXISTS `ChatLogs` ("
"`id` INTEGER PRIMARY KEY AUTOINCREMENT, "
"`from_jid` TEXT NOT NULL, "
"`to_jid` TEXT NOT NULL, "
"`from_resource` TEXT, "
"`to_resource` TEXT, "
"`message` TEXT, "
"`timestamp` TEXT, "
"`type` TEXT, "
"`stanza_id` TEXT, "
"`archive_id` TEXT UNIQUE, "
"`encryption` TEXT, "
"`marked_read` INTEGER, "
"`replace_id` TEXT, "
"`replaces_db_id` INTEGER, "
"`replaced_by_db_id` INTEGER)";
if (SQLITE_OK != sqlite3_exec(g_chatlog_database, query, NULL, 0, &err_msg)) {
goto out;
}
@@ -218,7 +193,7 @@ log_database_init(ProfAccount* account)
}
if (db_version == -1) {
query = "INSERT OR IGNORE INTO `DbVersion` (`version`) VALUES ('2')";
query = "INSERT INTO `DbVersion` (`version`) VALUES ('2') ON CONFLICT(`version`) DO NOTHING";
if (SQLITE_OK != sqlite3_exec(g_chatlog_database, query, NULL, 0, &err_msg)) {
goto out;
}
@@ -237,6 +212,10 @@ log_database_init(ProfAccount* account)
cons_show_error("Database Initialization Error: Unable to migrate database to version 2. Please, check error logs for details.");
goto out;
}
if (db_version < 3 && (!_check_available_space_for_db_migration(filename) || !_migrate_to_v3())) {
cons_show_error("Database Initialization Error: Unable to migrate database to version 3. Please, check error logs for details.");
goto out;
}
cons_show("Database schema migration was successful.");
}
@@ -350,11 +329,14 @@ log_database_get_limits_info(const gchar* const contact_barejid, gboolean is_las
msg->stanzaid = _db_strdup(archive_id);
msg->timestamp = g_date_time_new_from_iso8601(date, NULL);
} else {
message_free(msg);
msg = NULL;
}
sqlite3_finalize(stmt);
// If nothing was found and caller expects the last message, provide a sane default
if (!msg->timestamp && is_last) {
if (msg && !msg->timestamp && is_last) {
msg->timestamp = g_date_time_new_now_utc();
}
@@ -381,8 +363,7 @@ log_database_get_previous_chat(const gchar* const contact_barejid, const gchar*
// Flip order when querying older pages
const gchar* sort1 = from_start ? "ASC" : "DESC";
const gchar* sort2 = !flip ? "ASC" : "DESC";
GDateTime* now = g_date_time_new_now_local();
auto_gchar gchar* end_date_fmt = end_time ? g_strdup(end_time) : g_date_time_format_iso8601(now);
auto_gchar gchar* end_date_fmt = end_time ? g_strdup(end_time) : prof_date_time_format_iso8601(NULL);
auto_sqlite gchar* query = sqlite3_mprintf("SELECT * FROM ("
"SELECT COALESCE(B.`message`, A.`message`) AS message, "
"A.`timestamp`, A.`from_jid`, A.`from_resource`, A.`to_jid`, A.`to_resource`, A.`type`, A.`encryption`, A.`stanza_id` FROM `ChatLogs` AS A "
@@ -395,8 +376,6 @@ log_database_get_previous_chat(const gchar* const contact_barejid, const gchar*
"ORDER BY `timestamp` %s;",
contact_barejid, myjid->barejid, myjid->barejid, contact_barejid, end_date_fmt, start_time, start_time, sort1, MESSAGES_TO_RETRIEVE, sort2);
g_date_time_unref(now);
if (!query) {
log_error("Could not allocate memory.");
return DB_RESPONSE_ERROR;
@@ -518,17 +497,7 @@ _add_to_db(ProfMessage* message, const char* type, const Jid* const from_jid, co
return;
}
char* err_msg;
auto_gchar gchar* date_fmt = NULL;
if (message->timestamp) {
date_fmt = g_date_time_format_iso8601(message->timestamp);
} else {
GDateTime* dt = g_date_time_new_now_local();
date_fmt = g_date_time_format_iso8601(dt);
g_date_time_unref(dt);
}
auto_gchar gchar* date_fmt = prof_date_time_format_iso8601(message->timestamp);
const char* enc = _get_message_enc_str(message->enc);
if (!type) {
@@ -571,26 +540,7 @@ _add_to_db(ProfMessage* message, const char* type, const Jid* const from_jid, co
}
// stanza-id (XEP-0359) doesn't have to be present in the message.
// But if it's duplicated, it's a serious server-side problem, so we better track it.
// Unless it's MAM, in that case it's expected behaviour.
if (message->stanzaid && !message->is_mam) {
auto_sqlite char* duplicate_check_query = sqlite3_mprintf("SELECT 1 FROM `ChatLogs` WHERE (`archive_id` = %Q)",
message->stanzaid);
if (!duplicate_check_query) {
log_error("Could not allocate memory for SQL duplicate query in log_database_add()");
return;
}
sqlite3_stmt* stmt;
if (_db_prepare_ctx(duplicate_check_query, &stmt, "_add_to_db(duplicate_check)")) {
if (sqlite3_step(stmt) == SQLITE_ROW) {
log_error("Duplicate stanza-id found for the message. stanza_id: %s; archive_id: %s; sender: %s; content: %s", message->id, message->stanzaid, from_jid->barejid, message->plain);
cons_show_error("Got a message with duplicate (server-generated) stanza-id from %s.", from_jid->fulljid);
}
sqlite3_finalize(stmt);
}
}
// We use archive_id UNIQUE constraint and ON CONFLICT DO NOTHING for deduplication.
auto_sqlite char* orig_message_id = original_message_id == -1 ? NULL : sqlite3_mprintf("%d", original_message_id);
@@ -598,7 +548,9 @@ _add_to_db(ProfMessage* message, const char* type, const Jid* const from_jid, co
"(`from_jid`, `from_resource`, `to_jid`, `to_resource`, "
"`message`, `timestamp`, `stanza_id`, `archive_id`, "
"`replaces_db_id`, `replace_id`, `type`, `encryption`) "
"VALUES (%Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q)",
"VALUES (%Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q) "
"ON CONFLICT(`archive_id`) DO NOTHING "
"RETURNING id",
from_jid->barejid,
from_jid->resourcepart,
to_jid->barejid,
@@ -618,19 +570,23 @@ _add_to_db(ProfMessage* message, const char* type, const Jid* const from_jid, co
log_debug("Writing to DB. Query: %s", query);
if (SQLITE_OK != sqlite3_exec(g_chatlog_database, query, NULL, 0, &err_msg)) {
if (err_msg) {
log_error("SQLite error in _add_to_db(): %s", err_msg);
sqlite3_free(err_msg);
} else {
log_error("Unknown SQLite error in _add_to_db().");
}
} else {
int inserted_rows_count = sqlite3_changes(g_chatlog_database);
if (inserted_rows_count < 1) {
log_error("SQLite did not insert message (rows: %d, id: %s, content: %s)", inserted_rows_count, message->id, message->plain);
}
sqlite3_stmt* stmt = NULL;
int rc = sqlite3_prepare_v2(g_chatlog_database, query, -1, &stmt, NULL);
if (rc != SQLITE_OK) {
log_error("SQLite error in _add_to_db() (prepare): %s", sqlite3_errmsg(g_chatlog_database));
return;
}
rc = sqlite3_step(stmt);
if (rc == SQLITE_ROW) {
log_debug("Successfully inserted message into database.");
} else if (rc == SQLITE_DONE) {
log_debug("Message already exists in database (archive_id: %s), skipping.", message->stanzaid);
} else {
log_error("SQLite error in _add_to_db() (step): %s", sqlite3_errmsg(g_chatlog_database));
}
sqlite3_finalize(stmt);
}
static int
@@ -735,3 +691,78 @@ _check_available_space_for_db_migration(char* path_to_db)
return FALSE;
}
}
static gboolean
_migrate_to_v3(void)
{
char* err_msg = NULL;
const char* sql_statements[] = {
"BEGIN TRANSACTION",
"CREATE TABLE `ChatLogs_v3_migration` ("
"`id` INTEGER PRIMARY KEY AUTOINCREMENT, "
"`from_jid` TEXT NOT NULL, "
"`to_jid` TEXT NOT NULL, "
"`from_resource` TEXT, "
"`to_resource` TEXT, "
"`message` TEXT, "
"`timestamp` TEXT, "
"`type` TEXT, "
"`stanza_id` TEXT, "
"`archive_id` TEXT UNIQUE, "
"`encryption` TEXT, "
"`marked_read` INTEGER, "
"`replace_id` TEXT, "
"`replaces_db_id` INTEGER, "
"`replaced_by_db_id` INTEGER)",
"INSERT INTO `ChatLogs_v3_migration` "
"SELECT * FROM `ChatLogs` "
"WHERE `archive_id` IS NULL "
"UNION ALL "
"SELECT * FROM (SELECT * FROM `ChatLogs` WHERE `archive_id` IS NOT NULL GROUP BY `archive_id`)",
"DROP TABLE `ChatLogs` ",
"ALTER TABLE `ChatLogs_v3_migration` RENAME TO `ChatLogs` ",
"CREATE INDEX ChatLogs_timestamp_IDX ON `ChatLogs` (`timestamp`)",
"CREATE INDEX ChatLogs_to_from_jid_IDX ON `ChatLogs` (`to_jid`, `from_jid`)",
"CREATE TRIGGER update_corrected_message "
"AFTER INSERT ON ChatLogs "
"FOR EACH ROW "
"WHEN NEW.replaces_db_id IS NOT NULL "
"BEGIN "
"UPDATE ChatLogs "
"SET replaced_by_db_id = NEW.id "
"WHERE id = NEW.replaces_db_id; "
"END;",
"UPDATE `DbVersion` SET `version` = 3;",
"END TRANSACTION"
};
int statements_count = sizeof(sql_statements) / sizeof(sql_statements[0]);
for (int i = 0; i < statements_count; i++) {
if (SQLITE_OK != sqlite3_exec(g_chatlog_database, sql_statements[i], NULL, 0, &err_msg)) {
log_error("SQLite error in _migrate_to_v3() on statement %d: %s", i, err_msg);
if (err_msg) {
sqlite3_free(err_msg);
err_msg = NULL;
}
goto cleanup;
}
}
return TRUE;
cleanup:
if (SQLITE_OK != sqlite3_exec(g_chatlog_database, "ROLLBACK;", NULL, 0, &err_msg)) {
log_error("DB Migration] Unable to ROLLBACK: %s", err_msg);
if (err_msg) {
sqlite3_free(err_msg);
}
}
return FALSE;
}

View File

@@ -2,35 +2,9 @@
* database.h
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2020 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2020 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef DATABASE_H

View File

@@ -3,35 +3,9 @@
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2019 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2019 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -118,7 +92,7 @@ cl_ev_reconnect(void)
void
cl_ev_presence_send(const resource_presence_t presence_type, const int idle_secs)
{
auto_char char* signed_status = NULL;
auto_gchar gchar* signed_status = NULL;
#ifdef HAVE_LIBGPGME
ProfAccount* account = accounts_get_account(session_get_account_name());
@@ -137,9 +111,14 @@ cl_ev_send_msg_correct(ProfChatWin* chatwin, const char* const msg, const char*
chat_state_active(chatwin->state);
gboolean request_receipt = prefs_get_boolean(PREF_RECEIPTS_REQUEST);
if (request_receipt) {
auto_char char* jid = chat_session_get_jid(chatwin->barejid);
request_receipt = caps_jid_has_feature(jid, XMPP_FEATURE_RECEIPTS);
}
auto_char char* plugin_msg = plugins_pre_chat_message_send(chatwin->barejid, msg);
const char* const message = plugin_msg ?: msg;
auto_gchar gchar* sanitized_msg = str_xml_sanitize(plugin_msg ?: msg);
const char* message = sanitized_msg;
char* replace_id = NULL;
if (correct_last_msg) {
@@ -201,7 +180,8 @@ void
cl_ev_send_muc_msg_corrected(ProfMucWin* mucwin, const char* const msg, const char* const oob_url, gboolean correct_last_msg)
{
auto_char char* plugin_msg = plugins_pre_room_message_send(mucwin->roomjid, msg);
const char* const message = plugin_msg ?: msg;
auto_gchar gchar* sanitized_msg = str_xml_sanitize(plugin_msg ?: msg);
const char* message = sanitized_msg;
char* replace_id = NULL;
if (correct_last_msg) {
@@ -242,7 +222,8 @@ cl_ev_send_priv_msg(ProfPrivateWin* privwin, const char* const msg, const char*
privwin_message_left_room(privwin);
} else {
auto_char char* plugin_msg = plugins_pre_priv_message_send(privwin->fulljid, msg);
const char* const message = plugin_msg ?: msg;
auto_gchar gchar* sanitized_msg = str_xml_sanitize(plugin_msg ?: msg);
const char* message = sanitized_msg;
auto_jid Jid* jidp = jid_create(privwin->fulljid);
auto_char char* id = message_send_private(privwin->fulljid, message, oob_url);

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef EVENT_CLIENT_EVENTS_H

View File

@@ -2,35 +2,9 @@
* common.c
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2019 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2019 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"

View File

@@ -2,35 +2,9 @@
* common.h
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2019 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2019 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef EVENT_COMMON_H

View File

@@ -3,35 +3,9 @@
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2019 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2019 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -86,6 +60,10 @@ void
sv_ev_login_account_success(char* account_name, gboolean secured)
{
ProfAccount* account = accounts_get_account(account_name);
if (!account) {
log_error("Could not find account: %s", account_name);
return;
}
bookmark_ignore_on_connect(account->jid);
@@ -587,6 +565,8 @@ _sv_ev_incoming_omemo(ProfChatWin* chatwin, gboolean new_win, ProfMessage* messa
chat_log_omemo_msg_in(message);
}
chatwin->pgp_recv = FALSE;
wins_omemo_trust_changed(chatwin->barejid);
#endif
}
@@ -596,6 +576,9 @@ _sv_ev_incoming_plain(ProfChatWin* chatwin, gboolean new_win, ProfMessage* messa
if (message->body) {
message->enc = PROF_MSG_ENC_NONE;
message->plain = strdup(message->body);
if (message->plain == NULL) {
return;
}
_clean_incoming_message(message);
chatwin_incoming_msg(chatwin, message, new_win);
log_database_add_incoming(message);
@@ -1150,14 +1133,13 @@ int
sv_ev_certfail(const char* const errormsg, const TLSCertificate* cert)
{
// check profanity trusted certs
if (tlscerts_exists(cert->fingerprint)) {
if (tlscerts_exists(cert)) {
cafile_add(cert);
return 1;
}
// check current cert
char* current_fp = tlscerts_get_current();
if (current_fp && g_strcmp0(current_fp, cert->fingerprint) == 0) {
if (tlscerts_current_fingerprint_equals(cert)) {
return 1;
}
@@ -1188,11 +1170,11 @@ sv_ev_certfail(const char* const errormsg, const TLSCertificate* cert)
if (g_strcmp0(cmd, "/tls allow") == 0) {
cons_show("Continuing with connection.");
tlscerts_set_current(cert->fingerprint);
tlscerts_set_current(cert);
return 1;
} else if (g_strcmp0(cmd, "/tls always") == 0) {
cons_show("Adding %s to trusted certificates.", cert->fingerprint);
if (!tlscerts_exists(cert->fingerprint)) {
if (!tlscerts_exists(cert)) {
tlscerts_add(cert);
cafile_add(cert);
}
@@ -1303,6 +1285,10 @@ sv_ev_bookmark_autojoin(Bookmark* bookmark)
static void
_cut(ProfMessage* message, const char* cut)
{
if (message->plain == NULL) {
return;
}
if (strstr(message->plain, cut)) {
auto_gcharv gchar** split = g_strsplit(message->plain, cut, -1);
free(message->plain);

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef EVENT_SERVER_EVENTS_H

6
src/gitversion.h.in Normal file
View File

@@ -0,0 +1,6 @@
#ifndef PROF_GIT_BRANCH
#define PROF_GIT_BRANCH @PROF_GIT_BRANCH@
#endif
#ifndef PROF_GIT_REVISION
#define PROF_GIT_REVISION @PROF_GIT_REVISION@
#endif

View File

@@ -3,35 +3,9 @@
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2018 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2018 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -60,6 +34,7 @@ static FILE* logp;
static gchar* mainlogfile = NULL;
static gboolean user_provided_log = FALSE;
static log_level_t level_filter;
static pid_t prof_pid;
static int stderr_inited;
static log_level_t stderr_level;
@@ -75,6 +50,8 @@ enum {
static void
_rotate_log_file(void)
{
if (!mainlogfile)
return;
auto_gchar gchar* log_file = g_strdup(mainlogfile);
size_t len = strlen(log_file);
auto_gchar gchar* log_file_new = malloc(len + 5);
@@ -198,6 +175,8 @@ log_init(log_level_t filter, const char* const log_file)
logp = fopen(mainlogfile, "a");
g_chmod(mainlogfile, S_IRUSR | S_IWUSR);
prof_pid = getpid();
}
const gchar*
@@ -225,14 +204,11 @@ log_close(void)
static void
_log_msg(log_level_t level, const char* const area, const char* const msg)
{
GDateTime* dt = g_date_time_new_now_local();
char* level_str = _log_abbreviation_string_from_level(level);
auto_gchar gchar* date_fmt = g_date_time_format_iso8601(dt);
auto_gchar gchar* date_fmt = prof_date_time_format_iso8601(NULL);
fprintf(logp, "%s: %s: %s: %s\n", date_fmt, area, level_str, msg);
g_date_time_unref(dt);
fprintf(logp, "%s: %08d: %s: %s: %s\n", date_fmt, prof_pid, area, level_str, msg);
fflush(logp);
@@ -359,11 +335,6 @@ log_stderr_init(log_level_t level)
if (rc != 0)
goto err;
close(STDERR_FILENO);
rc = dup2(stderr_pipe[1], STDERR_FILENO);
if (rc < 0)
goto err_close;
rc = log_stderr_nonblock_set(stderr_pipe[0])
?: log_stderr_nonblock_set(stderr_pipe[1]);
if (rc != 0)
@@ -371,15 +342,21 @@ log_stderr_init(log_level_t level)
stderr_buf = malloc(STDERR_BUFSIZE);
stderr_msg = g_string_sized_new(STDERR_BUFSIZE);
stderr_level = level;
stderr_inited = 1;
prof_add_shutdown_routine(_log_stderr_close);
if (stderr_buf == NULL || stderr_msg == NULL) {
errno = ENOMEM;
goto err_free;
}
int dup_fd = dup2(stderr_pipe[1], STDERR_FILENO);
if (dup_fd < 0)
goto err_free;
close(dup_fd);
stderr_level = level;
stderr_inited = 1;
prof_add_shutdown_routine(_log_stderr_close);
return;
err_free:

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef LOG_H

View File

@@ -3,35 +3,9 @@
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2019 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2019 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -78,7 +52,7 @@ main(int argc, char** argv)
GOptionEntry entries[] = {
{ "version", 'v', 0, G_OPTION_ARG_NONE, &version, "Show version information", NULL },
{ "account", 'a', 0, G_OPTION_ARG_STRING, &account_name, "Auto connect to an account on startup" },
{ "account", 'a', 0, G_OPTION_ARG_STRING, &account_name, "Auto connect to an account on startup", NULL },
{ "log", 'l', 0, G_OPTION_ARG_STRING, &log, "Set logging levels, DEBUG, INFO, WARN (default), ERROR", "LEVEL" },
{ "config", 'c', 0, G_OPTION_ARG_STRING, &config_file, "Use an alternative configuration file", NULL },
{ "logfile", 'f', 0, G_OPTION_ARG_STRING, &log_file, "Specify log file", NULL },
@@ -93,9 +67,9 @@ main(int argc, char** argv)
context = g_option_context_new(NULL);
g_option_context_add_main_entries(context, entries, NULL);
if (!g_option_context_parse(context, &argc, &argv, &error)) {
g_print("%s\n", error->message);
g_print("%s\n", PROF_GERROR_MESSAGE(error));
g_option_context_free(context);
g_error_free(error);
PROF_GERROR_FREE(error);
return 1;
}
@@ -107,7 +81,7 @@ main(int argc, char** argv)
// lets use fixed email instead of PACKAGE_BUGREPORT
g_print("Copyright (C) 2012 - 2019 James Booth <boothj5web@gmail.com>.\n");
g_print("Copyright (C) 2019 - 2025 Michael Vetter <jubalh@iodoru.org>.\n");
g_print("Copyright (C) 2019 - 2026 Michael Vetter <jubalh@iodoru.org>.\n");
g_print("License GPLv3+: GNU GPL version 3 or later <https://www.gnu.org/licenses/gpl.html>\n");
g_print("\n");
g_print("This is free software; you are free to change and redistribute it.\n");

View File

@@ -4,39 +4,18 @@
*
* Copyright (C) 2019 Paul Fariello <paul@fariello.eu>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
#include <assert.h>
#ifdef HAVE_LIBOMEMO_C
#include <omemo/signal_protocol.h>
#include <omemo/signal_protocol_types.h>
#else
#include <signal/signal_protocol.h>
#include <signal/signal_protocol_types.h>
#endif
#include "log.h"
#include "omemo/omemo.h"
@@ -389,7 +368,7 @@ out:
gcry_error_t
aes256gcm_crypt_file(FILE* in, FILE* out, off_t file_size,
unsigned char key[], unsigned char nonce[], bool encrypt)
unsigned char key[], unsigned char nonce[], gboolean encrypt)
{
if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) {

View File

@@ -4,37 +4,18 @@
*
* Copyright (C) 2019 Paul Fariello <paul@fariello.eu>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include <stdio.h>
#include <stdbool.h>
#include "config.h"
#ifdef HAVE_LIBOMEMO_C
#include <omemo/signal_protocol_types.h>
#else
#include <signal/signal_protocol_types.h>
#endif
#include <gcrypt.h>
#define AES128_GCM_KEY_LENGTH 16
@@ -185,7 +166,7 @@ int aes128gcm_decrypt(unsigned char* plaintext,
const unsigned char* const key, const unsigned char* const tag);
gcry_error_t aes256gcm_crypt_file(FILE* in, FILE* out, off_t file_size,
unsigned char key[], unsigned char nonce[], bool encrypt);
unsigned char key[], unsigned char nonce[], gboolean encrypt);
char* aes256gcm_create_secure_fragment(unsigned char* key,
unsigned char* nonce);

File diff suppressed because it is too large Load Diff

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2019 Paul Fariello <paul@fariello.eu>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include <glib.h>
#include <gcrypt.h>
@@ -85,6 +59,9 @@ void omemo_trust(const char* const jid, const char* const fingerprint);
void omemo_untrust(const char* const jid, const char* const fingerprint);
GList* omemo_known_device_identities(const char* const jid);
gboolean omemo_is_trusted_identity(const char* const jid, const char* const fingerprint);
gboolean omemo_is_jid_trusted(const char* const jid);
GList* omemo_get_jid_untrusted_fingerprints(const char* const jid);
gboolean omemo_is_device_active(const char* const jid, const char* const fingerprint);
char* omemo_fingerprint_autocomplete(const char* const search_str, gboolean previous, void* context);
void omemo_fingerprint_autocomplete_reset(void);
gboolean omemo_automatic_start(const char* const recipient);
@@ -95,8 +72,9 @@ void omemo_start_muc_sessions(const char* const roomjid);
void omemo_start_device_session(const char* const jid, uint32_t device_id, GList* prekeys, uint32_t signed_prekey_id, const unsigned char* const signed_prekey, size_t signed_prekey_len, const unsigned char* const signature, size_t signature_len, const unsigned char* const identity_key, size_t identity_key_len);
gboolean omemo_loaded(void);
char* omemo_on_message_send(ProfWin* win, const char* const message, gboolean request_receipt, gboolean muc, const char* const replace_id);
char* omemo_on_message_recv(const char* const from, uint32_t sid, const unsigned char* const iv, size_t iv_len, GList* keys, const unsigned char* const payload, size_t payload_len, gboolean muc, gboolean* trusted);
char* omemo_on_message_recv(const char* const from, uint32_t sid, const unsigned char* const iv, size_t iv_len, GList* keys, const unsigned char* const payload, size_t payload_len, gboolean muc, gboolean* trusted, omemo_error_t* error) __attribute__((nonnull(9, 10)));
char* omemo_encrypt_file(FILE* in, FILE* out, off_t file_size, int* gcry_res);
gcry_error_t omemo_decrypt_file(FILE* in, FILE* out, off_t file_size, const char* fragment);

View File

@@ -4,38 +4,17 @@
*
* Copyright (C) 2019 Paul Fariello <paul@fariello.eu>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include <glib.h>
#include <signal/signal_protocol.h>
#include "config.h"
#ifdef HAVE_LIBOMEMO_C
#include <omemo/signal_protocol.h>
#else
#include <signal/signal_protocol.h>
#endif
#include "log.h"
#include "omemo/omemo.h"
#include "omemo/store.h"

View File

@@ -4,38 +4,16 @@
*
* Copyright (C) 2019 Paul Fariello <paul@fariello.eu>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include <signal/signal_protocol.h>
#include "config.h"
#ifdef HAVE_LIBOMEMO_C
#include <omemo/signal_protocol.h>
#else
#include <signal/signal_protocol.h>
#endif
#define OMEMO_STORE_GROUP_IDENTITY "identity"
#define OMEMO_STORE_GROUP_PREKEYS "prekeys"
#define OMEMO_STORE_GROUP_SIGNED_PREKEYS "signed_prekeys"
@@ -50,7 +28,7 @@ typedef struct
signal_buffer* private;
uint32_t registration_id;
GHashTable* trusted;
bool recv;
gboolean recv;
} identity_key_store_t;
GHashTable* session_store_new(void);

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -296,7 +270,8 @@ otr_on_message_recv(const char* const barejid, const char* const resource, const
// check for OTR whitespace (opportunistic or always)
if (policy == PROF_OTRPOLICY_OPPORTUNISTIC || policy == PROF_OTRPOLICY_ALWAYS) {
if (whitespace_base) {
if (strstr(message, OTRL_MESSAGE_TAG_V2) || strstr(message, OTRL_MESSAGE_TAG_V1)) {
char* tag_position = whitespace_base + strlen(OTRL_MESSAGE_TAG_BASE);
if (strncmp(tag_position, OTRL_MESSAGE_TAG_V2, strlen(OTRL_MESSAGE_TAG_V2)) == 0 || strncmp(tag_position, OTRL_MESSAGE_TAG_V1, strlen(OTRL_MESSAGE_TAG_V1)) == 0) {
// Remove whitespace pattern for proper display in UI
// Handle both BASE+TAGV1/2(16+8) and BASE+TAGV1+TAGV2(16+8+8)
int tag_length = 24;
@@ -661,11 +636,9 @@ otr_get_policy(const char* const recipient)
prof_otrpolicy_t result = PROF_OTRPOLICY_MANUAL;
if (g_strcmp0(account->otr_policy, "manual") == 0) {
result = PROF_OTRPOLICY_MANUAL;
}
if (g_strcmp0(account->otr_policy, "opportunistic") == 0) {
} else if (g_strcmp0(account->otr_policy, "opportunistic") == 0) {
result = PROF_OTRPOLICY_OPPORTUNISTIC;
}
if (g_strcmp0(account->otr_policy, "always") == 0) {
} else if (g_strcmp0(account->otr_policy, "always") == 0) {
result = PROF_OTRPOLICY_ALWAYS;
}
account_free(account);

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef OTR_OTR_H

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef OTR_OTRLIB_H

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"

View File

@@ -3,35 +3,9 @@
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2018 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2018 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -66,27 +40,28 @@ static GHashTable* pubkeys;
static prof_keyfile_t pubkeys_prof_keyfile;
static GKeyFile* pubkeyfile;
static char* passphrase;
static char* passphrase_attempt;
static gchar* passphrase;
static gchar* passphrase_attempt;
static Autocomplete key_ac;
static char* _remove_header_footer(char* str, const char* const footer);
static char* _add_header_footer(const char* const str, const char* const header, const char* const footer);
static char* _gpgme_data_to_char(gpgme_data_t data);
static gchar* _remove_header_footer(gchar* str, const char* const footer);
static gchar* _add_header_footer(const gchar* const str, const char* const header, const char* const footer);
static gchar* _gpgme_data_to_char(gpgme_data_t data);
static void _save_pubkeys(void);
static ProfPGPKey* _gpgme_key_to_ProfPGPKey(gpgme_key_t key);
static const gchar* _gpgme_key_get_email(gpgme_key_t key);
void
_p_gpg_free_pubkeyid(ProfPGPPubKeyId* pubkeyid)
{
if (pubkeyid) {
free(pubkeyid->id);
g_free(pubkeyid->id);
}
free(pubkeyid);
g_free(pubkeyid);
}
static gpgme_error_t*
static gpgme_error_t
_p_gpg_passphrase_cb(void* hook, const char* uid_hint, const char* passphrase_info, int prev_was_bad, int fd)
{
if (passphrase) {
@@ -94,21 +69,21 @@ _p_gpg_passphrase_cb(void* hook, const char* uid_hint, const char* passphrase_in
} else {
GString* pass_term = g_string_new("");
auto_char char* password = ui_ask_pgp_passphrase(uid_hint, prev_was_bad);
auto_gchar gchar* password = ui_ask_pgp_passphrase(uid_hint, prev_was_bad);
if (password) {
g_string_append(pass_term, password);
}
g_string_append(pass_term, "\n");
if (passphrase_attempt) {
free(passphrase_attempt);
g_free(passphrase_attempt);
}
passphrase_attempt = g_string_free(pass_term, FALSE);
gpgme_io_write(fd, passphrase_attempt, strlen(passphrase_attempt));
}
return 0;
return GPG_ERR_NO_ERROR;
}
static void
@@ -126,13 +101,11 @@ _p_gpg_close(void)
key_ac = NULL;
if (passphrase) {
free(passphrase);
passphrase = NULL;
GFREE_SET_NULL(passphrase);
}
if (passphrase_attempt) {
free(passphrase_attempt);
passphrase_attempt = NULL;
GFREE_SET_NULL(passphrase_attempt);
}
}
@@ -156,7 +129,7 @@ p_gpg_init(void)
}
void
p_gpg_on_connect(const char* const barejid)
p_gpg_on_connect(const gchar* const barejid)
{
gchar* pubsloc = files_file_in_account_data_path(DIR_PGP, barejid, "pubkeys");
if (!pubsloc) {
@@ -179,13 +152,13 @@ p_gpg_on_connect(const char* const barejid)
return;
}
for (int i = 0; i < len; i++) {
for (gsize i = 0; i < len; i++) {
GError* gerr = NULL;
gchar* jid = jids[i];
auto_gchar gchar* keyid = g_key_file_get_string(pubkeyfile, jid, "keyid", &gerr);
if (gerr) {
log_error("Error loading PGP key id for %s", jid);
g_error_free(gerr);
PROF_GERROR_FREE(gerr);
} else {
gpgme_key_t key = NULL;
error = gpgme_get_key(ctx, keyid, &key, 0);
@@ -194,10 +167,10 @@ p_gpg_on_connect(const char* const barejid)
continue;
}
ProfPGPPubKeyId* pubkeyid = malloc(sizeof(ProfPGPPubKeyId));
pubkeyid->id = strdup(keyid);
ProfPGPPubKeyId* pubkeyid = g_new0(ProfPGPPubKeyId, 1);
pubkeyid->id = g_strdup(keyid);
pubkeyid->received = FALSE;
g_hash_table_replace(pubkeys, strdup(jid), pubkeyid);
g_hash_table_replace(pubkeys, g_strdup(jid), pubkeyid);
gpgme_key_unref(key);
}
}
@@ -216,7 +189,7 @@ p_gpg_on_disconnect(void)
}
gboolean
p_gpg_addkey(const char* const jid, const char* const keyid)
p_gpg_addkey(const gchar* const jid, const gchar* const keyid)
{
gpgme_ctx_t ctx;
gpgme_error_t error = gpgme_new(&ctx);
@@ -239,10 +212,10 @@ p_gpg_addkey(const char* const jid, const char* const keyid)
_save_pubkeys();
// update in memory pubkeys list
ProfPGPPubKeyId* pubkeyid = malloc(sizeof(ProfPGPPubKeyId));
pubkeyid->id = strdup(keyid);
ProfPGPPubKeyId* pubkeyid = g_new0(ProfPGPPubKeyId, 1);
pubkeyid->id = g_strdup(keyid);
pubkeyid->received = FALSE;
g_hash_table_replace(pubkeys, strdup(jid), pubkeyid);
g_hash_table_replace(pubkeys, g_strdup(jid), pubkeyid);
gpgme_key_unref(key);
return TRUE;
@@ -251,7 +224,7 @@ p_gpg_addkey(const char* const jid, const char* const keyid)
ProfPGPKey*
p_gpg_key_new(void)
{
ProfPGPKey* p_pgpkey = malloc(sizeof(ProfPGPKey));
ProfPGPKey* p_pgpkey = g_new0(ProfPGPKey, 1);
p_pgpkey->id = NULL;
p_pgpkey->name = NULL;
p_pgpkey->fp = NULL;
@@ -268,10 +241,10 @@ void
p_gpg_free_key(ProfPGPKey* key)
{
if (key) {
free(key->id);
free(key->name);
free(key->fp);
free(key);
g_free(key->id);
g_free(key->name);
g_free(key->fp);
g_free(key);
}
}
@@ -294,7 +267,7 @@ GHashTable*
p_gpg_list_keys(void)
{
gpgme_error_t error;
GHashTable* result = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)p_gpg_free_key);
GHashTable* result = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)p_gpg_free_key);
gpgme_ctx_t ctx;
error = gpgme_new(&ctx);
@@ -312,7 +285,7 @@ p_gpg_list_keys(void)
while (!error) {
ProfPGPKey* p_pgpkey = _gpgme_key_to_ProfPGPKey(key);
if (p_pgpkey != NULL) {
g_hash_table_insert(result, strdup(p_pgpkey->name), p_pgpkey);
g_hash_table_insert(result, g_strdup(p_pgpkey->name), p_pgpkey);
}
gpgme_key_unref(key);
@@ -368,7 +341,7 @@ p_gpg_pubkeys(void)
return pubkeys;
}
const char*
const gchar*
p_gpg_libver(void)
{
if (libversion == NULL) {
@@ -378,14 +351,14 @@ p_gpg_libver(void)
}
gboolean
p_gpg_valid_key(const char* const keyid, char** err_str)
p_gpg_valid_key(const gchar* const keyid, gchar** err_str)
{
gpgme_ctx_t ctx;
gpgme_error_t error = gpgme_new(&ctx);
if (error) {
log_error("GPG: Failed to create gpgme context. %s %s", gpgme_strsource(error), gpgme_strerror(error));
if (err_str) {
*err_str = strdup(gpgme_strerror(error));
*err_str = g_strdup(gpgme_strerror(error));
}
return FALSE;
}
@@ -396,7 +369,7 @@ p_gpg_valid_key(const char* const keyid, char** err_str)
if (error || key == NULL) {
log_error("GPG: Failed to get key. %s %s", gpgme_strsource(error), gpgme_strerror(error));
if (err_str) {
*err_str = strdup(error ? gpgme_strerror(error) : "gpgme didn't return any error, but it didn't return a key");
*err_str = g_strdup(error ? gpgme_strerror(error) : "gpgme didn't return any error, but it didn't return a key");
}
gpgme_release(ctx);
return FALSE;
@@ -408,14 +381,14 @@ p_gpg_valid_key(const char* const keyid, char** err_str)
}
gboolean
p_gpg_available(const char* const barejid)
p_gpg_available(const gchar* const barejid)
{
char* pubkey = g_hash_table_lookup(pubkeys, barejid);
gchar* pubkey = g_hash_table_lookup(pubkeys, barejid);
return (pubkey != NULL);
}
void
p_gpg_verify(const char* const barejid, const char* const sign)
p_gpg_verify(const gchar* const barejid, const gchar* const sign)
{
if (!sign) {
return;
@@ -429,7 +402,7 @@ p_gpg_verify(const char* const barejid, const char* const sign)
return;
}
auto_char char* sign_with_header_footer = _add_header_footer(sign, PGP_SIGNATURE_HEADER, PGP_SIGNATURE_FOOTER);
auto_gchar gchar* sign_with_header_footer = _add_header_footer(sign, PGP_SIGNATURE_HEADER, PGP_SIGNATURE_FOOTER);
gpgme_data_t sign_data;
gpgme_data_new_from_mem(&sign_data, sign_with_header_footer, strlen(sign_with_header_footer), 1);
@@ -455,10 +428,10 @@ p_gpg_verify(const char* const barejid, const char* const sign)
log_debug("Could not find PGP key with ID %s for %s", result->signatures->fpr, barejid);
} else {
log_debug("Fingerprint found for %s: %s ", barejid, key->subkeys->fpr);
ProfPGPPubKeyId* pubkeyid = malloc(sizeof(ProfPGPPubKeyId));
pubkeyid->id = strdup(key->subkeys->keyid);
ProfPGPPubKeyId* pubkeyid = g_new0(ProfPGPPubKeyId, 1);
pubkeyid->id = g_strdup(key->subkeys->keyid);
pubkeyid->received = TRUE;
g_hash_table_replace(pubkeys, strdup(barejid), pubkeyid);
g_hash_table_replace(pubkeys, g_strdup(barejid), pubkeyid);
}
gpgme_key_unref(key);
@@ -468,8 +441,8 @@ p_gpg_verify(const char* const barejid, const char* const sign)
gpgme_release(ctx);
}
char*
p_gpg_sign(const char* const str, const char* const fp)
gchar*
p_gpg_sign(const gchar* const str, const gchar* const fp)
{
gpgme_ctx_t ctx;
gpgme_error_t error = gpgme_new(&ctx);
@@ -505,6 +478,10 @@ p_gpg_sign(const char* const str, const char* const fp)
} else {
str_or_empty = strdup("");
}
if (!str_or_empty) {
log_error("GPG: strdup failed");
return NULL;
}
gpgme_data_t str_data;
gpgme_data_new_from_mem(&str_data, str_or_empty, strlen(str_or_empty), 1);
@@ -522,10 +499,10 @@ p_gpg_sign(const char* const str, const char* const fp)
return NULL;
}
char* result = NULL;
gchar* result = NULL;
size_t len = 0;
char* signed_str = gpgme_data_release_and_get_mem(signed_data, &len);
gchar* signed_str = gpgme_data_release_and_get_mem(signed_data, &len);
if (signed_str) {
GString* signed_gstr = g_string_new("");
g_string_append_len(signed_gstr, signed_str, len);
@@ -535,14 +512,14 @@ p_gpg_sign(const char* const str, const char* const fp)
}
if (passphrase_attempt) {
passphrase = strdup(passphrase_attempt);
passphrase = g_strdup(passphrase_attempt);
}
return result;
}
char*
p_gpg_encrypt(const char* const barejid, const char* const message, const char* const fp)
gchar*
p_gpg_encrypt(const gchar* const barejid, const gchar* const message, const gchar* const fp)
{
ProfPGPPubKeyId* pubkeyid = g_hash_table_lookup(pubkeys, barejid);
if (!pubkeyid) {
@@ -616,8 +593,8 @@ p_gpg_encrypt(const char* const barejid, const char* const message, const char*
return result;
}
char*
p_gpg_decrypt(const char* const cipher)
gchar*
p_gpg_decrypt(const gchar* const cipher)
{
gpgme_ctx_t ctx;
gpgme_error_t error = gpgme_new(&ctx);
@@ -629,7 +606,7 @@ p_gpg_decrypt(const char* const cipher)
gpgme_set_passphrase_cb(ctx, (gpgme_passphrase_cb_t)_p_gpg_passphrase_cb, NULL);
auto_char char* cipher_with_headers = _add_header_footer(cipher, PGP_MESSAGE_HEADER, PGP_MESSAGE_FOOTER);
auto_gchar gchar* cipher_with_headers = _add_header_footer(cipher, PGP_MESSAGE_HEADER, PGP_MESSAGE_FOOTER);
gpgme_data_t cipher_data;
gpgme_data_new_from_mem(&cipher_data, cipher_with_headers, strlen(cipher_with_headers), 1);
@@ -655,11 +632,9 @@ p_gpg_decrypt(const char* const cipher)
error = gpgme_get_key(ctx, recipient->keyid, &key, 1);
if (!error && key) {
for (gpgme_user_id_t uid = key->uids; uid != NULL; uid = uid->next) {
if (uid->email) {
g_string_append(recipients_str, uid->email);
break;
}
const gchar* addr = _gpgme_key_get_email(key);
if (addr) {
g_string_append(recipients_str, addr);
}
gpgme_key_unref(key);
} else if (error) {
@@ -680,7 +655,7 @@ p_gpg_decrypt(const char* const cipher)
gpgme_release(ctx);
if (passphrase_attempt) {
passphrase = strdup(passphrase_attempt);
passphrase = g_strdup(passphrase_attempt);
}
return _gpgme_data_to_char(plain_data);
@@ -692,8 +667,8 @@ p_gpg_free_decrypted(char* decrypted)
g_free(decrypted);
}
char*
p_gpg_autocomplete_key(const char* const search_str, gboolean previous, void* context)
gchar*
p_gpg_autocomplete_key(const gchar* const search_str, gboolean previous, void* context)
{
return autocomplete_complete(key_ac, search_str, TRUE, previous);
}
@@ -704,8 +679,8 @@ p_gpg_autocomplete_key_reset(void)
autocomplete_reset(key_ac);
}
char*
p_gpg_format_fp_str(char* fp)
gchar*
p_gpg_format_fp_str(gchar* fp)
{
if (!fp) {
return NULL;
@@ -728,12 +703,12 @@ p_gpg_format_fp_str(char* fp)
*
* @param keyid The key ID for which to retrieve the public key data.
* If the key ID is empty or NULL, returns NULL.
* @return The public key data as a null-terminated char* string allocated using malloc.
* @return The public key data as a null-terminated gchar* string allocated using malloc.
* The returned string should be freed by the caller.
* Returns NULL on error, and errors are written to the error log.
*/
char*
p_gpg_get_pubkey(const char* keyid)
gchar*
p_gpg_get_pubkey(const gchar* keyid)
{
if (!keyid || *keyid == '\0') {
return NULL;
@@ -777,18 +752,18 @@ cleanup:
* @return TRUE if the buffer has the expected header and footer of an armored public key, FALSE otherwise.
*/
gboolean
p_gpg_is_public_key_format(const char* buffer)
p_gpg_is_public_key_format(const gchar* buffer)
{
if (buffer == NULL || buffer[0] == '\0') {
return false;
}
const char* headerPos = strstr(buffer, PGP_PUBLIC_KEY_HEADER);
const gchar* headerPos = strstr(buffer, PGP_PUBLIC_KEY_HEADER);
if (headerPos == NULL) {
return false;
}
const char* footerPos = strstr(buffer, PGP_PUBLIC_KEY_FOOTER);
const gchar* footerPos = strstr(buffer, PGP_PUBLIC_KEY_FOOTER);
return (footerPos != NULL && footerPos > headerPos);
}
@@ -803,7 +778,7 @@ p_gpg_is_public_key_format(const char* buffer)
* by calling p_gpg_free_key() to avoid resource leaks.
*/
ProfPGPKey*
p_gpg_import_pubkey(const char* buffer)
p_gpg_import_pubkey(const gchar* buffer)
{
gpgme_ctx_t ctx;
ProfPGPKey* result = NULL;
@@ -873,9 +848,9 @@ _gpgme_key_to_ProfPGPKey(gpgme_key_t key)
ProfPGPKey* p_pgpkey = p_gpg_key_new();
gpgme_subkey_t sub = key->subkeys;
p_pgpkey->id = strdup(sub->keyid);
p_pgpkey->name = strdup(key->uids->uid);
p_pgpkey->fp = strdup(sub->fpr);
p_pgpkey->id = g_strdup(sub->keyid);
p_pgpkey->name = g_strdup(key->uids->uid);
p_pgpkey->fp = g_strdup(sub->fpr);
while (sub) {
if (sub->can_encrypt)
@@ -892,6 +867,40 @@ _gpgme_key_to_ProfPGPKey(gpgme_key_t key)
return p_pgpkey;
}
/**
* Extract the first email address from a gpgme_key_t object.
* This function provides backwards compatibility for both old and new GPGME versions.
* - GPGME < 2.0.0: Uses gpgme_key_get_string_attr (if available)
* - GPGME >= 2.0.0: Uses modern key->uids->email API
*
* @param key The gpgme_key_t object to extract email from.
* @return The first email address found in the key's user IDs, or NULL if none found.
* The returned string should not be freed as it points to internal gpgme memory.
*/
static const gchar*
_gpgme_key_get_email(gpgme_key_t key)
{
if (!key) {
return NULL;
}
#ifdef GPGME_ATTR_EMAIL
/* Use deprecated function if available (GPGME < 2.0.0) */
return gpgme_key_get_string_attr(key, GPGME_ATTR_EMAIL, NULL, 0);
#else
/* Use modern API for GPGME >= 2.0.0 */
gpgme_user_id_t uid = key->uids;
while (uid) {
if (uid->email && strlen(uid->email) > 0) {
return uid->email;
}
uid = uid->next;
}
return NULL;
#endif
}
/**
* Convert a gpgme_data_t object to a null-terminated char* string.
*
@@ -899,7 +908,7 @@ _gpgme_key_to_ProfPGPKey(gpgme_key_t key)
* @return The converted string allocated using malloc, which should be freed by the caller.
* If an error occurs or the data is empty, NULL is returned and errors are written to the error log.
*/
static char*
static gchar*
_gpgme_data_to_char(gpgme_data_t data)
{
size_t buffer_size = 0;
@@ -910,16 +919,13 @@ _gpgme_data_to_char(gpgme_data_t data)
return NULL;
}
char* buffer = malloc(buffer_size + 1);
memcpy(buffer, gpgme_buffer, buffer_size);
buffer[buffer_size] = '\0';
gchar* buffer = g_strndup(gpgme_buffer, buffer_size);
gpgme_free(gpgme_buffer);
return buffer;
}
static char*
_remove_header_footer(char* str, const char* const footer)
static gchar*
_remove_header_footer(gchar* str, const char* const footer)
{
int pos = 0;
int newlines = 0;
@@ -935,15 +941,15 @@ _remove_header_footer(char* str, const char* const footer)
}
}
char* stripped = strdup(&str[pos]);
char* footer_start = g_strrstr(stripped, footer);
gchar* stripped = g_strdup(&str[pos]);
gchar* footer_start = g_strrstr(stripped, footer);
footer_start[0] = '\0';
return stripped;
}
static char*
_add_header_footer(const char* const str, const char* const header, const char* const footer)
static gchar*
_add_header_footer(const gchar* const str, const char* const header, const char* const footer)
{
return g_strdup_printf("%s\n\n%s\n%s", header, str, footer);
}

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef PGP_GPG_H
@@ -38,9 +12,9 @@
typedef struct pgp_key_t
{
char* id;
char* name;
char* fp;
gchar* id;
gchar* name;
gchar* fp;
gboolean encrypt;
gboolean sign;
gboolean certify;
@@ -50,31 +24,31 @@ typedef struct pgp_key_t
typedef struct pgp_pubkeyid_t
{
char* id;
gchar* id;
gboolean received;
} ProfPGPPubKeyId;
void p_gpg_init(void);
void p_gpg_on_connect(const char* const barejid);
void p_gpg_on_connect(const gchar* const barejid);
void p_gpg_on_disconnect(void);
GHashTable* p_gpg_list_keys(void);
void p_gpg_free_keys(GHashTable* keys);
gboolean p_gpg_addkey(const char* const jid, const char* const keyid);
gboolean p_gpg_addkey(const gchar* const jid, const gchar* const keyid);
GHashTable* p_gpg_pubkeys(void);
gboolean p_gpg_valid_key(const char* const keyid, char** err_str);
gboolean p_gpg_available(const char* const barejid);
const char* p_gpg_libver(void);
char* p_gpg_sign(const char* const str, const char* const fp);
void p_gpg_verify(const char* const barejid, const char* const sign);
char* p_gpg_encrypt(const char* const barejid, const char* const message, const char* const fp);
char* p_gpg_decrypt(const char* const cipher);
void p_gpg_free_decrypted(char* decrypted);
char* p_gpg_autocomplete_key(const char* const search_str, gboolean previous, void* context);
gboolean p_gpg_valid_key(const gchar* const keyid, gchar** err_str);
gboolean p_gpg_available(const gchar* const barejid);
const gchar* p_gpg_libver(void);
gchar* p_gpg_sign(const gchar* const str, const gchar* const fp);
void p_gpg_verify(const gchar* const barejid, const gchar* const sign);
gchar* p_gpg_encrypt(const gchar* const barejid, const gchar* const message, const gchar* const fp);
gchar* p_gpg_decrypt(const gchar* const cipher);
void p_gpg_free_decrypted(gchar* decrypted);
gchar* p_gpg_autocomplete_key(const gchar* const search_str, gboolean previous, void* context);
void p_gpg_autocomplete_key_reset(void);
char* p_gpg_format_fp_str(char* fp);
char* p_gpg_get_pubkey(const char* const keyid);
gboolean p_gpg_is_public_key_format(const char* buffer);
ProfPGPKey* p_gpg_import_pubkey(const char* buffer);
gchar* p_gpg_format_fp_str(gchar* fp);
gchar* p_gpg_get_pubkey(const gchar* const keyid);
gboolean p_gpg_is_public_key_format(const gchar* buffer);
ProfPGPKey* p_gpg_import_pubkey(const gchar* buffer);
ProfPGPKey* p_gpg_key_new(void);
void p_gpg_free_key(ProfPGPKey* key);

View File

@@ -3,35 +3,9 @@
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2020 Stefan Kropp <stefan@debxwoody.de>
* Copyright (C) 2020 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2020 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -85,6 +59,7 @@ ox_gpg_public_keys(void)
if (error != GPG_ERR_EOF && error != GPG_ERR_NO_ERROR) {
log_error("OX: gpgme_op_keylist_next %s %s", gpgme_strsource(error), gpgme_strerror(error));
g_hash_table_destroy(result);
gpgme_release(ctx);
return NULL;
}
while (!error) {
@@ -145,10 +120,16 @@ ox_gpg_public_keys(void)
char*
p_ox_gpg_signcrypt(const char* const sender_barejid, const char* const recipient_barejid, const char* const message)
{
char* result = NULL;
gpgme_ctx_t ctx = NULL;
gpgme_key_t recp[3] = { NULL, NULL, NULL };
gpgme_data_t plain = NULL;
gpgme_data_t cipher = NULL;
char* cipher_str = NULL;
setlocale(LC_ALL, "");
gpgme_check_version(NULL);
gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
gpgme_ctx_t ctx;
gpgme_error_t error = gpgme_new(&ctx);
if (GPG_ERR_NO_ERROR != error) {
@@ -165,13 +146,6 @@ p_ox_gpg_signcrypt(const char* const sender_barejid, const char* const recipient
gpgme_set_textmode(ctx, 0);
gpgme_set_offline(ctx, 1);
gpgme_set_keylist_mode(ctx, GPGME_KEYLIST_MODE_LOCAL);
if (error != 0) {
log_error("OX: Signcrypt error: %s", gpgme_strerror(error));
}
gpgme_key_t recp[3];
recp[0] = NULL,
recp[1] = NULL;
char* xmpp_jid_me = alloca((strlen(sender_barejid) + 6) * sizeof(char));
char* xmpp_jid_recipient = alloca((strlen(recipient_barejid) + 6) * sizeof(char));
@@ -185,64 +159,73 @@ p_ox_gpg_signcrypt(const char* const sender_barejid, const char* const recipient
// lookup own key
recp[0] = _ox_key_lookup(sender_barejid, TRUE);
if (error != 0) {
if (recp[0] == NULL) {
cons_show_error("Can't find OX key for %s", xmpp_jid_me);
log_error("OX: Key not found for %s. Error: %s", xmpp_jid_me, gpgme_strerror(error));
return NULL;
log_error("OX: Key not found for %s.", xmpp_jid_me);
goto cleanup;
}
error = gpgme_signers_add(ctx, recp[0]);
if (error != 0) {
log_error("OX: gpgme_signers_add %s. Error: %s", xmpp_jid_me, gpgme_strerror(error));
return NULL;
goto cleanup;
}
// lookup key of recipient
recp[1] = _ox_key_lookup(recipient_barejid, FALSE);
if (error != 0) {
if (recp[1] == NULL) {
cons_show_error("Can't find OX key for %s", xmpp_jid_recipient);
log_error("OX: Key not found for %s. Error: %s", xmpp_jid_recipient, gpgme_strerror(error));
return NULL;
log_error("OX: Key not found for %s.", xmpp_jid_recipient);
goto cleanup;
}
recp[2] = NULL;
log_debug("OX: %s <%s>", recp[0]->uids->name, recp[0]->uids->email);
log_debug("OX: %s <%s>", recp[1]->uids->name, recp[1]->uids->email);
if (recp[0]->uids) {
log_debug("OX: %s <%s>", recp[0]->uids->name, recp[0]->uids->email);
}
if (recp[1]->uids) {
log_debug("OX: %s <%s>", recp[1]->uids->name, recp[1]->uids->email);
}
gpgme_encrypt_flags_t flags = 0;
gpgme_data_t plain;
gpgme_data_t cipher;
error = gpgme_data_new(&plain);
if (error != 0) {
log_error("OX: %s", gpgme_strerror(error));
return NULL;
}
error = gpgme_data_new_from_mem(&plain, message, strlen(message), 0);
if (error != 0) {
log_error("OX: %s", gpgme_strerror(error));
return NULL;
goto cleanup;
}
error = gpgme_data_new(&cipher);
if (error != 0) {
log_error("OX: %s", gpgme_strerror(error));
return NULL;
goto cleanup;
}
error = gpgme_op_encrypt_sign(ctx, recp, flags, plain, cipher);
if (error != 0) {
log_error("OX: %s", gpgme_strerror(error));
return NULL;
goto cleanup;
}
size_t len;
char* cipher_str = gpgme_data_release_and_get_mem(cipher, &len);
char* result = g_base64_encode((unsigned char*)cipher_str, len);
gpgme_key_release(recp[0]);
gpgme_key_release(recp[1]);
gpgme_release(ctx);
cipher_str = gpgme_data_release_and_get_mem(cipher, &len);
cipher = NULL; // Already released by gpgme_data_release_and_get_mem
result = g_base64_encode((unsigned char*)cipher_str, len);
cleanup:
if (cipher_str)
gpgme_free(cipher_str);
if (plain)
gpgme_data_release(plain);
if (cipher)
gpgme_data_release(cipher);
if (recp[0])
gpgme_key_release(recp[0]);
if (recp[1])
gpgme_key_release(recp[1]);
if (ctx)
gpgme_release(ctx);
return result;
}
@@ -313,6 +296,7 @@ _ox_key_lookup(const char* const barejid, gboolean secret_only)
if (uid->name && strlen(uid->name) >= 10) {
if (g_strcmp0(uid->name, xmppuri->str) == 0) {
gpgme_release(ctx);
g_string_free(xmppuri, TRUE);
return key;
}
}
@@ -321,6 +305,7 @@ _ox_key_lookup(const char* const barejid, gboolean secret_only)
gpgme_key_unref(key);
error = gpgme_op_keylist_next(ctx, &key);
}
g_string_free(xmppuri, TRUE);
}
gpgme_release(ctx);
@@ -362,6 +347,13 @@ _ox_key_is_usable(gpgme_key_t key, const char* const barejid, gboolean secret)
char*
p_ox_gpg_decrypt(char* base64)
{
char* result = NULL;
gpgme_ctx_t ctx = NULL;
gpgme_data_t plain = NULL;
gpgme_data_t cipher = NULL;
guchar* encrypted = NULL;
char* plain_str = NULL;
// if there is no private key avaibale,
// we don't try do decrypt
if (!ox_is_private_key_available(connection_get_barejid())) {
@@ -370,7 +362,6 @@ p_ox_gpg_decrypt(char* base64)
setlocale(LC_ALL, "");
gpgme_check_version(NULL);
gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
gpgme_ctx_t ctx;
gpgme_error_t error = gpgme_new(&ctx);
if (GPG_ERR_NO_ERROR != error) {
@@ -387,25 +378,19 @@ p_ox_gpg_decrypt(char* base64)
gpgme_set_textmode(ctx, 0);
gpgme_set_offline(ctx, 1);
gpgme_set_keylist_mode(ctx, GPGME_KEYLIST_MODE_LOCAL);
if (error != 0) {
log_error("OX: %s", gpgme_strerror(error));
}
gpgme_data_t plain = NULL;
gpgme_data_t cipher = NULL;
gsize s;
guchar* encrypted = g_base64_decode(base64, &s);
encrypted = g_base64_decode(base64, &s);
error = gpgme_data_new_from_mem(&cipher, (char*)encrypted, s, 0);
if (error != 0) {
log_error("OX: gpgme_data_new_from_mem: %s", gpgme_strerror(error));
return NULL;
goto cleanup;
}
error = gpgme_data_new(&plain);
if (error != 0) {
log_error("OX: %s", gpgme_strerror(error));
return NULL;
goto cleanup;
}
error = gpgme_op_decrypt_verify(ctx, cipher, plain);
@@ -413,18 +398,29 @@ p_ox_gpg_decrypt(char* base64)
log_error("OX: gpgme_op_decrypt: %s", gpgme_strerror(error));
error = gpgme_op_decrypt(ctx, cipher, plain);
if (error != 0) {
return NULL;
goto cleanup;
}
}
size_t len;
char* plain_str = gpgme_data_release_and_get_mem(plain, &len);
char* result = NULL;
plain_str = gpgme_data_release_and_get_mem(plain, &len);
plain = NULL; // Already released by gpgme_data_release_and_get_mem
if (plain_str) {
result = strndup(plain_str, len);
gpgme_free(plain_str);
}
cleanup:
if (encrypted)
g_free(encrypted);
if (plain_str)
gpgme_free(plain_str);
if (plain)
gpgme_data_release(plain);
if (cipher)
gpgme_data_release(cipher);
if (ctx)
gpgme_release(ctx);
return result;
}
@@ -455,30 +451,33 @@ p_ox_gpg_readkey(const char* const filename, char** key, char** fp)
{
log_info("PX: Read OpenPGP Key from file %s", filename);
GError* error = NULL;
GError* gerr = NULL;
gchar* data = NULL;
gsize size = -1;
gpgme_ctx_t ctx = NULL;
gpgme_data_t gpgme_data = NULL;
gpgme_key_t gkey = NULL;
gpgme_key_t end = NULL;
gboolean success = g_file_get_contents(filename,
&data,
&size,
&error);
&gerr);
if (success) {
setlocale(LC_ALL, "");
gpgme_check_version(NULL);
gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
gpgme_ctx_t ctx;
gpgme_error_t error = gpgme_new(&ctx);
if (GPG_ERR_NO_ERROR != error) {
log_error("OX: Read OpenPGP key from file: gpgme_new failed: %s", gpgme_strerror(error));
return;
goto cleanup;
}
error = gpgme_set_protocol(ctx, GPGME_PROTOCOL_OPENPGP);
if (error != GPG_ERR_NO_ERROR) {
log_error("OX: Read OpenPGP key from file: set GPGME_PROTOCOL_OPENPGP: %s", gpgme_strerror(error));
return;
goto cleanup;
}
gpgme_set_armor(ctx, 0);
@@ -486,49 +485,54 @@ p_ox_gpg_readkey(const char* const filename, char** key, char** fp)
gpgme_set_offline(ctx, 1);
gpgme_set_keylist_mode(ctx, GPGME_KEYLIST_MODE_LOCAL);
gpgme_data_t gpgme_data = NULL;
error = gpgme_data_new(&gpgme_data);
if (error != GPG_ERR_NO_ERROR) {
log_error("OX: Read OpenPGP key from file: gpgme_data_new %s", gpgme_strerror(error));
return;
}
error = gpgme_data_new_from_mem(&gpgme_data, (char*)data, size, 0);
if (error != GPG_ERR_NO_ERROR) {
log_error("OX: Read OpenPGP key from file: gpgme_data_new_from_mem %s", gpgme_strerror(error));
return;
goto cleanup;
}
error = gpgme_op_keylist_from_data_start(ctx, gpgme_data, 0);
if (error != GPG_ERR_NO_ERROR) {
log_error("OX: Read OpenPGP key from file: gpgme_op_keylist_from_data_start %s", gpgme_strerror(error));
return;
goto cleanup;
}
gpgme_key_t gkey;
error = gpgme_op_keylist_next(ctx, &gkey);
if (error != GPG_ERR_NO_ERROR) {
log_error("OX: Read OpenPGP key from file: gpgme_op_keylist_next %s", gpgme_strerror(error));
return;
goto cleanup;
}
gpgme_key_t end;
error = gpgme_op_keylist_next(ctx, &end);
if (error == GPG_ERR_NO_ERROR) {
log_error("OX: Read OpenPGP key from file: ambiguous key");
return;
goto cleanup;
}
if (gkey->revoked || gkey->expired || gkey->disabled || gkey->invalid || gkey->secret) {
log_error("OX: Read OpenPGP key from file: Key is not valid");
return;
goto cleanup;
}
gchar* keybase64 = g_base64_encode((const guchar*)data, size);
*key = strdup(keybase64);
*fp = strdup(gkey->fpr);
g_free(keybase64);
} else {
log_error("OX: Read OpenPGP key from file: Unable to read file: %s", error->message);
log_error("OX: Read OpenPGP key from file: Unable to read file: %s", gerr->message);
g_error_free(gerr);
}
cleanup:
if (data)
g_free(data);
if (gpgme_data)
gpgme_data_release(gpgme_data);
if (gkey)
gpgme_key_unref(gkey);
if (end)
gpgme_key_unref(end);
if (ctx)
gpgme_release(ctx);
}
gboolean
@@ -536,22 +540,26 @@ p_ox_gpg_import(char* base64_public_key)
{
gsize size = -1;
guchar* key = g_base64_decode(base64_public_key, &size);
gboolean result = TRUE;
setlocale(LC_ALL, "");
gpgme_check_version(NULL);
gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
gpgme_ctx_t ctx;
gpgme_ctx_t ctx = NULL;
gpgme_data_t gpgme_data = NULL;
gpgme_error_t error = gpgme_new(&ctx);
if (GPG_ERR_NO_ERROR != error) {
log_error("OX: Read OpenPGP key from file: gpgme_new failed: %s", gpgme_strerror(error));
return FALSE;
result = FALSE;
goto cleanup;
}
error = gpgme_set_protocol(ctx, GPGME_PROTOCOL_OPENPGP);
if (error != GPG_ERR_NO_ERROR) {
log_error("OX: Read OpenPGP key from file: set GPGME_PROTOCOL_OPENPGP: %s", gpgme_strerror(error));
return FALSE;
result = FALSE;
goto cleanup;
}
gpgme_set_armor(ctx, 0);
@@ -559,18 +567,26 @@ p_ox_gpg_import(char* base64_public_key)
gpgme_set_offline(ctx, 1);
gpgme_set_keylist_mode(ctx, GPGME_KEYLIST_MODE_LOCAL);
gpgme_data_t gpgme_data = NULL;
error = gpgme_data_new(&gpgme_data);
error = gpgme_data_new_from_mem(&gpgme_data, (gchar*)key, size, 0);
if (error != GPG_ERR_NO_ERROR) {
log_error("OX: Read OpenPGP key from file: gpgme_data_new %s", gpgme_strerror(error));
return FALSE;
log_error("OX: Read OpenPGP key from file: gpgme_data_new_from_mem %s", gpgme_strerror(error));
result = FALSE;
goto cleanup;
}
gpgme_data_new_from_mem(&gpgme_data, (gchar*)key, size, 0);
error = gpgme_op_import(ctx, gpgme_data);
if (error != GPG_ERR_NO_ERROR) {
log_error("OX: Failed to import key");
result = FALSE;
}
return TRUE;
cleanup:
if (key)
g_free(key);
if (gpgme_data)
gpgme_data_release(gpgme_data);
if (ctx)
gpgme_release(ctx);
return result;
}

View File

@@ -3,35 +3,9 @@
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2020 Stefan Kropp <stefan@debxwoody.de>
* Copyright (C) 2020 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2020 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef PGP_OX_H

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -112,29 +86,29 @@ api_register_command(const char* const plugin_name, const char* command_name, in
char** synopsis, const char* description, char* arguments[][2], char** examples,
void* callback, void (*callback_exec)(PluginCommand* command, gchar** args), void (*callback_destroy)(void* callback))
{
PluginCommand* command = calloc(1, sizeof(PluginCommand));
command->command_name = strdup(command_name);
PluginCommand* command = g_new0(PluginCommand, 1);
command->command_name = g_strdup(command_name);
command->min_args = min_args;
command->max_args = max_args;
command->callback = callback;
command->callback_exec = callback_exec;
command->callback_destroy = callback_destroy;
CommandHelp* help = calloc(1, sizeof(CommandHelp));
CommandHelp* help = g_new0(CommandHelp, 1);
int i;
for (i = 0; synopsis[i] != NULL; i++) {
help->synopsis[i] = strdup(synopsis[i]);
help->synopsis[i] = g_strdup(synopsis[i]);
}
help->desc = strdup(description);
help->desc = g_strdup(description);
for (i = 0; arguments[i][0] != NULL; i++) {
help->args[i][0] = strdup(arguments[i][0]);
help->args[i][1] = strdup(arguments[i][1]);
help->args[i][0] = g_strdup(arguments[i][0]);
help->args[i][1] = g_strdup(arguments[i][1]);
}
for (i = 0; examples[i] != NULL; i++) {
help->examples[i] = strdup(examples[i]);
help->examples[i] = g_strdup(examples[i]);
}
command->help = help;
@@ -146,7 +120,7 @@ void
api_register_timed(const char* const plugin_name, void* callback, int interval_seconds,
void (*callback_exec)(PluginTimedFunction* timed_function), void (*callback_destroy)(void* callback))
{
PluginTimedFunction* timed_function = malloc(sizeof(PluginTimedFunction));
PluginTimedFunction* timed_function = g_new0(PluginTimedFunction, 1);
timed_function->callback = callback;
timed_function->callback_exec = callback_exec;
timed_function->callback_destroy = callback_destroy;
@@ -234,7 +208,7 @@ api_get_current_nick(void)
ProfMucWin* mucwin = (ProfMucWin*)current;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
const char* const nick = muc_nick(mucwin->roomjid);
return nick ? strdup(nick) : NULL;
return nick ? g_strdup(nick) : NULL;
} else {
return NULL;
}
@@ -243,7 +217,7 @@ api_get_current_nick(void)
char*
api_get_name_from_roster(const char* barejid)
{
return strdup(roster_get_display_name(barejid));
return g_strdup(roster_get_display_name(barejid));
}
char*
@@ -261,14 +235,22 @@ api_get_current_occupants(void)
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
GList* occupants_list = muc_roster(mucwin->roomjid);
char** result = malloc((g_list_length(occupants_list) + 1) * sizeof(char*));
if (result == NULL) {
g_list_free(occupants_list);
return NULL;
}
GList* curr = occupants_list;
int i = 0;
while (curr) {
Occupant* occupant = curr->data;
result[i++] = strdup(occupant->nick);
result[i++] = g_strdup(occupant->nick);
curr = g_list_next(curr);
}
result[i] = NULL;
g_list_free(occupants_list);
return result;
} else {
return NULL;
@@ -291,7 +273,7 @@ api_get_room_nick(const char* barejid)
{
const char* const nick = muc_nick(barejid);
return nick ? strdup(nick) : NULL;
return nick ? g_strdup(nick) : NULL;
}
void
@@ -339,7 +321,7 @@ api_win_create(
return;
}
PluginWindowCallback* window = malloc(sizeof(PluginWindowCallback));
PluginWindowCallback* window = g_new0(PluginWindowCallback, 1);
window->callback = callback;
window->callback_exec = callback_exec;
window->callback_destroy = callback_destroy;
@@ -493,7 +475,7 @@ api_incoming_message(const char* const barejid, const char* const resource, cons
{
ProfMessage* message = message_init();
message->from_jid = jid_create_from_bare_and_resource(barejid, resource);
message->plain = strdup(plain);
message->plain = g_strdup(plain);
sv_ev_incoming_message(message);

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef PLUGINS_API_H

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -75,14 +49,14 @@ autocompleters_add(const char* const plugin_name, const char* key, char** items)
} else {
Autocomplete new_ac = autocomplete_new();
autocomplete_add_all(new_ac, items);
g_hash_table_insert(key_to_ac, strdup(key), new_ac);
g_hash_table_insert(key_to_ac, g_strdup(key), new_ac);
}
} else {
key_to_ac = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)autocomplete_free);
Autocomplete new_ac = autocomplete_new();
autocomplete_add_all(new_ac, items);
g_hash_table_insert(key_to_ac, strdup(key), new_ac);
g_hash_table_insert(plugin_to_acs, strdup(plugin_name), key_to_ac);
g_hash_table_insert(key_to_ac, g_strdup(key), new_ac);
g_hash_table_insert(plugin_to_acs, g_strdup(plugin_name), key_to_ac);
}
}
@@ -123,11 +97,11 @@ autocompleters_filepath_add(const char* const plugin_name, const char* prefix)
{
GHashTable* prefixes = g_hash_table_lookup(plugin_to_filepath_acs, plugin_name);
if (prefixes) {
g_hash_table_add(prefixes, strdup(prefix));
g_hash_table_add(prefixes, g_strdup(prefix));
} else {
prefixes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
g_hash_table_add(prefixes, strdup(prefix));
g_hash_table_insert(plugin_to_filepath_acs, strdup(plugin_name), prefixes);
g_hash_table_add(prefixes, g_strdup(prefix));
g_hash_table_insert(plugin_to_filepath_acs, g_strdup(plugin_name), prefixes);
}
}

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef PLUGINS_AUTOCOMPLETERS_H

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -94,7 +68,7 @@ c_api_register_command(const char* filename, const char* command_name, int min_a
auto_char char* plugin_name = _c_plugin_name(filename);
log_debug("Register command %s for %s", command_name, plugin_name);
CommandWrapper* wrapper = malloc(sizeof(CommandWrapper));
CommandWrapper* wrapper = g_new0(CommandWrapper, 1);
wrapper->func = callback;
api_register_command(plugin_name, command_name, min_args, max_args, synopsis,
description, arguments, examples, wrapper, c_command_callback, free);
@@ -106,7 +80,7 @@ c_api_register_timed(const char* filename, void (*callback)(void), int interval_
auto_char char* plugin_name = _c_plugin_name(filename);
log_debug("Register timed for %s", plugin_name);
TimedWrapper* wrapper = malloc(sizeof(TimedWrapper));
TimedWrapper* wrapper = g_new0(TimedWrapper, 1);
wrapper->func = callback;
api_register_timed(plugin_name, wrapper, interval_seconds, c_timed_callback, free);
}
@@ -248,7 +222,7 @@ c_api_win_create(const char* filename, char* tag, void (*callback)(char* tag, ch
{
auto_char char* plugin_name = _c_plugin_name(filename);
WindowWrapper* wrapper = malloc(sizeof(WindowWrapper));
WindowWrapper* wrapper = g_new0(WindowWrapper, 1);
wrapper->func = callback;
api_win_create(plugin_name, tag, wrapper, c_window_callback, free);
}

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef PLUGINS_C_API_H

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -78,8 +52,8 @@ c_plugin_create(const char* const filename)
return NULL;
}
plugin = malloc(sizeof(ProfPlugin));
plugin->name = strdup(filename);
plugin = g_new0(ProfPlugin, 1);
plugin->name = g_strdup(filename);
plugin->lang = LANG_C;
plugin->module = handle;
plugin->init_func = c_init_hook;

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef PLUGINS_C_PLUGINS_H

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -139,9 +113,9 @@ _free_timed_function_list(GList* timed_functions)
void
callbacks_init(void)
{
p_commands = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_command_hash);
p_timed_functions = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_timed_function_list);
p_window_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_window_callbacks);
p_commands = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_free_command_hash);
p_timed_functions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_free_timed_function_list);
p_window_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_free_window_callbacks);
}
void
@@ -191,11 +165,11 @@ callbacks_add_command(const char* const plugin_name, PluginCommand* command)
{
GHashTable* command_hash = g_hash_table_lookup(p_commands, plugin_name);
if (command_hash) {
g_hash_table_insert(command_hash, strdup(command->command_name), command);
g_hash_table_insert(command_hash, g_strdup(command->command_name), command);
} else {
command_hash = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_command);
g_hash_table_insert(command_hash, strdup(command->command_name), command);
g_hash_table_insert(p_commands, strdup(plugin_name), command_hash);
command_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_free_command);
g_hash_table_insert(command_hash, g_strdup(command->command_name), command);
g_hash_table_insert(p_commands, g_strdup(plugin_name), command_hash);
}
cmd_ac_add(command->command_name);
cmd_ac_add_help(&command->command_name[1]);
@@ -210,7 +184,7 @@ callbacks_add_timed(const char* const plugin_name, PluginTimedFunction* timed_fu
timed_function_list = g_list_append(timed_function_list, timed_function);
} else {
timed_function_list = g_list_append(timed_function_list, timed_function);
g_hash_table_insert(p_timed_functions, strdup(plugin_name), timed_function_list);
g_hash_table_insert(p_timed_functions, g_strdup(plugin_name), timed_function_list);
}
}
@@ -242,11 +216,11 @@ callbacks_add_window_handler(const char* const plugin_name, const char* tag, Plu
{
GHashTable* window_callbacks = g_hash_table_lookup(p_window_callbacks, plugin_name);
if (window_callbacks) {
g_hash_table_insert(window_callbacks, strdup(tag), window_callback);
g_hash_table_insert(window_callbacks, g_strdup(tag), window_callback);
} else {
window_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_window_callback);
g_hash_table_insert(window_callbacks, strdup(tag), window_callback);
g_hash_table_insert(p_window_callbacks, strdup(plugin_name), window_callbacks);
window_callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_free_window_callback);
g_hash_table_insert(window_callbacks, g_strdup(tag), window_callback);
g_hash_table_insert(p_window_callbacks, g_strdup(plugin_name), window_callbacks);
}
}

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef PLUGINS_CALLBACKS_H

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -60,21 +34,21 @@ disco_add_feature(const char* plugin_name, char* feature)
}
if (!features) {
features = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);
features = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
}
if (!plugin_to_features) {
plugin_to_features = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_free_features);
plugin_to_features = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_free_features);
}
GHashTable* plugin_features = g_hash_table_lookup(plugin_to_features, plugin_name);
gboolean added = FALSE;
if (plugin_features == NULL) {
plugin_features = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);
g_hash_table_add(plugin_features, strdup(feature));
g_hash_table_insert(plugin_to_features, strdup(plugin_name), plugin_features);
plugin_features = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
g_hash_table_add(plugin_features, g_strdup(feature));
g_hash_table_insert(plugin_to_features, g_strdup(plugin_name), plugin_features);
added = TRUE;
} else if (!g_hash_table_contains(plugin_features, feature)) {
g_hash_table_add(plugin_features, strdup(feature));
g_hash_table_add(plugin_features, g_strdup(feature));
added = TRUE;
}
@@ -83,12 +57,12 @@ disco_add_feature(const char* plugin_name, char* feature)
}
if (!g_hash_table_contains(features, feature)) {
g_hash_table_insert(features, strdup(feature), GINT_TO_POINTER(1));
g_hash_table_insert(features, g_strdup(feature), GINT_TO_POINTER(1));
} else {
void* refcountp = g_hash_table_lookup(features, feature);
int refcount = GPOINTER_TO_INT(refcountp);
refcount++;
g_hash_table_replace(features, strdup(feature), GINT_TO_POINTER(refcount));
g_hash_table_replace(features, g_strdup(feature), GINT_TO_POINTER(refcount));
}
}
@@ -119,7 +93,7 @@ disco_remove_features(const char* plugin_name)
g_hash_table_remove(features, feature);
} else {
refcount--;
g_hash_table_replace(features, strdup(feature), GINT_TO_POINTER(refcount));
g_hash_table_replace(features, g_strdup(feature), GINT_TO_POINTER(refcount));
}
}
}

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef PLUGINS_DISCO_H

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include <string.h>
@@ -108,7 +82,7 @@ void
plugins_init(void)
{
prof_add_shutdown_routine(_plugins_shutdown);
plugins = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);
plugins = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
callbacks_init();
autocompleters_init();
plugin_themes_init();
@@ -126,14 +100,14 @@ plugins_init(void)
if (!plugins_pref) {
return;
}
for (int i = 0; i < g_strv_length(plugins_pref); i++) {
for (guint i = 0; i < g_strv_length(plugins_pref); i++) {
gboolean loaded = FALSE;
gchar* filename = plugins_pref[i];
#ifdef HAVE_PYTHON
if (g_str_has_suffix(filename, ".py")) {
ProfPlugin* plugin = python_plugin_create(filename);
if (plugin) {
g_hash_table_insert(plugins, strdup(filename), plugin);
g_hash_table_insert(plugins, g_strdup(filename), plugin);
loaded = TRUE;
}
}
@@ -142,7 +116,7 @@ plugins_init(void)
if (g_str_has_suffix(filename, ".so")) {
ProfPlugin* plugin = c_plugin_create(filename);
if (plugin) {
g_hash_table_insert(plugins, strdup(filename), plugin);
g_hash_table_insert(plugins, g_strdup(filename), plugin);
loaded = TRUE;
}
}
@@ -171,14 +145,14 @@ plugins_free_install_result(PluginsInstallResult* result)
if (!result) {
return;
}
g_slist_free_full(result->installed, free);
g_slist_free_full(result->failed, free);
g_slist_free_full(result->installed, g_free);
g_slist_free_full(result->failed, g_free);
}
PluginsInstallResult*
plugins_install_all(const char* const path)
{
PluginsInstallResult* result = malloc(sizeof(PluginsInstallResult));
PluginsInstallResult* result = g_new0(PluginsInstallResult, 1);
result->installed = NULL;
result->failed = NULL;
GSList* contents = NULL;
@@ -191,9 +165,9 @@ plugins_install_all(const char* const path)
if (g_str_has_suffix(curr->data, ".py") || g_str_has_suffix(curr->data, ".so")) {
gchar* plugin_name = g_path_get_basename(curr->data);
if (plugins_install(plugin_name, curr->data, error_message)) {
result->installed = g_slist_append(result->installed, strdup(curr->data));
result->installed = g_slist_append(result->installed, g_strdup(curr->data));
} else {
result->failed = g_slist_append(result->failed, strdup(curr->data));
result->failed = g_slist_append(result->failed, g_strdup(curr->data));
}
}
curr = g_slist_next(curr);
@@ -214,10 +188,8 @@ plugins_uninstall(const char* const plugin_name)
g_string_append(target_path, "/");
g_string_append(target_path, plugin_name);
GFile* file = g_file_new_for_path(target_path->str);
GError* error = NULL;
gboolean result = g_file_delete(file, NULL, &error);
gboolean result = g_file_delete(file, NULL, NULL);
g_object_unref(file);
g_error_free(error);
g_string_free(target_path, TRUE);
return result;
}
@@ -255,7 +227,7 @@ plugins_load_all(void)
while (curr) {
error_message = g_string_new(NULL);
if (plugins_load(curr->data, error_message)) {
loaded = g_slist_append(loaded, strdup(curr->data));
loaded = g_slist_append(loaded, g_strdup(curr->data));
}
curr = g_slist_next(curr);
g_string_free(error_message, TRUE);
@@ -290,7 +262,7 @@ plugins_load(const char* const name, GString* error_message)
#endif
}
if (plugin) {
g_hash_table_insert(plugins, strdup(name), plugin);
g_hash_table_insert(plugins, g_strdup(name), plugin);
if (connection_get_status() == JABBER_CONNECTED) {
plugin->init_func(plugin, PACKAGE_VERSION, PACKAGE_STATUS, session_get_account_name(), connection_get_fulljid());
} else {
@@ -313,7 +285,7 @@ plugins_unload_all(void)
GList* plugin_names_dup = NULL;
GList* curr = plugin_names;
while (curr) {
plugin_names_dup = g_list_append(plugin_names_dup, strdup(curr->data));
plugin_names_dup = g_list_append(plugin_names_dup, g_strdup(curr->data));
curr = g_list_next(curr);
}
g_list_free(plugin_names);
@@ -326,7 +298,7 @@ plugins_unload_all(void)
curr = g_list_next(curr);
}
g_list_free_full(plugin_names_dup, free);
g_list_free_full(plugin_names_dup, g_free);
return result;
}
@@ -368,7 +340,7 @@ plugins_reload_all(void)
GList* plugin_names_dup = NULL;
GList* curr = plugin_names;
while (curr) {
plugin_names_dup = g_list_append(plugin_names_dup, strdup(curr->data));
plugin_names_dup = g_list_append(plugin_names_dup, g_strdup(curr->data));
curr = g_list_next(curr);
}
g_list_free(plugin_names);
@@ -382,7 +354,7 @@ plugins_reload_all(void)
curr = g_list_next(curr);
}
g_list_free_full(plugin_names_dup, free);
g_list_free_full(plugin_names_dup, g_free);
}
gboolean
@@ -411,7 +383,7 @@ _plugins_unloaded_list_dir(const gchar* const dir, GSList** result)
while (plugin) {
ProfPlugin* found = g_hash_table_lookup(plugins, plugin);
if ((g_str_has_suffix(plugin, ".so") || g_str_has_suffix(plugin, ".py")) && !found) {
*result = g_slist_append(*result, strdup(plugin));
*result = g_slist_append(*result, g_strdup(plugin));
}
plugin = g_dir_read_name(plugins_dir);
}
@@ -522,15 +494,15 @@ plugins_pre_chat_message_display(const char* const barejid, const char* const re
return NULL;
}
char* new_message = NULL;
char* curr_message = strdup(message);
gchar* new_message = NULL;
gchar* curr_message = g_strdup(message);
GList* curr = values;
while (curr) {
ProfPlugin* plugin = curr->data;
new_message = plugin->pre_chat_message_display(plugin, barejid, resource, curr_message);
if (new_message) {
free(curr_message);
g_free(curr_message);
curr_message = new_message;
}
curr = g_list_next(curr);
@@ -561,15 +533,15 @@ plugins_pre_chat_message_send(const char* const barejid, const char* message)
return NULL;
}
char* new_message = NULL;
char* curr_message = strdup(message);
gchar* new_message = NULL;
gchar* curr_message = g_strdup(message);
GList* curr = values;
while (curr) {
ProfPlugin* plugin = curr->data;
if (plugin->contains_hook(plugin, "prof_pre_chat_message_send")) {
new_message = plugin->pre_chat_message_send(plugin, barejid, curr_message);
free(curr_message);
g_free(curr_message);
if (new_message) {
curr_message = new_message;
} else {
@@ -606,15 +578,15 @@ plugins_pre_room_message_display(const char* const barejid, const char* const ni
return NULL;
}
char* new_message = NULL;
char* curr_message = strdup(message);
gchar* new_message = NULL;
gchar* curr_message = g_strdup(message);
GList* curr = values;
while (curr) {
ProfPlugin* plugin = curr->data;
new_message = plugin->pre_room_message_display(plugin, barejid, nick, curr_message);
if (new_message) {
free(curr_message);
g_free(curr_message);
curr_message = new_message;
}
curr = g_list_next(curr);
@@ -645,15 +617,15 @@ plugins_pre_room_message_send(const char* const barejid, const char* message)
return NULL;
}
char* new_message = NULL;
char* curr_message = strdup(message);
gchar* new_message = NULL;
gchar* curr_message = g_strdup(message);
GList* curr = values;
while (curr) {
ProfPlugin* plugin = curr->data;
if (plugin->contains_hook(plugin, "prof_pre_room_message_send")) {
new_message = plugin->pre_room_message_send(plugin, barejid, curr_message);
free(curr_message);
g_free(curr_message);
if (new_message) {
curr_message = new_message;
} else {
@@ -702,7 +674,7 @@ plugins_on_room_history_message(const char* const barejid, const char* const nic
}
g_list_free(values);
free(timestamp_str);
g_free(timestamp_str);
}
char*
@@ -714,15 +686,15 @@ plugins_pre_priv_message_display(const char* const fulljid, const char* message)
}
auto_jid Jid* jidp = jid_create(fulljid);
char* new_message = NULL;
char* curr_message = strdup(message);
gchar* new_message = NULL;
gchar* curr_message = g_strdup(message);
GList* curr = values;
while (curr) {
ProfPlugin* plugin = curr->data;
new_message = plugin->pre_priv_message_display(plugin, jidp->barejid, jidp->resourcepart, curr_message);
if (new_message) {
free(curr_message);
g_free(curr_message);
curr_message = new_message;
}
curr = g_list_next(curr);
@@ -755,15 +727,15 @@ plugins_pre_priv_message_send(const char* const fulljid, const char* const messa
}
auto_jid Jid* jidp = jid_create(fulljid);
char* new_message = NULL;
char* curr_message = strdup(message);
gchar* new_message = NULL;
gchar* curr_message = g_strdup(message);
GList* curr = values;
while (curr) {
ProfPlugin* plugin = curr->data;
if (plugin->contains_hook(plugin, "prof_pre_priv_message_send")) {
new_message = plugin->pre_priv_message_send(plugin, jidp->barejid, jidp->resourcepart, curr_message);
free(curr_message);
g_free(curr_message);
if (new_message) {
curr_message = new_message;
} else {
@@ -803,15 +775,15 @@ plugins_on_message_stanza_send(const char* const text)
return NULL;
}
char* new_stanza = NULL;
char* curr_stanza = strdup(text);
gchar* new_stanza = NULL;
gchar* curr_stanza = g_strdup(text);
GList* curr = values;
while (curr) {
ProfPlugin* plugin = curr->data;
new_stanza = plugin->on_message_stanza_send(plugin, curr_stanza);
if (new_stanza) {
free(curr_stanza);
g_free(curr_stanza);
curr_stanza = new_stanza;
}
curr = g_list_next(curr);
@@ -849,15 +821,15 @@ plugins_on_presence_stanza_send(const char* const text)
return NULL;
}
char* new_stanza = NULL;
char* curr_stanza = strdup(text);
gchar* new_stanza = NULL;
gchar* curr_stanza = g_strdup(text);
GList* curr = values;
while (curr) {
ProfPlugin* plugin = curr->data;
new_stanza = plugin->on_presence_stanza_send(plugin, curr_stanza);
if (new_stanza) {
free(curr_stanza);
g_free(curr_stanza);
curr_stanza = new_stanza;
}
curr = g_list_next(curr);
@@ -896,14 +868,14 @@ plugins_on_iq_stanza_send(const char* const text)
}
char* new_stanza = NULL;
char* curr_stanza = strdup(text);
char* curr_stanza = g_strdup(text);
GList* curr = values;
while (curr) {
ProfPlugin* plugin = curr->data;
new_stanza = plugin->on_iq_stanza_send(plugin, curr_stanza);
if (new_stanza) {
free(curr_stanza);
g_free(curr_stanza);
curr_stanza = new_stanza;
}
curr = g_list_next(curr);

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef PLUGINS_PLUGINS_H

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef PLUGINS_PROF_API_H

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#undef _XOPEN_SOURCE
@@ -460,10 +434,10 @@ python_api_get_name_from_roster(PyObject* self, PyObject* args)
Py_RETURN_NONE;
}
char* barejid_str = python_str_or_unicode_to_string(barejid);
gchar* barejid_str = python_str_or_unicode_to_string(barejid);
allow_python_threads();
char* name = strdup(roster_get_display_name(barejid_str));
gchar* name = g_strdup(roster_get_display_name(barejid_str));
free(barejid_str);
disable_python_threads();
if (name) {
@@ -1593,7 +1567,11 @@ static struct PyModuleDef profModule = {
"prof",
"",
-1,
apiMethods
apiMethods,
NULL, /* m_slots */
NULL, /* m_traverse */
NULL, /* m_clear */
NULL /* m_free */
};
#endif
@@ -1636,16 +1614,16 @@ _python_plugin_name(void)
#if PY_VERSION_HEX >= 0x030B0000
PyFrameObject* frame = PyThreadState_GetFrame(ts);
PyCodeObject* code = PyFrame_GetCode(frame);
char* filename = python_str_or_unicode_to_string(code->co_filename);
gchar* filename = python_str_or_unicode_to_string(code->co_filename);
Py_DECREF(code);
Py_DECREF(frame);
#else
PyFrameObject* frame = ts->frame;
char* filename = python_str_or_unicode_to_string(frame->f_code->co_filename);
gchar* filename = python_str_or_unicode_to_string(frame->f_code->co_filename);
#endif
gchar** split = g_strsplit(filename, "/", 0);
free(filename);
char* plugin_name = strdup(split[g_strv_length(split) - 1]);
gchar* plugin_name = g_strdup(split[g_strv_length(split) - 1]);
g_strfreev(split);
return plugin_name;
@@ -1665,20 +1643,20 @@ python_str_or_unicode_to_string(void* obj)
#ifdef PY_IS_PYTHON3
if (PyUnicode_Check(pyobj)) {
PyObject* utf8_str = PyUnicode_AsUTF8String(pyobj);
char* result = strdup(PyBytes_AS_STRING(utf8_str));
gchar* result = g_strdup(PyBytes_AS_STRING(utf8_str));
Py_XDECREF(utf8_str);
return result;
} else {
return strdup(PyBytes_AS_STRING(pyobj));
return g_strdup(PyBytes_AS_STRING(pyobj));
}
#else
if (PyUnicode_Check(pyobj)) {
PyObject* utf8_str = PyUnicode_AsUTF8String(pyobj);
char* result = strdup(PyString_AsString(utf8_str));
gchar* result = g_strdup(PyString_AsString(utf8_str));
Py_XDECREF(utf8_str);
return result;
} else {
return strdup(PyString_AsString(pyobj));
return g_strdup(PyString_AsString(pyobj));
}
#endif
}

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef PLUGINS_PYTHON_API_H

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#undef _XOPEN_SOURCE
@@ -130,8 +104,8 @@ python_plugin_create(const char* const filename)
python_check_error();
if (p_module) {
ProfPlugin* plugin = malloc(sizeof(ProfPlugin));
plugin->name = strdup(filename);
ProfPlugin* plugin = g_new0(ProfPlugin, 1);
plugin->name = g_strdup(filename);
plugin->lang = LANG_PYTHON;
plugin->module = p_module;
plugin->init_func = python_init_hook;

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef PLUGINS_PYTHON_PLUGINS_H

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -88,7 +62,7 @@ plugin_settings_string_get(const char* const group, const char* const key, const
if (group && key && g_key_file_has_key(settings, group, key, NULL)) {
return g_key_file_get_string(settings, group, key, NULL);
} else if (def) {
return strdup(def);
return g_strdup(def);
} else {
return NULL;
}

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef PLUGINS_SETTINGS_H

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef PLUGINS_THEMES_H

View File

@@ -3,35 +3,9 @@
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2019 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2019 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
#include <unistd.h>
@@ -56,6 +30,7 @@
#include "config/accounts.h"
#include "config/preferences.h"
#include "config/theme.h"
#include "tools/spellcheck.h"
#include "config/tlscerts.h"
#include "config/scripts.h"
#include "command/cmd_defs.h"
@@ -117,7 +92,7 @@ prof_run(gchar* log_level, gchar* account_name, gchar* config_file, gchar* log_f
char* line = NULL;
GTimer* waittimer = g_timer_new();
g_timer_stop(waittimer);
int waittime;
int waittime = 0;
while (cont && !force_quit) {
log_stderr_handler();
session_check_autoaway();
@@ -206,6 +181,13 @@ _connect_default(const char* const account)
}
}
static void
sigterm_handler(int sig)
{
log_info("Received signal %d, exiting", sig);
force_quit = TRUE;
}
static void
_init(char* log_level, char* config_file, char* log_file, char* theme_name)
{
@@ -215,6 +197,8 @@ _init(char* log_level, char* config_file, char* log_file, char* theme_name)
signal(SIGINT, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
signal(SIGWINCH, ui_sigwinch_handler);
signal(SIGTERM, sigterm_handler);
signal(SIGHUP, sigterm_handler);
if (pthread_mutex_init(&lock, NULL) != 0) {
log_error("Mutex init failed");
exit(1);
@@ -262,6 +246,7 @@ _init(char* log_level, char* config_file, char* log_file, char* theme_name)
#ifdef HAVE_OMEMO
omemo_init();
#endif
spellcheck_init();
atexit(_shutdown);
plugins_init();
#ifdef HAVE_GTK
@@ -294,7 +279,7 @@ prof_add_shutdown_routine(void (*routine)(void))
if (g_list_find_custom(shutdown_routines, &this, (GCompareFunc)_cmp_shutdown_routine)) {
return;
}
struct shutdown_routine* r = malloc(sizeof *r);
struct shutdown_routine* r = g_new(struct shutdown_routine, 1);
r->routine = routine;
shutdown_routines = g_list_prepend(shutdown_routines, r);
}

View File

@@ -3,35 +3,9 @@
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2019 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2019 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef PROFANITY_H

View File

@@ -5,33 +5,7 @@
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2020 William Wennerström <william@wstrm.dev>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -69,7 +43,7 @@ aesgcm_file_get(void* userdata)
// and tag stored in the URL fragment.
if (omemo_parse_aesgcm_url(aesgcm_dl->url, &https_url, &fragment) != 0) {
cons_show_error("Download failed: Cannot parse URL '%s'.", aesgcm_dl->url);
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id,
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id, THEME_ERROR, ENTRY_ERROR,
"Download failed: Cannot parse URL '%s'.",
aesgcm_dl->url);
return NULL;
@@ -80,7 +54,7 @@ aesgcm_file_get(void* userdata)
auto_gchar gchar* tmpname = NULL;
auto_gfd gint tmpfd = 0;
if ((tmpfd = g_file_open_tmp("profanity.XXXXXX", &tmpname, NULL)) == -1) {
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id,
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id, THEME_ERROR, ENTRY_ERROR,
"Downloading '%s' failed: Unable to create "
"temporary ciphertext file for writing "
"(%s).",
@@ -91,7 +65,7 @@ aesgcm_file_get(void* userdata)
// Open the target file for storing the cleartext.
auto_FILE FILE* outfh = fopen(aesgcm_dl->filename, "wb");
if (outfh == NULL) {
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id,
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id, THEME_ERROR, ENTRY_ERROR,
"Downloading '%s' failed: Unable to open "
"output file at '%s' for writing (%s).",
https_url, aesgcm_dl->filename,
@@ -101,14 +75,16 @@ aesgcm_file_get(void* userdata)
// We wrap the HTTPDownload tool and use it for retrieving the ciphertext
// and storing it in the temporary file previously opened.
HTTPDownload* http_dl = calloc(1, sizeof(HTTPDownload));
HTTPDownload* http_dl = g_new0(HTTPDownload, 1);
http_dl->window = aesgcm_dl->window;
http_dl->worker = aesgcm_dl->worker;
http_dl->id = strdup(aesgcm_dl->id);
http_dl->url = strdup(https_url);
http_dl->display_url = strdup(aesgcm_dl->url);
http_dl->filename = strdup(tmpname);
http_dl->cmd_template = NULL;
http_dl->silent = FALSE;
http_dl->silent_done = TRUE;
http_dl->return_bytes_received = TRUE;
aesgcm_dl->http_dl = http_dl;
@@ -121,7 +97,7 @@ aesgcm_file_get(void* userdata)
FILE* tmpfh = fopen(tmpname, "rb");
if (tmpfh == NULL) {
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id,
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id, THEME_ERROR, ENTRY_ERROR,
"Downloading '%s' failed: Unable to open "
"temporary file at '%s' for reading (%s).",
aesgcm_dl->url, tmpname,
@@ -136,13 +112,15 @@ aesgcm_file_get(void* userdata)
remove(tmpname);
if (crypt_res != GPG_ERR_NO_ERROR) {
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id,
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id, THEME_ERROR, ENTRY_ERROR,
"Downloading '%s' failed: Failed to decrypt "
"file (%s).",
https_url, gcry_strerror(crypt_res));
} else {
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id,
"Decrypted file saved to '%s'", aesgcm_dl->filename);
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id, THEME_ONLINE, ENTRY_COMPLETED,
"Downloading '%s': done\nSaved to '%s'",
aesgcm_dl->url, aesgcm_dl->filename);
win_mark_received(aesgcm_dl->window, aesgcm_dl->id);
}
if (aesgcm_dl->cmd_template != NULL) {
@@ -152,7 +130,7 @@ aesgcm_file_get(void* userdata)
// TODO: Log the error.
if (!call_external(argv)) {
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id,
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id, THEME_ERROR, ENTRY_ERROR,
"Downloading '%s' failed: Unable to call "
"command '%s' with file at '%s' (%s).",
aesgcm_dl->url,

View File

@@ -5,33 +5,7 @@
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2020 William Wennerström <william@wstrm.dev>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef TOOLS_AESGCM_DOWNLOAD_H
@@ -50,7 +24,7 @@
typedef struct aesgcm_download_t
{
char* id;
gchar* id;
char* url;
char* filename;
char* cmd_template;

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -62,7 +36,7 @@ static gchar* _search(Autocomplete ac, GList* curr, gboolean quote, search_direc
Autocomplete
autocomplete_new(void)
{
return calloc(1, sizeof(struct autocomplete_t));
return g_new0(struct autocomplete_t, 1);
}
void
@@ -175,7 +149,7 @@ autocomplete_add(Autocomplete ac, const char* item)
void
autocomplete_add_all(Autocomplete ac, char** items)
{
for (int i = 0; i < g_strv_length(items); i++) {
for (guint i = 0; i < g_strv_length(items); i++) {
autocomplete_add(ac, items[i]);
}
}
@@ -205,7 +179,7 @@ autocomplete_remove(Autocomplete ac, const char* const item)
void
autocomplete_remove_all(Autocomplete ac, char** items)
{
for (int i = 0; i < g_strv_length(items); i++) {
for (guint i = 0; i < g_strv_length(items); i++) {
autocomplete_remove(ac, items[i]);
}
}
@@ -260,7 +234,16 @@ autocomplete_complete(Autocomplete ac, const gchar* search_str, gboolean quote,
FREE_SET_NULL(ac->search_str);
}
ac->search_str = strdup(search_str);
// unescape search string
GString* unescaped = g_string_new("");
for (const char* p = search_str; *p; p++) {
if (*p == '\\' && (*(p + 1) != '\0')) {
p++;
}
g_string_append_c(unescaped, *p);
}
ac->search_str = g_string_free(unescaped, FALSE);
found = _search(ac, ac->items, quote, NEXT);
return found;
@@ -396,22 +379,48 @@ autocomplete_remove_older_than_max_reverse(Autocomplete ac, int maxsize)
static gchar*
_search(Autocomplete ac, GList* curr, gboolean quote, search_direction direction)
{
auto_gchar gchar* search_str_fold = g_utf8_casefold(ac->search_str, -1);
auto_gchar gchar* search_str_ascii = g_str_to_ascii(ac->search_str, NULL);
auto_gchar gchar* search_str_lower = g_ascii_strdown(search_str_ascii, -1);
auto_gchar gchar* search_str_ascii_lower = g_ascii_strdown(search_str_ascii, -1);
while (curr) {
auto_gchar gchar* curr_ascii = g_str_to_ascii(curr->data, NULL);
auto_gchar gchar* curr_lower = g_ascii_strdown(curr_ascii, -1);
gboolean match = FALSE;
// match found
if (strncmp(curr_lower, search_str_lower, strlen(search_str_lower)) == 0) {
// Try exact UTF-8 case insensitive match
auto_gchar gchar* curr_fold = g_utf8_casefold(curr->data, -1);
if (g_str_has_prefix(curr_fold, search_str_fold)) {
match = TRUE;
}
// Try transliterated match (allow typing 'e' for 'è')
if (!match) {
auto_gchar gchar* curr_ascii = g_str_to_ascii(curr->data, NULL);
auto_gchar gchar* curr_ascii_lower = g_ascii_strdown(curr_ascii, -1);
// We only use transliterated match if the search string conversion didn't result
// in unknown characters ('?'), to avoid false matches between different scripts.
if (strchr(search_str_ascii_lower, '?') == NULL) {
if (g_str_has_prefix(curr_ascii_lower, search_str_ascii_lower)) {
match = TRUE;
}
}
}
if (match) {
// set pointer to last found
ac->last_found = curr;
// if contains space, quote before returning
if (quote && g_strrstr(curr->data, " ")) {
return g_strdup_printf("\"%s\"", (gchar*)curr->data);
GString* escaped = g_string_new("\"");
for (const char* p = curr->data; *p; p++) {
if (*p == '"' || *p == '\\') {
g_string_append_c(escaped, '\\');
}
g_string_append_c(escaped, *p);
}
g_string_append_c(escaped, '"');
return g_string_free(escaped, FALSE);
// otherwise just return the string
} else {
return strdup(curr->data);

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef TOOLS_AUTOCOMPLETE_H

View File

@@ -2,35 +2,9 @@
* bookmark_ignore.c
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2020 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2020 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -73,7 +47,7 @@ bookmark_ignore_on_connect(const char* const barejid)
}
void
bookmark_ignore_on_disconnect()
bookmark_ignore_on_disconnect(void)
{
free_keyfile(&bookmark_ignore_prof_keyfile);
bookmark_ignore_keyfile = NULL;

View File

@@ -2,42 +2,16 @@
* bookmark_ignore.h
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2020 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2020 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef BOOKMARK_IGNORE_H
#define BOOKMARK_IGNORE_H
void bookmark_ignore_on_connect();
void bookmark_ignore_on_disconnect();
void bookmark_ignore_on_connect(const char* const barejid);
void bookmark_ignore_on_disconnect(void);
gboolean bookmark_ignored(Bookmark* bookmark);
gchar** bookmark_ignore_list(gsize* len);
void bookmark_ignore_add(const char* const barejid);

View File

@@ -2,35 +2,9 @@
* clipboard.c
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2019 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2019 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -41,6 +15,7 @@
#include <stdlib.h>
#include "log.h"
#include "ui/tray.h"
/*
For now we rely on tray_init(void)
@@ -53,6 +28,9 @@ void clipboard_init(int argc, char **argv) {
char*
clipboard_get(void)
{
if (!tray_gtk_ready()) {
return NULL;
}
gchar* clip;
GtkClipboard* cl = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);

View File

@@ -2,35 +2,9 @@
* clipboard.h
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2019 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2019 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef UI_CLIPBOARD_H

View File

@@ -2,37 +2,11 @@
* editor.c
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2022 - 2025 Michael Vetter <jubalh@iodoru.org>
* Copyright (C) 2022 - 2026 Michael Vetter <jubalh@iodoru.org>
* Copyright (C) 2022 MarcoPolo PasTonMolo <marcopolopastonmolo@protonmail.com>
* Copyright (C) 2022 Steffen Jaeckel <jaeckel-floss@eyet-services.de>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include <fcntl.h>
@@ -52,6 +26,47 @@
#include "ncurses.h"
#include "ui/ui.h"
#include "xmpp/xmpp.h"
#include "ui/ui.h"
typedef struct EditorContext
{
gchar* filename;
void (*callback)(gchar* content, void* user_data);
void* user_data;
} EditorContext;
static void
_editor_exit_cb(GPid pid, gint status, gpointer data)
{
EditorContext* ctx = data;
gchar* contents = NULL;
GError* error = NULL;
ui_resume();
ui_resize();
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
if (g_file_get_contents(ctx->filename, &contents, NULL, &error)) {
g_strchomp(contents);
ctx->callback(contents, ctx->user_data);
g_free(contents);
} else {
log_error("[Editor] could not read from %s: %s", ctx->filename, error->message);
cons_show_error("Could not read edited content: %s", error->message);
g_error_free(error);
}
} else {
cons_show_error("Editor exited with error status %d", WEXITSTATUS(status));
}
if (remove(ctx->filename) != 0) {
log_error("[Editor] error during file deletion of %s", ctx->filename);
}
g_free(ctx->filename);
g_free(ctx);
g_spawn_close_pid(pid);
}
EditorTask editor_task = { 0, FALSE, NULL, NULL, PTHREAD_MUTEX_INITIALIZER, 0, NULL, NULL };
@@ -234,13 +249,10 @@ editor_process(ProfWin* window)
// Please avoid using it, since it blocks execution of the message handling and other important functionality until the editor is closed.
// Returns true if an error occurred
gboolean
get_message_from_editor(gchar* message, gchar** returned_message)
launch_editor(gchar* initial_content, void (*callback)(gchar* content, void* data), void* user_data)
{
/* Make sure that there's no junk in the return-pointer in error cases */
*returned_message = NULL;
auto_gchar gchar* filename = NULL;
GError* glib_error = NULL;
auto_gerror GError* glib_error = NULL;
const char* jid = connection_get_barejid();
if (jid) {
filename = files_file_in_account_data_path(DIR_EDITOR, jid, "compose.md");
@@ -248,64 +260,67 @@ get_message_from_editor(gchar* message, gchar** returned_message)
log_debug("[Editor] could not get JID");
auto_gchar gchar* data_dir = files_get_data_path(DIR_EDITOR);
if (!create_dir(data_dir)) {
cons_show_error("Could not create editor directory.");
return TRUE;
}
filename = g_strdup_printf("%s/compose.md", data_dir);
}
if (!filename) {
log_error("[Editor] something went wrong while creating compose file");
cons_show_error("Could not create compose file.");
return TRUE;
}
gsize messagelen = 0;
if (message != NULL) {
messagelen = strlen(message);
if (initial_content != NULL) {
messagelen = strlen(initial_content);
}
if (!g_file_set_contents(filename, message, messagelen, &glib_error)) {
log_error("[Editor] could not write to %s: %s", filename, glib_error ? glib_error->message : "No GLib error given");
if (glib_error) {
g_error_free(glib_error);
}
if (!g_file_set_contents(filename, initial_content, messagelen, &glib_error)) {
log_error("[Editor] could not write to %s: %s", filename, PROF_GERROR_MESSAGE(glib_error));
cons_show_error("Could not write to compose file: %s", PROF_GERROR_MESSAGE(glib_error));
return TRUE;
}
auto_gchar gchar* editor = prefs_get_string(PREF_COMPOSE_EDITOR);
auto_gchar gchar* editor_with_filename = g_strdup_printf("%s %s", editor, filename);
auto_gcharv gchar** editor_argv = g_strsplit(editor_with_filename, " ", 0);
gchar** editor_argv = NULL;
GError* error = NULL;
// Fork / exec
pid_t pid = fork();
if (pid == 0) {
int x = execvp(editor_argv[0], editor_argv);
if (x == -1) {
log_error("[Editor] Failed to exec %s", editor);
}
_exit(EXIT_FAILURE);
} else {
if (pid == -1) {
return TRUE;
}
waitpid(pid, NULL, 0);
gchar* contents;
gsize length;
if (!g_file_get_contents(filename, &contents, &length, &glib_error)) {
log_error("[Editor] could not read from %s: %s", filename, glib_error ? glib_error->message : "No GLib error given");
if (glib_error) {
g_error_free(glib_error);
}
return TRUE;
}
/* Remove all trailing new-line characters */
g_strchomp(contents);
*returned_message = contents;
if (remove(filename) != 0) {
log_error("[Editor] error during file deletion of %s", filename);
} else {
log_debug("[Editor] deleted file: %s", filename);
}
auto_gchar gchar* full_cmd = g_strdup_printf("%s %s", editor, filename);
if (!g_shell_parse_argv(full_cmd, NULL, &editor_argv, &error)) {
log_error("[Editor] Failed to parse editor command: %s", error->message);
cons_show_error("Failed to parse editor command: %s", error->message);
g_error_free(error);
return TRUE;
}
EditorContext* ctx = g_new0(EditorContext, 1);
ctx->filename = g_steal_pointer(&filename);
ctx->callback = callback;
ctx->user_data = user_data;
ui_suspend();
pid_t pid = fork();
if (pid == -1) {
log_error("[Editor] Failed to fork: %s", strerror(errno));
ui_resume();
ui_resize();
cons_show_error("Failed to start editor: %s", strerror(errno));
g_strfreev(editor_argv);
g_free(ctx->filename);
g_free(ctx);
return TRUE;
} else if (pid == 0) {
// Child process: Inherits TTY from parent
if (editor_argv && editor_argv[0]) {
execvp(editor_argv[0], editor_argv);
}
_exit(EXIT_FAILURE);
}
// Parent process: Watch the child asynchronously
g_child_watch_add((GPid)pid, _editor_exit_cb, ctx);
g_strfreev(editor_argv);
return FALSE;
}

View File

@@ -2,36 +2,10 @@
* editor.h
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2022 - 2025 Michael Vetter <jubalh@iodoru.org>
* Copyright (C) 2022 - 2026 Michael Vetter <jubalh@iodoru.org>
* Copyright (C) 2022 MarcoPolo PasTonMolo <marcopolopastonmolo@protonmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef TOOLS_EDITOR_H
@@ -56,5 +30,6 @@ extern EditorTask editor_task;
gboolean get_message_from_editor(gchar* message, gchar** returned_message);
gboolean get_message_from_editor_async(gchar* message);
void editor_process(ProfWin* window);
gboolean launch_editor(gchar* initial_content, void (*callback)(gchar* content, void* data), void* user_data);
#endif

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2020 William Wennerström <william@wstrm.dev>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -45,7 +19,7 @@
#define FALLBACK_MSG ""
void
http_print_transfer_update(ProfWin* window, char* id, const char* fmt, ...)
http_print_transfer_update(ProfWin* window, char* id, theme_item_t theme_item, int flags, const char* fmt, ...)
{
va_list args;
@@ -55,7 +29,7 @@ http_print_transfer_update(ProfWin* window, char* id, const char* fmt, ...)
va_end(args);
if (window->type != WIN_CONSOLE) {
win_update_entry_message(window, id, msg->str);
win_update_entry(window, id, msg->str, theme_item, flags);
} else {
cons_show("%s", msg->str);
}
@@ -64,7 +38,7 @@ http_print_transfer_update(ProfWin* window, char* id, const char* fmt, ...)
}
void
http_print_transfer(ProfWin* window, char* id, const char* fmt, ...)
http_print_transfer(ProfWin* window, char* id, theme_item_t theme_item, const char* fmt, ...)
{
va_list args;
@@ -73,7 +47,7 @@ http_print_transfer(ProfWin* window, char* id, const char* fmt, ...)
g_string_vprintf(msg, fmt, args);
va_end(args);
win_print_http_transfer(window, msg->str, id);
win_print_status_with_id(window, msg->str, id, theme_item, 0);
g_string_free(msg, TRUE);
}

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2020 William Wennerström <william@wstrm.dev>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef TOOLS_HTTP_COMMON_H
@@ -39,9 +13,9 @@
#include <glib.h>
#include "ui/window.h"
G_GNUC_PRINTF(3, 4)
void http_print_transfer(ProfWin* window, char* id, const char* fmt, ...);
G_GNUC_PRINTF(3, 4)
void http_print_transfer_update(ProfWin* window, char* id, const char* fmt, ...);
G_GNUC_PRINTF(4, 5)
void http_print_transfer(ProfWin* window, char* id, theme_item_t theme_item, const char* fmt, ...);
G_GNUC_PRINTF(5, 6)
void http_print_transfer_update(ProfWin* window, char* id, theme_item_t theme_item, int flags, const char* fmt, ...);
#endif

View File

@@ -4,35 +4,9 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2020 William Wennerström <william@wstrm.dev>
* Copyright (C) 2019 - 2025 Michael Vetter <jubalh@iodoru.org>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
* Copyright (C) 2019 - 2026 Michael Vetter <jubalh@iodoru.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -58,7 +32,6 @@
#include "common.h"
GSList* download_processes = NULL;
gboolean silent = FALSE;
static int
_xferinfo(void* userdata, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
@@ -84,9 +57,18 @@ _xferinfo(void* userdata, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultot
dlperc = (100 * dlnow) / dltotal;
}
if (!silent)
http_print_transfer_update(download->window, download->url,
"Downloading '%s': %d%%", download->url, dlperc);
if (!download->silent) {
const char* url = download->display_url ? download->display_url : download->url;
if (dlnow == dltotal && dltotal > 0) {
if (!download->silent_done) {
http_print_transfer_update(download->window, download->id, THEME_ONLINE, ENTRY_COMPLETED,
"Downloading '%s': done", url);
}
} else {
http_print_transfer_update(download->window, download->id, THEME_DEFAULT, 0,
"Downloading '%s': %d%%", url, dlperc);
}
}
pthread_mutex_unlock(&lock);
@@ -111,20 +93,20 @@ http_file_get(void* userdata)
CURL* curl;
CURLcode res;
silent = download->silent;
download->cancel = 0;
download->bytes_received = 0;
pthread_mutex_lock(&lock);
if (!silent) {
http_print_transfer(download->window, download->id,
"Downloading '%s': 0%%", download->url);
const char* display_url = download->display_url ? download->display_url : download->url;
if (!download->silent) {
http_print_transfer(download->window, download->id, THEME_DEFAULT,
"Downloading '%s': 0%%", display_url);
}
FILE* outfh = fopen(download->filename, "wb");
if (outfh == NULL) {
http_print_transfer_update(download->window, download->id,
http_print_transfer_update(download->window, download->id, THEME_ERROR, ENTRY_ERROR,
"Downloading '%s' failed: Unable to open "
"output file at '%s' for writing (%s).",
download->url, download->filename,
@@ -177,7 +159,7 @@ http_file_get(void* userdata)
err = strdup(curl_easy_strerror(res));
}
if (ftell(outfh) == 0) {
if (!err && ftell(outfh) == 0) {
err = strdup("Output file is empty.");
}
@@ -185,7 +167,9 @@ http_file_get(void* userdata)
curl_global_cleanup();
if (fclose(outfh) == EOF) {
err = strdup(g_strerror(errno));
if (!err) {
err = strdup(g_strerror(errno));
}
}
pthread_mutex_lock(&lock);
@@ -193,25 +177,29 @@ http_file_get(void* userdata)
g_free(cert_path);
if (err) {
if (download->cancel) {
http_print_transfer_update(download->window, download->id,
http_print_transfer_update(download->window, download->id, THEME_ERROR, ENTRY_ERROR,
"Downloading '%s' failed: "
"Download was canceled",
download->url);
display_url);
} else {
http_print_transfer_update(download->window, download->id,
http_print_transfer_update(download->window, download->id, THEME_ERROR, ENTRY_ERROR,
"Downloading '%s' failed: %s",
download->url, err);
display_url, err);
}
free(err);
} else {
if (!download->cancel && !silent) {
http_print_transfer_update(download->window, download->id,
"Downloading '%s': done\nSaved to '%s'",
download->url, download->filename);
win_mark_received(download->window, download->id);
if (!download->cancel) {
if (!download->silent && !download->silent_done) {
http_print_transfer_update(download->window, download->id, THEME_ONLINE, ENTRY_COMPLETED,
"Downloading '%s': done\nSaved to '%s'",
display_url, download->filename);
win_mark_received(download->window, download->id);
}
if (download->return_bytes_received) {
ret = malloc(sizeof(*ret));
*ret = download->bytes_received;
if (ret) {
*ret = download->bytes_received;
}
}
}
}
@@ -223,10 +211,10 @@ http_file_get(void* userdata)
// TODO: Log the error.
if (!call_external(argv)) {
http_print_transfer_update(download->window, download->id,
http_print_transfer_update(download->window, download->id, THEME_ERROR, ENTRY_ERROR,
"Downloading '%s' failed: Unable to call "
"command '%s' with file at '%s' (%s).",
download->url,
display_url,
download->cmd_template,
download->filename,
"TODO: Log the error");
@@ -243,6 +231,7 @@ out:
free(download->filename);
free(download->url);
free(download->display_url);
free(download->id);
free(download);

View File

@@ -5,33 +5,7 @@
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2020 William Wennerström <william@wstrm.dev>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef TOOLS_HTTP_DOWNLOAD_H
@@ -51,6 +25,7 @@ typedef struct http_download_t
{
char* id;
char* url;
char* display_url;
char* filename;
char* cmd_template;
curl_off_t bytes_received;
@@ -58,6 +33,7 @@ typedef struct http_download_t
pthread_t worker;
int cancel;
gboolean silent;
gboolean silent_done;
gboolean return_bytes_received;
} HTTPDownload;

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -91,11 +65,21 @@ _xferinfo(void* userdata, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultot
ulperc = (100 * ulnow) / ultotal;
}
gchar* msg = g_strdup_printf("Uploading '%s': %d%%", upload->filename, ulperc);
gchar* msg = NULL;
theme_item_t theme = THEME_DEFAULT;
int flags = 0;
if (ulnow == ultotal && ultotal > 0) {
msg = g_strdup_printf("Uploading '%s': done", upload->filename);
theme = THEME_ONLINE;
flags = ENTRY_COMPLETED;
} else {
msg = g_strdup_printf("Uploading '%s': %d%%", upload->filename, ulperc);
}
if (!msg) {
msg = g_strdup(FALLBACK_MSG);
}
win_update_entry_message(upload->window, upload->put_url, msg);
win_update_entry(upload->window, upload->put_url, msg, theme, flags);
g_free(msg);
pthread_mutex_unlock(&lock);
@@ -176,7 +160,7 @@ http_file_put(void* userdata)
if (!msg) {
msg = g_strdup(FALLBACK_MSG);
}
win_print_http_transfer(upload->window, msg, upload->put_url);
win_print_status_with_id(upload->window, msg, upload->put_url, THEME_DEFAULT, 0);
auto_gchar gchar* cert_path = prefs_get_string(PREF_TLS_CERTPATH);
auto_gchar gchar* cafile = cafile_get_name();
@@ -304,21 +288,22 @@ http_file_put(void* userdata)
if (!err_msg) {
err_msg = g_strdup(FALLBACK_MSG);
}
win_update_entry(upload->window, upload->put_url, err_msg, THEME_ERROR, ENTRY_ERROR);
} else {
err_msg = g_strdup_printf("Uploading '%s' failed: %s", upload->filename, err);
if (!err_msg) {
err_msg = g_strdup(FALLBACK_MSG);
}
win_update_entry_message(upload->window, upload->put_url, err_msg);
win_update_entry(upload->window, upload->put_url, err_msg, THEME_ERROR, ENTRY_ERROR);
}
cons_show_error("%s", err_msg);
} else {
if (!upload->cancel) {
auto_gchar gchar* status_msg = g_strdup_printf("Uploading '%s': 100%%", upload->filename);
auto_gchar gchar* status_msg = g_strdup_printf("Uploading '%s': done", upload->filename);
if (!status_msg) {
status_msg = g_strdup(FALLBACK_MSG);
}
win_update_entry_message(upload->window, upload->put_url, status_msg);
win_update_entry(upload->window, upload->put_url, status_msg, THEME_ONLINE, ENTRY_COMPLETED);
win_mark_received(upload->window, upload->put_url);
char* url = NULL;

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef TOOLS_HTTP_UPLOAD_H

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "config.h"
@@ -58,8 +32,7 @@ _parse_args_helper(const char* const inp, int min, int max, gboolean* result, gb
gboolean in_token = FALSE;
gboolean in_freetext = FALSE;
gboolean in_quotes = FALSE;
char* token_start = &copy[0];
int token_size = 0;
GString* current_token = g_string_new("");
int num_tokens = 0;
GSList* tokens = NULL;
@@ -68,6 +41,23 @@ _parse_args_helper(const char* const inp, int min, int max, gboolean* result, gb
gchar* curr_ch = g_utf8_offset_to_pointer(copy, i);
gunichar curr_uni = g_utf8_get_char(curr_ch);
if (curr_uni == '\\' && (i + 1 < inp_size)) {
if (!in_token) {
in_token = TRUE;
if (with_freetext) {
num_tokens++;
}
if (with_freetext && (num_tokens == max + 1)) {
in_freetext = TRUE;
}
}
i++;
gchar* next_ch = g_utf8_offset_to_pointer(copy, i);
gunichar next_uni = g_utf8_get_char(next_ch);
g_string_append_unichar(current_token, next_uni);
continue;
}
if (!in_token) {
if (curr_uni == ' ') {
continue;
@@ -81,58 +71,61 @@ _parse_args_helper(const char* const inp, int min, int max, gboolean* result, gb
} else if (curr_uni == '"') {
in_quotes = TRUE;
i++;
gchar* next_ch = g_utf8_next_char(curr_ch);
gunichar next_uni = g_utf8_get_char(next_ch);
if (i < inp_size) {
gchar* next_ch = g_utf8_offset_to_pointer(copy, i);
gunichar next_uni = g_utf8_get_char(next_ch);
if (next_uni == '"') {
tokens = g_slist_append(tokens, g_strndup(curr_ch,
0));
token_size = 0;
if (next_uni == '"') {
tokens = g_slist_append(tokens, g_strdup(""));
in_token = FALSE;
in_quotes = FALSE;
} else if (next_uni == '\\' && (i + 1 < inp_size)) {
i++;
gchar* escaped_ch = g_utf8_offset_to_pointer(copy, i);
gunichar escaped_uni = g_utf8_get_char(escaped_ch);
g_string_append_unichar(current_token, escaped_uni);
} else {
g_string_append_unichar(current_token, next_uni);
}
} else {
// trailing quote
tokens = g_slist_append(tokens, g_strdup(""));
in_token = FALSE;
in_quotes = FALSE;
} else {
token_start = next_ch;
token_size += g_unichar_to_utf8(next_uni, NULL);
}
}
if (curr_uni == '"') {
gchar* next_ch = g_utf8_next_char(curr_ch);
token_start = next_ch;
} else {
token_start = curr_ch;
token_size += g_unichar_to_utf8(curr_uni, NULL);
if (in_token && curr_uni != '"') {
g_string_append_unichar(current_token, curr_uni);
}
}
} else {
if (in_quotes) {
if (curr_uni == '"') {
tokens = g_slist_append(tokens, g_strndup(token_start,
token_size));
token_size = 0;
tokens = g_slist_append(tokens, g_string_free(current_token, FALSE));
current_token = g_string_new("");
in_token = FALSE;
in_quotes = FALSE;
} else {
if (curr_uni != '"') {
token_size += g_unichar_to_utf8(curr_uni, NULL);
}
g_string_append_unichar(current_token, curr_uni);
}
} else {
if (with_freetext && in_freetext) {
token_size += g_unichar_to_utf8(curr_uni, NULL);
g_string_append_unichar(current_token, curr_uni);
} else if (curr_uni == ' ') {
tokens = g_slist_append(tokens, g_strndup(token_start,
token_size));
token_size = 0;
tokens = g_slist_append(tokens, g_string_free(current_token, FALSE));
current_token = g_string_new("");
in_token = FALSE;
} else {
token_size += g_unichar_to_utf8(curr_uni, NULL);
g_string_append_unichar(current_token, curr_uni);
}
}
}
}
if (in_token) {
tokens = g_slist_append(tokens, g_strndup(token_start, token_size));
tokens = g_slist_append(tokens, g_string_free(current_token, FALSE));
} else {
g_string_free(current_token, TRUE);
}
int num = g_slist_length(tokens) - 1;
@@ -271,9 +264,23 @@ count_tokens(const char* const string)
gchar* curr_ch = g_utf8_offset_to_pointer(string, i);
gunichar curr_uni = g_utf8_get_char(curr_ch);
if (curr_uni == '\\' && (i + 1 < length)) {
i++;
continue;
}
if (curr_uni == ' ') {
if (!in_quotes) {
num_tokens++;
while (i + 1 < length) {
gchar* next_ch = g_utf8_offset_to_pointer(string, i + 1);
gunichar next_uni = g_utf8_get_char(next_ch);
if (next_uni == ' ') {
i++;
} else {
break;
}
}
}
} else if (curr_uni == '"') {
if (in_quotes) {
@@ -302,15 +309,37 @@ get_start(const char* const string, int tokens)
gchar* curr_ch = g_utf8_offset_to_pointer(string, i);
gunichar curr_uni = g_utf8_get_char(curr_ch);
if (curr_uni == '\\' && (i + 1 < length)) {
if (num_tokens < tokens) {
g_string_append_unichar(result, curr_uni);
}
i++;
curr_ch = g_utf8_offset_to_pointer(string, i);
curr_uni = g_utf8_get_char(curr_ch);
if (num_tokens < tokens) {
g_string_append_unichar(result, curr_uni);
}
continue;
}
if (num_tokens < tokens) {
auto_gchar gchar* uni_char = g_malloc(7);
int len = g_unichar_to_utf8(curr_uni, uni_char);
uni_char[len] = '\0';
g_string_append(result, uni_char);
g_string_append_unichar(result, curr_uni);
}
if (curr_uni == ' ') {
if (!in_quotes) {
num_tokens++;
while (i + 1 < length) {
gchar* next_ch = g_utf8_offset_to_pointer(string, i + 1);
gunichar next_uni = g_utf8_get_char(next_ch);
if (next_uni == ' ') {
if (num_tokens <= tokens) {
g_string_append_unichar(result, next_uni);
}
i++;
} else {
break;
}
}
}
} else if (curr_uni == '"') {
if (in_quotes) {
@@ -328,7 +357,7 @@ GHashTable*
parse_options(gchar** args, gchar** opt_keys, gboolean* res)
{
GList* keys = NULL;
for (int i = 0; i < g_strv_length(opt_keys); i++) {
for (guint i = 0; i < g_strv_length(opt_keys); i++) {
keys = g_list_append(keys, opt_keys[i]);
}
@@ -344,7 +373,7 @@ parse_options(gchar** args, gchar** opt_keys, gboolean* res)
// validate options
GList* found_keys = NULL;
for (int curr = 0; curr < g_strv_length(args); curr += 2) {
for (guint curr = 0; curr < g_strv_length(args); curr += 2) {
// check if option valid
if (g_list_find_custom(keys, args[curr], (GCompareFunc)g_strcmp0) == NULL) {
*res = FALSE;
@@ -377,7 +406,7 @@ parse_options(gchar** args, gchar** opt_keys, gboolean* res)
// create map
options = g_hash_table_new(g_str_hash, g_str_equal);
*res = TRUE;
for (int curr = 0; curr < g_strv_length(args); curr += 2) {
for (guint curr = 0; curr < g_strv_length(args); curr += 2) {
g_hash_table_insert(options, args[curr], args[curr + 1]);
}

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity 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 3 of the License, or
* (at your option) any later version.
*
* Profanity 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#ifndef TOOLS_PARSER_H

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