Compare commits

...

22 Commits

Author SHA1 Message Date
692c9513c0 docs(prof.py): overhaul documentation to align with Google Python Style Guide
Some checks failed
CI / Check spelling (pull_request) Successful in 20s
CI / Test C API Documentation Generation (pull_request) Failing after 26s
CI / Check coding style (pull_request) Successful in 32s
CI / Test Python API Documentation Generation (pull_request) Failing after 24s
CI / Linux (arch) (pull_request) Has been cancelled
CI / Linux (debian) (pull_request) Has been cancelled
CI / Linux (ubuntu) (pull_request) Has been cancelled
- Updated project references from Profanity to CProof.
- Removed Python 2 and unicode references.
- Added type hints for all parameters and return types.
- Organized functions into logical sections with RST comments for Sphinx.
- Improved wording for clarity and precision based on source code analysis.
- Ensured compliance with Google Python Style Guide for readable docstrings.

Related to #30
2025-09-10 18:10:37 +02:00
a21dd9de5b ci: add GitHub Actions workflow to test C and Python API doc generation
Some checks failed
CI / Check coding style (pull_request) Successful in 38s
CI / Check spelling (pull_request) Successful in 19s
CI / Test C API Documentation Generation (pull_request) Failing after 27s
CI / Test Python API Documentation Generation (pull_request) Failing after 27s
CI / Linux (arch) (pull_request) Successful in 15m0s
CI / Linux (ubuntu) (pull_request) Successful in 15m8s
CI / Linux (debian) (pull_request) Successful in 15m16s
Introduce separate jobs to test C (Doxygen) and Python (Sphinx) API documentation generation. Ensures build failures are caught early, as API changes often produce warnings that developers miss without automated checks.
2025-09-10 17:21:57 +02:00
Steffen Jaeckel
9b1cb6ab85 If config keyfile does not exist, create it.
All checks were successful
CI / Check spelling (pull_request) Successful in 22s
CI / Check coding style (pull_request) Successful in 36s
CI / Linux (ubuntu) (pull_request) Successful in 14m11s
CI / Linux (debian) (pull_request) Successful in 16m2s
CI / Linux (arch) (pull_request) Successful in 20m21s
CI / Check spelling (push) Successful in 19s
CI / Check coding style (push) Successful in 34s
CI / Linux (debian) (push) Successful in 13m41s
CI / Linux (ubuntu) (push) Successful in 15m3s
CI / Linux (arch) (push) Successful in 20m23s
Fixes #1911
Alternative to #2056

Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>

(cherry picked from commit b12521ca21)
2025-09-10 14:20:08 +02:00
Michael Vetter
f419e65fad Update issue templates
According to the new way: https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/about-issue-and-pull-request-templates

(cherry picked from commit 5dcbd84f75)
2025-09-10 14:18:01 +02:00
Michael Vetter
110b3d27b4 Rename issue template
Seems like GH changed how the templates work.

(cherry picked from commit f1e12a33cf)
2025-09-10 14:17:15 +02:00
Steffen Jaeckel
75b378cf54 Don't use memchr() on strings potentially shorter than 4 bytes.
When running profanity under Valgrind with slashguard enabled, the
following error could occur:

```
[...]
==4021347== Invalid read of size 1
==4021347==    at 0x4851F49: memchr (vg_replace_strmem.c:986)
==4021347==    by 0x45CEAD: _inp_slashguard_check (inputwin.c:183)
==4021347==    by 0x45CEAD: inp_readline (inputwin.c:225)
==4021347==    by 0x431184: prof_run (profanity.c:121)
==4021347==    by 0x42C609: main (main.c:176)
==4021347==  Address 0xe850883 is 0 bytes after a block of size 3 alloc'd
==4021347==    at 0x48477C4: malloc (vg_replace_malloc.c:446)
[...]
```

`memchr()` requires the complete memory that shall be searched to be
accessible. Using `strchr()` could work for shorter strings, but we only
want to search in the first 4 chars.

Instead of somehow working around those limitations, simply search manually
in the first 4 bytes.

Fixes: 3c56b289 ("Add slashguard feature")
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>

(cherry picked from commit 7f48452d84)
2025-09-10 14:16:19 +02:00
Steffen Jaeckel
988d3663d1 Introduce tests/prof_cmocka.h
As 9f2abc75 accidentally got the ordering of some of the includes wrong,
I decided to propose my initial solution again.

Additional to that, I've opened a MR against CMocka to solve this on
their side, since I believe that the current way this is done is not
sustainable [0].

[0] https://gitlab.com/cmocka/cmocka/-/merge_requests/91

Fixes: 9f2abc75 ("Fix tests with gcc15 (uintptr_t)")
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>

CProof note: our new tests need to also be updated.
2025-09-10 14:11:03 +02:00
Steffen Jaeckel
d3fa1c2f78 Tidy up some code
* less allocations
* less duplicate code

Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>

(cherry picked from commit 9d335729a0)
2025-09-10 14:07:41 +02:00
Steffen Jaeckel
1a385b8cd2 Refactor slashguard
Fixes #2054
Fixes: 95c2199c ("Some more memory improvements")

Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
(cherry picked from commit 40aafd06e7)
2025-09-10 14:05:30 +02:00
Steffen Jaeckel
39aab45162 Fix memory leak.
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>

(cherry picked from commit e0f107f75e)
2025-09-10 14:01:22 +02:00
Steffen Jaeckel
0d5123e69a Trampoline Python unref again.
In the past `Py_XDECREF()` was a macro. Preserve compat to ancient Python
versions by having a trampoline which calls `Py_XDECREF()`.

Fixes: #2043
Fixes: c0da36c4 ("Rage-cleanup.")

Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
(cherry picked from commit 3299dd8fc6)
2025-09-10 14:00:51 +02:00
Steffen Jaeckel
36f183d6a4 Separate entries visually in my-prof.supp
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>

(cherry picked from commit 3370f8a7f1)
2025-09-10 14:00:07 +02:00
Martin Dosch
6b6576b31c Fix typo in examples.
(cherry picked from commit 5696bf77c7)

Author:    Martin Dosch <martin@mdosch.de>
2025-09-10 13:58:57 +02:00
Andreas Stieger
1ae78400a4 Fix tests with gcc15 (uintptr_t)
fixes: error: ‘uintptr_t’ undeclared, defined in header ‘<stdint.h>
(cherry picked from commit 9f2abc75ad)

Author:    Andreas Stieger <Andreas.Stieger@gmx.de>
2025-09-10 13:57:36 +02:00
ea8a758ecf Merge branch 'fix/correct-autocompletion'
All checks were successful
CI / Check spelling (push) Successful in 18s
CI / Check coding style (push) Successful in 31s
CI / Linux (debian) (push) Successful in 10m43s
CI / Linux (arch) (push) Successful in 13m6s
CI / Linux (ubuntu) (push) Successful in 13m13s
2025-09-02 14:20:23 +02:00
2808def933 fix(chatwin): Fix LMC autocompletion to suggest corrected message content
All checks were successful
CI / Check spelling (pull_request) Successful in 18s
CI / Check coding style (pull_request) Successful in 33s
CI / Linux (debian) (pull_request) Successful in 9m45s
CI / Linux (ubuntu) (pull_request) Successful in 10m0s
CI / Linux (arch) (pull_request) Successful in 16m48s
- Modified chatwin_outgoing_msg to call _chatwin_set_last_message for corrected messages, using replace_id per XEP-0308.
- Updated _chatwin_set_last_message to skip redundant and invalid free/strdup for same pointers.
- Added null checks in _chatwin_set_last_message for safety.
- Fixes autocompletion suggesting original message content instead of corrected content.

