Compare commits
1 Commits
build/reen
...
3a23bb3273
| Author | SHA1 | Date | |
|---|---|---|---|
|
3a23bb3273
|
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: jubalh
|
||||
patreon: # Replace with Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: # Replace with a single custom sponsorship URL
|
||||
2
.github/ISSUE_TEMPLATE
vendored
2
.github/ISSUE_TEMPLATE
vendored
@@ -20,6 +20,8 @@
|
||||
<!--- Give us a screenshot (if it's helpful for this particular bug) -->
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
4.
|
||||
|
||||
## Context
|
||||
<!--- How has this issue affected you? What are you trying to accomplish? -->
|
||||
|
||||
4
.github/pull_request_template.md
vendored
4
.github/pull_request_template.md
vendored
@@ -5,5 +5,5 @@
|
||||
- [ ] I ran valgrind when using my new feature
|
||||
|
||||
### How to test the functionality
|
||||
- step 1
|
||||
- step 2
|
||||
* step 1
|
||||
* step 2
|
||||
|
||||
6
.github/workflows/main.yml
vendored
6
.github/workflows/main.yml
vendored
@@ -20,7 +20,7 @@ jobs:
|
||||
|
||||
name: Linux
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v2
|
||||
- name: Run tests
|
||||
run: |
|
||||
docker build -f Dockerfile.${{ matrix.flavor }} -t profanity .
|
||||
@@ -78,11 +78,11 @@ jobs:
|
||||
exit $failed
|
||||
|
||||
spell-check:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
name: Check spelling
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v2
|
||||
- name: install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -44,9 +44,6 @@ src/gitversion.h.in
|
||||
src/stamp-h1
|
||||
src/plugins/profapi.lo
|
||||
|
||||
# clangd
|
||||
.cache/
|
||||
|
||||
# out-of-tree build folders
|
||||
build*/
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ We recommend for people to always work on a dedicated git branch for each fix or
|
||||
Don't work on master.
|
||||
So that they can easily pull master and rebase their work if needed.
|
||||
|
||||
For fixing (reported) bugs we usually use `git switch -c fix/issuenumber-somedescription`.
|
||||
When working on a new feature we usually use `git switch -c feature/optionalissuenumber-somedescription`.
|
||||
For fixing (reported) bugs we usually use `git checkout -b fix/issuenumber-somedescription`.
|
||||
When working on a new feature we usually use `git checkout -b feature/optionalissuenumber-somedescription`.
|
||||
|
||||
However this is not a rule just a recommendation to keep an overview of things.
|
||||
If your change isn't a bugfix or new feature you can also just use any branch name.
|
||||
|
||||
37
README.md
37
README.md
@@ -3,6 +3,8 @@
|
||||
|
||||
Profanity is a console based XMPP client inspired by [Irssi](http://www.irssi.org/).
|
||||
|
||||
If you like Profanity consider becoming a sponsor or [donate](https://profanity-im.github.io/donate.html) some money.
|
||||
|
||||

|
||||
|
||||
See the [User Guide](https://profanity-im.github.io/userguide.html) for information on installing and using Profanity.
|
||||
@@ -10,10 +12,26 @@ See the [User Guide](https://profanity-im.github.io/userguide.html) for informat
|
||||
## Project
|
||||
This project is about freedom, privacy and choice. We want to enable people to chat with one another in a safe way. Thus supporting encryption (OTR, PGP, OMEMO, OX) and being decentralized, meaning everyone can run their own server. We believe [XMPP](https://xmpp.org/) is a great proven protocol with an excellent community serving this purpose well.
|
||||
|
||||
Feel free to follow us on [twitter](https://twitter.com/profanityim), join our [mailing list](https://lists.posteo.de/listinfo/profanity) and/or [MUC](xmpp:profanity@rooms.dismail.de?join).
|
||||
|
||||
## Installation
|
||||
Our [user guide](https://profanity-im.github.io/userguide.html) contains an [install](https://profanity-im.github.io/guide/latest/install.html) section and a section for [building](https://profanity-im.github.io/guide/latest/build.html) from source yourself.
|
||||
|
||||
## Donations
|
||||
We would highly appreciate it if you support us via [GitHub Sponsors](https://github.com/sponsors/jubalh/). Especially if you make feature requests or need help using Profanity.
|
||||
Sponsoring enables us to spend time on Profanity.
|
||||
|
||||
An alternative way to support us would be to ask for our IBAN or use Bitcoin: `bc1qx265eat7hfasqkqmk9qf38delydnrnuvzhzy0x`.
|
||||
|
||||
Issues backed by a sponsor will be tagged with the [sponsored](https://github.com/profanity-im/profanity/issues?q=label%3Asponsored+) label.
|
||||
Feature requests that we consider out of scope, either because of interest or because of time needed to implement them, will be marked with the [unfunded](https://github.com/profanity-im/profanity/issues?q=label%3Aunfunded) label.
|
||||
|
||||
Another way to sponsor us or get an issue solved is to comment on an issue that you are willing to sponsor it.
|
||||
|
||||
Tasks from our [sponsors](SPONSORS.md) will be tackled first.
|
||||
|
||||
Thank you! <3
|
||||
|
||||
## How to contribute
|
||||
We tried to sum things up on our [helpout](https://profanity-im.github.io/helpout.html) page.
|
||||
Additionally you can check out our [blog](https://profanity-im.github.io/blog/) where we have articles like:
|
||||
@@ -22,19 +40,26 @@ For more technical details check out our [CONTRIBUTING.md](CONTRIBUTING.md) file
|
||||
|
||||
## Getting help
|
||||
To get help, first read our [User Guide](https://profanity-im.github.io/userguide.html) then check out the [FAQ](https://profanity-im.github.io/faq.html).
|
||||
If you are having a problem then first search the [issue tracker](https://github.com/profanity-im/profanity/issues).
|
||||
If you have are having a problem then first search the [issue tracker](https://github.com/profanity-im/profanity/issues).
|
||||
If you don't find anything there either come to our [MUC](xmpp:profanity@rooms.dismail.de?join) or create a new issue depending on what your problem is.
|
||||
|
||||
## Links
|
||||
|
||||
### Website
|
||||
<!-- TODO:
|
||||
URL: https://jabber.space/
|
||||
-->
|
||||
URL: https://profanity-im.github.io
|
||||
|
||||
Repo: https://git.jabber.space/devs/profanity
|
||||
Repo: https://github.com/profanity-im/profanity-im.github.io
|
||||
|
||||
<!-- TODO: blog/docs link -->
|
||||
### Blog
|
||||
URL: https://profanity-im.github.io/blog
|
||||
|
||||
Repo: https://github.com/profanity-im/blog
|
||||
|
||||
### Mailinglist
|
||||
Mailing List: https://lists.posteo.de/listinfo/profanity
|
||||
|
||||
### Chatroom
|
||||
MUC: profanity@rooms.dismail.de
|
||||
|
||||
### Plugins
|
||||
Plugins repository: https://github.com/profanity-im/profanity-plugins
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* Generate HTML docs (the docgen argument only works when package status is development)
|
||||
`./profanity docgen`
|
||||
|
||||
* Determine if `libprofanity`'s version needs to be [increased](https://github.com/profanity-im/profanity/issues/973)
|
||||
* Determine if libprofanitys version needs to be [increased](https://github.com/profanity-im/profanity/issues/973)
|
||||
* Update plugin API docs (./apidocs/c and ./apidocs/python) need to run the `gen.sh` and commit the results to the website git repo
|
||||
* Update CHANGELOG
|
||||
* Update profrc.example
|
||||
|
||||
22
SPONSORS.md
Normal file
22
SPONSORS.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Giving back
|
||||
|
||||
Thank you very much to all of our sponsors and donors (including those that want to stay private)!
|
||||
|
||||
## Sponsors
|
||||
[Martin Dosch](https://github.com/mdosch) since January 2020
|
||||
|
||||
[Alexander Dahl](https://github.com/LeSpocky) since January 2021
|
||||
|
||||
[James Pond](https://github.com/jamesponddotco) since February 2021
|
||||
|
||||
## Donors
|
||||
[Martin Dosch](https://github.com/mdosch)
|
||||
|
||||
[Julian Huhn](https://github.com/huhndev)
|
||||
|
||||
[Matteo Bini](https://github.com/matteobin)
|
||||
|
||||
## Services
|
||||
[Stefan Kropp](https://github.com/StefanKropp) for sponsoring our [mailing list](https://lists.posteo.de/listinfo/profanity)
|
||||
|
||||
[dismail](https://dismail.de/) for hosting our [MUC](xmpp:profanity@rooms.dismail.de?join)
|
||||
@@ -1865,7 +1865,7 @@ MAN_LINKS = NO
|
||||
# captures the structure of the code including all documentation.
|
||||
# The default value is: NO.
|
||||
|
||||
GENERATE_XML = YES
|
||||
GENERATE_XML = NO
|
||||
|
||||
# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
|
||||
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
|
||||
|
||||
@@ -1 +1 @@
|
||||
sphinx-apidoc -f -o . src && make xml
|
||||
sphinx-apidoc -f -o . src && make html
|
||||
|
||||
53
prof.supp
53
prof.supp
@@ -5,7 +5,7 @@
|
||||
#
|
||||
# This file is a combination of our own rules and
|
||||
# * the glib2 suppressions file that usually can be found at /usr/share/glib-2.0/valgrind/glib.supp
|
||||
# * python suppressions file from https://github.com/python/cpython/blob/main/Misc/valgrind-python.supp
|
||||
# * python suppressions file from http://svn.python.org/projects/python/trunk/Misc/valgrind-python.supp
|
||||
#
|
||||
|
||||
{
|
||||
@@ -1557,10 +1557,6 @@
|
||||
...
|
||||
fun:xdg_mime_init
|
||||
}
|
||||
|
||||
# Python Valgrind .supp start
|
||||
# taken from https://github.com/python/cpython/blob/main/Misc/valgrind-python.supp
|
||||
|
||||
#
|
||||
# This is a valgrind suppression file that should be used when using valgrind.
|
||||
#
|
||||
@@ -1658,49 +1654,6 @@
|
||||
fun:COMMENT_THIS_LINE_TO_DISABLE_LEAK_WARNING
|
||||
}
|
||||
|
||||
#
|
||||
# Leaks: dlopen() called without dlclose()
|
||||
#
|
||||
|
||||
{
|
||||
dlopen() called without dlclose()
|
||||
Memcheck:Leak
|
||||
fun:malloc
|
||||
fun:malloc
|
||||
fun:strdup
|
||||
fun:_dl_load_cache_lookup
|
||||
}
|
||||
{
|
||||
dlopen() called without dlclose()
|
||||
Memcheck:Leak
|
||||
fun:malloc
|
||||
fun:malloc
|
||||
fun:strdup
|
||||
fun:_dl_map_object
|
||||
}
|
||||
{
|
||||
dlopen() called without dlclose()
|
||||
Memcheck:Leak
|
||||
fun:malloc
|
||||
fun:*
|
||||
fun:_dl_new_object
|
||||
}
|
||||
{
|
||||
dlopen() called without dlclose()
|
||||
Memcheck:Leak
|
||||
fun:calloc
|
||||
fun:*
|
||||
fun:_dl_new_object
|
||||
}
|
||||
{
|
||||
dlopen() called without dlclose()
|
||||
Memcheck:Leak
|
||||
fun:calloc
|
||||
fun:*
|
||||
fun:_dl_check_map_versions
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Non-python specific leaks
|
||||
#
|
||||
@@ -2095,10 +2048,6 @@
|
||||
fun:PyUnicode_FSConverter
|
||||
}
|
||||
|
||||
# Python Valgrind .supp end
|
||||
|
||||
|
||||
|
||||
# Actual GTK things
|
||||
{
|
||||
GtkWidgetClass action GPtrArray
|
||||
|
||||
@@ -1715,15 +1715,8 @@ cmd_help(ProfWin* window, const char* const command, gchar** args)
|
||||
gboolean
|
||||
cmd_about(ProfWin* window, const char* const command, gchar** args)
|
||||
{
|
||||
ProfWin* console = wins_get_console();
|
||||
cons_show("");
|
||||
cons_about();
|
||||
win_println(console, THEME_DEFAULT, "-", "Licensed under GNU GPL v3.");
|
||||
win_println(console, THEME_DEFAULT, "-", "CProof is an independent unaffiliated fork of Profanity.");
|
||||
win_println(console, THEME_DEFAULT, "-", "Profanity: Copyright (C) 2012–2019 James Booth, 2019–2025 Michael Vetter");
|
||||
win_println(console, THEME_DEFAULT, "-", "Copyright (C) 2025 CProof Developers");
|
||||
win_println(console, THEME_DEFAULT, "-", "");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -5240,43 +5233,54 @@ cmd_console(ProfWin* window, const char* const command, gchar** args)
|
||||
gboolean
|
||||
cmd_presence(ProfWin* window, const char* const command, gchar** args)
|
||||
{
|
||||
if (strcmp(args[0], "console") != 0 && strcmp(args[0], "chat") != 0 && strcmp(args[0], "room") != 0 && strcmp(args[0], "titlebar") != 0) {
|
||||
cons_bad_cmd_usage(command);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (strcmp(args[0], "titlebar") == 0) {
|
||||
_cmd_set_boolean_preference(args[1], "Contact presence", PREF_PRESENCE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
const struct presence_preferences
|
||||
{
|
||||
preference_t pref;
|
||||
const char *name, *description;
|
||||
} presence_prefs[] = {
|
||||
{ .pref = PREF_STATUSES_CONSOLE, .name = "console", .description = "the console" },
|
||||
{ .pref = PREF_STATUSES_CHAT, .name = "chat", .description = "chat windows" },
|
||||
{ .pref = PREF_STATUSES_MUC, .name = "room", .description = "chat room windows" },
|
||||
};
|
||||
size_t n = 0;
|
||||
for (; n < ARRAY_SIZE(presence_prefs); ++n) {
|
||||
const struct presence_preferences* pp = &presence_prefs[n];
|
||||
if (g_strcmp0(args[0], pp->name) != 0)
|
||||
continue;
|
||||
if (strcmp(args[1], "all") == 0) {
|
||||
cons_show("All presence updates will appear in %s.", pp->description);
|
||||
} else if (strcmp(args[1], "online") == 0) {
|
||||
cons_show("Only %s presence updates will appear in %s.",
|
||||
pp->pref == PREF_STATUSES_MUC ? "join/leave" : "online/offline",
|
||||
pp->description);
|
||||
} else if (strcmp(args[1], "none") == 0) {
|
||||
cons_show("Presence updates will not appear in %s.", pp->description);
|
||||
} else {
|
||||
cons_bad_cmd_usage(command);
|
||||
return TRUE;
|
||||
}
|
||||
prefs_set_string(pp->pref, args[1]);
|
||||
break;
|
||||
}
|
||||
if (n == ARRAY_SIZE(presence_prefs)) {
|
||||
if (strcmp(args[1], "all") != 0 && strcmp(args[1], "online") != 0 && strcmp(args[1], "none") != 0) {
|
||||
cons_bad_cmd_usage(command);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (strcmp(args[0], "console") == 0) {
|
||||
prefs_set_string(PREF_STATUSES_CONSOLE, args[1]);
|
||||
if (strcmp(args[1], "all") == 0) {
|
||||
cons_show("All presence updates will appear in the console.");
|
||||
} else if (strcmp(args[1], "online") == 0) {
|
||||
cons_show("Only online/offline presence updates will appear in the console.");
|
||||
} else {
|
||||
cons_show("Presence updates will not appear in the console.");
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(args[0], "chat") == 0) {
|
||||
prefs_set_string(PREF_STATUSES_CHAT, args[1]);
|
||||
if (strcmp(args[1], "all") == 0) {
|
||||
cons_show("All presence updates will appear in chat windows.");
|
||||
} else if (strcmp(args[1], "online") == 0) {
|
||||
cons_show("Only online/offline presence updates will appear in chat windows.");
|
||||
} else {
|
||||
cons_show("Presence updates will not appear in chat windows.");
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(args[0], "room") == 0) {
|
||||
prefs_set_string(PREF_STATUSES_MUC, args[1]);
|
||||
if (strcmp(args[1], "all") == 0) {
|
||||
cons_show("All presence updates will appear in chat room windows.");
|
||||
} else if (strcmp(args[1], "online") == 0) {
|
||||
cons_show("Only join/leave presence updates will appear in chat room windows.");
|
||||
} else {
|
||||
cons_show("Presence updates will not appear in chat room windows.");
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -5310,8 +5314,7 @@ cmd_time(ProfWin* window, const char* const command, gchar** args)
|
||||
};
|
||||
gboolean redraw = FALSE;
|
||||
gboolean set_all = g_strcmp0(args[0], "all") == 0;
|
||||
size_t n = 0;
|
||||
for (; n < ARRAY_SIZE(time_prefs); ++n) {
|
||||
for (size_t n = 0; n < ARRAY_SIZE(time_prefs); ++n) {
|
||||
if (!set_all && g_strcmp0(args[0], time_prefs[n].name) != 0)
|
||||
continue;
|
||||
const struct time_preferences* tp = &time_prefs[n];
|
||||
@@ -5352,9 +5355,6 @@ cmd_time(ProfWin* window, const char* const command, gchar** args)
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
if (!set_all && n == ARRAY_SIZE(time_prefs)) {
|
||||
cons_bad_cmd_usage(command);
|
||||
}
|
||||
if (redraw)
|
||||
ui_redraw();
|
||||
return TRUE;
|
||||
@@ -9527,7 +9527,16 @@ cmd_change_password(ProfWin* window, const char* const command, gchar** args)
|
||||
gboolean
|
||||
cmd_editor(ProfWin* window, const char* const command, gchar** args)
|
||||
{
|
||||
get_message_from_editor_async(NULL);
|
||||
auto_gchar gchar* message = NULL;
|
||||
|
||||
if (get_message_from_editor(NULL, &message)) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
rl_insert_text(message);
|
||||
ui_resize();
|
||||
rl_point = rl_end;
|
||||
rl_forced_update_display();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -387,7 +387,7 @@ release_get_latest(void)
|
||||
|
||||
curl_easy_setopt(handle, CURLOPT_URL, url);
|
||||
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, _data_callback);
|
||||
curl_easy_setopt(handle, CURLOPT_TIMEOUT, 2L);
|
||||
curl_easy_setopt(handle, CURLOPT_TIMEOUT, 2);
|
||||
curl_easy_setopt(handle, CURLOPT_WRITEDATA, (void*)&output);
|
||||
|
||||
curl_easy_perform(handle);
|
||||
|
||||
@@ -171,8 +171,6 @@ typedef enum {
|
||||
RESOURCE_XA
|
||||
} resource_presence_t;
|
||||
|
||||
extern gboolean background_mode;
|
||||
|
||||
gboolean string_to_verbosity(const char* cmd, int* verbosity, gchar** err_msg);
|
||||
|
||||
gboolean create_dir(const char* name);
|
||||
|
||||
@@ -56,9 +56,10 @@
|
||||
#include "config/preferences.h"
|
||||
#include "config/color.h"
|
||||
|
||||
static GString* theme_loc = NULL;
|
||||
static GKeyFile* theme = NULL;
|
||||
static GHashTable* defaults = NULL;
|
||||
static GString* theme_loc;
|
||||
static GKeyFile* theme;
|
||||
static GHashTable* bold_items;
|
||||
static GHashTable* defaults;
|
||||
|
||||
static void _load_preferences(void);
|
||||
static void _theme_list_dir(const gchar* const dir, GSList** result);
|
||||
@@ -77,6 +78,10 @@ _theme_close(void)
|
||||
g_string_free(theme_loc, TRUE);
|
||||
theme_loc = NULL;
|
||||
}
|
||||
if (bold_items) {
|
||||
g_hash_table_destroy(bold_items);
|
||||
bold_items = NULL;
|
||||
}
|
||||
if (defaults) {
|
||||
g_hash_table_destroy(defaults);
|
||||
defaults = NULL;
|
||||
@@ -86,12 +91,6 @@ _theme_close(void)
|
||||
void
|
||||
theme_init(const char* const theme_name)
|
||||
{
|
||||
if (defaults || theme_loc || theme) {
|
||||
log_warning("theme_init(): Detected non-NULL state (theme=%p, theme_loc=%p, defaults=%p). Cleaning up previous initialization.",
|
||||
theme, theme_loc, defaults);
|
||||
_theme_close();
|
||||
}
|
||||
|
||||
if (!_theme_load_file(theme_name)) {
|
||||
log_error("Loading theme %s failed.", theme_name);
|
||||
|
||||
|
||||
@@ -222,7 +222,6 @@ out:
|
||||
void
|
||||
log_database_close(void)
|
||||
{
|
||||
log_debug("log_database_close() called");
|
||||
if (g_chatlog_database) {
|
||||
sqlite3_close(g_chatlog_database);
|
||||
sqlite3_shutdown();
|
||||
@@ -319,25 +318,19 @@ log_database_get_limits_info(const gchar* const contact_barejid, gboolean is_las
|
||||
// Query previous chats, constraints start_time and end_time. If end_time is
|
||||
// null the current time is used. from_start gets first few messages if true
|
||||
// otherwise the last ones. Flip flips the order of the results
|
||||
db_history_result_t
|
||||
log_database_get_previous_chat(const gchar* const contact_barejid, const gchar* start_time, const gchar* end_time, gboolean from_start, gboolean flip, GSList** result)
|
||||
GSList*
|
||||
log_database_get_previous_chat(const gchar* const contact_barejid, const char* start_time, char* end_time, gboolean from_start, gboolean flip)
|
||||
{
|
||||
if (!g_chatlog_database) {
|
||||
log_warning("log_database_get_previous_chat() called but db is not initialized");
|
||||
return DB_RESPONSE_ERROR;
|
||||
}
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
const Jid* myjid = connection_get_jid();
|
||||
if (!myjid->str) {
|
||||
log_warning("log_database_get_previous_chat() called but no connection detected.");
|
||||
return DB_RESPONSE_ERROR;
|
||||
}
|
||||
if (!myjid->str)
|
||||
return NULL;
|
||||
|
||||
// Flip order when querying older pages
|
||||
gchar* sort1 = from_start ? "ASC" : "DESC";
|
||||
gchar* sort2 = !flip ? "ASC" : "DESC";
|
||||
GDateTime* now = g_date_time_new_now_local();
|
||||
auto_gchar gchar* end_date_fmt = end_time ? g_strdup(end_time) : g_date_time_format_iso8601(now);
|
||||
auto_gchar gchar* end_date_fmt = end_time ? end_time : g_date_time_format_iso8601(now);
|
||||
auto_sqlite gchar* query = sqlite3_mprintf("SELECT * FROM ("
|
||||
"SELECT COALESCE(B.`message`, A.`message`) AS message, "
|
||||
"A.`timestamp`, A.`from_jid`, A.`from_resource`, A.`to_jid`, A.`to_resource`, A.`type`, A.`encryption`, A.`stanza_id` FROM `ChatLogs` AS A "
|
||||
@@ -353,16 +346,18 @@ log_database_get_previous_chat(const gchar* const contact_barejid, const gchar*
|
||||
g_date_time_unref(now);
|
||||
|
||||
if (!query) {
|
||||
log_error("Could not allocate memory.");
|
||||
return DB_RESPONSE_ERROR;
|
||||
log_error("Could not allocate memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int rc = sqlite3_prepare_v2(g_chatlog_database, query, -1, &stmt, NULL);
|
||||
if (rc != SQLITE_OK) {
|
||||
log_error("SQLite error in log_database_get_previous_chat(): (error code: %d) %s", rc, sqlite3_errmsg(g_chatlog_database));
|
||||
return DB_RESPONSE_ERROR;
|
||||
log_error("SQLite error in log_database_get_previous_chat(): %s", sqlite3_errmsg(g_chatlog_database));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GSList* history = NULL;
|
||||
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
char* message = (char*)sqlite3_column_text(stmt, 0);
|
||||
char* date = (char*)sqlite3_column_text(stmt, 1);
|
||||
@@ -383,11 +378,11 @@ log_database_get_previous_chat(const gchar* const contact_barejid, const gchar*
|
||||
msg->type = _get_message_type_type(type);
|
||||
msg->enc = _get_message_enc_type(encryption);
|
||||
|
||||
*result = g_slist_append(*result, msg);
|
||||
history = g_slist_append(history, msg);
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
return g_slist_length(*result) != 0 ? DB_RESPONSE_SUCCESS : DB_RESPONSE_EMPTY;
|
||||
return history;
|
||||
}
|
||||
|
||||
static const char*
|
||||
|
||||
@@ -40,20 +40,14 @@
|
||||
#include "config/account.h"
|
||||
#include "xmpp/xmpp.h"
|
||||
|
||||
#define MESSAGES_TO_RETRIEVE 100
|
||||
|
||||
typedef enum {
|
||||
DB_RESPONSE_ERROR,
|
||||
DB_RESPONSE_EMPTY,
|
||||
DB_RESPONSE_SUCCESS
|
||||
} db_history_result_t;
|
||||
#define MESSAGES_TO_RETRIEVE 10
|
||||
|
||||
gboolean log_database_init(ProfAccount* account);
|
||||
void log_database_add_incoming(ProfMessage* message);
|
||||
void log_database_add_outgoing_chat(const char* const id, const char* const barejid, const char* const message, const char* const replace_id, prof_enc_t enc);
|
||||
void log_database_add_outgoing_muc(const char* const id, const char* const barejid, const char* const message, const char* const replace_id, prof_enc_t enc);
|
||||
void log_database_add_outgoing_muc_pm(const char* const id, const char* const barejid, const char* const message, const char* const replace_id, prof_enc_t enc);
|
||||
db_history_result_t log_database_get_previous_chat(const gchar* const contact_barejid, const gchar* start_time, const gchar* end_time, gboolean from_start, gboolean flip, GSList** result);
|
||||
GSList* log_database_get_previous_chat(const gchar* const contact_barejid, const char* start_time, char* end_time, gboolean from_start, gboolean flip);
|
||||
ProfMessage* log_database_get_limits_info(const gchar* const contact_barejid, gboolean is_last);
|
||||
void log_database_close(void);
|
||||
|
||||
|
||||
@@ -156,7 +156,14 @@ sv_ev_roster_received(void)
|
||||
if (!p_gpg_valid_key(account->pgp_keyid, &err_str)) {
|
||||
cons_show_error("Invalid PGP key ID specified: %s, %s", account->pgp_keyid, err_str);
|
||||
}
|
||||
|
||||
// Redraw the screen after entry of the PGP secret key, but not init
|
||||
ProfWin* win = wins_get_current();
|
||||
auto_gchar gchar* theme = prefs_get_string(PREF_THEME);
|
||||
win_redraw(win);
|
||||
theme_init(theme);
|
||||
ui_resize();
|
||||
ui_show_roster();
|
||||
}
|
||||
account_free(account);
|
||||
#endif
|
||||
|
||||
@@ -664,8 +664,7 @@ p_gpg_decrypt(const char* const cipher)
|
||||
}
|
||||
gpgme_key_unref(key);
|
||||
} else if (error) {
|
||||
// Emails are used only to fetch PGP recipients for debug logging. If something went wrong here, it's not worthy of warning.
|
||||
log_debug("GPGME error on gpgme_get_key(): %s", gpgme_strerror(error));
|
||||
log_warning("GPGME error: %s", gpgme_strerror(error));
|
||||
}
|
||||
|
||||
if (recipient->next) {
|
||||
|
||||
@@ -900,8 +900,6 @@ _python_type_error(ProfPlugin* plugin, char* hook, char* type)
|
||||
g_string_free(err_msg, TRUE);
|
||||
}
|
||||
|
||||
// Converts a Python string or None result to a C string and decreases the Python object's reference count.
|
||||
// If the result is NULL, or not a string/unicode/bytes/None, logs an error and returns NULL.
|
||||
static char*
|
||||
_handle_string_or_none_result(ProfPlugin* plugin, PyObject* result, char* hook)
|
||||
{
|
||||
@@ -912,16 +910,18 @@ _handle_string_or_none_result(ProfPlugin* plugin, PyObject* result, char* hook)
|
||||
}
|
||||
#ifdef PY_IS_PYTHON3
|
||||
if (result != Py_None && !PyUnicode_Check(result) && !PyBytes_Check(result)) {
|
||||
#else
|
||||
if (result != Py_None && !PyUnicode_Check(result) && !PyString_Check(result)) {
|
||||
#endif
|
||||
Py_XDECREF(result);
|
||||
allow_python_threads();
|
||||
_python_type_error(plugin, hook, "string, unicode or None");
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
if (result != Py_None && !PyUnicode_Check(result) && !PyString_Check(result)) {
|
||||
allow_python_threads();
|
||||
_python_type_error(plugin, hook, "string, unicode or None");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
char* result_str = python_str_or_unicode_to_string(result);
|
||||
Py_XDECREF(result);
|
||||
allow_python_threads();
|
||||
return result_str;
|
||||
}
|
||||
|
||||
@@ -59,7 +59,6 @@
|
||||
#include "config/tlscerts.h"
|
||||
#include "config/scripts.h"
|
||||
#include "command/cmd_defs.h"
|
||||
#include "tools/editor.h"
|
||||
#include "plugins/plugins.h"
|
||||
#include "event/client_events.h"
|
||||
#include "ui/ui.h"
|
||||
@@ -94,9 +93,6 @@ static void _connect_default(const char* const account);
|
||||
pthread_mutex_t lock;
|
||||
static gboolean force_quit = FALSE;
|
||||
|
||||
// main.c (prof_run section)
|
||||
gboolean background_mode = FALSE;
|
||||
|
||||
void
|
||||
prof_run(gchar* log_level, gchar* account_name, gchar* config_file, gchar* log_file, gchar* theme_name, gchar** commands)
|
||||
{
|
||||
@@ -122,44 +118,42 @@ prof_run(gchar* log_level, gchar* account_name, gchar* config_file, gchar* log_f
|
||||
log_stderr_handler();
|
||||
session_check_autoaway();
|
||||
|
||||
if (!background_mode) {
|
||||
line = commands ? *commands : inp_readline();
|
||||
if (commands && line && memcmp(line, "/sleep", 6) == 0) {
|
||||
if (!g_timer_is_active(waittimer)) {
|
||||
gchar* err_msg;
|
||||
if (strtoi_range(line + 7, &waittime, 0, 300, &err_msg)) {
|
||||
g_timer_start(waittimer);
|
||||
/* Increase the minimal runtime by the waiting time
|
||||
* so we can be sure there's runtime left after executing
|
||||
* the last command.
|
||||
*/
|
||||
min_runtime += waittime;
|
||||
} else {
|
||||
log_error(err_msg);
|
||||
g_free(err_msg);
|
||||
commands = NULL;
|
||||
}
|
||||
} else if (g_timer_elapsed(waittimer, NULL) >= waittime) {
|
||||
g_timer_stop(waittimer);
|
||||
commands++;
|
||||
if (!(*commands))
|
||||
commands = NULL;
|
||||
}
|
||||
cont = TRUE;
|
||||
} else if (line) {
|
||||
ProfWin* window = wins_get_current();
|
||||
cont = cmd_process_input(window, line);
|
||||
if (commands) {
|
||||
commands++;
|
||||
if (!(*commands))
|
||||
commands = NULL;
|
||||
line = commands ? *commands : inp_readline();
|
||||
if (commands && line && memcmp(line, "/sleep", 6) == 0) {
|
||||
if (!g_timer_is_active(waittimer)) {
|
||||
gchar* err_msg;
|
||||
if (strtoi_range(line + 7, &waittime, 0, 300, &err_msg)) {
|
||||
g_timer_start(waittimer);
|
||||
/* Increase the minimal runtime by the waiting time
|
||||
* so we can be sure there's runtime left after executing
|
||||
* the last command.
|
||||
*/
|
||||
min_runtime += waittime;
|
||||
} else {
|
||||
free(line);
|
||||
line = NULL;
|
||||
log_error(err_msg);
|
||||
g_free(err_msg);
|
||||
commands = NULL;
|
||||
}
|
||||
} else {
|
||||
cont = TRUE;
|
||||
} else if (g_timer_elapsed(waittimer, NULL) >= waittime) {
|
||||
g_timer_stop(waittimer);
|
||||
commands++;
|
||||
if (!(*commands))
|
||||
commands = NULL;
|
||||
}
|
||||
cont = TRUE;
|
||||
} else if (line) {
|
||||
ProfWin* window = wins_get_current();
|
||||
cont = cmd_process_input(window, line);
|
||||
if (commands) {
|
||||
commands++;
|
||||
if (!(*commands))
|
||||
commands = NULL;
|
||||
} else {
|
||||
free(line);
|
||||
line = NULL;
|
||||
}
|
||||
} else {
|
||||
cont = TRUE;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBOTR
|
||||
@@ -169,12 +163,7 @@ prof_run(gchar* log_level, gchar* account_name, gchar* config_file, gchar* log_f
|
||||
notify_remind();
|
||||
session_process_events();
|
||||
iq_autoping_check();
|
||||
|
||||
editor_process(wins_get_current());
|
||||
|
||||
if (!background_mode) {
|
||||
ui_update();
|
||||
}
|
||||
ui_update();
|
||||
#ifdef HAVE_GTK
|
||||
tray_update();
|
||||
#endif
|
||||
|
||||
@@ -140,9 +140,6 @@ aesgcm_file_get(void* userdata)
|
||||
"Downloading '%s' failed: Failed to decrypt "
|
||||
"file (%s).",
|
||||
https_url, gcry_strerror(crypt_res));
|
||||
} else {
|
||||
http_print_transfer_update(aesgcm_dl->window, aesgcm_dl->id,
|
||||
"Decrypted file saved to '%s'", aesgcm_dl->filename);
|
||||
}
|
||||
|
||||
if (aesgcm_dl->cmd_template != NULL) {
|
||||
|
||||
@@ -38,200 +38,15 @@
|
||||
#include <fcntl.h>
|
||||
#include <glib.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h> // necessary for readline
|
||||
#include <readline/readline.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "config/files.h"
|
||||
#include "config/preferences.h"
|
||||
#include "editor.h"
|
||||
#include "log.h"
|
||||
#include "common.h"
|
||||
#include "ncurses.h"
|
||||
#include "ui/ui.h"
|
||||
#include "xmpp/xmpp.h"
|
||||
|
||||
EditorTask editor_task = { 0, FALSE, NULL, NULL, PTHREAD_MUTEX_INITIALIZER, 0, NULL, NULL };
|
||||
|
||||
void*
|
||||
editor_thread(void* arg)
|
||||
{
|
||||
EditorTask* task = (EditorTask*)arg;
|
||||
auto_gcharv gchar** argv = g_strsplit(task->editor_cmd, " ", 0);
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
execvp(argv[0], argv);
|
||||
log_error("[Editor] Failed to exec %s", argv[0]);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&task->mutex);
|
||||
if (pid > 0) {
|
||||
task->pid = pid;
|
||||
int status;
|
||||
// Unlock mutex to avoid deadlock on the main loop
|
||||
pthread_mutex_unlock(&task->mutex);
|
||||
waitpid(pid, &status, 0);
|
||||
pthread_mutex_lock(&task->mutex);
|
||||
|
||||
gsize length;
|
||||
if (!g_file_get_contents(task->filename, &task->result, &length, &task->error)) {
|
||||
log_error("[Editor] could not read from %s: %s", task->filename,
|
||||
task->error ? task->error->message : "No GLib error given");
|
||||
task->result = g_strdup(""); // Ensure valid result
|
||||
} else {
|
||||
g_strchomp(task->result);
|
||||
if (remove(task->filename) != 0) {
|
||||
log_error("[Editor] error during file deletion of %s", task->filename);
|
||||
} else {
|
||||
log_debug("[Editor] deleted file: %s", task->filename);
|
||||
}
|
||||
}
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||
task->error = g_error_new(G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
||||
"Editor process failed with status %d", WEXITSTATUS(status));
|
||||
}
|
||||
} else {
|
||||
task->error = g_error_new(G_FILE_ERROR, G_FILE_ERROR_FAILED, "Fork failed: %s", strerror(errno));
|
||||
task->result = g_strdup(""); // Ensure valid result
|
||||
}
|
||||
|
||||
task->active = FALSE;
|
||||
pthread_mutex_unlock(&task->mutex);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Returns true if an error occurred
|
||||
gboolean
|
||||
get_message_from_editor_async(gchar* message)
|
||||
{
|
||||
// Check if editor is already running
|
||||
pthread_mutex_lock(&editor_task.mutex);
|
||||
if (editor_task.active) {
|
||||
pthread_mutex_unlock(&editor_task.mutex);
|
||||
log_error("[Editor] Editor already running");
|
||||
return TRUE;
|
||||
}
|
||||
pthread_mutex_unlock(&editor_task.mutex);
|
||||
|
||||
// Create temporary file
|
||||
auto_gchar gchar* filename = NULL;
|
||||
GError* glib_error = NULL;
|
||||
const char* jid = connection_get_barejid();
|
||||
if (jid) {
|
||||
filename = files_file_in_account_data_path(DIR_EDITOR, jid, "compose.md");
|
||||
} else {
|
||||
log_debug("[Editor] could not get JID");
|
||||
auto_gchar gchar* data_dir = files_get_data_path(DIR_EDITOR);
|
||||
if (!create_dir(data_dir)) {
|
||||
log_error("[Editor] could not create directory %s", data_dir);
|
||||
return TRUE;
|
||||
}
|
||||
filename = g_strdup_printf("%s/compose.md", data_dir);
|
||||
}
|
||||
if (!filename) {
|
||||
log_error("[Editor] something went wrong while creating compose file");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Write message to file
|
||||
gsize messagelen = message ? strlen(message) : 0;
|
||||
if (!g_file_set_contents(filename, message ? message : "", messagelen, &glib_error)) {
|
||||
log_error("[Editor] could not write to %s: %s", filename,
|
||||
glib_error ? glib_error->message : "No GLib error given");
|
||||
if (glib_error) {
|
||||
g_error_free(glib_error);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Prepare editor command
|
||||
auto_gchar gchar* editor = prefs_get_string(PREF_COMPOSE_EDITOR);
|
||||
auto_gchar gchar* editor_with_filename = g_strdup_printf("%s %s", editor, filename);
|
||||
|
||||
// Suspend NCurses
|
||||
def_prog_mode();
|
||||
endwin();
|
||||
|
||||
// Initialize thread task
|
||||
pthread_mutex_lock(&editor_task.mutex);
|
||||
editor_task.active = TRUE;
|
||||
editor_task.result = NULL;
|
||||
editor_task.error = NULL;
|
||||
g_free(editor_task.filename);
|
||||
g_free(editor_task.editor_cmd);
|
||||
editor_task.filename = g_strdup(filename);
|
||||
editor_task.editor_cmd = g_strdup(editor_with_filename);
|
||||
pthread_mutex_unlock(&editor_task.mutex);
|
||||
|
||||
// Set background mode
|
||||
background_mode = TRUE;
|
||||
log_debug("[Editor] Entering background mode");
|
||||
|
||||
// Start editor thread
|
||||
if (pthread_create(&editor_task.thread, NULL, editor_thread, &editor_task) != 0) {
|
||||
pthread_mutex_lock(&editor_task.mutex);
|
||||
editor_task.active = FALSE;
|
||||
editor_task.error = g_error_new(G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
||||
"Failed to create editor thread: %s", strerror(errno));
|
||||
g_free(editor_task.filename);
|
||||
g_free(editor_task.editor_cmd);
|
||||
editor_task.filename = NULL;
|
||||
editor_task.editor_cmd = NULL;
|
||||
pthread_mutex_unlock(&editor_task.mutex);
|
||||
background_mode = FALSE;
|
||||
log_debug("[Editor] Exiting background mode");
|
||||
reset_prog_mode();
|
||||
doupdate();
|
||||
log_error("[Editor] Failed to create editor thread");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
editor_process(ProfWin* window)
|
||||
{
|
||||
pthread_mutex_lock(&editor_task.mutex);
|
||||
if (editor_task.active) {
|
||||
pthread_mutex_unlock(&editor_task.mutex);
|
||||
return;
|
||||
}
|
||||
if (!editor_task.result) {
|
||||
pthread_mutex_unlock(&editor_task.mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
g_strchomp(editor_task.result);
|
||||
rl_replace_line(editor_task.result, 0);
|
||||
rl_point = rl_end;
|
||||
rl_forced_update_display();
|
||||
reset_prog_mode();
|
||||
doupdate();
|
||||
ui_resize();
|
||||
g_free(editor_task.result);
|
||||
g_free(editor_task.filename);
|
||||
g_free(editor_task.editor_cmd);
|
||||
editor_task.result = NULL;
|
||||
editor_task.filename = NULL;
|
||||
editor_task.editor_cmd = NULL;
|
||||
if (editor_task.error) {
|
||||
log_error("[Editor] %s", editor_task.error->message);
|
||||
g_error_free(editor_task.error);
|
||||
editor_task.error = NULL;
|
||||
}
|
||||
pthread_mutex_unlock(&editor_task.mutex);
|
||||
background_mode = FALSE;
|
||||
log_debug("[Editor] Exiting background mode");
|
||||
}
|
||||
|
||||
// Deprecated synchronous editor call. Returns a message as returned_message.
|
||||
// Please avoid using it, since it blocks execution of the message handling and other important functionality until the editor is closed.
|
||||
// Returns true if an error occurred
|
||||
gboolean
|
||||
get_message_from_editor(gchar* message, gchar** returned_message)
|
||||
|
||||
@@ -37,24 +37,8 @@
|
||||
#ifndef TOOLS_EDITOR_H
|
||||
#define TOOLS_EDITOR_H
|
||||
|
||||
#include "ui/win_types.h"
|
||||
#include <glib.h>
|
||||
typedef struct
|
||||
{
|
||||
pid_t pid; // Editor process PID
|
||||
gboolean active; // Thread running
|
||||
gchar* result; // Edited message
|
||||
GError* error; // Error if any
|
||||
pthread_mutex_t mutex; // Protect access
|
||||
pthread_t thread; // Editor thread
|
||||
gchar* filename; // Temporary file path
|
||||
gchar* editor_cmd; // Editor command with filename
|
||||
} EditorTask;
|
||||
|
||||
extern EditorTask editor_task;
|
||||
|
||||
gboolean get_message_from_editor(gchar* message, gchar** returned_message);
|
||||
gboolean get_message_from_editor_async(gchar* message);
|
||||
void editor_process(ProfWin* window);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -109,7 +109,6 @@ _buffer_add(ProfBuff buffer, const char* show_char, int pad_indent, GDateTime* t
|
||||
buffer->lines += e->_lines;
|
||||
|
||||
while (g_slist_length(buffer->entries) >= MAX_BUFFER_SIZE) {
|
||||
// Delete message from the opposite size to free buffer
|
||||
GSList* buffer_entry_to_delete = append ? buffer->entries : g_slist_last(buffer->entries);
|
||||
ProfBuffEntry* entry_to_delete = (ProfBuffEntry*)buffer_entry_to_delete->data;
|
||||
buffer->lines -= entry_to_delete->_lines;
|
||||
@@ -118,13 +117,7 @@ _buffer_add(ProfBuff buffer, const char* show_char, int pad_indent, GDateTime* t
|
||||
}
|
||||
|
||||
if (from_jid && y_end_pos == y_start_pos) {
|
||||
log_warning("Ncurses Overflow! From: %s, position: %d, ID: %s, append: %s, used message buffer size: %d, message buffer size: %d, rendered lines buffer size: %d",
|
||||
from_jid, y_start_pos, id, append ? "TRUE" : "FALSE", g_slist_length(buffer->entries), MAX_BUFFER_SIZE, PAD_SIZE);
|
||||
// At this point we have a message that caused overflow of the render buffer.
|
||||
// Ideally, we want to clean other messages to rerender everything properly. To do so,
|
||||
// first we need to determine the size of the message that we are trying to display,
|
||||
// then we need to print the message.
|
||||
// However, _buffer_add is too late in the code to do this, therefore it has to be done in the win_print_old_history.
|
||||
log_warning("Ncurses Overflow! From: %s, pos: %d, ID: %s, message: %s", from_jid, y_end_pos, id, message);
|
||||
}
|
||||
|
||||
buffer->entries = append ? g_slist_append(buffer->entries, e) : g_slist_prepend(buffer->entries, e);
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "glib.h"
|
||||
#include "xmpp/chat_session.h"
|
||||
#include "window_list.h"
|
||||
#include "xmpp/roster_list.h"
|
||||
@@ -562,8 +561,7 @@ static void
|
||||
_chatwin_history(ProfChatWin* chatwin, const char* const contact_barejid)
|
||||
{
|
||||
if (!chatwin->history_shown) {
|
||||
GSList* history = NULL;
|
||||
log_database_get_previous_chat(contact_barejid, NULL, NULL, FALSE, FALSE, &history);
|
||||
GSList* history = log_database_get_previous_chat(contact_barejid, NULL, NULL, FALSE, FALSE);
|
||||
GSList* curr = history;
|
||||
|
||||
while (curr) {
|
||||
@@ -585,17 +583,15 @@ _chatwin_history(ProfChatWin* chatwin, const char* const contact_barejid)
|
||||
// Print history starting from start_time to end_time if end_time is null the
|
||||
// first entry's timestamp in the buffer is used. Flip true to prepend to buffer.
|
||||
// Timestamps should be in iso8601
|
||||
db_history_result_t
|
||||
chatwin_db_history(ProfChatWin* chatwin, const gchar* start_time, const gchar* end_time, gboolean flip)
|
||||
gboolean
|
||||
chatwin_db_history(ProfChatWin* chatwin, const char* start_time, char* end_time, gboolean flip)
|
||||
{
|
||||
auto_gchar gchar* _end_time = NULL;
|
||||
if (!end_time && buffer_size(((ProfWin*)chatwin)->layout->buffer) > 0) {
|
||||
_end_time = g_date_time_format_iso8601(buffer_get_entry(((ProfWin*)chatwin)->layout->buffer, 0)->time);
|
||||
end_time = _end_time;
|
||||
if (!end_time) {
|
||||
end_time = buffer_size(((ProfWin*)chatwin)->layout->buffer) == 0 ? NULL : g_date_time_format_iso8601(buffer_get_entry(((ProfWin*)chatwin)->layout->buffer, 0)->time);
|
||||
}
|
||||
|
||||
GSList* history = NULL;
|
||||
db_history_result_t result = log_database_get_previous_chat(chatwin->barejid, start_time, end_time, !flip, flip, &history);
|
||||
GSList* history = log_database_get_previous_chat(chatwin->barejid, start_time, end_time, !flip, flip);
|
||||
gboolean has_items = g_slist_length(history) != 0;
|
||||
GSList* curr = history;
|
||||
|
||||
while (curr) {
|
||||
@@ -614,12 +610,9 @@ chatwin_db_history(ProfChatWin* chatwin, const gchar* start_time, const gchar* e
|
||||
}
|
||||
|
||||
g_slist_free_full(history, (GDestroyNotify)message_free);
|
||||
// TODO: Potential optimization
|
||||
// if (flip)
|
||||
// since adding messages to history without overflowing buffer does not require a win_redraw
|
||||
win_redraw((ProfWin*)chatwin);
|
||||
|
||||
return result;
|
||||
return has_items;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -387,9 +387,16 @@ cons_about(void)
|
||||
_cons_splash_logo();
|
||||
} else {
|
||||
auto_gchar gchar* prof_version = prof_get_version();
|
||||
win_println(console, THEME_DEFAULT, "-", "Welcome to CProof, version %s", prof_version);
|
||||
win_println(console, THEME_DEFAULT, "-", "Welcome to Profanity, version %s", prof_version);
|
||||
}
|
||||
|
||||
win_println(console, THEME_DEFAULT, "-", "Copyright (C) 2012 - 2019 James Booth <boothj5web@gmail.com>.");
|
||||
win_println(console, THEME_DEFAULT, "-", "Copyright (C) 2019 - 2025 Michael Vetter <jubalh@iodoru.org>.");
|
||||
win_println(console, THEME_DEFAULT, "-", "License GPLv3+: GNU GPL version 3 or later <https://www.gnu.org/licenses/gpl.html>");
|
||||
win_println(console, THEME_DEFAULT, "-", "");
|
||||
win_println(console, THEME_DEFAULT, "-", "This is free software; you are free to change and redistribute it.");
|
||||
win_println(console, THEME_DEFAULT, "-", "There is NO WARRANTY, to the extent permitted by law.");
|
||||
win_println(console, THEME_DEFAULT, "-", "");
|
||||
win_println(console, THEME_DEFAULT, "-", "Type '/help' to show complete help.");
|
||||
win_println(console, THEME_DEFAULT, "-", "");
|
||||
|
||||
@@ -477,7 +484,7 @@ cons_show_wins(gboolean unread)
|
||||
}
|
||||
curr = g_slist_next(curr);
|
||||
}
|
||||
g_slist_free_full(window_strings, g_free);
|
||||
g_slist_free_full(window_strings, free);
|
||||
|
||||
cons_alert(NULL);
|
||||
}
|
||||
@@ -498,7 +505,7 @@ cons_show_wins_attention()
|
||||
}
|
||||
curr = g_slist_next(curr);
|
||||
}
|
||||
g_slist_free_full(window_strings, g_free);
|
||||
g_slist_free_full(window_strings, free);
|
||||
|
||||
cons_alert(NULL);
|
||||
}
|
||||
@@ -2697,12 +2704,13 @@ _cons_splash_logo(void)
|
||||
ProfWin* console = wins_get_console();
|
||||
win_println(console, THEME_DEFAULT, "-", "Welcome to");
|
||||
|
||||
win_println(console, THEME_SPLASH, "-", " _____ _____ __ ");
|
||||
win_println(console, THEME_SPLASH, "-", " / ____| __ \\ / _|");
|
||||
win_println(console, THEME_SPLASH, "-", " | | | |__) | __ ___ ___ | |_ ");
|
||||
win_println(console, THEME_SPLASH, "-", " | | | ___/ '__/ _ \\ / _ \\| _|");
|
||||
win_println(console, THEME_SPLASH, "-", " | |____| | | | | (_) | (_) | | ");
|
||||
win_println(console, THEME_SPLASH, "-", " \\_____|_| |_| \\___/ \\___/|_| ");
|
||||
win_println(console, THEME_SPLASH, "-", " ___ _ ");
|
||||
win_println(console, THEME_SPLASH, "-", " / __) (_)_ ");
|
||||
win_println(console, THEME_SPLASH, "-", " ____ ___ ___ | |__ ____ ____ _| |_ _ _ ");
|
||||
win_println(console, THEME_SPLASH, "-", "| _ \\ / __) _ \\| __) _ | _ \\| | _) | | |");
|
||||
win_println(console, THEME_SPLASH, "-", "| | ) | | | (_) | | | ( | | | | | | |_| |_| |");
|
||||
win_println(console, THEME_SPLASH, "-", "| ||_/|_| \\___/|_| \\_||_|_| |_|_|\\___)__ |");
|
||||
win_println(console, THEME_SPLASH, "-", "|_| (____/ ");
|
||||
win_println(console, THEME_SPLASH, "-", "");
|
||||
|
||||
auto_gchar gchar* prof_version = prof_get_version();
|
||||
|
||||
@@ -974,7 +974,14 @@ _inp_rl_send_to_editor(int count, int key)
|
||||
|
||||
auto_gchar gchar* message = NULL;
|
||||
|
||||
get_message_from_editor_async(rl_line_buffer);
|
||||
if (get_message_from_editor(rl_line_buffer, &message)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rl_replace_line(message, 0);
|
||||
ui_resize();
|
||||
rl_point = rl_end;
|
||||
rl_forced_update_display();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
#include "config/account.h"
|
||||
#include "config/preferences.h"
|
||||
#include "command/cmd_funcs.h"
|
||||
#include "database.h"
|
||||
#include "ui/win_types.h"
|
||||
#include "xmpp/message.h"
|
||||
#include "xmpp/muc.h"
|
||||
@@ -146,7 +145,7 @@ void chatwin_set_incoming_char(ProfChatWin* chatwin, const char* const ch);
|
||||
void chatwin_unset_incoming_char(ProfChatWin* chatwin);
|
||||
void chatwin_set_outgoing_char(ProfChatWin* chatwin, const char* const ch);
|
||||
void chatwin_unset_outgoing_char(ProfChatWin* chatwin);
|
||||
db_history_result_t chatwin_db_history(ProfChatWin* chatwin, const gchar* start_time, const gchar* end_time, gboolean flip);
|
||||
gboolean chatwin_db_history(ProfChatWin* chatwin, const char* start_time, char* end_time, gboolean flip);
|
||||
|
||||
// MUC window
|
||||
ProfMucWin* mucwin_new(const char* const barejid);
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "database.h"
|
||||
#include "ui/window_list.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
@@ -63,8 +62,9 @@
|
||||
#include "xmpp/xmpp.h"
|
||||
#include "xmpp/roster_list.h"
|
||||
|
||||
static const int PAD_SIZE = 100;
|
||||
static const char* LOADING_MESSAGE = "Loading older messages…";
|
||||
static const char* CONS_WIN_TITLE = "CProof. Type /help for help information.";
|
||||
static const char* CONS_WIN_TITLE = "Profanity. Type /help for help information.";
|
||||
static const char* XML_WIN_TITLE = "XML Console";
|
||||
|
||||
#define CEILING(X) (X - (int)(X) > 0 ? (int)(X + 1) : (int)(X))
|
||||
@@ -629,68 +629,54 @@ win_free(ProfWin* window)
|
||||
void
|
||||
win_page_up(ProfWin* window, int scroll_size)
|
||||
{
|
||||
// Page offset from the start of the NCurses PAD (invisible window)
|
||||
int* page_start = &(window->layout->y_pos);
|
||||
int page_start_initial = *page_start;
|
||||
// Size of the visible chat page
|
||||
int total_rows = getcury(window->layout->win);
|
||||
int page_space = getmaxy(stdscr) - 4;
|
||||
if (scroll_size == 0)
|
||||
scroll_size = page_space;
|
||||
win_scroll_state_t* scroll_state = &window->scroll_state;
|
||||
*scroll_state = (*scroll_state == WIN_SCROLL_REACHED_BOTTOM) ? WIN_SCROLL_INNER : *scroll_state;
|
||||
*page_start -= scroll_size;
|
||||
gboolean has_scroll_past_buffer = *page_start < 0;
|
||||
|
||||
if (has_scroll_past_buffer && window->type == WIN_CHAT) {
|
||||
if (*page_start == -scroll_size && window->type == WIN_CHAT) {
|
||||
ProfChatWin* chatwin = (ProfChatWin*)window;
|
||||
ProfBuffEntry* first_entry = buffer_size(window->layout->buffer) != 0 ? buffer_get_entry(window->layout->buffer, 0) : NULL;
|
||||
|
||||
gboolean is_still_fetching_mam = first_entry && (first_entry->theme_item == THEME_ROOMINFO && g_strcmp0(first_entry->message, LOADING_MESSAGE) == 0);
|
||||
if (!is_still_fetching_mam) {
|
||||
// WIN_SCROLL_REACHED_TOP means that we reached top of DB and there is no need to refetch data from it
|
||||
gboolean is_db_offset_jump_needed = false;
|
||||
// Don't do anything if still fetching mam messages
|
||||
if (first_entry && !(first_entry->theme_item == THEME_ROOMINFO && g_strcmp0(first_entry->message, LOADING_MESSAGE) == 0)) {
|
||||
if (*scroll_state != WIN_SCROLL_REACHED_TOP) {
|
||||
db_history_result_t db_response = chatwin_db_history(chatwin, NULL, NULL, TRUE);
|
||||
is_db_offset_jump_needed = db_response == DB_RESPONSE_SUCCESS;
|
||||
*scroll_state = db_response == DB_RESPONSE_EMPTY ? WIN_SCROLL_REACHED_TOP : WIN_SCROLL_INNER;
|
||||
log_debug("Scroll state after DB history fetch: %s", *scroll_state ? "WIN_SCROLL_REACHED_TOP" : "WIN_SCROLL_INNER");
|
||||
*scroll_state = !chatwin_db_history(chatwin, NULL, NULL, TRUE) ? WIN_SCROLL_REACHED_TOP : WIN_SCROLL_INNER;
|
||||
}
|
||||
|
||||
if (*scroll_state == WIN_SCROLL_REACHED_TOP) {
|
||||
*page_start = 0;
|
||||
if (prefs_get_boolean(PREF_MAM)) {
|
||||
win_print_loading_history(window);
|
||||
iq_mam_request_older(chatwin);
|
||||
}
|
||||
if (*scroll_state == WIN_SCROLL_REACHED_TOP && prefs_get_boolean(PREF_MAM)) {
|
||||
win_print_loading_history(window);
|
||||
iq_mam_request_older(chatwin);
|
||||
}
|
||||
|
||||
// Recalculate scroll offset after loading older messages from the DB.
|
||||
// *page_start may become negative due to paging up beyond the current buffer.
|
||||
// To maintain smooth scroll positioning, we adjust it relative to the visual offset
|
||||
// (y_start_pos) of the first buffer entry *before* DB fetch.
|
||||
// This ensures a seamless transition as older messages are prepended, regardless
|
||||
// of how many visual lines they occupy (since messages can vary in height).
|
||||
// For example, if *page_start == -5 and first_entry->y_start_pos == 40,
|
||||
// we shift the scroll to 35, preserving the visual context for the user.
|
||||
if (is_db_offset_jump_needed) {
|
||||
*page_start = first_entry ? first_entry->y_start_pos + *page_start : 0;
|
||||
}
|
||||
int buff_size = buffer_size(window->layout->buffer);
|
||||
int offset_entry_id = buff_size > 10 ? 10 : buff_size - 1;
|
||||
int offset = buffer_get_entry(window->layout->buffer, offset_entry_id)->y_end_pos;
|
||||
*page_start = offset - page_space;
|
||||
}
|
||||
}
|
||||
|
||||
// went past beginning, show first page
|
||||
if (*page_start < 0) {
|
||||
log_debug("win_page_up(): *page_start adjusted to 0 due to negative value (expected if insufficient history messages). Previous value: %d", *page_start);
|
||||
*page_start = 0;
|
||||
}
|
||||
|
||||
// Update window location only if position has changed
|
||||
window->layout->paged = 1;
|
||||
|
||||
// update only if position has changed
|
||||
if (page_start_initial != *page_start) {
|
||||
win_update_virtual(window);
|
||||
}
|
||||
|
||||
// Update scrolling state
|
||||
int total_rows = getcury(window->layout->win);
|
||||
window->layout->paged = (total_rows) - *page_start > page_space;
|
||||
// switch off page if last line and space line visible
|
||||
if ((total_rows) - *page_start == page_space) {
|
||||
window->layout->paged = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -710,22 +696,20 @@ win_page_down(ProfWin* window, int scroll_size)
|
||||
// Scrolled down after reaching the bottom of the page
|
||||
if ((*page_start > total_rows - page_space || (*page_start == page_space && *page_start >= total_rows)) && window->type == WIN_CHAT) {
|
||||
int bf_size = buffer_size(window->layout->buffer);
|
||||
if (bf_size > 0 && *scroll_state != WIN_SCROLL_REACHED_BOTTOM) {
|
||||
// How many lines are left until end of the screen
|
||||
int current_offset = total_rows - *page_start;
|
||||
GDateTime* now = g_date_time_new_now_local();
|
||||
if (bf_size > 0) {
|
||||
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);
|
||||
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;
|
||||
|
||||
// similar to page_up (see explanation there)
|
||||
// Get offset of the message that was the latest prior to loading messages from the DB
|
||||
int original_pos = last_entry->y_end_pos;
|
||||
*page_start = original_pos - current_offset;
|
||||
GDateTime* now = g_date_time_new_now_local();
|
||||
gchar* end_date = g_date_time_format_iso8601(now);
|
||||
g_date_time_unref(now);
|
||||
if (*scroll_state != WIN_SCROLL_REACHED_BOTTOM && !chatwin_db_history((ProfChatWin*)window, start, end_date, FALSE)) {
|
||||
*scroll_state = WIN_SCROLL_REACHED_BOTTOM;
|
||||
} else if (*scroll_state == WIN_SCROLL_REACHED_BOTTOM) {
|
||||
g_free(end_date);
|
||||
}
|
||||
|
||||
int offset = last_entry->y_end_pos - 1;
|
||||
*page_start = offset - page_space + scroll_size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,9 +56,6 @@
|
||||
#include "xmpp/contact.h"
|
||||
#include "xmpp/muc.h"
|
||||
|
||||
// Max lines per window rendered by NCurses
|
||||
static const int PAD_SIZE = 10000;
|
||||
|
||||
void win_move_to_end(ProfWin* window);
|
||||
void win_show_status_string(ProfWin* window, const char* const from,
|
||||
const char* const show, const char* const status,
|
||||
|
||||
@@ -258,20 +258,22 @@ GList*
|
||||
wins_get_private_chats(const char* const roomjid)
|
||||
{
|
||||
GList* result = NULL;
|
||||
auto_gchar gchar* prefix = g_strdup_printf("%s/", roomjid);
|
||||
GString* prefix = g_string_new(roomjid);
|
||||
g_string_append(prefix, "/");
|
||||
GList* curr = values;
|
||||
|
||||
while (curr) {
|
||||
ProfWin* window = curr->data;
|
||||
if (window->type == WIN_PRIVATE) {
|
||||
ProfPrivateWin* privatewin = (ProfPrivateWin*)window;
|
||||
if (roomjid == NULL || g_str_has_prefix(privatewin->fulljid, prefix)) {
|
||||
if (roomjid == NULL || g_str_has_prefix(privatewin->fulljid, prefix->str)) {
|
||||
result = g_list_append(result, privatewin);
|
||||
}
|
||||
}
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
|
||||
g_string_free(prefix, TRUE);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1065,13 +1067,19 @@ wins_create_summary(gboolean unread)
|
||||
while (curr) {
|
||||
ProfWin* window = g_hash_table_lookup(windows, curr->data);
|
||||
if (!unread || (unread && win_unread(window) > 0)) {
|
||||
GString* line = g_string_new("");
|
||||
|
||||
int ui_index = GPOINTER_TO_INT(curr->data);
|
||||
auto_gchar gchar* winstring = win_to_string(window);
|
||||
if (!winstring) {
|
||||
g_string_free(line, TRUE);
|
||||
continue;
|
||||
}
|
||||
gchar* line = g_strdup_printf("%d: %s", ui_index, winstring);
|
||||
result = g_slist_append(result, line);
|
||||
|
||||
g_string_append_printf(line, "%d: %s", ui_index, winstring);
|
||||
|
||||
result = g_slist_append(result, strdup(line->str));
|
||||
g_string_free(line, TRUE);
|
||||
}
|
||||
|
||||
curr = g_list_next(curr);
|
||||
@@ -1100,13 +1108,19 @@ wins_create_summary_attention()
|
||||
has_attention = mucwin->has_attention;
|
||||
}
|
||||
if (has_attention) {
|
||||
GString* line = g_string_new("");
|
||||
|
||||
int ui_index = GPOINTER_TO_INT(curr->data);
|
||||
auto_gchar gchar* winstring = win_to_string(window);
|
||||
if (!winstring) {
|
||||
g_string_free(line, TRUE);
|
||||
continue;
|
||||
}
|
||||
gchar* line = g_strdup_printf("%d: %s", ui_index, winstring);
|
||||
result = g_slist_append(result, line);
|
||||
|
||||
g_string_append_printf(line, "%d: %s", ui_index, winstring);
|
||||
|
||||
result = g_slist_append(result, strdup(line->str));
|
||||
g_string_free(line, TRUE);
|
||||
}
|
||||
curr = g_list_next(curr);
|
||||
}
|
||||
|
||||
@@ -119,14 +119,6 @@ caps_init(void)
|
||||
g_hash_table_add(prof_features, strdup(STANZA_NS_LAST_MESSAGE_CORRECTION));
|
||||
}
|
||||
|
||||
if (prefs_get_boolean(PREF_MOOD)) {
|
||||
g_hash_table_add(prof_features, strdup(STANZA_NS_MOOD_NOTIFY));
|
||||
}
|
||||
|
||||
#ifdef HAVE_OMEMO
|
||||
g_hash_table_add(prof_features, strdup(XMPP_FEATURE_OMEMO_DEVICELIST_NOTIFY));
|
||||
#endif
|
||||
|
||||
my_sha1 = NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -2752,22 +2752,6 @@ iq_mam_request(ProfChatWin* win, GDateTime* enddate)
|
||||
return;
|
||||
}
|
||||
|
||||
// Trim the last 3 characters from the datetime string to remove unwanted suffix (timezone offset)
|
||||
static void
|
||||
_truncate_datetime_suffix(gchar* str)
|
||||
{
|
||||
if (!str) {
|
||||
log_warning("_truncate_datetime_suffix(): unexpected null datetime string");
|
||||
return;
|
||||
}
|
||||
size_t len = strlen(str);
|
||||
if (len >= 3) {
|
||||
str[len - 3] = '\0';
|
||||
} else {
|
||||
log_warning("_truncate_datetime_suffix(): unexpected short datetime string: %s", str);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
_mam_rsm_id_handler(xmpp_stanza_t* const stanza, void* const userdata)
|
||||
{
|
||||
@@ -2789,17 +2773,17 @@ _mam_rsm_id_handler(xmpp_stanza_t* const stanza, void* const userdata)
|
||||
|
||||
buffer_remove_entry(window->layout->buffer, 0);
|
||||
|
||||
auto_gchar gchar* start_str = NULL;
|
||||
auto_char char* start_str = NULL;
|
||||
if (data->start_datestr) {
|
||||
start_str = g_strdup(data->start_datestr);
|
||||
start_str = strdup(data->start_datestr);
|
||||
// Convert to iso8601
|
||||
_truncate_datetime_suffix(start_str);
|
||||
start_str[strlen(start_str) - 3] = '\0';
|
||||
}
|
||||
auto_gchar gchar* end_str = NULL;
|
||||
char* end_str = NULL;
|
||||
if (data->end_datestr) {
|
||||
end_str = g_strdup(data->end_datestr);
|
||||
end_str = strdup(data->end_datestr);
|
||||
// Convert to iso8601
|
||||
_truncate_datetime_suffix(end_str);
|
||||
end_str[strlen(end_str) - 3] = '\0';
|
||||
}
|
||||
|
||||
if (is_complete || !data->fetch_next) {
|
||||
|
||||
@@ -190,7 +190,7 @@ get_nick_from_full_jid(const char* const full_room_jid)
|
||||
/*
|
||||
* get the fulljid, fall back to the barejid
|
||||
*/
|
||||
const char*
|
||||
char*
|
||||
jid_fulljid_or_barejid(Jid* jid)
|
||||
{
|
||||
if (jid->fulljid) {
|
||||
|
||||
@@ -63,7 +63,7 @@ gboolean jid_is_valid_room_form(Jid* jid);
|
||||
char* create_fulljid(const char* const barejid, const char* const resource);
|
||||
char* get_nick_from_full_jid(const char* const full_room_jid);
|
||||
|
||||
const char* jid_fulljid_or_barejid(Jid* jid);
|
||||
char* jid_fulljid_or_barejid(Jid* jid);
|
||||
gchar* jid_random_resource(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -621,7 +621,7 @@ _available_handler(xmpp_stanza_t* const stanza)
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
const char* jid = jid_fulljid_or_barejid(xmpp_presence->jid);
|
||||
char* jid = jid_fulljid_or_barejid(xmpp_presence->jid);
|
||||
log_debug("Presence available handler fired for: %s", jid);
|
||||
}
|
||||
|
||||
@@ -632,7 +632,7 @@ _available_handler(xmpp_stanza_t* const stanza)
|
||||
XMPPCaps* caps = stanza_parse_caps(stanza);
|
||||
if ((g_strcmp0(my_jid->fulljid, xmpp_presence->jid->fulljid) != 0) && caps) {
|
||||
log_debug("Presence contains capabilities.");
|
||||
const char* jid = jid_fulljid_or_barejid(xmpp_presence->jid);
|
||||
char* jid = jid_fulljid_or_barejid(xmpp_presence->jid);
|
||||
_handle_caps(jid, caps);
|
||||
}
|
||||
stanza_free_caps(caps);
|
||||
@@ -644,7 +644,7 @@ _available_handler(xmpp_stanza_t* const stanza)
|
||||
const char* account_name = session_get_account_name();
|
||||
int max_sessions = accounts_get_max_sessions(account_name);
|
||||
if (max_sessions > 0) {
|
||||
auto_gchar gchar* cur_resource = accounts_get_resource(account_name);
|
||||
const gchar* cur_resource = accounts_get_resource(account_name);
|
||||
int res_count = connection_count_available_resources();
|
||||
if (res_count > max_sessions && g_strcmp0(cur_resource, resource->name)) {
|
||||
ProfWin* console = wins_get_console();
|
||||
|
||||
@@ -275,8 +275,11 @@ roster_remove(const char* const name, const char* const barejid)
|
||||
if (contact) {
|
||||
GList* resources = p_contact_get_available_resources(contact);
|
||||
while (resources) {
|
||||
auto_gchar gchar* fulljid = g_strdup_printf("%s/%s", barejid, (char*)resources->data);
|
||||
autocomplete_remove(roster->fulljid_ac, fulljid);
|
||||
GString* fulljid = g_string_new(barejid);
|
||||
g_string_append(fulljid, "/");
|
||||
g_string_append(fulljid, resources->data);
|
||||
autocomplete_remove(roster->fulljid_ac, fulljid->str);
|
||||
g_string_free(fulljid, TRUE);
|
||||
resources = g_list_next(resources);
|
||||
}
|
||||
g_list_free(resources);
|
||||
|
||||
@@ -281,7 +281,7 @@ shows_all_messages_in_console_when_window_not_focussed(void **state)
|
||||
assert_true(prof_output_exact("-> You have joined the room as stabber, role: participant, affiliation: none"));
|
||||
|
||||
prof_input("/win 1");
|
||||
assert_true(prof_output_exact("CProof. Type /help for help information."));
|
||||
assert_true(prof_output_exact("Profanity. Type /help for help information."));
|
||||
|
||||
stbbr_send(
|
||||
"<message type='groupchat' to='stabber@localhost/profanity' from='testroom@conference.localhost/testoccupant'>"
|
||||
@@ -322,7 +322,7 @@ shows_first_message_in_console_when_window_not_focussed(void **state)
|
||||
assert_true(prof_output_exact("-> You have joined the room as stabber, role: participant, affiliation: none"));
|
||||
|
||||
prof_input("/win 1");
|
||||
assert_true(prof_output_exact("CProof. Type /help for help information."));
|
||||
assert_true(prof_output_exact("Profanity. Type /help for help information."));
|
||||
|
||||
stbbr_send(
|
||||
"<message type='groupchat' to='stabber@localhost/profanity' from='testroom@conference.localhost/testoccupant'>"
|
||||
@@ -368,7 +368,7 @@ shows_no_message_in_console_when_window_not_focussed(void **state)
|
||||
assert_true(prof_output_exact("-> You have joined the room as stabber, role: participant, affiliation: none"));
|
||||
|
||||
prof_input("/win 1");
|
||||
assert_true(prof_output_exact("CProof. Type /help for help information."));
|
||||
assert_true(prof_output_exact("Profanity. Type /help for help information."));
|
||||
|
||||
stbbr_send(
|
||||
"<message type='groupchat' to='stabber@localhost/profanity' from='testroom@conference.localhost/testoccupant'>"
|
||||
|
||||
@@ -109,7 +109,7 @@ omemo_encrypt_file(FILE* in, FILE* out, off_t file_size, int* gcry_res)
|
||||
{
|
||||
return NULL;
|
||||
};
|
||||
void omemo_free(void* a) {};
|
||||
void omemo_free(void* a){};
|
||||
|
||||
uint32_t
|
||||
omemo_device_id()
|
||||
|
||||
@@ -219,7 +219,7 @@ returns_fulljid_when_exists(void** state)
|
||||
{
|
||||
Jid* jid = jid_create("localpart@domainpart/resourcepart");
|
||||
|
||||
const char* result = jid_fulljid_or_barejid(jid);
|
||||
char* result = jid_fulljid_or_barejid(jid);
|
||||
|
||||
assert_string_equal("localpart@domainpart/resourcepart", result);
|
||||
|
||||
@@ -231,7 +231,7 @@ returns_barejid_when_fulljid_not_exists(void** state)
|
||||
{
|
||||
Jid* jid = jid_create("localpart@domainpart");
|
||||
|
||||
const char* result = jid_fulljid_or_barejid(jid);
|
||||
char* result = jid_fulljid_or_barejid(jid);
|
||||
|
||||
assert_string_equal("localpart@domainpart", result);
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ aesgcm_file_get(void* userdata)
|
||||
return NULL;
|
||||
};
|
||||
|
||||
void aesgcm_download_cancel_processes(ProfWin* window) {};
|
||||
void aesgcm_download_add_download(AESGCMDownload* download) {};
|
||||
void aesgcm_download_cancel_processes(ProfWin* window){};
|
||||
void aesgcm_download_add_download(AESGCMDownload* download){};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -27,7 +27,7 @@ http_file_get(void* userdata)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void http_download_cancel_processes() {};
|
||||
void http_download_add_download() {};
|
||||
void http_download_cancel_processes(){};
|
||||
void http_download_add_download(){};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -38,7 +38,7 @@ file_size(int filedes)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void http_upload_cancel_processes() {};
|
||||
void http_upload_add_upload() {};
|
||||
void http_upload_cancel_processes(){};
|
||||
void http_upload_add_upload(){};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -484,10 +484,10 @@ mucwin_unset_message_char(ProfMucWin* mucwin)
|
||||
{
|
||||
}
|
||||
|
||||
void win_update_entry_message(ProfWin* window, const char* const id, const char* const message) {};
|
||||
void win_mark_received(ProfWin* window, const char* const id) {};
|
||||
void win_print_http_transfer(ProfWin* window, const char* const message, char* id) {};
|
||||
void win_print_loading_history(ProfWin* window) {};
|
||||
void win_update_entry_message(ProfWin* window, const char* const id, const char* const message){};
|
||||
void win_mark_received(ProfWin* window, const char* const id){};
|
||||
void win_print_http_transfer(ProfWin* window, const char* const message, char* id){};
|
||||
void win_print_loading_history(ProfWin* window){};
|
||||
|
||||
void
|
||||
ui_show_roster(void)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include <glib.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void avatar_pep_subscribe(void) {};
|
||||
void avatar_pep_subscribe(void){};
|
||||
|
||||
gboolean
|
||||
avatar_get_by_nick(const char* nick, gboolean open)
|
||||
|
||||
@@ -312,8 +312,8 @@ presence_sub_request_exists(const char* const bare_jid)
|
||||
}
|
||||
|
||||
// iq functions
|
||||
void iq_disable_carbons() {};
|
||||
void iq_enable_carbons() {};
|
||||
void iq_disable_carbons(){};
|
||||
void iq_enable_carbons(){};
|
||||
void
|
||||
iq_send_software_version(const char* const fulljid)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user