merge: sync upstream profanity-im/profanity
All checks were successful
CI Code / Check spelling (push) Successful in 18s
CI Code / Check coding style (push) Successful in 34s
CI Code / Code Coverage (push) Successful in 2m36s
CI Code / Linux (debian) (push) Successful in 4m41s
CI Code / Linux (ubuntu) (push) Successful in 4m52s
CI Code / Linux (arch) (push) Successful in 5m40s

Sync with upstream profanity-im/profanity.

Major upstream changes incorporated:

Memory management
  - Replace malloc+memset with g_new0 throughout codebase
  - Adopt auto_gchar / auto_gcharv / auto_gerror / auto_jid cleanup macros
  - Replace free() with g_free() for GAlloc'd memory

Editor rewrite
  - Remove pthread-based async editor; use GChildWatch callback API
  - New launch_editor(initial_content, callback, user_data) interface
  - Proper signal handling (SIGINT, SIGTSTP, SIGPIPE reset in child)
  - ui_suspend()/ui_resume() integration for TTY management

OMEMO improvements
  - Dual backend support: libsignal-protocol-c and libomemo-c
  - Proper pre-key removal after use (XEP-0384 compliance)
  - Automatic pre-key regeneration when store drops below threshold
  - New functions: omemo_is_device_active(), omemo_is_jid_trusted()
  - omemo_get_jid_untrusted_fingerprints() for better error messages
  - Fingerprint notifications on new device identity discovery
  - Deterministic pre-key ID generation tracking max_pre_key_id
  - omemo_trust_changed() UI updates on trust state changes