Fixes #24
2025-09-02 00:29:13 +02:00
741dc4c275 fix(ui.h): cons_show_qrcode declaration. Minor change
All checks were successful
CI / Check spelling (pull_request) Successful in 17s
CI / Check coding style (pull_request) Successful in 30s
CI / Linux (debian) (pull_request) Successful in 10m43s
CI / Linux (arch) (pull_request) Successful in 13m6s
CI / Linux (ubuntu) (pull_request) Successful in 13m18s
CI / Check coding style (push) Successful in 36s
CI / Check spelling (push) Successful in 20s
CI / Linux (debian) (push) Successful in 9m44s
CI / Linux (ubuntu) (push) Successful in 10m3s
CI / Linux (arch) (push) Successful in 12m12s
Prior to the change declaration did not include parameters,
leading to errors within static analyzers and potential issues with compilation.
2025-09-01 23:29:26 +02:00
65cf9ddb9c fix(cmd_sub): Prevent crash with malformed JID in /sub command
Added null check for jidp in cmd_sub to handle jid_create returning NULL.

Crash occurred when processing malformed JID inputs like @example.com.

Ensures robust handling of invalid JIDs.

Fixes #22
2025-09-01 23:29:26 +02:00
51d2355d97 fix(cmd_caps): Prevent crash in /caps with malformed JID input
All checks were successful
CI / Check spelling (pull_request) Successful in 15s
CI / Check coding style (pull_request) Successful in 29s
CI / Linux (debian) (pull_request) Successful in 9m54s
CI / Linux (ubuntu) (pull_request) Successful in 10m15s
CI / Linux (arch) (pull_request) Successful in 11m51s
CI / Check spelling (push) Successful in 18s
CI / Check coding style (push) Successful in 31s
CI / Linux (debian) (push) Successful in 10m35s
CI / Linux (ubuntu) (push) Successful in 11m0s
CI / Linux (arch) (push) Successful in 13m26s
- Added null check for `jid` in `cmd_caps` to handle `jid_create` returning NULL.
- Crash occurred when processing malformed inputs like `@example.com` in `/caps`.
- Ensures robust handling of invalid JID strings in `WIN_CHAT` and `WIN_CONSOLE` cases.

Fixes #20
2025-09-01 21:28:19 +02:00
e33c7a477d docs(rebranding): update readme
All checks were successful
CI / Check spelling (push) Successful in 16s
CI / Check coding style (push) Successful in 32s
CI / Linux (debian) (push) Successful in 10m39s
CI / Linux (arch) (push) Successful in 13m3s
CI / Linux (ubuntu) (push) Successful in 13m7s
2025-09-01 16:57:10 +02:00
f4405d114a Add unit tests for forced encryption check function
All checks were successful
CI / Check coding style (pull_request) Successful in 35s
CI / Check spelling (pull_request) Successful in 18s
CI / Linux (debian) (pull_request) Successful in 10m28s
CI / Linux (ubuntu) (pull_request) Successful in 10m51s
CI / Linux (arch) (pull_request) Successful in 13m17s
CI / Check spelling (push) Successful in 17s
CI / Check coding style (push) Successful in 33s
CI / Linux (arch) (push) Successful in 12m53s
CI / Linux (ubuntu) (push) Successful in 12m56s
CI / Linux (debian) (push) Successful in 13m4s
2025-08-27 16:48:27 +02:00
442bfb6ce1 feat: Add /force-encryption command and update message handling
All checks were successful
CI / Check spelling (pull_request) Successful in 18s
CI / Check coding style (pull_request) Successful in 34s
CI / Linux (ubuntu) (pull_request) Successful in 14m5s
CI / Linux (debian) (pull_request) Successful in 14m5s
CI / Linux (arch) (pull_request) Successful in 14m53s
Implement /force-encryption command to configure forced encryption
settings with on|off and policy resend-to-confirm|block options.

The changes enhance user experience by clarifying encryption requirements
and providing actionable commands. Users can now press Enter again to
confirm unencrypted messages in resend-to-confirm mode.
2025-08-25 21:11:27 +02:00
76 changed files with 1450 additions and 916 deletions

44
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,44 @@
---
name: Bug report
about: Create a report
title: ''
labels: bug
assignees: ''
---
<!--- Provide a general summary of the issue in the Title above -->
<!--- More than 50 issues open? Please don't file any new feature requests -->
<!--- Help us reduce the work first :-) -->
## Expected Behavior
<!--- If you're describing a bug, tell us what should happen -->
<!--- If you're suggesting a change/improvement, tell us how it should work -->
## Current Behavior
<!--- If describing a bug, tell us what happens instead of the expected behavior -->
<!--- If suggesting a change/improvement, explain the difference from current behavior -->
## Possible Solution
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
<!--- or ideas how to implement the addition or change -->
## Steps to Reproduce (for bugs)
<!--- Describe, in detail, what needs to happen to reproduce this bug -->
<!--- 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? -->
## Environment
* Give us the version and build information output generated by `profanity -v`
* If you could not yet build profanity, mention the revision you try to build from
* Operating System/Distribution
* glib version
* libstrophe version
* Some bugs might be due to specific implementation in the server. `/serversoftware example.domain` can be helpful

View File

@@ -90,3 +90,31 @@ jobs:
- name: Check spelling
run: |
codespell
test-c-api-docs:
runs-on: ubuntu-latest
name: Test C API Documentation Generation
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends make doxygen
- name: Test C API docs generation
run: |
cd profanity/apidocs/c/
rm -rf html && doxygen c-prof.conf
test-python-api-docs:
runs-on: ubuntu-latest
name: Test Python API Documentation Generation
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends make python3-sphinx
- name: Test Python API docs generation
run: |
cd profanity/apidocs/python/
sphinx-apidoc -f -o . src && make -j$(nproc) xml

View File