JID validation
  - RFC 6122-compliant validation in jid_is_valid()
  - Character-level checks (RFC 6122 forbidden chars: & ' / : < > @)
  - Length limits: 1023 per component, 3071 total
  - New jid_is_valid_user_jid() for user vs. service JID distinction

Database
  - Schema migration v3: UNIQUE constraint on archive_id for deduplication
  - Triggers for corrected message tracking (replaces_db_id / replaced_by_db_id)
  - db_history_result_t return type, _truncate_datetime_suffix()

UI / console
  - win_warn_needed() / win_warn_sent() warning deduplication hash table
  - PAD_MIN_HEIGHT dynamic pad sizing with PAD_THRESHOLD auto-cleanup
  - Spellcheck integration in input field with Unicode word detection
  - cons_spellcheck_setting() for /settings ui output
  - /[command]? shortcut for command help

Account config
  - Account name sanitization for GKeyFile special chars ([ ] = # \n \r)
  - Replace popen() with g_spawn_sync() for eval_password
  - TLS policy: add "direct" option alongside legacy

Connection
  - Port validation with g_assert (0–65535)
  - SHA-256 certificate fingerprint support (XMPP_CERT_PUBKEY_FINGERPRINT_SHA256)
  - "direct" TLS policy alias for legacy SSL

Common utilities
  - str_xml_sanitize() for XML 1.0 illegal character removal
  - string_matches_one_of() with formatted error messages
  - valid_tls_policy_option() helper
  - prof_date_time_format_iso8601() utility
  - Improved strip_arg_quotes() with backslash unescaping
  - prof_occurrences() uses g_slist_prepend + reverse for performance

PGP / OX
  - Proper GPGME resource cleanup with goto-cleanup pattern
  - g_string_free(xmppuri) leak fix in _ox_key_lookup

CSV export
  - Use GString + g_file_set_contents instead of raw write() syscalls

Tests
  - Restructured into subdirectories: command/, config/, xmpp/, ui/, omemo/, otr/, pgp/
  - New test_cmd_ac.c for autocompleter unit tests
  - Updated stubs for new UI suspend/resume functions

License headers
  - Migrate to SPDX-3.0 identifiers (GPL-3.0-or-later WITH OpenSSL-exception)

────────────────────────────────────────────────────
cproof-specific preservations:

  - XEP-0308 LMC: replace_id ?: id logic in message/stanza/omemo
  - Force encryption: cmd_force_encryption, test_forced_encryption
  - CWE-134: format string protection (cons_show("%s", ...))
  - y_start_pos-based paging in window.c
  - db_history_result_t return type, _truncate_datetime_suffix()

Merge-time fixes:

  - common.c: format-security (-Werror) — cons_show(errmsg) → cons_show("%s", errmsg)
  - database.c: null-deref guard — !msg->timestamp → msg && !msg->timestamp
  - console.c: implicit size_t → int cast — (int)(maxlen + 1)
  - tlscerts.c: %d for size_t — %zu

Build system:
  - Kept autotools (Makefile.am, configure.ac); upstream uses Meson
  - Restored deleted files: bootstrap.sh, autogen.sh, ax_valgrind_check.m4, configure-debug
  - Updated Makefile.am test paths for subdirectory structure
  - Added test_cmd_ac, test_forced_encryption to test sources

Functional tests:
  - Use cproof version; upstream requires stbbr_for_xmlns from updated stabber
  - Not yet available in devs/stabber fork

Closes #64

Merge author: jabber.developer2
Commits authors:
 Michael Vetter <jubalh@iodoru.org>
& Steffen Jaeckel <s@jaeckel.eu>
This commit is contained in:
2026-05-26 17:48:14 +00:00
parent 3b673150b4
commit 72f4f186da
303 changed files with 10658 additions and 9857 deletions

View File

@@ -65,7 +65,7 @@ buffer_create(void)
return new_buff;
}
int
unsigned int
buffer_size(ProfBuff buffer)
{
return g_slist_length(buffer->entries);
@@ -137,7 +137,7 @@ buffer_remove_entry_by_id(ProfBuff buffer, const char* const id)
}
void
buffer_remove_entry(ProfBuff buffer, int entry)
buffer_remove_entry(ProfBuff buffer, unsigned int entry)
{
GSList* node = g_slist_nth(buffer->entries, entry);
if (node == NULL) {
@@ -169,7 +169,7 @@ buffer_mark_received(ProfBuff buffer, const char* const id)
}
ProfBuffEntry*
buffer_get_entry(ProfBuff buffer, int entry)
buffer_get_entry(ProfBuff buffer, unsigned int entry)
{
GSList* node = g_slist_nth(buffer->entries, entry);
if (node == NULL) {
@@ -197,7 +197,7 @@ static ProfBuffEntry*
_create_entry(const char* show_char, int pad_indent, GDateTime* time, int flags, theme_item_t theme_item, const char* const display_from, const char* const from_jid, const char* const message, DeliveryReceipt* receipt, const char* const id, int y_start_pos, int y_end_pos)
{
assert(time != NULL);
ProfBuffEntry* e = malloc(sizeof(struct prof_buff_entry_t));
ProfBuffEntry* e = g_new0(ProfBuffEntry, 1);
e->show_char = STRDUP_OR_NULL(show_char);
e->pad_indent = pad_indent;
e->flags = flags;

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 UI_BUFFER_H
@@ -81,9 +55,9 @@ void buffer_free(ProfBuff buffer);
void buffer_append(ProfBuff buffer, const char* show_char, int pad_indent, GDateTime* time, int flags, theme_item_t theme_item, const char* const display_from, const char* const barejid, const char* const message, DeliveryReceipt* receipt, const char* const id, int y_start_pos, int y_end_pos);
void buffer_prepend(ProfBuff buffer, const char* show_char, int pad_indent, GDateTime* time, int flags, theme_item_t theme_item, const char* const display_from, const char* const barejid, const char* const message, DeliveryReceipt* receipt, const char* const id, int y_start_pos, int y_end_pos);
void buffer_remove_entry_by_id(ProfBuff buffer, const char* const id);
void buffer_remove_entry(ProfBuff buffer, int entry);
int buffer_size(ProfBuff buffer);
ProfBuffEntry* buffer_get_entry(ProfBuff buffer, int entry);
void buffer_remove_entry(ProfBuff buffer, unsigned int entry);
unsigned int buffer_size(ProfBuff buffer);
ProfBuffEntry* buffer_get_entry(ProfBuff buffer, unsigned int entry);
ProfBuffEntry* buffer_get_entry_by_id(ProfBuff buffer, const char* const id);
gboolean buffer_mark_received(ProfBuff buffer, const char* const id);

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"
@@ -419,11 +393,14 @@ chatwin_outgoing_msg(ProfChatWin* chatwin, const char* const message, const char
const char* display_message = plugin_message ?: message;
if (request_receipt && id) {
win_print_outgoing_with_receipt((ProfWin*)chatwin, enc_char, "me", display_message, id, replace_id);
auto_gchar gchar* outgoing_str = prefs_get_string(PREF_OUTGOING_STAMP);
win_print_outgoing_with_receipt((ProfWin*)chatwin, enc_char, outgoing_str, display_message, id, replace_id);
} else {
win_print_outgoing((ProfWin*)chatwin, enc_char, id, replace_id, display_message);
}
plugins_post_chat_message_display(myjid->barejid, myjid->resourcepart, display_message);
// Save last id and message for LMC
// Note: if the same message is to be corrected several times, the id of the original message is used in each case
// https://xmpp.org/extensions/xep-0308.html#rules
@@ -450,7 +427,16 @@ chatwin_outgoing_carbon(ProfChatWin* chatwin, ProfMessage* message)
ProfWin* window = (ProfWin*)chatwin;
char* old_plain = message->plain;
auto_char char* plugin_msg = plugins_pre_chat_message_display(message->from_jid->barejid, message->from_jid->resourcepart, message->plain);
if (plugin_msg)
message->plain = plugin_msg;
win_print_outgoing(window, enc_char, message->id, message->replace_id, message->plain);
plugins_post_chat_message_display(message->from_jid->barejid, message->from_jid->resourcepart, message->plain);
message->plain = old_plain;
int num = wins_get_num(window);
status_bar_active(num, WIN_CHAT, chatwin->barejid);
}
@@ -575,6 +561,7 @@ _chatwin_history(ProfChatWin* chatwin, const char* const contact_barejid)
if (plugin_msg)
msg->plain = plugin_msg;
win_print_history((ProfWin*)chatwin, msg);
plugins_post_chat_message_display(msg->from_jid->barejid, msg->from_jid->resourcepart, msg->plain);
msg->plain = old_plain;
curr = g_slist_next(curr);
}
@@ -614,6 +601,7 @@ chatwin_db_history(ProfChatWin* chatwin, const gchar* start_time, const gchar* e
} else {
win_print_history((ProfWin*)chatwin, msg);
}
plugins_post_chat_message_display(msg->from_jid->barejid, msg->from_jid->resourcepart, msg->plain);
msg->plain = old_plain;
curr = g_slist_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
*/
#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) 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"
@@ -90,6 +64,13 @@ cons_show(const char* const msg, ...)
va_end(arg);
}
#define cons_show_if_set(fmt, elmnt) \
do { \
if (elmnt) { \
cons_show(fmt, elmnt); \
} \
} while (0)
void
cons_show_padded(int pad, const char* const msg, ...)
{
@@ -110,9 +91,12 @@ cons_show_help(const char* const cmd, CommandHelp* help)
cons_show("");
win_println(console, THEME_HELP_HEADER, "-", "%s", &cmd[1]);
win_print(console, THEME_HELP_HEADER, "-", "");
int i;
for (i = 0; i < strlen(cmd) - 1; i++) {
win_append(console, THEME_HELP_HEADER, "-");
size_t i;
size_t cmd_len = strlen(cmd);
if (cmd_len > 0) {
for (i = 0; i < cmd_len - 1; i++) {
win_append(console, THEME_HELP_HEADER, "-");
}
}
win_appendln(console, THEME_HELP_HEADER, "");
cons_show("");
@@ -124,7 +108,7 @@ cons_show_help(const char* const cmd, CommandHelp* help)
win_println(console, THEME_HELP_HEADER, "-", "Description");
win_println(console, THEME_DEFAULT, "-", "%s", help->desc);
int maxlen = 0;
size_t maxlen = 0;
for (i = 0; help->args[i][0] != NULL; i++) {
if (strlen(help->args[i][0]) > maxlen)
maxlen = strlen(help->args[i][0]);
@@ -134,7 +118,7 @@ cons_show_help(const char* const cmd, CommandHelp* help)
cons_show("");
win_println(console, THEME_HELP_HEADER, "-", "Arguments");
for (i = 0; help->args[i][0] != NULL; i++) {
win_println_indent(console, maxlen + 3, "%-*s: %s", maxlen + 1, help->args[i][0], help->args[i][1]);
win_println_indent(console, (int)(maxlen + 3), "%-*s: %s", (int)(maxlen + 1), help->args[i][0], help->args[i][1]);
}
}
@@ -178,8 +162,8 @@ cons_show_tlscert_summary(const TLSCertificate* cert)
return;
}
cons_show("Subject : %s", cert->subject_commonname);
cons_show("Issuer : %s", cert->issuer_commonname);
cons_show("Subject : %s", cert->subject.commonname);
cons_show("Issuer : %s", cert->issuer.commonname);
cons_show("Fingerprint : %s", cert->fingerprint);
}
@@ -192,75 +176,39 @@ cons_show_tlscert(const TLSCertificate* cert)
cons_show("Certificate:");
cons_show(" Subject:");
if (cert->subject_commonname) {
cons_show(" Common name : %s", cert->subject_commonname);
}
if (cert->subject_distinguishedname) {
cons_show(" Distinguished name : %s", cert->subject_distinguishedname);
}
if (cert->subject_organisation) {
cons_show(" Organisation : %s", cert->subject_organisation);
}
if (cert->subject_organisation_unit) {
cons_show(" Organisation unit : %s", cert->subject_organisation_unit);
}
if (cert->subject_email) {
cons_show(" Email : %s", cert->subject_email);
}
if (cert->subject_state) {
cons_show(" State : %s", cert->subject_state);
}
if (cert->subject_country) {
cons_show(" Country : %s", cert->subject_country);
}
if (cert->subject_serialnumber) {
cons_show(" Serial number : %s", cert->subject_serialnumber);
}
cons_show(" Issuer:");
if (cert->issuer_commonname) {
cons_show(" Common name : %s", cert->issuer_commonname);
}
if (cert->issuer_distinguishedname) {
cons_show(" Distinguished name : %s", cert->issuer_distinguishedname);
}
if (cert->issuer_organisation) {
cons_show(" Organisation : %s", cert->issuer_organisation);
}
if (cert->issuer_organisation_unit) {
cons_show(" Organisation unit : %s", cert->issuer_organisation_unit);
}
if (cert->issuer_email) {
cons_show(" Email : %s", cert->issuer_email);
}
if (cert->issuer_state) {
cons_show(" State : %s", cert->issuer_state);
}
if (cert->issuer_country) {
cons_show(" Country : %s", cert->issuer_country);
}
if (cert->issuer_serialnumber) {
cons_show(" Serial number : %s", cert->issuer_serialnumber);
}
cons_show(" Version : %d", cert->version);
if (cert->serialnumber) {
cons_show(" Serial number : %s", cert->serialnumber);
}
cons_show(" Subject:");
cons_show_if_set(" Common name : %s", cert->subject.commonname);
cons_show_if_set(" Distinguished name : %s", cert->subject.distinguishedname);
cons_show_if_set(" Organisation : %s", cert->subject.organisation);
cons_show_if_set(" Organisation unit : %s", cert->subject.organisation_unit);
cons_show_if_set(" Email : %s", cert->subject.email);
cons_show_if_set(" State : %s", cert->subject.state);
cons_show_if_set(" Country : %s", cert->subject.country);
cons_show_if_set(" Serial number : %s", cert->subject.serialnumber);
if (cert->key_alg) {
cons_show(" Key algorithm : %s", cert->key_alg);
}
if (cert->signature_alg) {
cons_show(" Signature algorithm : %s", cert->signature_alg);
}
cons_show(" Issuer:");
cons_show_if_set(" Common name : %s", cert->issuer.commonname);
cons_show_if_set(" Distinguished name : %s", cert->issuer.distinguishedname);
cons_show_if_set(" Organisation : %s", cert->issuer.organisation);
cons_show_if_set(" Organisation unit : %s", cert->issuer.organisation_unit);
cons_show_if_set(" Email : %s", cert->issuer.email);
cons_show_if_set(" State : %s", cert->issuer.state);
cons_show_if_set(" Country : %s", cert->issuer.country);
cons_show_if_set(" Serial number : %s", cert->issuer.serialnumber);
cons_show(" Start : %s", cert->notbefore);
cons_show(" End : %s", cert->notafter);
cons_show_if_set(" Serial number : %s", cert->serialnumber);
cons_show(" Fingerprint : %s", cert->fingerprint);
cons_show_if_set(" Key algorithm : %s", cert->key_alg);
cons_show_if_set(" Signature algorithm : %s", cert->signature_alg);
cons_show_if_set(" Validity Start : %s", cert->notbefore);
cons_show_if_set(" Validity End : %s", cert->notafter);
cons_show_if_set(" Fingerprint SHA1 : %s", cert->fingerprint_sha1);
cons_show_if_set(" Fingerprint SHA256 : %s", cert->fingerprint_sha256);
cons_show_if_set(" Pubkey Fingerprint : %s", cert->pubkey_fingerprint);
}
void
@@ -417,7 +365,7 @@ cons_check_version(gboolean not_available_msg)
gboolean relase_valid = g_regex_match_simple("^\\d+\\.\\d+\\.\\d+$", latest_release, 0, 0);
if (relase_valid) {
if (release_is_new(latest_release)) {
if (release_is_new(PACKAGE_VERSION, latest_release)) {
win_println(console, THEME_DEFAULT, "-", "A new version of Profanity is available: %s", latest_release);
win_println(console, THEME_DEFAULT, "-", "Check <https://profanity-im.github.io> for details.");
win_println(console, THEME_DEFAULT, "-", "");
@@ -470,7 +418,7 @@ cons_show_wins(gboolean unread)
GSList* curr = window_strings;
while (curr) {
if (g_strstr_len((char*)curr->data, strlen((char*)curr->data), " unread") != NULL) {
if (g_strstr_len(curr->data, strlen(curr->data), " unread") != NULL) {
win_println(console, THEME_CMD_WINS_UNREAD, "-", "%s", (char*)curr->data);
} else {
win_println(console, THEME_DEFAULT, "-", "%s", (char*)curr->data);
@@ -483,7 +431,7 @@ cons_show_wins(gboolean unread)
}
void
cons_show_wins_attention()
cons_show_wins_attention(void)
{
ProfWin* console = wins_get_console();
cons_show("");
@@ -491,7 +439,7 @@ cons_show_wins_attention()
GSList* curr = window_strings;
while (curr) {
if (g_strstr_len((char*)curr->data, strlen((char*)curr->data), " unread") != NULL) {
if (g_strstr_len(curr->data, strlen(curr->data), " unread") != NULL) {
win_println(console, THEME_CMD_WINS_UNREAD, "-", "%s", (char*)curr->data);
} else {
win_println(console, THEME_DEFAULT, "-", "%s", (char*)curr->data);
@@ -845,7 +793,7 @@ cons_show_qrcode(const char* const text)
static const size_t ZOOM_SIZE = 10;
QRcode* qrcode = QRcode_encodeString(text, 0, QR_ECLEVEL_L, QR_MODE_8, 1);
int width = (qrcode->width * ZOOM_SIZE);
size_t width = (qrcode->width * ZOOM_SIZE);
unsigned char* data = qrcode->data;
ProfWin* console = wins_get_console();
@@ -857,7 +805,7 @@ cons_show_qrcode(const char* const text)
return;
}
for (int i = 0; i < width + 2 * ZOOM_SIZE; i += ZOOM_SIZE) {
for (size_t i = 0; i < width + 2 * ZOOM_SIZE; i += ZOOM_SIZE) {
strcat(pad, "\u2588\u2588");
}
@@ -1318,6 +1266,21 @@ cons_splash_setting(void)
cons_show("Splash screen (/splash) : OFF");
}
void
cons_spellcheck_setting(void)
{
#ifdef HAVE_SPELLCHECK
if (prefs_get_boolean(PREF_SPELLCHECK_ENABLE)) {
auto_gchar gchar* lang = prefs_get_string(PREF_SPELLCHECK_LANG);
cons_show("Spellcheck (/spellcheck) : ON (%s)", lang);
} else {
cons_show("Spellcheck (/spellcheck) : OFF");
}
#else
cons_show("Spellcheck (/spellcheck) : built without spellcheck support");
#endif
}
void
cons_occupants_setting(void)
{
@@ -1341,7 +1304,7 @@ cons_occupants_setting(void)
else
cons_show("Occupants wrap (/occupants) : OFF");
auto_char char* occupants_ch = prefs_get_occupants_char();
auto_gchar gchar* occupants_ch = prefs_get_occupants_char();
if (occupants_ch) {
cons_show("Occupants char (/occupants) : %s", occupants_ch);
} else {
@@ -1354,7 +1317,7 @@ cons_occupants_setting(void)
int size = prefs_get_occupants_size();
cons_show("Occupants size (/occupants) : %d", size);
auto_char char* header_ch = prefs_get_occupants_header_char();
auto_gchar gchar* header_ch = prefs_get_occupants_header_char();
if (header_ch) {
cons_show("Occupants header char (/occupants) : %s", header_ch);
} else {
@@ -1471,42 +1434,42 @@ cons_roster_setting(void)
else
cons_show("Roster offline (/roster) : hide");
auto_char char* header_ch = prefs_get_roster_header_char();
auto_gchar gchar* header_ch = prefs_get_roster_header_char();
if (header_ch) {
cons_show("Roster header char (/roster) : %s", header_ch);
} else {
cons_show("Roster header char (/roster) : none");
}
auto_char char* contact_ch = prefs_get_roster_contact_char();
auto_gchar gchar* contact_ch = prefs_get_roster_contact_char();
if (contact_ch) {
cons_show("Roster contact char (/roster) : %s", contact_ch);
} else {
cons_show("Roster contact char (/roster) : none");
}
auto_char char* resource_ch = prefs_get_roster_resource_char();
auto_gchar gchar* resource_ch = prefs_get_roster_resource_char();
if (resource_ch) {
cons_show("Roster resource char (/roster) : %s", resource_ch);
} else {
cons_show("Roster resource char (/roster) : none");
}
auto_char char* room_ch = prefs_get_roster_room_char();
auto_gchar gchar* room_ch = prefs_get_roster_room_char();
if (room_ch) {
cons_show("Roster room char (/roster) : %s", room_ch);
} else {
cons_show("Roster room char (/roster) : none");
}
auto_char char* room_priv_ch = prefs_get_roster_room_private_char();
auto_gchar gchar* room_priv_ch = prefs_get_roster_room_private_char();
if (room_priv_ch) {
cons_show("Roster room private char (/roster) : %s", room_priv_ch);
} else {
cons_show("Roster room private char (/roster) : none");
}
auto_char char* private_ch = prefs_get_roster_private_char();
auto_gchar gchar* private_ch = prefs_get_roster_private_char();
if (private_ch) {
cons_show("Roster private char (/roster) : %s", private_ch);
} else {
@@ -1637,6 +1600,7 @@ cons_show_ui_prefs(void)
cons_beep_setting();
cons_flash_setting();
cons_splash_setting();
cons_spellcheck_setting();
cons_winpos_setting();
cons_wrap_setting();
cons_time_setting();
@@ -2378,6 +2342,7 @@ cons_help(void)
cons_show_padded(pad, "/help commands ui : List commands for manipulating the user interface.");
cons_show_padded(pad, "/help commands plugins : List plugin commands.");
cons_show_padded(pad, "/help [command] : Detailed help on a specific command.");
cons_show_padded(pad, "/[command]? : Shortcut to get detailed help on a specific command.");
cons_show_padded(pad, "/help navigation : How to navigate around Profanity.");
cons_show("");
@@ -2494,137 +2459,123 @@ cons_get_string(ProfConsoleWin* conswin)
return g_strdup("Console");
}
void
_cons_theme_bar_prop(theme_item_t theme, char* prop)
static void
_cons_theme_bar_prop(ProfWin* console, theme_item_t theme, char* prop)
{
ProfWin* console = wins_get_console();
auto_gchar gchar* propstr = g_strdup_printf("%-24s", prop);
win_print(console, THEME_TEXT, "-", "%s", propstr);
GString* propstr = g_string_new(" ");
g_string_append_printf(propstr, "%-24s", prop);
win_print(console, THEME_TEXT, "-", "%s", propstr->str);
g_string_free(propstr, TRUE);
GString* valstr = g_string_new(" ");
char* setting = theme_get_string(prop);
g_string_append_printf(valstr, "%s ", setting);
theme_free_string(setting);
win_append(console, theme, "%s", valstr->str);
auto_gchar gchar* setting = theme_get_string(prop);
win_append(console, theme, "%s", setting);
win_appendln(console, THEME_TEXT, "");
g_string_free(valstr, TRUE);
}
void
_cons_theme_prop(theme_item_t theme, char* prop)
static void
_cons_theme_prop(ProfWin* console, theme_item_t theme, char* prop)
{
ProfWin* console = wins_get_console();
auto_gchar gchar* propstr = g_strdup_printf("%-24s", prop);
win_print(console, THEME_TEXT, "-", "%s", propstr);
GString* propstr = g_string_new(" ");
g_string_append_printf(propstr, "%-24s", prop);
win_print(console, THEME_TEXT, "-", "%s", propstr->str);
g_string_free(propstr, TRUE);
GString* valstr = g_string_new("");
char* setting = theme_get_string(prop);
g_string_append_printf(valstr, "%s", setting);
theme_free_string(setting);
win_appendln(console, theme, "%s", valstr->str);
g_string_free(valstr, TRUE);
auto_gchar gchar* setting = theme_get_string(prop);
win_appendln(console, theme, "%s", setting);
}
void
cons_theme_properties(void)
{
ProfWin* console = wins_get_console();
cons_show("Current colours:");
_cons_theme_bar_prop(THEME_TITLE_TEXT, "titlebar.text");
_cons_theme_bar_prop(THEME_TITLE_BRACKET, "titlebar.brackets");
_cons_theme_bar_prop(console, THEME_TITLE_TEXT, "titlebar.text");
_cons_theme_bar_prop(console, THEME_TITLE_BRACKET, "titlebar.brackets");
_cons_theme_bar_prop(THEME_TITLE_SCROLLED, "titlebar.scrolled");
_cons_theme_bar_prop(console, THEME_TITLE_SCROLLED, "titlebar.scrolled");
_cons_theme_bar_prop(THEME_TITLE_UNENCRYPTED, "titlebar.unencrypted");
_cons_theme_bar_prop(THEME_TITLE_ENCRYPTED, "titlebar.encrypted");
_cons_theme_bar_prop(THEME_TITLE_UNTRUSTED, "titlebar.untrusted");
_cons_theme_bar_prop(THEME_TITLE_TRUSTED, "titlebar.trusted");
_cons_theme_bar_prop(console, THEME_TITLE_UNENCRYPTED, "titlebar.unencrypted");
_cons_theme_bar_prop(console, THEME_TITLE_ENCRYPTED, "titlebar.encrypted");
_cons_theme_bar_prop(console, THEME_TITLE_UNTRUSTED, "titlebar.untrusted");
_cons_theme_bar_prop(console, THEME_TITLE_TRUSTED, "titlebar.trusted");
_cons_theme_bar_prop(THEME_TITLE_CHAT, "titlebar.chat");
_cons_theme_bar_prop(THEME_TITLE_ONLINE, "titlebar.online");
_cons_theme_bar_prop(THEME_TITLE_AWAY, "titlebar.away");
_cons_theme_bar_prop(THEME_TITLE_XA, "titlebar.xa");
_cons_theme_bar_prop(THEME_TITLE_DND, "titlebar.dnd");
_cons_theme_bar_prop(THEME_TITLE_OFFLINE, "titlebar.offline");
_cons_theme_bar_prop(console, THEME_TITLE_CHAT, "titlebar.chat");
_cons_theme_bar_prop(console, THEME_TITLE_ONLINE, "titlebar.online");
_cons_theme_bar_prop(console, THEME_TITLE_AWAY, "titlebar.away");
_cons_theme_bar_prop(console, THEME_TITLE_XA, "titlebar.xa");
_cons_theme_bar_prop(console, THEME_TITLE_DND, "titlebar.dnd");
_cons_theme_bar_prop(console, THEME_TITLE_OFFLINE, "titlebar.offline");
_cons_theme_bar_prop(THEME_STATUS_TEXT, "statusbar.text");
_cons_theme_bar_prop(THEME_STATUS_BRACKET, "statusbar.brackets");
_cons_theme_bar_prop(THEME_STATUS_ACTIVE, "statusbar.active");
_cons_theme_bar_prop(THEME_STATUS_CURRENT, "statusbar.current");
_cons_theme_bar_prop(THEME_STATUS_NEW, "statusbar.new");
_cons_theme_bar_prop(THEME_STATUS_TIME, "statusbar.time");
_cons_theme_bar_prop(console, THEME_STATUS_TEXT, "statusbar.text");
_cons_theme_bar_prop(console, THEME_STATUS_BRACKET, "statusbar.brackets");
_cons_theme_bar_prop(console, THEME_STATUS_ACTIVE, "statusbar.active");
_cons_theme_bar_prop(console, THEME_STATUS_CURRENT, "statusbar.current");
_cons_theme_bar_prop(console, THEME_STATUS_NEW, "statusbar.new");
_cons_theme_bar_prop(console, THEME_STATUS_TIME, "statusbar.time");
_cons_theme_prop(THEME_TIME, "main.time");
_cons_theme_prop(THEME_TEXT, "main.text");
_cons_theme_prop(THEME_SPLASH, "main.splash");
_cons_theme_prop(THEME_ERROR, "error");
_cons_theme_prop(THEME_OTR_STARTED_TRUSTED, "otr.started.trusted");
_cons_theme_prop(THEME_OTR_STARTED_UNTRUSTED, "otr.started.untrusted");
_cons_theme_prop(THEME_OTR_ENDED, "otr.ended");
_cons_theme_prop(THEME_OTR_TRUSTED, "otr.trusted");
_cons_theme_prop(THEME_OTR_UNTRUSTED, "otr.untrusted");
_cons_theme_prop(console, THEME_TIME, "main.time");
_cons_theme_prop(console, THEME_TEXT, "main.text");
_cons_theme_prop(console, THEME_SPLASH, "main.splash");
_cons_theme_prop(console, THEME_ERROR, "error");
_cons_theme_prop(console, THEME_OTR_STARTED_TRUSTED, "otr.started.trusted");
_cons_theme_prop(console, THEME_OTR_STARTED_UNTRUSTED, "otr.started.untrusted");
_cons_theme_prop(console, THEME_OTR_ENDED, "otr.ended");
_cons_theme_prop(console, THEME_OTR_TRUSTED, "otr.trusted");
_cons_theme_prop(console, THEME_OTR_UNTRUSTED, "otr.untrusted");
_cons_theme_prop(THEME_ME, "me");
_cons_theme_prop(THEME_TEXT_ME, "main.text.me");
_cons_theme_prop(THEME_THEM, "them");
_cons_theme_prop(THEME_TEXT_THEM, "main.text.them");
_cons_theme_prop(THEME_TEXT_HISTORY, "main.text.history");
_cons_theme_prop(console, THEME_ME, "me");
_cons_theme_prop(console, THEME_TEXT_ME, "main.text.me");
_cons_theme_prop(console, THEME_THEM, "them");
_cons_theme_prop(console, THEME_TEXT_THEM, "main.text.them");
_cons_theme_prop(console, THEME_TEXT_HISTORY, "main.text.history");
_cons_theme_prop(THEME_CHAT, "chat");
_cons_theme_prop(THEME_ONLINE, "online");
_cons_theme_prop(THEME_AWAY, "away");
_cons_theme_prop(THEME_XA, "xa");
_cons_theme_prop(THEME_DND, "dnd");
_cons_theme_prop(THEME_OFFLINE, "offline");
_cons_theme_prop(THEME_SUBSCRIBED, "subscribed");
_cons_theme_prop(THEME_UNSUBSCRIBED, "unsubscribed");
_cons_theme_prop(console, THEME_CHAT, "chat");
_cons_theme_prop(console, THEME_ONLINE, "online");
_cons_theme_prop(console, THEME_AWAY, "away");
_cons_theme_prop(console, THEME_XA, "xa");
_cons_theme_prop(console, THEME_DND, "dnd");
_cons_theme_prop(console, THEME_OFFLINE, "offline");
_cons_theme_prop(console, THEME_SUBSCRIBED, "subscribed");
_cons_theme_prop(console, THEME_UNSUBSCRIBED, "unsubscribed");
_cons_theme_prop(THEME_INCOMING, "incoming");
_cons_theme_prop(THEME_MENTION, "mention");
_cons_theme_prop(THEME_TRIGGER, "trigger");
_cons_theme_prop(THEME_TYPING, "typing");
_cons_theme_prop(THEME_GONE, "gone");
_cons_theme_prop(console, THEME_INCOMING, "incoming");
_cons_theme_prop(console, THEME_MENTION, "mention");
_cons_theme_prop(console, THEME_TRIGGER, "trigger");
_cons_theme_prop(console, THEME_TYPING, "typing");
_cons_theme_prop(console, THEME_GONE, "gone");
_cons_theme_prop(THEME_ROOMINFO, "roominfo");
_cons_theme_prop(THEME_ROOMMENTION, "roommention");
_cons_theme_prop(THEME_ROOMMENTION_TERM, "roommention.term");
_cons_theme_prop(THEME_ROOMTRIGGER, "roomtrigger");
_cons_theme_prop(THEME_ROOMTRIGGER_TERM, "roomtrigger.term");
_cons_theme_prop(console, THEME_ROOMINFO, "roominfo");
_cons_theme_prop(console, THEME_ROOMMENTION, "roommention");
_cons_theme_prop(console, THEME_ROOMMENTION_TERM, "roommention.term");
_cons_theme_prop(console, THEME_ROOMTRIGGER, "roomtrigger");
_cons_theme_prop(console, THEME_ROOMTRIGGER_TERM, "roomtrigger.term");
_cons_theme_prop(THEME_ROSTER_HEADER, "roster.header");
_cons_theme_prop(THEME_ROSTER_CHAT, "roster.chat");
_cons_theme_prop(THEME_ROSTER_ONLINE, "roster.online");
_cons_theme_prop(THEME_ROSTER_AWAY, "roster.away");
_cons_theme_prop(THEME_ROSTER_XA, "roster.xa");
_cons_theme_prop(THEME_ROSTER_DND, "roster.dnd");
_cons_theme_prop(THEME_ROSTER_OFFLINE, "roster.offline");
_cons_theme_prop(THEME_ROSTER_CHAT_ACTIVE, "roster.chat.active");
_cons_theme_prop(THEME_ROSTER_ONLINE_ACTIVE, "roster.online.active");
_cons_theme_prop(THEME_ROSTER_AWAY_ACTIVE, "roster.away.active");
_cons_theme_prop(THEME_ROSTER_XA_ACTIVE, "roster.xa.active");
_cons_theme_prop(THEME_ROSTER_DND_ACTIVE, "roster.dnd.active");
_cons_theme_prop(THEME_ROSTER_OFFLINE_ACTIVE, "roster.offline.active");
_cons_theme_prop(THEME_ROSTER_CHAT_UNREAD, "roster.chat.unread");
_cons_theme_prop(THEME_ROSTER_ONLINE_UNREAD, "roster.online.unread");
_cons_theme_prop(THEME_ROSTER_AWAY_UNREAD, "roster.away.unread");
_cons_theme_prop(THEME_ROSTER_XA_UNREAD, "roster.xa.unread");
_cons_theme_prop(THEME_ROSTER_DND_UNREAD, "roster.dnd.unread");
_cons_theme_prop(THEME_ROSTER_OFFLINE_UNREAD, "roster.offline.unread");
_cons_theme_prop(THEME_ROSTER_ROOM, "roster.room");
_cons_theme_prop(THEME_ROSTER_ROOM_UNREAD, "roster.room.unread");
_cons_theme_prop(THEME_ROSTER_ROOM_TRIGGER, "roster.room.trigger");
_cons_theme_prop(THEME_ROSTER_ROOM_MENTION, "roster.room.mention");
_cons_theme_prop(console, THEME_ROSTER_HEADER, "roster.header");
_cons_theme_prop(console, THEME_ROSTER_CHAT, "roster.chat");
_cons_theme_prop(console, THEME_ROSTER_ONLINE, "roster.online");
_cons_theme_prop(console, THEME_ROSTER_AWAY, "roster.away");
_cons_theme_prop(console, THEME_ROSTER_XA, "roster.xa");
_cons_theme_prop(console, THEME_ROSTER_DND, "roster.dnd");
_cons_theme_prop(console, THEME_ROSTER_OFFLINE, "roster.offline");
_cons_theme_prop(console, THEME_ROSTER_CHAT_ACTIVE, "roster.chat.active");
_cons_theme_prop(console, THEME_ROSTER_ONLINE_ACTIVE, "roster.online.active");
_cons_theme_prop(console, THEME_ROSTER_AWAY_ACTIVE, "roster.away.active");
_cons_theme_prop(console, THEME_ROSTER_XA_ACTIVE, "roster.xa.active");
_cons_theme_prop(console, THEME_ROSTER_DND_ACTIVE, "roster.dnd.active");
_cons_theme_prop(console, THEME_ROSTER_OFFLINE_ACTIVE, "roster.offline.active");
_cons_theme_prop(console, THEME_ROSTER_CHAT_UNREAD, "roster.chat.unread");
_cons_theme_prop(console, THEME_ROSTER_ONLINE_UNREAD, "roster.online.unread");
_cons_theme_prop(console, THEME_ROSTER_AWAY_UNREAD, "roster.away.unread");
_cons_theme_prop(console, THEME_ROSTER_XA_UNREAD, "roster.xa.unread");
_cons_theme_prop(console, THEME_ROSTER_DND_UNREAD, "roster.dnd.unread");
_cons_theme_prop(console, THEME_ROSTER_OFFLINE_UNREAD, "roster.offline.unread");
_cons_theme_prop(console, THEME_ROSTER_ROOM, "roster.room");
_cons_theme_prop(console, THEME_ROSTER_ROOM_UNREAD, "roster.room.unread");
_cons_theme_prop(console, THEME_ROSTER_ROOM_TRIGGER, "roster.room.trigger");
_cons_theme_prop(console, THEME_ROSTER_ROOM_MENTION, "roster.room.mention");
_cons_theme_prop(THEME_OCCUPANTS_HEADER, "occupants.header");
_cons_theme_prop(console, THEME_OCCUPANTS_HEADER, "occupants.header");
_cons_theme_prop(THEME_RECEIPT_SENT, "receipt.sent");
_cons_theme_prop(console, THEME_RECEIPT_SENT, "receipt.sent");
_cons_theme_prop(THEME_INPUT_TEXT, "input.text");
_cons_theme_prop(console, THEME_INPUT_TEXT, "input.text");
_cons_theme_prop(console, THEME_INPUT_MISSPELLED, "input.misspelled");
cons_show("");
}
@@ -2786,7 +2737,7 @@ cons_show_bookmarks_ignore(gchar** list, gsize len)
cons_show("");
cons_show("Ignored bookmarks:");
for (int i = 0; i < len; i++) {
for (gsize i = 0; i < len; i++) {
win_print(console, THEME_DEFAULT, "-", " %s", list[i]);
win_newline(console);
}
@@ -2839,13 +2790,15 @@ cons_strophe_setting(void)
}
}
cons_show("XEP-0198 Stream-Management : %s", sm_setting);
cons_show("libstrophe Verbosity : %s", prefs_get_string(PREF_STROPHE_VERBOSITY));
auto_gchar gchar* verbosity = prefs_get_string(PREF_STROPHE_VERBOSITY);
cons_show("libstrophe Verbosity : %s", verbosity);
}
void
cons_privacy_setting(void)
{
cons_show("Database logging : %s", prefs_get_string(PREF_DBLOG));
auto_gchar gchar* dblog = prefs_get_string(PREF_DBLOG);
cons_show("Database logging : %s", dblog);
if (prefs_get_boolean(PREF_HISTORY)) {
cons_show("Chat history (/history) : ON");

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"
@@ -146,6 +120,11 @@ ui_sigwinch_handler(int sig)
void
ui_update(void)
{
// UI is suspended
if (isendwin()) {
return;
}
ProfWin* current = wins_get_current();
if (current->layout->paged == 0) {
win_move_to_end(current);
@@ -187,7 +166,7 @@ ui_get_idle_time(void)
// if no libxss or xss idle time failed, use profanity idle time
#endif
gdouble seconds_elapsed = g_timer_elapsed(ui_idle_time, NULL);
unsigned long ms_elapsed = seconds_elapsed * 1000.0;
unsigned long ms_elapsed = (unsigned long)(seconds_elapsed * 1000.0);
return ms_elapsed;
}
@@ -197,9 +176,28 @@ ui_reset_idle_time(void)
g_timer_start(ui_idle_time);
}
void
ui_suspend(void)
{
inp_suspend();
endwin();
}
void
ui_resume(void)
{
refresh();
inp_resume();
}
void
ui_resize(void)
{
// UI is suspended
if (isendwin()) {
return;
}
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
erase();
@@ -218,6 +216,11 @@ ui_resize(void)
void
ui_redraw(void)
{
// UI is suspended
if (isendwin()) {
return;
}
title_bar_resize();
wins_resize_all();
status_bar_resize();
@@ -361,7 +364,7 @@ void
ui_handle_login_account_success(ProfAccount* account, gboolean secured)
{
if (account->theme) {
if (theme_load(account->theme, false)) {
if (theme_load(account->theme, FALSE)) {
ui_load_colours();
if (prefs_get_boolean(PREF_ROSTER)) {
ui_show_roster();

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
*/
#define _XOPEN_SOURCE_EXTENDED
@@ -76,6 +50,7 @@
#include "xmpp/roster_list.h"
#include "xmpp/chat_state.h"
#include "tools/editor.h"
#include "tools/spellcheck.h"
static WINDOW* inp_win;
static int pad_start = 0;
@@ -90,6 +65,7 @@ static fd_set fds;
static int r;
static char* inp_line = NULL;
static gboolean get_password = FALSE;
static gboolean is_suspended = FALSE;
static void _inp_win_update_virtual(void);
static int _inp_edited(const wint_t ch);
@@ -204,6 +180,12 @@ _inp_slashguard_check(void)
char*
inp_readline(void)
{
// UI is suspended
if (is_suspended || isendwin()) {
g_usleep(100000); // 100ms
return NULL;
}
p_rl_timeout.tv_sec = inp_timeout / 1000;
p_rl_timeout.tv_usec = inp_timeout % 1000 * 1000;
FD_ZERO(&fds);
@@ -304,6 +286,22 @@ inp_close(void)
discard = NULL;
}
void
inp_suspend(void)
{
is_suspended = TRUE;
rl_callback_handler_remove();
rl_deprep_terminal();
}
void
inp_resume(void)
{
is_suspended = FALSE;
rl_callback_handler_install(NULL, _inp_rl_linehandler);
rl_prep_terminal(0);
}
char*
inp_get_line(void)
{
@@ -380,12 +378,17 @@ _inp_write(char* line, int offset)
getyx(inp_win, y, x);
col += x;
gboolean do_spell = prefs_get_boolean(PREF_SPELLCHECK_ENABLE) && (line[0] != '/');
for (size_t i = 0; line[i] != '\0'; i++) {
char* c = &line[i];
char retc[PROF_MB_CUR_MAX] = { 0 };
size_t ch_len = mbrlen(c, MB_CUR_MAX, NULL);
if ((ch_len == (size_t)-2) || (ch_len == (size_t)-1)) {
// ch_len == 0 means mbrlen consumed the null wide character;
// skipping it here keeps `i += ch_len - 1` below from
// underflowing to SIZE_MAX.
if ((ch_len == (size_t)-2) || (ch_len == (size_t)-1) || ch_len == 0) {
waddch(inp_win, ' ');
continue;
}
@@ -393,7 +396,7 @@ _inp_write(char* line, int offset)
if (line[i] == '\n') {
c = retc;
ch_len = wctomb(retc, L'\u23ce'); /* return symbol */
if (ch_len == -1) { /* not representable */
if (ch_len == (size_t)-1) { /* not representable */
retc[0] = '\\';
ch_len = 1;
}
@@ -401,7 +404,55 @@ _inp_write(char* line, int offset)
i += ch_len - 1;
}
waddnstr(inp_win, c, ch_len);
if (do_spell) {
gunichar uc = g_utf8_get_char(c);
if (g_unichar_isalnum(uc) || uc == '\'') {
// start of a word
size_t start = i - (ch_len - 1);
size_t end = start + ch_len;
while (line[end] != '\0') {
size_t next_ch_len = mbrlen(&line[end], MB_CUR_MAX, NULL);
// ch_len == 0 means embedded NUL — stop, otherwise
// `end += next_ch_len` loops forever.
if (next_ch_len == (size_t)-2 || next_ch_len == (size_t)-1 || next_ch_len == 0)
break;
gunichar next_uc = g_utf8_get_char(&line[end]);
if (!g_unichar_isalnum(next_uc) && next_uc != '\'')
break;
end += next_ch_len;
}
auto_gchar gchar* word = g_strndup(&line[start], end - start);
gboolean misspelled = spellcheck_is_misspelled(word);
if (misspelled) {
wattron(inp_win, theme_attrs(THEME_INPUT_MISSPELLED));
}
// add the word
size_t word_pos = start;
while (word_pos < end) {
size_t cur_ch_len = mbrlen(&line[word_pos], MB_CUR_MAX, NULL);
// Defensive: invalid or zero-length step would loop
// forever; advance one byte and continue.
if (cur_ch_len == (size_t)-2 || cur_ch_len == (size_t)-1 || cur_ch_len == 0) {
word_pos++;
continue;
}
waddnstr(inp_win, &line[word_pos], (int)cur_ch_len);
word_pos += cur_ch_len;
}
if (misspelled) {
wattroff(inp_win, theme_attrs(THEME_INPUT_MISSPELLED));
}
i = end - 1;
continue;
}
}
waddnstr(inp_win, c, (int)ch_len);
}
wmove(inp_win, 0, col);
@@ -454,11 +505,13 @@ _inp_offset_to_col(char* str, int offset)
while (i < offset && str[i] != '\0') {
gunichar uni = g_utf8_get_char(&str[i]);
size_t ch_len = mbrlen(&str[i], MB_CUR_MAX, NULL);
if ((ch_len == (size_t)-2) || (ch_len == (size_t)-1)) {
// ch_len == 0 (embedded NUL) would freeze the loop on the same
// byte; treat it like an invalid step.
if ((ch_len == (size_t)-2) || (ch_len == (size_t)-1) || ch_len == 0) {
i++;
continue;
}
i += ch_len;
i += (int)ch_len;
col++;
if (g_unichar_iswide(uni)) {
col++;
@@ -1005,6 +1058,16 @@ _inp_rl_down_arrow_handler(int count, int key)
return 0;
}
static void
_editor_finished_cb(gchar* message, void* user_data)
{
if (message) {
rl_replace_line(message, 0);
rl_point = rl_end;
rl_forced_update_display();
}
}
static int
_inp_rl_send_to_editor(int count, int key)
{
@@ -1012,9 +1075,7 @@ _inp_rl_send_to_editor(int count, int key)
return 0;
}
auto_gchar gchar* message = NULL;
get_message_from_editor_async(rl_line_buffer);
launch_editor(rl_line_buffer, _editor_finished_cb, NULL);
return 0;
}

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 UI_INPUTWIN_H
@@ -44,6 +18,8 @@ void create_input_window(void);
void inp_close(void);
void inp_win_resize(void);
void inp_put_back(void);
void inp_suspend(void);
void inp_resume(void);
char* inp_get_password(void);
char* inp_get_line(void);
void inp_set_line(const char* const new_line);

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"
@@ -408,7 +382,7 @@ _mucwin_print_mention(ProfWin* window, const char* const message, const char* co
auto_gchar gchar* mynick_str = g_utf8_substring(message, pos, pos + mynick_len);
win_append_highlight(window, THEME_ROOMMENTION_TERM, "%s", mynick_str);
last_pos = pos + mynick_len;
last_pos = pos + (int)mynick_len;
curr = g_slist_next(curr);
}
@@ -426,8 +400,8 @@ _mucwin_print_mention(ProfWin* window, const char* const message, const char* co
gint
_cmp_trigger_weight(gconstpointer a, gconstpointer b)
{
int alen = strlen((char*)a);
int blen = strlen((char*)b);
size_t alen = strlen((char*)a);
size_t blen = strlen((char*)b);
if (alen > blen)
return -1;
@@ -464,10 +438,10 @@ _mucwin_print_triggers(ProfWin* window, const char* const message, GList* trigge
}
// found, replace vars if earlier than previous
int trigger_pos = trigger_ptr - message_lower;
int trigger_pos = (int)(trigger_ptr - message_lower);
if (first_trigger_pos == -1 || trigger_pos < first_trigger_pos) {
first_trigger_pos = trigger_pos;
first_trigger_len = strlen(trigger_lower);
first_trigger_len = (int)strlen(trigger_lower);
}
curr = g_list_next(curr);
@@ -497,7 +471,7 @@ _mucwin_print_triggers(ProfWin* window, const char* const message, GList* trigge
}
trigger_section[i] = '\0';
if (first_trigger_pos + first_trigger_len < strlen(message)) {
if (first_trigger_pos + first_trigger_len < (int)strlen(message)) {
win_append_highlight(window, THEME_ROOMTRIGGER_TERM, "%s", trigger_section);
_mucwin_print_triggers(window, &message[first_trigger_pos + first_trigger_len], triggers);
} else {

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"
@@ -52,6 +26,9 @@
#include "config/preferences.h"
#include "ui/ui.h"
#include "ui/window_list.h"
#ifdef HAVE_GTK
#include "ui/tray.h"
#endif
#include "xmpp/xmpp.h"
#include "xmpp/muc.h"
@@ -80,6 +57,11 @@ _notifier_uninit(void)
static void
_notify(const char* const message, int timeout, const char* const category)
{
#ifdef HAVE_GTK
if (!tray_gtk_ready()) {
return;
}
#endif
log_debug("Attempting notification: %s", message);
if (notify_is_initted()) {
log_debug("Reinitialising libnotify");
@@ -97,14 +79,13 @@ _notify(const char* const message, int timeout, const char* const category)
notify_notification_set_category(notification, category);
notify_notification_set_urgency(notification, NOTIFY_URGENCY_NORMAL);
GError* error = NULL;
auto_gerror GError* error = NULL;
gboolean notify_success = notify_notification_show(notification, &error);
if (!notify_success) {
log_error("Error sending desktop notification:");
log_error(" -> Message : %s", message);
log_error(" -> Error : %s", error->message);
g_error_free(error);
log_error(" -> Error : %s", PROF_GERROR_MESSAGE(error));
} else {
log_debug("Notification sent.");
}

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"

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) 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"
@@ -578,7 +552,7 @@ _rosterwin_resources(ProfLayoutSplit* layout, PContact contact, int current_inde
g_string_append(msg, " ");
this_indent--;
}
auto_char char* ch = prefs_get_roster_resource_char();
auto_gchar gchar* ch = prefs_get_roster_resource_char();
if (ch) {
g_string_append_printf(msg, "%s", ch);
}

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
*/
int screen_titlebar_row(void);

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"
@@ -74,25 +48,27 @@ typedef struct _status_bar_t
char* prompt;
char* fulljid;
GHashTable* tabs;
int current_tab;
guint current_tab;
} StatusBar;
static GTimeZone* tz;
static StatusBar* statusbar;
static WINDOW* statusbar_win;
void _get_range_bounds(int* start, int* end, gboolean is_static);
static int _status_bar_draw_time(int pos);
static int _status_bar_draw_maintext(int pos);
static int _status_bar_draw_dbbackend(int pos);
static int _status_bar_draw_bracket(gboolean current, int pos, const char* ch);
static int _status_bar_draw_extended_tabs(int pos, gboolean prefix, int start, int end, gboolean is_static);
static int _status_bar_draw_tab(StatusBarTab* tab, int pos, int num, gboolean include_brackets);
static int _status_bar_draw_tabs(int pos);
#define CONSOLE_TAB_ID 10 // Console tab ID in status bar hash table
void _get_range_bounds(guint* start, guint* end, gboolean is_static);
static guint _status_bar_draw_time(guint pos);
static guint _status_bar_draw_maintext(guint pos);
static guint _status_bar_draw_dbbackend(guint pos);
static guint _status_bar_draw_bracket(gboolean current, guint pos, const char* ch);
static guint _status_bar_draw_extended_tabs(guint pos, gboolean prefix, guint start, guint end, gboolean is_static);
static guint _status_bar_draw_tab(StatusBarTab* tab, guint pos, guint num, gboolean include_brackets);
static guint _status_bar_draw_tabs(guint pos);
static void _destroy_tab(StatusBarTab* tab);
static int _tabs_width(int start, int end);
static unsigned int _count_digits(int number);
static unsigned int _count_digits_in_range(int start, int end);
static guint _tabs_width(guint start, guint end);
static guint _count_digits(guint number);
static guint _count_digits_in_range(guint start, guint end);
static char* _display_name(StatusBarTab* tab);
static gboolean _tabmode_is_actlist(void);
@@ -101,12 +77,12 @@ status_bar_init(void)
{
tz = g_time_zone_new_local();
statusbar = malloc(sizeof(StatusBar));
statusbar = g_new0(StatusBar, 1);
statusbar->time = NULL;
statusbar->prompt = NULL;
statusbar->fulljid = NULL;
statusbar->tabs = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)_destroy_tab);
StatusBarTab* console = calloc(1, sizeof(StatusBarTab));
StatusBarTab* console = g_new0(StatusBarTab, 1);
console->window_type = WIN_CONSOLE;
console->identifier = strdup("console");
console->display_name = NULL;
@@ -180,10 +156,10 @@ status_bar_set_all_inactive(void)
}
void
status_bar_current(int i)
status_bar_current(guint i)
{
if (i == 0) {
statusbar->current_tab = 10;
statusbar->current_tab = CONSOLE_TAB_ID;
} else {
statusbar->current_tab = i;
}
@@ -194,12 +170,7 @@ status_bar_current(int i)
void
status_bar_inactive(const int win)
{
int true_win = win;
if (true_win == 0) {
true_win = 10;
}
g_hash_table_remove(statusbar->tabs, GINT_TO_POINTER(true_win));
g_hash_table_remove(statusbar->tabs, GINT_TO_POINTER((win == 0) ? CONSOLE_TAB_ID : win));
status_bar_draw();
}
@@ -207,9 +178,7 @@ status_bar_inactive(const int win)
void
_create_tab(const int win, win_type_t wintype, char* identifier, gboolean highlight)
{
int true_win = win == 0 ? 10 : win;
StatusBarTab* tab = malloc(sizeof(StatusBarTab));
StatusBarTab* tab = g_new0(StatusBarTab, 1);
tab->identifier = strdup(identifier);
tab->highlight = highlight;
tab->window_type = wintype;
@@ -238,7 +207,7 @@ _create_tab(const int win, win_type_t wintype, char* identifier, gboolean highli
}
}
g_hash_table_replace(statusbar->tabs, GINT_TO_POINTER(true_win), tab);
g_hash_table_replace(statusbar->tabs, GINT_TO_POINTER((win == 0) ? CONSOLE_TAB_ID : win), tab);
status_bar_draw();
}
@@ -310,8 +279,8 @@ status_bar_draw(void)
werase(statusbar_win);
wbkgd(statusbar_win, theme_attrs(THEME_STATUS_TEXT));
gint max_tabs = prefs_get_statusbartabs();
int pos = 1;
guint max_tabs = prefs_get_statusbartabs();
guint pos = 1;
pos = _status_bar_draw_time(pos);
pos = _status_bar_draw_maintext(pos);
@@ -323,24 +292,27 @@ status_bar_draw(void)
inp_put_back();
}
static int
_status_bar_draw_tabs(int pos)
static guint
_status_bar_draw_tabs(guint pos)
{
auto_gchar gchar* tabmode = prefs_get_string(PREF_STATUSBAR_TABMODE);
if (g_strcmp0(tabmode, "actlist") != 0) {
int start, end;
guint start, end;
gboolean is_static = g_strcmp0(tabmode, "dynamic") != 0;
_get_range_bounds(&start, &end, is_static);
pos = getmaxx(stdscr) - _tabs_width(start, end);
if (pos < 0) {
guint tabs_w = _tabs_width(start, end);
int max_x = getmaxx(stdscr);
if (max_x > 0 && (guint)max_x > tabs_w) {
pos = (guint)max_x - tabs_w;
} else {
pos = 0;
}
pos = _status_bar_draw_extended_tabs(pos, TRUE, start, end, is_static);
for (int i = start; i <= end; i++) {
for (guint i = start; i <= end; i++) {
StatusBarTab* tab = g_hash_table_lookup(statusbar->tabs, GINT_TO_POINTER(i));
if (tab) {
pos = _status_bar_draw_tab(tab, pos, i, TRUE);
@@ -388,9 +360,9 @@ _status_bar_draw_tabs(int pos)
static gboolean
_has_new_msgs_beyond_range_on_side(gboolean left_side, int display_tabs_start, int display_tabs_end)
{
gint max_tabs = prefs_get_statusbartabs();
guint max_tabs = prefs_get_statusbartabs();
int tabs_count = g_hash_table_size(statusbar->tabs);
if (tabs_count <= max_tabs) {
if ((guint)tabs_count <= max_tabs) {
return FALSE;
}
@@ -407,10 +379,10 @@ _has_new_msgs_beyond_range_on_side(gboolean left_side, int display_tabs_start, i
return FALSE;
}
static int
_status_bar_draw_extended_tabs(int pos, gboolean prefix, int start, int end, gboolean is_static)
static guint
_status_bar_draw_extended_tabs(guint pos, gboolean prefix, guint start, guint end, gboolean is_static)
{
gint max_tabs = prefs_get_statusbartabs();
guint max_tabs = prefs_get_statusbartabs();
if (max_tabs == 0) {
return pos;
}
@@ -423,7 +395,9 @@ _status_bar_draw_extended_tabs(int pos, gboolean prefix, int start, int end, gbo
if (prefix && start < 2) {
return pos;
}
if (!prefix && end > opened_tabs - 1) {
// Guard against underflow when opened_tabs == 0 (reachable if the
// earlier `opened_tabs <= max_tabs` early-return no longer holds).
if (!prefix && end >= opened_tabs) {
return pos;
}
gboolean is_current = is_static && statusbar->current_tab > max_tabs;
@@ -449,8 +423,8 @@ _status_bar_draw_extended_tabs(int pos, gboolean prefix, int start, int end, gbo
return pos;
}
static int
_status_bar_draw_tab(StatusBarTab* tab, int pos, int num, gboolean include_brackets)
static guint
_status_bar_draw_tab(StatusBarTab* tab, guint pos, guint num, gboolean include_brackets)
{
gboolean is_current = num == statusbar->current_tab;
@@ -498,8 +472,8 @@ _status_bar_draw_tab(StatusBarTab* tab, int pos, int num, gboolean include_brack
return pos;
}
static int
_status_bar_draw_bracket(gboolean current, int pos, const char* ch)
static guint
_status_bar_draw_bracket(gboolean current, guint pos, const char* ch)
{
int bracket_attrs = theme_attrs(THEME_STATUS_BRACKET);
wattron(statusbar_win, bracket_attrs);
@@ -514,8 +488,8 @@ _status_bar_draw_bracket(gboolean current, int pos, const char* ch)
return pos;
}
static int
_status_bar_draw_time(int pos)
static guint
_status_bar_draw_time(guint pos)
{
auto_gchar gchar* time_pref = prefs_get_string(PREF_TIME_STATUSBAR);
if (g_strcmp0(time_pref, "off") == 0) {
@@ -535,7 +509,7 @@ _status_bar_draw_time(int pos)
int bracket_attrs = theme_attrs(THEME_STATUS_BRACKET);
int time_attrs = theme_attrs(THEME_STATUS_TIME);
size_t len = strlen(statusbar->time);
guint len = (guint)strlen(statusbar->time);
wattron(statusbar_win, bracket_attrs);
mvwaddch(statusbar_win, 0, pos, '[');
pos++;
@@ -559,8 +533,8 @@ _tabmode_is_actlist(void)
return g_strcmp0(tabmode, "actlist") == 0;
}
static int
_status_bar_draw_maintext(int pos)
static guint
_status_bar_draw_maintext(guint pos)
{
const char* maintext = NULL;
auto_jid Jid* jidp = NULL;
@@ -606,8 +580,8 @@ _status_bar_draw_maintext(int pos)
return pos;
}
static int
_status_bar_draw_dbbackend(int pos)
static guint
_status_bar_draw_dbbackend(guint pos)
{
if (!prefs_get_boolean(PREF_STATUSBAR_SHOW_DBBACKEND))
return pos;
@@ -633,20 +607,20 @@ _destroy_tab(StatusBarTab* tab)
}
}
static int
_tabs_width(int start, int end)
static guint
_tabs_width(guint start, guint end)
{
gboolean show_number = prefs_get_boolean(PREF_STATUSBAR_SHOW_NUMBER);
gboolean show_name = prefs_get_boolean(PREF_STATUSBAR_SHOW_NAME);
gboolean show_read = prefs_get_boolean(PREF_STATUSBAR_SHOW_READ);
gint max_tabs = prefs_get_statusbartabs();
guint max_tabs = prefs_get_statusbartabs();
guint opened_tabs = g_hash_table_size(statusbar->tabs);
int width = start < 2 ? 1 : 4;
width += end > opened_tabs - 1 ? 0 : 3;
width += (end < opened_tabs) ? 3 : 0;
if (show_name && show_number) {
for (int i = start; i <= end; i++) {
for (guint i = start; i <= end; i++) {
StatusBarTab* tab = g_hash_table_lookup(statusbar->tabs, GINT_TO_POINTER(i));
if (tab) {
gboolean is_current = i == statusbar->current_tab;
@@ -663,7 +637,7 @@ _tabs_width(int start, int end)
}
if (show_name && !show_number) {
for (int i = start; i <= end; i++) {
for (guint i = start; i <= end; i++) {
StatusBarTab* tab = g_hash_table_lookup(statusbar->tabs, GINT_TO_POINTER(i));
if (tab) {
gboolean is_current = i == statusbar->current_tab;
@@ -739,7 +713,7 @@ _display_name(StatusBarTab* tab)
}
void
_get_range_bounds(int* start, int* end, gboolean is_static)
_get_range_bounds(guint* start, guint* end, gboolean is_static)
{
int current_tab = statusbar->current_tab;
gint display_range = prefs_get_statusbartabs();
@@ -762,12 +736,10 @@ _get_range_bounds(int* start, int* end, gboolean is_static)
}
// Counts amount of digits in a number
static unsigned int
_count_digits(int number)
static guint
_count_digits(guint number)
{
unsigned int digits_count = 0;
if (number < 0)
number = -number;
guint digits_count = 0;
do {
number /= 10;
@@ -779,12 +751,11 @@ _count_digits(int number)
// Counts the total number of digits in a range of numbers, inclusive.
// Example: _count_digits_in_range(2, 3) returns 2, _count_digits_in_range(2, 922) returns 2657
static unsigned int
_count_digits_in_range(int start, int end)
static guint
_count_digits_in_range(guint start, guint end)
{
int total_digits = 0;
for (int i = start; i <= end; i++) {
guint total_digits = 0;
for (guint i = start; i <= end; i++) {
total_digits += _count_digits(i);
}

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 UI_STATUSBAR_H
@@ -44,6 +18,6 @@ void status_bar_set_prompt(const char* const prompt);
void status_bar_clear_prompt(void);
void status_bar_set_fulljid(const char* const fulljid);
void status_bar_clear_fulljid(void);
void status_bar_current(int i);
void status_bar_current(guint i);
#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) 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 <stdlib.h>
@@ -50,6 +24,9 @@
#include "ui/window_list.h"
#include "ui/window.h"
#include "ui/screen.h"
#ifdef HAVE_OMEMO
#include "omemo/omemo.h"
#endif
#include "xmpp/roster_list.h"
#include "xmpp/chat_session.h"
@@ -69,6 +46,24 @@ static void _show_privacy(ProfChatWin* chatwin);
static void _show_muc_privacy(ProfMucWin* mucwin);
static void _show_scrolled(ProfWin* current);
static void _show_attention(ProfWin* current, gboolean attention);
static void _show_trust_indicator(gboolean trusted, int bracket_attrs, int trusted_attrs, int untrusted_attrs);
static inline void
_wprintw_withattr(WINDOW* w, const char* text, int attrs)
{
wattron(w, attrs);
wprintw(w, "%s", text);
wattroff(w, attrs);
}
static void
_show_trust_indicator(gboolean trusted, int bracket_attrs, int trusted_attrs, int untrusted_attrs)
{
wprintw(win, " ");
_wprintw_withattr(win, "[", bracket_attrs);
_wprintw_withattr(win, trusted ? "trusted" : "untrusted", trusted ? trusted_attrs : untrusted_attrs);
_wprintw_withattr(win, "]", bracket_attrs);
}
void
create_title_bar(void)
@@ -230,7 +225,7 @@ _title_bar_draw(void)
auto_gchar gchar* title = win_get_title(current);
mvwprintw(win, 0, 0, " %s", title);
pos = strlen(title) + 1;
pos = (int)strlen(title) + 1;
// presence is written from the right side
// calculate it first so we have a maxposition
@@ -443,6 +438,10 @@ _show_muc_privacy(ProfMucWin* mucwin)
{
int bracket_attrs = theme_attrs(THEME_TITLE_BRACKET);
int encrypted_attrs = theme_attrs(THEME_TITLE_ENCRYPTED);
#ifdef HAVE_OMEMO
int trusted_attrs = theme_attrs(THEME_TITLE_TRUSTED);
int untrusted_attrs = theme_attrs(THEME_TITLE_UNTRUSTED);
#endif
if (mucwin->is_omemo) {
wprintw(win, " ");
@@ -456,6 +455,10 @@ _show_muc_privacy(ProfMucWin* mucwin)
wprintw(win, "]");
wattroff(win, bracket_attrs);
#ifdef HAVE_OMEMO
_show_trust_indicator(mucwin->omemo_trusted, bracket_attrs, trusted_attrs, untrusted_attrs);
#endif
return;
}
@@ -522,29 +525,7 @@ _show_privacy(ProfChatWin* chatwin)
wattron(win, bracket_attrs);
wprintw(win, "]");
wattroff(win, bracket_attrs);
if (chatwin->otr_is_trusted) {
wprintw(win, " ");
wattron(win, bracket_attrs);
wprintw(win, "[");
wattroff(win, bracket_attrs);
wattron(win, trusted_attrs);
wprintw(win, "trusted");
wattroff(win, trusted_attrs);
wattron(win, bracket_attrs);
wprintw(win, "]");
wattroff(win, bracket_attrs);
} else {
wprintw(win, " ");
wattron(win, bracket_attrs);
wprintw(win, "[");
wattroff(win, bracket_attrs);
wattron(win, untrusted_attrs);
wprintw(win, "untrusted");
wattroff(win, untrusted_attrs);
wattron(win, bracket_attrs);
wprintw(win, "]");
wattroff(win, bracket_attrs);
}
_show_trust_indicator(chatwin->otr_is_trusted, bracket_attrs, trusted_attrs, untrusted_attrs);
return;
}
@@ -585,6 +566,10 @@ _show_privacy(ProfChatWin* chatwin)
wprintw(win, "]");
wattroff(win, bracket_attrs);
#ifdef HAVE_OMEMO
_show_trust_indicator(chatwin->omemo_trusted, bracket_attrs, trusted_attrs, untrusted_attrs);
#endif
return;
}
@@ -616,7 +601,7 @@ _show_contact_presence(ProfChatWin* chatwin, int pos, int maxpos)
}
if (resource && prefs_get_boolean(PREF_RESOURCE_TITLE)) {
int needed = strlen(resource) + 1;
int needed = (int)strlen(resource) + 1;
if (pos + needed < maxpos) {
wprintw(win, "/");
wprintw(win, "%s", resource);

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 UI_TITLEBAR_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"
@@ -47,6 +21,11 @@
#include "ui/tray.h"
#include "ui/window_list.h"
#if defined(GDK_WINDOWING_X11) && defined(HAVE_XEXITHANDLER)
#include <gdk/gdkx.h>
#include <X11/Xlib.h>
#endif
static gboolean gtk_ready = FALSE;
static GtkStatusIcon* prof_tray = NULL;
static GString* icon_filename = NULL;
@@ -55,6 +34,21 @@ static gint unread_messages;
static gboolean shutting_down;
static guint timer;
#if defined(GDK_WINDOWING_X11) && defined(HAVE_XEXITHANDLER)
static void
_x_io_error_handler(Display* display, void* user_data)
{
log_warning("Error: X Server connection lost.");
gtk_ready = FALSE;
}
static int
_x_io_handler(Display* display)
{
return 0;
}
#endif
/*
* Get icons from installation share folder or (if defined) .locale user's folder
*
@@ -81,7 +75,7 @@ _get_icons(void)
auto_gchar gchar* icons_dir_s = files_get_config_path(DIR_ICONS);
icons_dir = g_string_new(icons_dir_s);
GError* err = NULL;
auto_gerror GError* err = NULL;
if (!g_file_test(icons_dir->str, G_FILE_TEST_IS_DIR)) {
return;
@@ -109,8 +103,7 @@ _get_icons(void)
}
g_string_free(name, TRUE);
} else {
log_error("Unable to open dir: %s", err->message);
g_error_free(err);
log_error("Unable to open dir: %s", PROF_GERROR_MESSAGE(err));
}
g_dir_close(dir);
g_string_free(icons_dir, TRUE);
@@ -125,7 +118,7 @@ _get_icons(void)
gboolean
_tray_change_icon(gpointer data)
{
if (shutting_down) {
if (shutting_down || !gtk_ready) {
return FALSE;
}
@@ -178,6 +171,14 @@ tray_init(void)
return;
}
#if defined(GDK_WINDOWING_X11) && defined(HAVE_XEXITHANDLER)
GdkDisplay* display = gdk_display_get_default();
if (GDK_IS_X11_DISPLAY(display)) {
XSetIOErrorExitHandler(GDK_DISPLAY_XDISPLAY(display), _x_io_error_handler, NULL);
XSetIOErrorHandler(_x_io_handler);
}
#endif
if (prefs_get_boolean(PREF_TRAY)) {
log_debug("Building GTK icon");
tray_enable();
@@ -194,9 +195,18 @@ tray_update(void)
}
}
gboolean
tray_gtk_ready(void)
{
return gtk_ready;
}
void
tray_set_timer(int interval)
{
if (!gtk_ready) {
return;
}
if (timer) {
g_source_remove(timer);
}
@@ -213,6 +223,9 @@ tray_set_timer(int interval)
void
tray_enable(void)
{
if (!gtk_ready) {
return;
}
prof_tray = gtk_status_icon_new_from_file(icon_filename->str);
shutting_down = FALSE;
_tray_change_icon(NULL);

View File

@@ -4,41 +4,17 @@
*
* 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 UI_TRAY_H
#define UI_TRAY_H
#ifdef HAVE_GTK
#include <glib.h>
void tray_init(void);
void tray_update(void);
gboolean tray_gtk_ready(void);
void tray_enable(void);
void tray_disable(void);

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 UI_UI_H
@@ -52,15 +26,19 @@
#include "otr/otr.h"
#endif
#define NO_ME 1
#define NO_DATE 2
#define NO_EOL 4
#define NO_COLOUR_FROM 8
#define NO_COLOUR_DATE 16
#define UNTRUSTED 32
#define NO_ME 1
#define NO_DATE 2
#define NO_EOL 4
#define NO_COLOUR_FROM 8
#define NO_COLOUR_DATE 16
#define UNTRUSTED 32
#define ENTRY_COMPLETED 64
#define ENTRY_ERROR 128
// core UI
void ui_init(void);
void ui_suspend(void);
void ui_resume(void);
void ui_load_colours(void);
void ui_update(void);
void ui_redraw(void);
@@ -273,7 +251,7 @@ void cons_show_contacts(GSList* list);
void cons_show_roster(GSList* list);
void cons_show_roster_group(const char* const group, GSList* list);
void cons_show_wins(gboolean unread);
void cons_show_wins_attention();
void cons_show_wins_attention(void);
gchar* cons_get_string(ProfConsoleWin* conswin);
void cons_show_status(const char* const barejid);
void cons_show_info(PContact pcontact);
@@ -313,6 +291,7 @@ void cons_console_setting(void);
void cons_flash_setting(void);
void cons_tray_setting(void);
void cons_splash_setting(void);
void cons_spellcheck_setting(void);
void cons_titlebar_setting(void);
void cons_vercheck_setting(void);
void cons_occupants_setting(void);

View File

@@ -4,33 +4,7 @@
*
* Copyright (C) 2022 Marouane L. <techmetx11@disroot.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.
*
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
*/
#include "ui/ui.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 UI_WIN_TYPES_H
@@ -162,6 +136,7 @@ typedef struct prof_win_t
ProfLayout* layout;
Autocomplete urls_ac;
Autocomplete quotes_ac;
GHashTable* warned_jids;
} ProfWin;
typedef struct prof_console_win_t
@@ -180,6 +155,7 @@ typedef struct prof_chat_win_t
gboolean pgp_send;
gboolean pgp_recv;
gboolean is_omemo;
gboolean omemo_trusted;
gboolean is_ox; // XEP-0373: OpenPGP for XMPP
char* resource_override;
gboolean history_shown;
@@ -205,6 +181,7 @@ typedef struct prof_muc_win_t
gboolean showjid;
gboolean showoffline;
gboolean is_omemo;
gboolean omemo_trusted;
unsigned long memcheck;
char* enctext;
char* message_char;

View File

@@ -3,41 +3,18 @@
* 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 "database.h"
#include "ui/win_types.h"
#include "ui/window_list.h"
#ifdef HAVE_OMEMO
#include "omemo/omemo.h"
#endif
#include <stdlib.h>
#include <string.h>
@@ -65,6 +42,31 @@
#include "xmpp/roster_list.h"
#include "ai/ai_client.h"
static const int PAD_MIN_HEIGHT = 100;
static const int PAD_THRESHOLD = 3000;
static gboolean _in_redraw = FALSE;
static void
_win_ensure_pad_capacity(ProfWin* window, WINDOW* win, int lines_needed)
{
if (!win) {
return;
}
int cur_height = getmaxy(win);
int cur_width = getmaxx(win);
if (lines_needed >= cur_height - 1) {
// If we are getting too large, trigger a redraw to clean up old lines
// but only if we are not already in a redraw process.
if (window && cur_height >= PAD_THRESHOLD && !_in_redraw) {
win_redraw(window);
} else {
// resize to required lines + some buffer for next messages
int new_height = lines_needed + 100;
wresize(win, new_height, cur_width);
}
}
}
static const char* LOADING_MESSAGE = "Loading older messages…";
static const char* CONS_WIN_TITLE = "CProof. Type /help for help information.";
static const char* XML_WIN_TITLE = "XML Console";
@@ -75,7 +77,7 @@ static void
_win_printf(ProfWin* window, const char* show_char, int pad_indent, GDateTime* timestamp, int flags, theme_item_t theme_item, const char* const display_from, const char* const from_jid, const char* const message_id, const char* const message, ...);
static void _win_print_internal(ProfWin* window, const char* show_char, int pad_indent, GDateTime* time,
int flags, theme_item_t theme_item, const char* const from, const char* const message, DeliveryReceipt* receipt);
static void _win_print_wrapped(WINDOW* win, const char* const message, size_t indent, int pad_indent);
static void _win_print_wrapped(WINDOW* win, const char* const message, int indent, int pad_indent);
// Helper: clamp a subwindow width to a sane range [1, cols-1] if possible
static int
@@ -111,9 +113,9 @@ _win_create_simple_layout(void)
{
int cols = getmaxx(stdscr);
ProfLayoutSimple* layout = malloc(sizeof(ProfLayoutSimple));
ProfLayoutSimple* layout = g_new0(ProfLayoutSimple, 1);
layout->base.type = LAYOUT_SIMPLE;
layout->base.win = newpad(PAD_SIZE, cols);
layout->base.win = newpad(PAD_MIN_HEIGHT, cols);
wbkgd(layout->base.win, theme_attrs(THEME_TEXT));
layout->base.buffer = buffer_create();
layout->base.y_pos = 0;
@@ -129,9 +131,9 @@ _win_create_split_layout(void)
{
int cols = getmaxx(stdscr);
ProfLayoutSplit* layout = malloc(sizeof(ProfLayoutSplit));
ProfLayoutSplit* layout = g_new0(ProfLayoutSplit, 1);
layout->base.type = LAYOUT_SPLIT;
layout->base.win = newpad(PAD_SIZE, cols);
layout->base.win = newpad(PAD_MIN_HEIGHT, cols);
wbkgd(layout->base.win, theme_attrs(THEME_TEXT));
layout->base.buffer = buffer_create();
layout->base.y_pos = 0;
@@ -148,7 +150,7 @@ _win_create_split_layout(void)
ProfWin*
win_create_console(void)
{
ProfConsoleWin* new_win = malloc(sizeof(ProfConsoleWin));
ProfConsoleWin* new_win = g_new0(ProfConsoleWin, 1);
new_win->window.type = WIN_CONSOLE;
new_win->window.scroll_state = WIN_SCROLL_INNER;
new_win->window.layout = _win_create_split_layout();
@@ -159,8 +161,7 @@ win_create_console(void)
ProfWin*
win_create_chat(const char* const barejid)
{
assert(barejid != NULL);
ProfChatWin* new_win = malloc(sizeof(ProfChatWin));
ProfChatWin* new_win = g_new0(ProfChatWin, 1);
new_win->window.type = WIN_CHAT;
new_win->window.scroll_state = WIN_SCROLL_INNER;
new_win->window.layout = _win_create_simple_layout();
@@ -172,6 +173,9 @@ win_create_chat(const char* const barejid)
new_win->pgp_recv = FALSE;
new_win->pgp_send = FALSE;
new_win->is_omemo = FALSE;
#ifdef HAVE_OMEMO
new_win->omemo_trusted = omemo_is_jid_trusted(barejid);
#endif
new_win->is_ox = FALSE;
new_win->history_shown = FALSE;
new_win->unread = 0;
@@ -191,23 +195,22 @@ win_create_chat(const char* const barejid)
ProfWin*
win_create_muc(const char* const roomjid)
{
assert(roomjid != NULL);
ProfMucWin* new_win = malloc(sizeof(ProfMucWin));
ProfMucWin* new_win = g_new0(ProfMucWin, 1);
int cols = getmaxx(stdscr);
new_win->window.type = WIN_MUC;
new_win->window.scroll_state = WIN_SCROLL_INNER;
ProfLayoutSplit* layout = malloc(sizeof(ProfLayoutSplit));
ProfLayoutSplit* layout = g_new0(ProfLayoutSplit, 1);
layout->base.type = LAYOUT_SPLIT;
if (prefs_get_boolean(PREF_OCCUPANTS)) {
int subwin_cols = win_occpuants_cols();
layout->base.win = newpad(PAD_SIZE, cols - subwin_cols);
layout->base.win = newpad(PAD_MIN_HEIGHT, cols - subwin_cols);
wbkgd(layout->base.win, theme_attrs(THEME_TEXT));
layout->subwin = newpad(PAD_SIZE, subwin_cols);
layout->subwin = newpad(PAD_MIN_HEIGHT, subwin_cols);
wbkgd(layout->subwin, theme_attrs(THEME_TEXT));
} else {
layout->base.win = newpad(PAD_SIZE, (cols));
layout->base.win = newpad(PAD_MIN_HEIGHT, (cols));
wbkgd(layout->base.win, theme_attrs(THEME_TEXT));
layout->subwin = NULL;
}
@@ -238,6 +241,9 @@ win_create_muc(const char* const roomjid)
new_win->enctext = NULL;
new_win->message_char = NULL;
new_win->is_omemo = FALSE;
#ifdef HAVE_OMEMO
new_win->omemo_trusted = omemo_is_jid_trusted(roomjid);
#endif
new_win->last_message = NULL;
new_win->last_msg_id = NULL;
new_win->has_attention = FALSE;
@@ -250,9 +256,7 @@ win_create_muc(const char* const roomjid)
ProfWin*
win_create_config(const char* const roomjid, DataForm* form, ProfConfWinCallback submit, ProfConfWinCallback cancel, const void* userdata)
{
assert(roomjid != NULL);
assert(form != NULL);
ProfConfWin* new_win = malloc(sizeof(ProfConfWin));
ProfConfWin* new_win = g_new0(ProfConfWin, 1);
new_win->window.type = WIN_CONFIG;
new_win->window.scroll_state = WIN_SCROLL_INNER;
new_win->window.layout = _win_create_simple_layout();
@@ -270,8 +274,7 @@ win_create_config(const char* const roomjid, DataForm* form, ProfConfWinCallback
ProfWin*
win_create_private(const char* const fulljid)
{
assert(fulljid != NULL);
ProfPrivateWin* new_win = malloc(sizeof(ProfPrivateWin));
ProfPrivateWin* new_win = g_new0(ProfPrivateWin, 1);
new_win->window.type = WIN_PRIVATE;
new_win->window.scroll_state = WIN_SCROLL_INNER;
new_win->window.layout = _win_create_simple_layout();
@@ -288,7 +291,7 @@ win_create_private(const char* const fulljid)
ProfWin*
win_create_xmlconsole(void)
{
ProfXMLWin* new_win = malloc(sizeof(ProfXMLWin));
ProfXMLWin* new_win = g_new0(ProfXMLWin, 1);
new_win->window.type = WIN_XML;
new_win->window.scroll_state = WIN_SCROLL_INNER;
new_win->window.layout = _win_create_simple_layout();
@@ -301,9 +304,7 @@ win_create_xmlconsole(void)
ProfWin*
win_create_plugin(const char* const plugin_name, const char* const tag)
{
assert(plugin_name != NULL);
assert(tag != NULL);
ProfPluginWin* new_win = malloc(sizeof(ProfPluginWin));
ProfPluginWin* new_win = g_new0(ProfPluginWin, 1);
new_win->window.type = WIN_PLUGIN;
new_win->window.scroll_state = WIN_SCROLL_INNER;
new_win->window.layout = _win_create_simple_layout();
@@ -319,8 +320,7 @@ win_create_plugin(const char* const plugin_name, const char* const tag)
ProfWin*
win_create_vcard(vCard* vcard)
{
assert(vcard != NULL);
ProfVcardWin* new_win = malloc(sizeof(ProfVcardWin));
ProfVcardWin* new_win = g_new0(ProfVcardWin, 1);
new_win->window.type = WIN_VCARD;
new_win->window.scroll_state = WIN_SCROLL_INNER;
new_win->window.layout = _win_create_simple_layout();
@@ -586,11 +586,11 @@ win_hide_subwin(ProfWin* window)
layout->subwin = NULL;
layout->sub_y_pos = 0;
int cols = getmaxx(stdscr);
wresize(layout->base.win, PAD_SIZE, cols);
wresize(layout->base.win, PAD_MIN_HEIGHT, cols);
win_redraw(window);
} else {
int cols = getmaxx(stdscr);
wresize(window->layout->win, PAD_SIZE, cols);
wresize(window->layout->win, PAD_MIN_HEIGHT, cols);
win_redraw(window);
}
}
@@ -612,27 +612,14 @@ win_show_subwin(ProfWin* window)
}
ProfLayoutSplit* layout = (ProfLayoutSplit*)window->layout;
// If a subwindow already exists (e.g. repeated call), destroy it to avoid leaks
/* Free a previous pad if win_show_subwin was called twice in a row
* without an intervening win_hide_subwin. */
if (layout->subwin) {
delwin(layout->subwin);
layout->subwin = NULL;
}
// Ensure minimum width to avoid creating a zero-width pad
if (subwin_cols <= 0) {
subwin_cols = 1;
}
layout->subwin = newpad(PAD_SIZE, subwin_cols);
if (layout->subwin == NULL) {
// Failed to allocate subwindow; keep base window resized to full width
log_error("Failed to create subwindow pad (cols=%d)", subwin_cols);
wresize(layout->base.win, PAD_SIZE, cols);
win_redraw(window);
return;
}
layout->subwin = newpad(PAD_MIN_HEIGHT, subwin_cols);
wbkgd(layout->subwin, theme_attrs(THEME_TEXT));
wresize(layout->base.win, PAD_SIZE, cols - subwin_cols);
wresize(layout->base.win, PAD_MIN_HEIGHT, cols - subwin_cols);
win_redraw(window);
}
@@ -652,6 +639,10 @@ win_free(ProfWin* window)
}
free(window->layout);
if (window->warned_jids) {
g_hash_table_destroy(window->warned_jids);
}
switch (window->type) {
case WIN_CHAT:
{
@@ -715,6 +706,44 @@ win_free(ProfWin* window)
free(window);
}
gboolean
win_warn_needed(ProfWin* window, const char* const type, const char* const jid)
{
if (!window || !type || !jid) {
return TRUE;
}
if (!window->warned_jids) {
return TRUE;
}
auto_gchar gchar* key = g_strdup_printf("%s:%s", type, jid);
return !g_hash_table_contains(window->warned_jids, key);
}
void
win_warn_sent(ProfWin* window, const char* const type, const char* const jid)
{
if (!window || !type || !jid) {
return;
}
if (!window->warned_jids) {
window->warned_jids = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
}
gchar* key = g_strdup_printf("%s:%s", type, jid);
g_hash_table_insert(window->warned_jids, key, GINT_TO_POINTER(1));
}
void
win_clear_warned_jids(ProfWin* window)
{
if (window && window->warned_jids) {
g_hash_table_remove_all(window->warned_jids);
}
}
void
win_page_up(ProfWin* window, int scroll_size)
{
@@ -811,7 +840,7 @@ win_page_down(ProfWin* window, int scroll_size)
GDateTime* now = g_date_time_new_now_local();
ProfBuffEntry* last_entry = buffer_get_entry(window->layout->buffer, bf_size - 1);
auto_gchar gchar* start = g_date_time_format_iso8601(last_entry->time);
auto_gchar gchar* end_date = g_date_time_format_iso8601(now);
auto_gchar gchar* end_date = prof_date_time_format_iso8601(NULL);
db_history_result_t db_response = chatwin_db_history((ProfChatWin*)window, start, end_date, FALSE);
if (db_response == DB_RESPONSE_EMPTY)
*scroll_state = WIN_SCROLL_REACHED_BOTTOM;
@@ -934,9 +963,9 @@ win_resize(ProfWin* window)
subwin_cols = win_occpuants_cols();
}
wbkgd(layout->base.win, theme_attrs(THEME_TEXT));
wresize(layout->base.win, PAD_SIZE, cols - subwin_cols);
wresize(layout->base.win, PAD_MIN_HEIGHT, cols - subwin_cols);
wbkgd(layout->subwin, theme_attrs(THEME_TEXT));
wresize(layout->subwin, PAD_SIZE, subwin_cols);
wresize(layout->subwin, PAD_MIN_HEIGHT, subwin_cols);
if (window->type == WIN_CONSOLE) {
rosterwin_roster();
} else if (window->type == WIN_MUC) {
@@ -946,11 +975,11 @@ win_resize(ProfWin* window)
}
} else {
wbkgd(layout->base.win, theme_attrs(THEME_TEXT));
wresize(layout->base.win, PAD_SIZE, cols);
wresize(layout->base.win, PAD_MIN_HEIGHT, cols);
}
} else {
wbkgd(window->layout->win, theme_attrs(THEME_TEXT));
wresize(window->layout->win, PAD_SIZE, cols);
wresize(window->layout->win, PAD_MIN_HEIGHT, cols);
}
win_redraw(window);
@@ -1078,11 +1107,11 @@ win_show_contact(ProfWin* window, PContact contact)
GTimeSpan span = g_date_time_difference(now, last_activity);
g_date_time_unref(now);
int hours = span / G_TIME_SPAN_HOUR;
int hours = (int)(span / G_TIME_SPAN_HOUR);
span = span - hours * G_TIME_SPAN_HOUR;
int minutes = span / G_TIME_SPAN_MINUTE;
int minutes = (int)(span / G_TIME_SPAN_MINUTE);
span = span - minutes * G_TIME_SPAN_MINUTE;
int seconds = span / G_TIME_SPAN_SECOND;
int seconds = (int)(span / G_TIME_SPAN_SECOND);
if (hours > 0) {
win_append(window, presence_colour, ", idle %dh%dm%ds", hours, minutes, seconds);
@@ -1203,11 +1232,11 @@ win_show_info(ProfWin* window, PContact contact)
GDateTime* now = g_date_time_new_now_local();
GTimeSpan span = g_date_time_difference(now, last_activity);
int hours = span / G_TIME_SPAN_HOUR;
int hours = (int)(span / G_TIME_SPAN_HOUR);
span = span - hours * G_TIME_SPAN_HOUR;
int minutes = span / G_TIME_SPAN_MINUTE;
int minutes = (int)(span / G_TIME_SPAN_MINUTE);
span = span - minutes * G_TIME_SPAN_MINUTE;
int seconds = span / G_TIME_SPAN_SECOND;
int seconds = (int)(span / G_TIME_SPAN_SECOND);
if (hours > 0) {
win_println(window, THEME_DEFAULT, "-", "Last activity: %dh%dm%ds", hours, minutes, seconds);
@@ -1743,7 +1772,7 @@ win_appendln_highlight(ProfWin* window, theme_item_t theme_item, const char* con
void
win_print_http_transfer(ProfWin* window, const char* const message, char* id)
{
win_print_outgoing_with_receipt(window, "!", NULL, message, id, NULL);
win_print_status_with_id(window, message, id, THEME_DEFAULT, 0);
}
void
@@ -1751,7 +1780,7 @@ win_print_outgoing_with_receipt(ProfWin* window, const char* show_char, const ch
{
GDateTime* time = g_date_time_new_now_local();
DeliveryReceipt* receipt = malloc(sizeof(struct delivery_receipt_t));
DeliveryReceipt* receipt = g_new0(struct delivery_receipt_t, 1);
receipt->received = FALSE;
const char* myjid = connection_get_fulljid();
@@ -1792,6 +1821,33 @@ win_update_entry_message(ProfWin* window, const char* const id, const char* cons
}
}
void
win_update_entry(ProfWin* window, const char* const id, const char* const message, theme_item_t theme_item, int flags)
{
if (window->type == WIN_CONSOLE)
return;
ProfBuffEntry* entry = buffer_get_entry_by_id(window->layout->buffer, id);
if (entry) {
if (message) {
free(entry->message);
entry->message = strdup(message);
}
entry->theme_item = theme_item;
entry->flags |= flags;
win_redraw(window);
}
}
void
win_print_status_with_id(ProfWin* window, const char* const message, char* id, theme_item_t theme_item, int flags)
{
GDateTime* time = g_date_time_new_now_local();
int y_start_pos = getcury(window->layout->win);
_win_print_internal(window, "!", 0, time, flags, theme_item, NULL, message, NULL);
buffer_append(window->layout->buffer, "!", 0, time, flags, theme_item, NULL, NULL, message, NULL, id, y_start_pos, getcury(window->layout->win));
g_date_time_unref(time);
}
void
win_remove_entry_message(ProfWin* window, const char* const id)
{
@@ -1851,7 +1907,7 @@ _win_print_internal(ProfWin* window, const char* show_char, int pad_indent, GDat
gboolean me_message = FALSE;
int offset = 0;
int colour = theme_attrs(THEME_ME);
size_t indent = 0;
int indent = 0;
auto_gchar gchar* time_pref = NULL;
switch (window->type) {
@@ -1884,7 +1940,7 @@ _win_print_internal(ProfWin* window, const char* show_char, int pad_indent, GDat
assert(date_fmt != NULL);
if (strlen(date_fmt) != 0) {
indent = 3 + strlen(date_fmt);
indent = 3 + (int)strlen(date_fmt);
}
if ((flags & NO_DATE) == 0) {
@@ -1945,6 +2001,8 @@ _win_print_internal(ProfWin* window, const char* show_char, int pad_indent, GDat
}
}
_win_ensure_pad_capacity(window, window->layout->win, getcury(window->layout->win));
if (prefs_get_boolean(PREF_WRAP)) {
_win_print_wrapped(window->layout->win, message + offset, indent, pad_indent);
} else {
@@ -1978,11 +2036,11 @@ _win_indent(WINDOW* win, int size)
}
static void
_win_print_wrapped(WINDOW* win, const char* const message, size_t indent, int pad_indent)
_win_print_wrapped(WINDOW* win, const char* const message, int indent, int pad_indent)
{
int starty = getcury(win);
int wordi = 0;
auto_char char* word = malloc(strlen(message) + 1);
auto_gchar gchar* word = g_malloc(strlen(message) + 1);
gchar* curr_ch = g_utf8_offset_to_pointer(message, 0);
@@ -2005,11 +2063,12 @@ _win_print_wrapped(WINDOW* win, const char* const message, size_t indent, int pa
int wordlen = 0;
while (*curr_ch != ' ' && *curr_ch != '\n' && *curr_ch != '\0') {
size_t ch_len = mbrlen(curr_ch, MB_CUR_MAX, NULL);
if ((ch_len == (size_t)-2) || (ch_len == (size_t)-1)) {
// 0 / invalid step: advance one byte to avoid spinning.
if ((ch_len == (size_t)-2) || (ch_len == (size_t)-1) || ch_len == 0) {
curr_ch++;
continue;
}
int offset = 0;
size_t offset = 0;
while (offset < ch_len) {
word[wordi++] = curr_ch[offset++];
}
@@ -2094,6 +2153,7 @@ _win_print_wrapped(WINDOW* win, const char* const message, size_t indent, int pa
void
win_print_trackbar(ProfWin* window)
{
_win_ensure_pad_capacity(window, window->layout->win, getcury(window->layout->win));
int cols = getmaxx(window->layout->win);
wbkgdset(window->layout->win, theme_attrs(THEME_TRACKBAR));
@@ -2109,12 +2169,20 @@ win_print_trackbar(ProfWin* window)
void
win_redraw(ProfWin* window)
{
int size = buffer_size(window->layout->buffer);
unsigned int size = buffer_size(window->layout->buffer);
_in_redraw = TRUE;
// shrink pad back to minimum size and erase it
int cols = getmaxx(window->layout->win);
wresize(window->layout->win, PAD_MIN_HEIGHT, cols);
werase(window->layout->win);
for (int i = 0; i < size; i++) {
for (unsigned int i = 0; i < size; i++) {
ProfBuffEntry* e = buffer_get_entry(window->layout->buffer, i);
// check if we need more space before printing
_win_ensure_pad_capacity(window, window->layout->win, getcury(window->layout->win));
e->y_start_pos = getcury(window->layout->win);
if (e->display_from == NULL && e->message && e->message[0] == '-') {
// just an indicator to print the trackbar/separator not the actual message
@@ -2129,6 +2197,8 @@ win_redraw(ProfWin* window)
e->_lines = e->y_end_pos - e->y_start_pos;
window->layout->buffer->lines += e->_lines;
}
_in_redraw = FALSE;
}
void
@@ -2263,6 +2333,7 @@ win_toggle_attention(ProfWin* window)
void
win_sub_print(WINDOW* win, char* msg, gboolean newline, gboolean wrap, int indent)
{
_win_ensure_pad_capacity(NULL, win, getcury(win));
int maxx = getmaxx(win);
int curx = getcurx(win);
int cury = getcury(win);
@@ -2351,11 +2422,11 @@ win_handle_command_exec_result_note(ProfWin* window, const char* const type, con
void
win_insert_last_read_position_marker(ProfWin* window, char* id)
{
int size = buffer_size(window->layout->buffer);
unsigned int size = buffer_size(window->layout->buffer);
// TODO: this is somewhat costly. We should improve this later.
// check if we already have a separator present
for (int i = 0; i < size; i++) {
for (unsigned int i = 0; i < size; i++) {
ProfBuffEntry* e = buffer_get_entry(window->layout->buffer, i);
// if yes, don't print a new one

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 UI_WINDOW_H
@@ -85,9 +59,15 @@ void win_sub_print(WINDOW* win, char* msg, gboolean newline, gboolean wrap, int
void win_sub_newline_lazy(WINDOW* win);
void win_mark_received(ProfWin* window, const char* const id);
void win_update_entry_message(ProfWin* window, const char* const id, const char* const message);
void win_update_entry(ProfWin* window, const char* const id, const char* const message, theme_item_t theme_item, int flags);
void win_print_status_with_id(ProfWin* window, const char* const message, char* id, theme_item_t theme_item, int flags);
gboolean win_has_active_subwin(ProfWin* window);
gboolean win_warn_needed(ProfWin* window, const char* const type, const char* const jid);
void win_warn_sent(ProfWin* window, const char* const type, const char* const jid);
void win_clear_warned_jids(ProfWin* window);
void win_page_up(ProfWin* window, int scroll_size);
void win_page_down(ProfWin* window, int scroll_size);
void win_sub_page_down(ProfWin* window);

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"
@@ -1056,6 +1030,31 @@ _wins_get_next_available_num(GList* used)
}
}
void
wins_omemo_trust_changed(const char* const jid)
{
GList* curr = values;
while (curr) {
ProfWin* window = curr->data;
if (window->type == WIN_CHAT) {
ProfChatWin* chatwin = (ProfChatWin*)window;
if (jid == NULL || strcmp(chatwin->barejid, jid) == 0) {
#ifdef HAVE_OMEMO
chatwin->omemo_trusted = omemo_is_jid_trusted(chatwin->barejid);
#endif
}
} else if (window->type == WIN_MUC) {
ProfMucWin* mucwin = (ProfMucWin*)window;
if (jid == NULL || strcmp(mucwin->roomjid, jid) == 0) {
#ifdef HAVE_OMEMO
mucwin->omemo_trusted = omemo_is_jid_trusted(mucwin->roomjid);
#endif
}
}
curr = g_list_next(curr);
}
}
gboolean
wins_tidy(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 UI_WINDOW_LIST_H
@@ -89,6 +63,7 @@ GSList* wins_get_chat_recipients(void);
GSList* wins_get_prune_wins(void);
void wins_lost_connection(void);
void wins_reestablished_connection(void);
void wins_omemo_trust_changed(const char* const jid);
gboolean wins_tidy(void);
GSList* wins_create_summary(gboolean unread);
GSList* wins_create_summary_attention();

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"