@@ -124,6 +124,7 @@ unittest_sources = \
src/event/server_events.c src/event/server_events.h \
src/event/client_events.c src/event/client_events.h \
src/ui/tray.h src/ui/tray.c \
tests/prof_cmocka.h \
tests/unittests/xmpp/stub_vcard.c \
tests/unittests/xmpp/stub_avatar.c \
tests/unittests/xmpp/stub_ox.c \
@@ -166,9 +167,11 @@ unittest_sources = \
tests/unittests/test_cmd_disconnect.c tests/unittests/test_cmd_disconnect.h \
tests/unittests/test_callbacks.c tests/unittests/test_callbacks.h \
tests/unittests/test_plugins_disco.c tests/unittests/test_plugins_disco.h \
tests/unittests/test_forced_encryption.c tests/unittests/test_forced_encryption.h \
tests/unittests/unittests.c
functionaltest_sources = \
tests/prof_cmocka.h \
tests/functionaltests/proftest.c tests/functionaltests/proftest.h \
tests/functionaltests/test_connect.c tests/functionaltests/test_connect.h \
tests/functionaltests/test_ping.c tests/functionaltests/test_ping.h \
@@ -283,6 +286,7 @@ endif
TESTS = tests/unittests/unittests
check_PROGRAMS = tests/unittests/unittests
tests_unittests_unittests_CPPFLAGS = -Itests/
tests_unittests_unittests_SOURCES = $(unittest_sources)
tests_unittests_unittests_LDADD = -lcmocka
@@ -346,9 +350,13 @@ endif
.PHONY: my-prof.supp
my-prof.supp:
@sed '/^# AUTO-GENERATED START/q' prof.supp > $@
@printf "\n\n# glib\n" >> $@
@cat /usr/share/glib-2.0/valgrind/glib.supp >> $@
@printf "\n\n# Python\n" >> $@
@wget -O- https://raw.githubusercontent.com/python/cpython/refs/tags/v`python3 --version | cut -d' ' -f2`/Misc/valgrind-python.supp >> $@
@printf "\n\n# gtk\n" >> $@
@test -z "@GTK_VERSION@" || wget -O- https://raw.githubusercontent.com/GNOME/gtk/refs/tags/@GTK_VERSION@/gtk.supp >> $@
@printf "\n\n# more gtk\n" >> $@
@test -z "@GTK_VERSION@" || cat /usr/share/gtk-3.0/valgrind/gtk.supp >> $@
check-unit: tests/unittests/unittests

View File

@@ -1,40 +1,36 @@
# Profanity
![Build Status](https://github.com/profanity-im/profanity/workflows/CI/badge.svg) [![GitHub contributors](https://img.shields.io/github/contributors/profanity-im/profanity.svg)](https://github.com/profanity-im/profanity/graphs/contributors/) [![Packaging status](https://repology.org/badge/tiny-repos/profanity.svg)](https://repology.org/project/profanity/versions)
# CProof
![Build Status](https://git.jabber.space/devs/cproof/actions/workflows/main.yml/badge.svg)
Profanity is a console based XMPP client inspired by [Irssi](http://www.irssi.org/).
CProof is a console based XMPP chat client based on [Profanity](https://profanity-im.github.io/).
![alt tag](https://profanity-im.github.io/images/prof-2.png)
![alt tag](https://jabber.space/images/CProof-ui.png)
See the [User Guide](https://profanity-im.github.io/userguide.html) for information on installing and using Profanity.
See the [Quick Start Guide](https://jabber.space/getting-started/quick-start/) for information on installing and using CProof.
## 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.
CProof enables you to communicate with privacy, freedom and comfort. Our open-source chat application delivers secure, end-to-end encrypted messaging (OTR, PGP, OMEMO, OX) built on the trusted [XMPP](https://xmpp.org/) protocol. With a decentralized design, you can connect directly or even host your own server, keeping your data in your hands. Whether you're chatting with friends or collaborating securely, CProof makes private communication simple, reliable, and truly yours.
## 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.
Check our [installation guide](https://jabber.space/getting-started/installation/) for detailed instructions.
## 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:
[How to get a backtrace](https://profanity-im.github.io/blog/post/how-to-get-a-backtrace/) and [Contributing a Patch via GitHub](https://profanity-im.github.io/blog/post/contributing-a-patch-via-github/).
For more technical details check out our [CONTRIBUTING.md](CONTRIBUTING.md) file.
See our [Helping Out](https://jabber.space/contributing/helpout/) page for a concise summary of ways to help us.
Review the [Contributing Guide](CONTRIBUTING.md) and [Code Overview](https://jabber.space/contributing/code-overview/) pages for advanced technical details.
## 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 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.
Prior to asking questions, check our [User Guide](https://profanity-im.github.io/userguide.html), then check out the [FAQ](https://jabber.space/about/faq/).
If you are still having a problem then search the [issue tracker](https://git.jabber.space/devs/cproof/issues).
As a last resort, feel free to write us on [support@jabber.tech](mailto:support@jabber.tech) or create a new issue depending on what your problem is.
## Links
### Website
<!-- TODO:
URL: https://jabber.space/
-->
Feel free to visit our website: [jabber.space](https://jabber.space/).
Repo: https://git.jabber.space/devs/profanity
<!-- TODO: blog/docs link -->
You may also check the repository if you like, available on [git.jabber.space/devs/profanity](https://git.jabber.space/devs/profanity).
### Plugins
Plugins repository: https://github.com/profanity-im/profanity-plugins
Plugins repository: https://git.jabber.space/devs/cproof-plugins

File diff suppressed because it is too large Load Diff

View File

@@ -136,6 +136,7 @@ static char* _mood_autocomplete(ProfWin* window, const char* const input, gboole
static char* _strophe_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _adhoc_cmd_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _vcard_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _force_encryption_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _script_autocomplete_func(const char* const prefix, gboolean previous, void* context);
@@ -296,6 +297,8 @@ static Autocomplete vcard_name_ac;
static Autocomplete vcard_set_param_ac;
static Autocomplete vcard_togglable_param_ac;
static Autocomplete vcard_address_type_ac;
static Autocomplete force_encryption_ac;
static Autocomplete force_encryption_policy_ac;
static Autocomplete* all_acs[] = {
&commands_ac,
@@ -448,6 +451,8 @@ static Autocomplete* all_acs[] = {
&vcard_set_param_ac,
&vcard_togglable_param_ac,
&vcard_address_type_ac,
&force_encryption_ac,
&force_encryption_policy_ac
};
static GHashTable* ac_funcs = NULL;
@@ -1343,6 +1348,13 @@ cmd_ac_init(void)
autocomplete_add(vcard_address_type_ac, "domestic");
autocomplete_add(vcard_address_type_ac, "international");
autocomplete_add(force_encryption_ac, "on");
autocomplete_add(force_encryption_ac, "off");
autocomplete_add(force_encryption_ac, "policy");
autocomplete_add(force_encryption_policy_ac, "block");
autocomplete_add(force_encryption_policy_ac, "resend-to-confirm");
if (ac_funcs != NULL)
g_hash_table_destroy(ac_funcs);
ac_funcs = g_hash_table_new(g_str_hash, g_str_equal);
@@ -1415,6 +1427,7 @@ cmd_ac_init(void)
g_hash_table_insert(ac_funcs, "/win", _win_autocomplete);
g_hash_table_insert(ac_funcs, "/wins", _wins_autocomplete);
g_hash_table_insert(ac_funcs, "/wintitle", _wintitle_autocomplete);
g_hash_table_insert(ac_funcs, "/force-encryption", _force_encryption_autocomplete);
}
void
@@ -1662,7 +1675,7 @@ char*
cmd_ac_complete_filepath(const char* const input, char* const startstr, gboolean previous)
{
unsigned int output_off = 0;
char* tmp;
char* tmp = NULL;
// strip command
char* inpcp = (char*)input + strlen(startstr);
@@ -1674,38 +1687,36 @@ cmd_ac_complete_filepath(const char* const input, char* const startstr, gboolean
// strip quotes
if (*inpcp == '"') {
tmp = strchr(inpcp + 1, '"');
tmp = strrchr(inpcp + 1, '"');
if (tmp) {
*tmp = '\0';
}
tmp = strdup(inpcp + 1);
free(inpcp);
inpcp = tmp;
tmp = NULL;
}
// expand ~ to $HOME
if (inpcp[0] == '~' && inpcp[1] == '/') {
tmp = g_strdup_printf("%s/%sfoo", getenv("HOME"), inpcp + 2);
if (!tmp) {
char* home = getenv("HOME");
if (!home) {
free(inpcp);
return NULL;
}
output_off = strlen(getenv("HOME")) + 1;
tmp = g_strdup_printf("%s/%sfoo", home, inpcp + 2);
output_off = strlen(home) + 1;
} else {
tmp = g_strdup_printf("%sfoo", inpcp);
if (!tmp) {
free(inpcp);
return NULL;
}
}
free(inpcp);
inpcp = tmp;
if (!tmp) {
return NULL;
}
char* inpcp2 = strdup(inpcp);
char* foofile = strdup(basename(inpcp2));
char* directory = strdup(dirname(inpcp));
free(inpcp);
free(inpcp2);
char* foofile = strdup(basename(tmp));
char* directory = strdup(dirname(tmp));
g_free(tmp);
GArray* files = g_array_new(TRUE, FALSE, sizeof(char*));
g_array_set_clear_func(files, (GDestroyNotify)_filepath_item_free);
@@ -1724,40 +1735,26 @@ cmd_ac_complete_filepath(const char* const input, char* const startstr, gboolean
continue;
}
char* acstring;
char* acstring = NULL;
if (output_off) {
tmp = g_strdup_printf("%s/%s", directory, dir->d_name);
if (!tmp) {
free(directory);
free(foofile);
return NULL;
if (tmp) {
acstring = g_strdup_printf("~/%s", tmp + output_off);
g_free(tmp);
}
acstring = g_strdup_printf("~/%s", tmp + output_off);
if (!acstring) {
free(directory);
free(foofile);
return NULL;
}
free(tmp);
} else if (strcmp(directory, "/") == 0) {
acstring = g_strdup_printf("/%s", dir->d_name);
if (!acstring) {
free(directory);
free(foofile);
return NULL;
}
} else {
acstring = g_strdup_printf("%s/%s", directory, dir->d_name);
if (!acstring) {
free(directory);
free(foofile);
return NULL;
}
}
if (!acstring) {
g_array_free(files, TRUE);
free(foofile);
free(directory);
return NULL;
}
char* acstring_cpy = strdup(acstring);
g_array_append_val(files, acstring_cpy);
free(acstring);
g_array_append_val(files, acstring);
}
closedir(d);
}
@@ -4406,3 +4403,17 @@ _vcard_autocomplete(ProfWin* window, const char* const input, gboolean previous)
return result;
}
static char*
_force_encryption_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;
result = autocomplete_param_with_ac(input, "/force-encryption policy", force_encryption_policy_ac, TRUE, previous);
if (result) {
return result;
}
result = autocomplete_param_with_ac(input, "/force-encryption", force_encryption_ac, TRUE, previous);
return result;
}

View File

@@ -433,7 +433,7 @@ static const struct cmd_t command_defs[] = {
{ "<contact>", "The contact you wish to view information about." },
{ "<nick>", "When in a chat room, the occupant you wish to view information about." })
CMD_EXAMPLES(
"/info thor@aasgard.server.org",
"/info thor@asgard.server.org",
"/info heimdall")
},
@@ -2729,6 +2729,7 @@ static const struct cmd_t command_defs[] = {
{ "os on|off", "Choose whether to include the OS name if a user asks for software information (XEP-0092)." }
)
CMD_EXAMPLES(
"/privacy",
"/privacy logging off",
"/privacy os off")
},
@@ -2744,6 +2745,31 @@ static const struct cmd_t command_defs[] = {
"Redraw user interface. Can be used when some other program interrupted profanity or wrote to the same terminal and the interface looks \"broken\"." )
},
{ CMD_PREAMBLE("/force-encryption",
parse_args, 1, 3, &cons_encryption_setting)
CMD_MAINFUNC(cmd_force_encryption)
CMD_TAGS(
CMD_TAG_CHAT)
CMD_SYN(
"/force-encryption",
"/force-encryption on|off",
"/force-encryption policy resend-to-confirm|block")
CMD_DESC(
"Configure forced encryption for outgoing messages in CProof. "
"When enabled, restricts sending unencrypted messages based on the specified policy. "
"Run without arguments to display current settings.")
CMD_ARGS(
{ "on|off", "Enable or disable forced encryption. When enabled, restricts unencrypted messages per the policy. When disabled, allows sending unencrypted messages without restrictions." },
{ "policy resend-to-confirm|block", "Set the policy for unencrypted messages when forced encryption is enabled. 'resend-to-confirm' requires pressing Enter again to confirm sending an unencrypted message (default). 'block' prevents sending unencrypted messages entirely." }
)
CMD_EXAMPLES(
"/force-encryption",
"/force-encryption on",
"/force-encryption off",
"/force-encryption policy resend-to-confirm",
"/force-encryption policy block")
},
// NEXT-COMMAND (search helper)
};

View File

@@ -1263,6 +1263,11 @@ cmd_sub(ProfWin* window, const char* const command, gchar** args)
auto_jid Jid* jidp = jid_create(jid);
if (jidp == NULL) {
cons_show("Malformed JID: %s", jid);
return TRUE;
}
if (strcmp(subcmd, "allow") == 0) {
presence_subscription(jidp->barejid, PRESENCE_SUBSCRIBED);
cons_show("Accepted subscription for %s", jidp->barejid);
@@ -3418,7 +3423,7 @@ cmd_caps(ProfWin* window, const char* const command, gchar** args)
if (args[0]) {
auto_jid Jid* jid = jid_create(args[0]);
if (jid->fulljid == NULL) {
if (jid == NULL || jid->fulljid == NULL) {
cons_show("You must provide a full jid to the /caps command.");
} else {
PContact pcontact = roster_get_contact(jid->barejid);
@@ -8572,19 +8577,20 @@ cmd_omemo_trust_mode(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_OMEMO
auto_gchar gchar* trust_mode = prefs_get_string(PREF_OMEMO_TRUST_MODE);
if (!args[1]) {
cons_show("Current trust mode is %s", prefs_get_string(PREF_OMEMO_TRUST_MODE));
cons_show("Current trust mode is %s", trust_mode);
return TRUE;
}
if (g_strcmp0(args[1], "manual") == 0) {
cons_show("Current trust mode is %s - setting to %s", prefs_get_string(PREF_OMEMO_TRUST_MODE), args[1]);
cons_show("Current trust mode is %s - setting to %s", trust_mode, args[1]);
cons_show("You need to trust all OMEMO fingerprints manually");
} else if (g_strcmp0(args[1], "firstusage") == 0) {
cons_show("Current trust mode is %s - setting to %s", prefs_get_string(PREF_OMEMO_TRUST_MODE), args[1]);
cons_show("Current trust mode is %s - setting to %s", trust_mode, args[1]);
cons_show("The first seen OMEMO fingerprints will be trusted automatically - new keys must be trusted manually");
} else if (g_strcmp0(args[1], "blind") == 0) {
cons_show("Current trust mode is %s - setting to %s", prefs_get_string(PREF_OMEMO_TRUST_MODE), args[1]);
cons_show("Current trust mode is %s - setting to %s", trust_mode, args[1]);
cons_show("ALL OMEMO fingerprints will be trusted automatically");
} else {
cons_bad_cmd_usage(command);
@@ -10633,3 +10639,22 @@ cmd_vcard_save(ProfWin* window, const char* const command, gchar** args)
cons_show("User vCard uploaded");
return TRUE;
}
gboolean
cmd_force_encryption(ProfWin* window, const char* const command, gchar** args)
{
if (g_strv_length(args) == 1 && (g_strcmp0(args[0], "on") == 0 || g_strcmp0(args[0], "off") == 0)) {
_cmd_set_boolean_preference(args[0], "Forces encryption", PREF_FORCE_ENCRYPTION);
} else if (g_strv_length(args) == 2 && g_strcmp0(args[0], "policy") == 0) {
if (g_strcmp0(args[1], "resend-to-confirm") != 0 && g_strcmp0(args[1], "block") != 0) {
cons_show_error("Invalid policy: \"%s\". See '/help force-encryption' for details.", args[1]);
return TRUE;
}
prefs_set_string(PREF_FORCE_ENCRYPTION_MODE, args[1]);
cons_show("Force encryption policy has been set to \"%s\".", args[1]);
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}

View File

@@ -269,5 +269,6 @@ gboolean cmd_vcard_photo(ProfWin* window, const char* const command, gchar** arg
gboolean cmd_vcard_refresh(ProfWin* window, const char* const command, gchar** args);
gboolean cmd_vcard_set(ProfWin* window, const char* const command, gchar** args);
gboolean cmd_vcard_save(ProfWin* window, const char* const command, gchar** args);
gboolean cmd_force_encryption(ProfWin* window, const char* const command, gchar** args);
#endif

View File

@@ -45,6 +45,7 @@
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <curl/curl.h>
#include <curl/easy.h>
@@ -199,6 +200,10 @@ load_custom_keyfile(prof_keyfile_t* keyfile, gchar* filename)
if (g_file_test(keyfile->filename, G_FILE_TEST_EXISTS)) {
g_chmod(keyfile->filename, S_IRUSR | S_IWUSR);
} else {
int fno = g_creat(keyfile->filename, S_IRUSR | S_IWUSR);
if (fno != -1)
g_close(fno, NULL);
}
return _load_keyfile(keyfile);

View File

@@ -1792,6 +1792,8 @@ _get_group(preference_t pref)
case PREF_OUTGOING_STAMP:
case PREF_INCOMING_STAMP:
case PREF_MOOD:
case PREF_FORCE_ENCRYPTION:
case PREF_FORCE_ENCRYPTION_MODE:
return PREF_GROUP_UI;
case PREF_STATES:
case PREF_OUTTYPE:
@@ -2150,6 +2152,10 @@ _get_key(preference_t pref)
return "strophe.sm.enabled";
case PREF_STROPHE_SM_RESEND:
return "strophe.sm.resend";
case PREF_FORCE_ENCRYPTION:
return "force-encryption.enabled";
case PREF_FORCE_ENCRYPTION_MODE:
return "force-encryption.policy";
default:
return NULL;
}
@@ -2204,6 +2210,7 @@ _get_default_boolean(preference_t pref)
case PREF_STROPHE_SM_RESEND:
return TRUE;
case PREF_PGP_PUBKEY_AUTOIMPORT:
case PREF_FORCE_ENCRYPTION:
default:
return FALSE;
}
@@ -2310,6 +2317,8 @@ _get_default_string(preference_t pref)
return "0";
case PREF_DBLOG:
return "on";
case PREF_FORCE_ENCRYPTION_MODE:
return "resend-to-confirm";
default:
return NULL;
}

View File

@@ -187,6 +187,8 @@ typedef enum {
PREF_STROPHE_SM_RESEND,
PREF_VCARD_PHOTO_CMD,
PREF_STATUSBAR_TABMODE,
PREF_FORCE_ENCRYPTION,
PREF_FORCE_ENCRYPTION_MODE
} preference_t;
typedef struct prof_alias_t

View File

@@ -42,9 +42,11 @@
#include "log.h"
#include "chatlog.h"
#include "database.h"
#include "client_events.h"
#include "config/preferences.h"
#include "event/common.h"
#include "plugins/plugins.h"
#include "ui/inputwin.h"
#include "ui/window_list.h"
#include "xmpp/chat_session.h"
#include "xmpp/session.h"
@@ -177,7 +179,7 @@ cl_ev_send_msg_correct(ProfChatWin* chatwin, const char* const msg, const char*
#ifdef HAVE_LIBOTR
handled = otr_on_message_send(chatwin, message, request_receipt, replace_id);
#endif
if (!handled) {
if (!handled && allow_unencrypted_message(chatwin, message)) {
auto_char char* id = message_send_chat(chatwin->barejid, message, oob_url, request_receipt, replace_id);
chat_log_msg_out(chatwin->barejid, message, NULL);
log_database_add_outgoing_chat(id, chatwin->barejid, message, replace_id, PROF_MSG_ENC_NONE);
@@ -251,3 +253,34 @@ cl_ev_send_priv_msg(ProfPrivateWin* privwin, const char* const msg, const char*
plugins_post_priv_message_send(privwin->fulljid, message);
}
}
gboolean
allow_unencrypted_message(ProfChatWin* chatwin, const char* const msg)
{
if (!prefs_get_boolean(PREF_FORCE_ENCRYPTION)) {
return TRUE; // Encryption not enforced
}
auto_gchar gchar* force_enc_mode = prefs_get_string(PREF_FORCE_ENCRYPTION_MODE);
if (g_strcmp0(force_enc_mode, "block") == 0) {
win_println((ProfWin*)chatwin, THEME_ERROR, "-", "Message not sent: encryption required. Enable (omemo/pgp/otr) encryption or /force-encryption off.");
return FALSE;
}
if (g_strcmp0(force_enc_mode, "resend-to-confirm") == 0) {
// We do not use chatwin->last_message because it should be set only if it's sent.
guint msg_hash = g_str_hash(msg);
if (msg_hash == chatwin->last_attempted_msg_hash) {
chatwin->last_attempted_msg_hash = 0; // reset hash
return TRUE;
}
win_println((ProfWin*)chatwin, THEME_ERROR, "-", "Message not sent: encryption required. Enable (omemo/pgp/otr) encryption or press Enter again to send without encryption. Use /force-encryption off to disable this protection.");
chatwin->last_attempted_msg_hash = msg_hash;
inp_set_line(msg); // reset message to prevent the need to retype it
return FALSE;
}
win_println((ProfWin*)chatwin, THEME_ERROR, "-", "Message not sent: invalid encryption mode (%s). Use '/force-encryption policy resend-to-confirm'.", force_enc_mode);
return FALSE;
}

View File

@@ -52,4 +52,8 @@ void cl_ev_send_muc_msg_corrected(ProfMucWin* mucwin, const char* const msg, con
void cl_ev_send_muc_msg(ProfMucWin* mucwin, const char* const msg, const char* const oob_url);
void cl_ev_send_priv_msg(ProfPrivateWin* privwin, const char* const msg, const char* const oob_url);
// Checks if an unencrypted message can be sent based on encryption preferences.
// Returns TRUE if allowed, FALSE if blocked.
gboolean allow_unencrypted_message(ProfChatWin* chatwin, const char* const msg);
#endif

View File

@@ -86,10 +86,16 @@ python_get_version_number(void)
return version_number;
}
static void
_unref_module(PyObject* module)
{
Py_XDECREF(module);
}
void
python_env_init(void)
{
loaded_modules = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)Py_XDECREF);
loaded_modules = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_unref_module);
python_init_prof();

View File

@@ -424,9 +424,11 @@ chatwin_outgoing_msg(ProfChatWin* chatwin, const char* const message, const char
win_print_outgoing((ProfWin*)chatwin, enc_char, id, replace_id, display_message);
}
// save last id and message for LMC in case if it's not LMC message
if (id && !replace_id) {
_chatwin_set_last_message(chatwin, id, 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
if (id) {
_chatwin_set_last_message(chatwin, replace_id ?: id, display_message);
}
}
@@ -625,9 +627,13 @@ chatwin_db_history(ProfChatWin* chatwin, const gchar* start_time, const gchar* e
static void
_chatwin_set_last_message(ProfChatWin* chatwin, const char* const id, const char* const message)
{
free(chatwin->last_message);
chatwin->last_message = strdup(message);
if (message && chatwin->last_message != message) {
free(chatwin->last_message);
chatwin->last_message = strdup(message);
}
free(chatwin->last_msg_id);
chatwin->last_msg_id = strdup(id);
if (id && chatwin->last_msg_id != id) {
free(chatwin->last_msg_id);
chatwin->last_msg_id = strdup(id);
}
}

View File

@@ -2891,3 +2891,11 @@ cons_privacy_setting(void)
}
}
}
void
cons_encryption_setting(void)
{
cons_show("Force encryption : %sabled", prefs_get_boolean(PREF_FORCE_ENCRYPTION) ? "en" : "dis");
cons_show("Force encryption mode : %s", prefs_get_string(PREF_FORCE_ENCRYPTION_MODE));
}

View File

@@ -170,6 +170,29 @@ create_input_window(void)
_inp_win_update_virtual();
}
static gboolean
_inp_slashguard_check(void)
{
if (get_password)
return false;
/* ignore empty and quoted messages */
if (inp_line == NULL || inp_line[0] == '\0' || inp_line[0] == '>')
return false;
if (!prefs_get_boolean(PREF_SLASH_GUARD))
return false;
size_t n = 1;
while (inp_line[n] != '\0' && n < 4) {
if (inp_line[n] == '/') {
cons_show("Your text contains a slash in the first 4 characters");
free(inp_line);
inp_line = NULL;
return true;
}
n++;
}
return false;
}
char*
inp_readline(void)
{
@@ -203,17 +226,7 @@ inp_readline(void)
chat_state_idle();
}
if (inp_line) {
if (!get_password && prefs_get_boolean(PREF_SLASH_GUARD)) {
// ignore quoted messages
if (strlen(inp_line) > 1 && inp_line[0] != '>') {
char* res = (char*)memchr(inp_line + 1, '/', 3);
if (res) {
cons_show("Your text contains a slash in the first 4 characters");
return NULL;
}
}
}
if (inp_line && !_inp_slashguard_check()) {
char* ret = inp_line;
inp_line = NULL;
return ret;
@@ -294,6 +307,14 @@ inp_get_line(void)
return line;
}
void
inp_set_line(const char* const new_line)
{
rl_replace_line(new_line, 1);
rl_point = rl_end;
_inp_redisplay();
}
char*
inp_get_password(void)
{

View File

@@ -46,5 +46,6 @@ void inp_win_resize(void);
void inp_put_back(void);
char* inp_get_password(void);
char* inp_get_line(void);
void inp_set_line(const char* const new_line);
#endif

View File

@@ -289,7 +289,7 @@ void cons_show_disco_info(const char* from, GSList* identities, GSList* features
void cons_show_disco_contact_information(GHashTable* addresses);
void cons_show_qrcode();
void cons_show_qrcode(const char* const text);
void cons_show_room_invite(const char* const invitor, const char* const room, const char* const reason);
void cons_check_version(gboolean not_available_msg);
@@ -351,6 +351,7 @@ void cons_theme_properties(void);
void cons_theme_colours(void);
void cons_show_tlscert(const TLSCertificate* cert);
void cons_show_tlscert_summary(const TLSCertificate* cert);
void cons_encryption_setting(void);
void cons_alert(ProfWin* alert_origin_window);
void cons_remove_alert(ProfWin* window);

View File

@@ -188,6 +188,7 @@ typedef struct prof_chat_win_t
char* last_message;
char* last_msg_id;
gboolean has_attention;
guint last_attempted_msg_hash;
} ProfChatWin;
typedef struct prof_muc_win_t

View File

@@ -164,6 +164,7 @@ win_create_chat(const char* const barejid)
new_win->last_message = NULL;
new_win->last_msg_id = NULL;
new_win->has_attention = FALSE;
new_win->last_attempted_msg_hash = 0;
new_win->memcheck = PROFCHATWIN_MEMCHECK;
return &new_win->window;

View File

@@ -1,10 +1,7 @@
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <sys/stat.h>
#include "config.h"

View File

@@ -2,11 +2,8 @@
#include <sys/wait.h>
#include <glib.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdio.h>
#include <unistd.h>
#include <errno.h>

View File

@@ -1,8 +1,5 @@
#include <glib.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>

View File

@@ -1,8 +1,5 @@
#include <glib.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>

View File

@@ -1,8 +1,5 @@
#include <glib.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>

View File

@@ -1,8 +1,5 @@
#include <glib.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>

View File

@@ -1,8 +1,5 @@
#include <glib.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>
@@ -27,6 +24,9 @@ message_send(void **state)
assert_true(prof_output_regex("me: .+Hi there"));
}
// TODO: `/message correct` XEP-0308 compliance (whether each correction links to the original message ID)
// https://xmpp.org/extensions/xep-0308.html#rules
void
message_receive_console(void **state)
{

View File

@@ -1,8 +1,5 @@
#include <glib.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>

View File

@@ -1,8 +1,5 @@
#include <glib.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>

View File

@@ -1,8 +1,5 @@
#include <glib.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>

View File

@@ -1,8 +1,5 @@
#include <glib.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>

View File

@@ -1,8 +1,5 @@
#include <glib.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>

View File

@@ -1,8 +1,5 @@
#include <glib.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>

View File

@@ -1,8 +1,5 @@
#include <glib.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>

5
tests/prof_cmocka.h Normal file
View File

@@ -0,0 +1,5 @@
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <setjmp.h>
#include <cmocka.h>

View File

@@ -21,8 +21,7 @@
*/
#include <glib.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <xmpp/xmpp.h>

View File

@@ -1,7 +1,4 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include "common.h"
#include "config/account.h"

View File

@@ -21,8 +21,7 @@
*/
#include <glib.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include "database.h"

View File

@@ -1,8 +1,5 @@
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdlib.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <glib.h>
#include <stdio.h>
#include <unistd.h>

View File

@@ -21,8 +21,7 @@
*/
#include <glib.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include "log.h"

View File

@@ -2,10 +2,7 @@
#include <libotr/message.h>
#include <glib.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include "config/account.h"

View File

@@ -1,8 +1,5 @@
#include <glib.h>
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include "xmpp/contact.h"

View File

@@ -1,7 +1,4 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>
#include <glib.h>

View File

@@ -1,8 +1,5 @@
#include <stdarg.h>
#include <string.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include "xmpp/chat_session.h"

View File

@@ -1,7 +1,4 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>
#include <glib.h>

View File

@@ -1,7 +1,4 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>
#include <glib.h>

View File

@@ -1,7 +1,4 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>
#include <glib.h>

View File

@@ -1,7 +1,4 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>
#include <glib.h>

View File

@@ -1,7 +1,4 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>

View File

@@ -1,7 +1,4 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>
#include <glib.h>

View File

@@ -1,7 +1,4 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>
#include <glib.h>

View File

@@ -1,7 +1,4 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>
#include <glib.h>

View File

@@ -1,7 +1,4 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>
#include <glib.h>

View File

@@ -1,7 +1,4 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>
#include <glib.h>

View File

@@ -1,7 +1,4 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>
#include <glib.h>

View File

@@ -1,7 +1,4 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>
#include <glib.h>
@@ -40,3 +37,17 @@ cmd_sub_shows_usage_when_no_arg(void** state)
gboolean result = cmd_sub(NULL, CMD_SUB, args);
assert_true(result);
}
void
test_cmd_sub_malformed_jid(void** state)
{
ProfWin win;
win.type = WIN_CONSOLE;
gchar* args[] = { "request", "@example.com" };
will_return(connection_get_status, JABBER_CONNECTED);
expect_cons_show("Malformed JID: @example.com");
gboolean result = cmd_sub((ProfWin*)&win, CMD_SUB, args);
assert_true(result);
}

View File

@@ -1,2 +1,3 @@
void cmd_sub_shows_message_when_not_connected(void** state);
void cmd_sub_shows_usage_when_no_arg(void** state);
void test_cmd_sub_malformed_jid(void** state);

View File

@@ -1,9 +1,6 @@
#include "xmpp/resource.h"
#include "common.h"
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
void

View File

@@ -1,9 +1,6 @@
#include <glib.h>
#include <stdarg.h>
#include <string.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include "xmpp/contact.h"

View File

@@ -0,0 +1,135 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include <glib.h>
#include "event/client_events.h"
#include "command/cmd_funcs.h"
#include "config/preferences.h"
#include "ui/stub_ui.h"
#define CMD_FORCE_ENCRYPTION "/force-encryption"
// Test: /force-encryption with no arguments shows error.
void
test_cmd_force_encryption_no_args_bad_cmd(void** state)
{
char* args[] = { NULL };
expect_string(cons_bad_cmd_usage, cmd, CMD_FORCE_ENCRYPTION);
assert_true(cmd_force_encryption(NULL, CMD_FORCE_ENCRYPTION, args));
}
// Test: /force-encryption on enables encryption.
void
test_cmd_force_encryption_toggles_on(void** state)
{
prefs_set_boolean(PREF_FORCE_ENCRYPTION, FALSE);
char* args[] = { "on", NULL };
expect_cons_show("Forces encryption enabled.");
assert_true(cmd_force_encryption(NULL, CMD_FORCE_ENCRYPTION, args));
assert_true(prefs_get_boolean(PREF_FORCE_ENCRYPTION));
}
// Test: /force-encryption off disables encryption.
void
test_cmd_force_encryption_toggles_off(void** state)
{
prefs_set_boolean(PREF_FORCE_ENCRYPTION, TRUE);
char* args[] = { "off", NULL };
expect_cons_show("Forces encryption disabled.");
assert_true(cmd_force_encryption(NULL, CMD_FORCE_ENCRYPTION, args));
assert_false(prefs_get_boolean(PREF_FORCE_ENCRYPTION));
}
// Test: /force-encryption off when already off.
void
test_cmd_force_encryption_toggles_off_already(void** state)
{
prefs_set_boolean(PREF_FORCE_ENCRYPTION, FALSE);
char* args[] = { "off", NULL };
expect_cons_show("Forces encryption is already disabled.");
assert_true(cmd_force_encryption(NULL, CMD_FORCE_ENCRYPTION, args));
assert_false(prefs_get_boolean(PREF_FORCE_ENCRYPTION));
}
// Test: /force-encryption on when already on.
void
test_cmd_force_encryption_toggles_on_already(void** state)
{
prefs_set_boolean(PREF_FORCE_ENCRYPTION, TRUE);
char* args[] = { "on", NULL };
expect_cons_show("Forces encryption is already enabled.");
assert_true(cmd_force_encryption(NULL, CMD_FORCE_ENCRYPTION, args));
assert_true(prefs_get_boolean(PREF_FORCE_ENCRYPTION));
}
// Test: /force-encryption policy block sets block mode.
void
test_cmd_force_encryption_sets_policy_block(void** state)
{
char* args[] = { "policy", "block", NULL };
expect_cons_show("Force encryption policy has been set to \"block\".");
assert_true(cmd_force_encryption(NULL, CMD_FORCE_ENCRYPTION, args));
auto_gchar gchar* pref_force_enc_mode = prefs_get_string(PREF_FORCE_ENCRYPTION_MODE);
assert_string_equal(pref_force_enc_mode, "block");
}
// Test: /force-encryption policy resend-to-confirm sets resend mode.
void
test_cmd_force_encryption_sets_policy_resend(void** state)
{
char* args[] = { "policy", "resend-to-confirm", NULL };
expect_cons_show("Force encryption policy has been set to \"resend-to-confirm\".");
assert_true(cmd_force_encryption(NULL, CMD_FORCE_ENCRYPTION, args));
auto_gchar gchar* pref_force_enc_mode = prefs_get_string(PREF_FORCE_ENCRYPTION_MODE);
assert_string_equal(pref_force_enc_mode, "resend-to-confirm");
}
// Test: Unencrypted message blocked when policy is block.
void
test_allow_unencrypted_message_blocks(void** state)
{
prefs_set_boolean(PREF_FORCE_ENCRYPTION, TRUE);
prefs_set_string(PREF_FORCE_ENCRYPTION_MODE, "block");
ProfChatWin win = {};
char* msg = "test message";
expect_win_println("Message not sent: encryption required. Enable (omemo/pgp/otr) encryption or /force-encryption off.");
assert_false(allow_unencrypted_message(&win, msg));
}
// Test: Unencrypted message prompts confirmation, then allows on second attempt.
void
test_allow_unencrypted_message_confirms_on_second_attempt(void** state)
{
prefs_set_boolean(PREF_FORCE_ENCRYPTION, TRUE);
prefs_set_string(PREF_FORCE_ENCRYPTION_MODE, "resend-to-confirm");
ProfChatWin win = { .last_attempted_msg_hash = 0 };
char* msg = "test message";
expect_win_println("Message not sent: encryption required. Enable (omemo/pgp/otr) encryption or press Enter again to send without encryption. Use /force-encryption off to disable this protection.");
assert_false(allow_unencrypted_message(&win, msg));
assert_int_not_equal(win.last_attempted_msg_hash, 0);
assert_true(allow_unencrypted_message(&win, msg));
assert_int_equal(win.last_attempted_msg_hash, 0); // ensure that value resets since we don't want to approve the same message twice
}
// Test: Invalid policy argument fails gracefully.
void
test_cmd_force_encryption_invalid_policy(void** state)
{
char* args[] = { "policy", "invalid", NULL };
expect_cons_show_error("Invalid policy: \"invalid\". See '/help force-encryption' for details.");
assert_true(cmd_force_encryption(NULL, CMD_FORCE_ENCRYPTION, args));
}
// Test: Invalid encryption mode blocks message.
void
test_allow_unencrypted_message_invalid_mode(void** state)
{
prefs_set_boolean(PREF_FORCE_ENCRYPTION, TRUE);
prefs_set_string(PREF_FORCE_ENCRYPTION_MODE, "invalid");
ProfChatWin win = { .last_attempted_msg_hash = 0 };
char* msg = "test message";
expect_win_println("Message not sent: invalid encryption mode (invalid). Use '/force-encryption policy resend-to-confirm'.");
assert_false(allow_unencrypted_message(&win, msg));
assert_int_equal(win.last_attempted_msg_hash, 0);
}

View File

@@ -0,0 +1,16 @@
#ifndef TEST_FORCED_ENCRYPTION_H
#define TEST_FORCED_ENCRYPTION_H
void test_cmd_force_encryption_no_args_bad_cmd(void** state);
void test_cmd_force_encryption_toggles_on(void** state);
void test_cmd_force_encryption_toggles_off(void** state);
void test_cmd_force_encryption_toggles_off_already(void** state);
void test_cmd_force_encryption_toggles_on_already(void** state);
void test_cmd_force_encryption_sets_policy_block(void** state);
void test_cmd_force_encryption_sets_policy_resend(void** state);
void test_allow_unencrypted_message_blocks(void** state);
void test_allow_unencrypted_message_confirms_on_second_attempt(void** state);
void test_cmd_force_encryption_invalid_policy(void** state);
void test_allow_unencrypted_message_invalid_mode(void** state);
#endif // TEST_FORCED_ENCRYPTION_H

View File

@@ -1,8 +1,5 @@
#include <stdarg.h>
#include <string.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include "xmpp/form.h"

View File

@@ -1,7 +1,4 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include "xmpp/jid.h"

View File

@@ -1,7 +1,4 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>

View File

@@ -1,7 +1,4 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include "xmpp/muc.h"

View File

@@ -1,7 +1,4 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include "tools/parser.h"

View File

@@ -1,7 +1,4 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include "plugins/disco.h"

View File

@@ -1,7 +1,4 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>
#include <glib.h>

View File

@@ -1,9 +1,6 @@
#include <glib.h>
#include <stdarg.h>
#include <string.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include "xmpp/contact.h"

View File

@@ -1,7 +1,4 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <stdlib.h>
#include <string.h>
#include <glib.h>

View File

@@ -3,8 +3,7 @@
#include <glib.h>
#include <wchar.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include "ui/window.h"
#include "ui/ui.h"
@@ -675,6 +674,11 @@ inp_readline(void)
return NULL;
}
void
inp_set_line(const char* const new_line)
{
}
void
inp_nonblocking(gboolean reset)
{
@@ -1157,6 +1161,11 @@ cons_privacy_setting(void)
{
}
void
cons_encryption_setting(void)
{
}
void
cons_show_bookmarks_ignore(gchar** list, gsize len)
{

View File

@@ -1,10 +1,7 @@
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include <sys/stat.h>
#include <stdlib.h>
#include <locale.h>
@@ -24,6 +21,7 @@
#include "test_cmd_presence.h"
#include "test_cmd_otr.h"
#include "test_cmd_pgp.h"
#include "test_forced_encryption.h"
#include "test_jid.h"
#include "test_parser.h"
#include "test_roster_list.h"
@@ -385,6 +383,7 @@ main(int argc, char* argv[])
cmocka_unit_test(cmd_sub_shows_message_when_not_connected),
cmocka_unit_test(cmd_sub_shows_usage_when_no_arg),
cmocka_unit_test(test_cmd_sub_malformed_jid),
cmocka_unit_test(contact_in_group),
cmocka_unit_test(contact_not_in_group),
@@ -644,6 +643,19 @@ main(int argc, char* argv[])
cmocka_unit_test(does_not_add_duplicate_feature),
cmocka_unit_test(removes_plugin_features),
cmocka_unit_test(does_not_remove_feature_when_more_than_one_reference),
// Forced encryption
cmocka_unit_test_setup_teardown(test_cmd_force_encryption_no_args_bad_cmd, load_preferences, close_preferences),
cmocka_unit_test_setup_teardown(test_cmd_force_encryption_toggles_on, load_preferences, close_preferences),
cmocka_unit_test_setup_teardown(test_cmd_force_encryption_toggles_off, load_preferences, close_preferences),
cmocka_unit_test_setup_teardown(test_cmd_force_encryption_toggles_off_already, load_preferences, close_preferences),
cmocka_unit_test_setup_teardown(test_cmd_force_encryption_toggles_on_already, load_preferences, close_preferences),
cmocka_unit_test_setup_teardown(test_cmd_force_encryption_sets_policy_block, load_preferences, close_preferences),
cmocka_unit_test_setup_teardown(test_cmd_force_encryption_sets_policy_resend, load_preferences, close_preferences),
cmocka_unit_test_setup_teardown(test_allow_unencrypted_message_blocks, load_preferences, close_preferences),
cmocka_unit_test_setup_teardown(test_allow_unencrypted_message_confirms_on_second_attempt, load_preferences, close_preferences),
cmocka_unit_test_setup_teardown(test_cmd_force_encryption_invalid_policy, load_preferences, close_preferences),
cmocka_unit_test_setup_teardown(test_allow_unencrypted_message_invalid_mode, load_preferences, close_preferences),
};
return cmocka_run_group_tests(all_tests, NULL, NULL);
}

View File

@@ -1,7 +1,4 @@
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
#include "prof_cmocka.h"
#include "xmpp/xmpp.h"