about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.git-blame-ignore-revs1
-rw-r--r--.github/workflows/main.yml29
-rw-r--r--CONTRIBUTING.md2
-rwxr-xr-xdocs/profanity.133
-rw-r--r--src/config/color.c2
-rw-r--r--src/plugins/c_api.c2
-rw-r--r--src/plugins/profapi.c125
-rw-r--r--src/plugins/profapi.h142
-rw-r--r--src/ui/inputwin.c13
9 files changed, 197 insertions, 152 deletions
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index 804f0a87..9aa5f57f 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -9,3 +9,4 @@ f21595597f4fa872b77d7f76ae04916f4aae732e
 0d8b62c9a29d539889939150ed4da4f33407fa0e
 9b55f2dec0ea27a9ce4856e303425e12f866cea2
 a04031cec9e20f4a805a174d44bf8b682a69d7a7
+d17bcf619c45bfbbf4d0e0bcf218fe6550c185f5
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 6a9e439f..ee0c48c9 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -36,24 +36,27 @@ jobs:
         run: ./ci-build.sh
 
   code-style:
-    runs-on: ubuntu-20.04
+    runs-on: ubuntu-22.04
     name: Check coding style
     continue-on-error: true
     steps:
       - uses: actions/checkout@v2
+      - name: Run clang-format
+        uses: jidicula/clang-format-action@v4.11.0
+        with:
+          clang-format-version: '16'
+          check-path: 'src'
+
+  spell-check:
+    runs-on: ubuntu-22.04
+    name: Check spelling
+    continue-on-error: true
+    steps:
+      - uses: actions/checkout@v2
       - name: install dependencies
         run: |
           sudo apt update
-          sudo apt install -y --no-install-recommends autoconf autoconf-archive automake expect gcc git libcmocka-dev libcurl3-dev libgcrypt-dev libglib2.0-dev libgpgme11-dev libgtk2.0-dev libmicrohttpd-dev libncursesw5-dev libnotify-dev libotr5-dev libreadline-dev libsignal-protocol-c-dev libssl-dev libtool libxss-dev make pkg-config python3-dev python-dev-is-python3 libsqlite3-dev
-      - name: Install libstrophe
-        run: |
-          git clone https://github.com/strophe/libstrophe ../libstrophe
-          cd ../libstrophe && ./bootstrap.sh && ./configure && make -j$(nproc) && sudo make install
-      - name: Configure
-        run: |
-          ./bootstrap.sh
-          ./configure
-      - name: Check style
+          sudo apt install -y --no-install-recommends codespell
+      - name: Check spelling
         run: |
-          make format
-          git diff --exit-code
+          codespell
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index baf999df..7a26b657 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -95,6 +95,8 @@ what may have been staged/committed.
 If you're in a hurry you can add the `--no-verify` flag when issuing `git push`
 and the `pre-push` hook will be skipped.
 
+*Note:* We provide a config file that describes our coding style for clang. But due to a mistake on their side it might happen that you can get a different result that what we expect. See [here](https://github.com/profanity-im/profanity/pull/1774) and [here](https://github.com/profanity-im/profanity/pull/1828) for details. We will try to always run latest clang-format.
+
 ## Finding mistakes
 Test your changes with the following tools to find mistakes.
 
diff --git a/docs/profanity.1 b/docs/profanity.1
index 42b765f7..67783bb6 100755
--- a/docs/profanity.1
+++ b/docs/profanity.1
@@ -106,6 +106,39 @@ for interactive history search and
 for reloading inputrc without restart.
 .SH USING PROFANITY
 The user guide can be found at <https://profanity-im.github.io/userguide.html>.
+.SH ENCRYPTION
+Profanity supports various kinds of encryption: OMEMO, OTR, PGP, OX.
+You can only enable one of them per correspondent at a time.
+.TP
+.BR OMEMO
+OMEMO (/omemo) is defined in XEP-0384. It uses an implementation of the Signal protocol for key management and to synchronize messages among different clients. It works even when other clients are offline. And offers Perfect Forward Secrecy and Plausible deniability. Servers need to support PEP (XEP-0163).
+We implement the "siacs" version of OMEMO. Version 0.3.0, which is currently the widest adopted option.
+OMEMO is the only encryption option in Profanity that also supports encryption for MUCs (XEP-0045) and file transfer via HTTP upload (XEP-0363).
+.TP
+.BR OTR
+OTR (/otr) is defined in XEP-0364. It uses a combination of the AES symmetric-key algorithm, the Diffie–Hellman key exchange, and the SHA-1 hash function. It offers deniable authentication and Perfect Forward Secrecy. To initialize a session both clients need to be online at the same time. A session is between two clients, so multiclient chats are not working. Which is a feature not a bug. OTR does by design not work for MUCs.
+.TP
+.BR OpenPGP
+OpenPGP (/pgp) is defined in XEP-0027. Is uses a public and secret key. It is also known as Legacy OpenPGP and has been deprecated. It doesn't provide protection against replay attacks. MUCs and file transfer via HTTP upload are not specified and thus not supported.
+.TP
+.BR OX
+OX (/ox) is defined in XEP-0373 and XEP-0374. It's a more modern way to use OpenPGP on XMPP and tries to fix the shortcomings of legacy XEP-0027. Servers need to support PEP (XEP-0163). MUCs and file transfer via HTTP upload are not specified and thus not supported.
+.TP
+.BR DETAILS
+For more details read the relevant XEPs and look at the overview at <https://wiki.xmpp.org/web/XMPP_E2E_Security>
+.SH TERMINOLOGY
+There is some XMPP specific terminology that might be unknown for fresh users. We will try to describe them here since they are often references in the help and man pages.
+.TP
+.BR JID
+Stands for Jabber ID. It refers to an XMPP address. Historically XMPP was also known as Jabber.
+.BR MAM
+Stands for Message Archive Management (XEP-0313) and describes the ability to store messages on the server and retrieve them later.
+.BR MUC
+Stands for Mutli-User Chats (XEP-0045) and are also called, groups, group chats, chatrooms or conferences.
+.BR Roster
+The roster is your contact list. By default displayed at the right side on the console window. See RFC6121.
+.BR XEP
+XMPP is aa extendable protocol. There are core features and optional features described in XMPP Extension Protocols, short XEPs.
 .SH SEE ALSO
 .B Profanity
 itself has a lot of built\-in help. Check the
diff --git a/src/config/color.c b/src/config/color.c
index 7676253f..9c1998f5 100644
--- a/src/config/color.c
+++ b/src/config/color.c
@@ -59,7 +59,7 @@ static struct color_pair_cache
     struct
     {
         int16_t fg, bg;
-    } * pairs;
+    }* pairs;
     int size;
     int capacity;
 } cache = { 0 };
diff --git a/src/plugins/c_api.c b/src/plugins/c_api.c
index cda40c4d..8daf633d 100644
--- a/src/plugins/c_api.c
+++ b/src/plugins/c_api.c
@@ -455,7 +455,7 @@ void
 c_command_callback(PluginCommand* command, gchar** args)
 {
     CommandWrapper* wrapper = command->callback;
-    void (*f)(gchar * *args) = wrapper->func;
+    void (*f)(gchar** args) = wrapper->func;
     f(args);
 }
 
diff --git a/src/plugins/profapi.c b/src/plugins/profapi.c
index 9011f1a2..fe3393ab 100644
--- a/src/plugins/profapi.c
+++ b/src/plugins/profapi.c
@@ -41,80 +41,83 @@
 #include "plugins/callbacks.h"
 
 void (*prof_cons_alert)(void) = NULL;
-int (*prof_cons_show)(const char * const message) = NULL;
-int (*prof_cons_show_themed)(const char *const group, const char *const item, const char *const def, const char *const message) = NULL;
-int (*prof_cons_bad_cmd_usage)(const char *const cmd) = NULL;
+int (*prof_cons_show)(const char* const message) = NULL;
+int (*prof_cons_show_themed)(const char* const group, const char* const item, const char* const def, const char* const message) = NULL;
+int (*prof_cons_bad_cmd_usage)(const char* const cmd) = NULL;
 
-void (*_prof_register_command)(const char *filename, const char *command_name, int min_args, int max_args,
-    char **synopsis, const char *description, char *arguments[][2], char **examples,
-    CMD_CB callback) = NULL;
+void (*_prof_register_command)(const char* filename, const char* command_name, int min_args, int max_args,
+                               char** synopsis, const char* description, char* arguments[][2], char** examples,
+                               CMD_CB callback)
+    = NULL;
 
-void (*_prof_register_timed)(const char *filename, TIMED_CB callback, int interval_seconds) = NULL;
+void (*_prof_register_timed)(const char* filename, TIMED_CB callback, int interval_seconds) = NULL;
 
-void (*_prof_completer_add)(const char *filename, const char *key, char **items) = NULL;
-void (*_prof_completer_remove)(const char *filename, const char *key, char **items) = NULL;
-void (*_prof_completer_clear)(const char *filename, const char *key) = NULL;
-void (*_prof_filepath_completer_add)(const char *filename, const char *prefix) = NULL;
+void (*_prof_completer_add)(const char* filename, const char* key, char** items) = NULL;
+void (*_prof_completer_remove)(const char* filename, const char* key, char** items) = NULL;
+void (*_prof_completer_clear)(const char* filename, const char* key) = NULL;
+void (*_prof_filepath_completer_add)(const char* filename, const char* prefix) = NULL;
 
-void (*prof_notify)(const char *message, int timeout_ms, const char *category) = NULL;
+void (*prof_notify)(const char* message, int timeout_ms, const char* category) = NULL;
 
-void (*prof_send_line)(char *line) = NULL;
+void (*prof_send_line)(char* line) = NULL;
 
 char* (*prof_get_current_recipient)(void) = NULL;
 char* (*prof_get_current_muc)(void) = NULL;
 int (*prof_current_win_is_console)(void) = NULL;
 char* (*prof_get_current_nick)(void) = NULL;
-char* (*prof_get_name_from_roster)(const char *barejid) = NULL;
-char* (*prof_get_barejid_from_roster)(const char *name) = NULL;
+char* (*prof_get_name_from_roster)(const char* barejid) = NULL;
+char* (*prof_get_barejid_from_roster)(const char* name) = NULL;
 char** (*prof_get_current_occupants)(void) = NULL;
 
-char* (*prof_get_room_nick)(const char *barejid) = NULL;
+char* (*prof_get_room_nick)(const char* barejid) = NULL;
 
-void (*prof_log_debug)(const char *message) = NULL;
-void (*prof_log_info)(const char *message) = NULL;
-void (*prof_log_warning)(const char *message) = NULL;
-void (*prof_log_error)(const char *message) = NULL;
+void (*prof_log_debug)(const char* message) = NULL;
+void (*prof_log_info)(const char* message) = NULL;
+void (*prof_log_warning)(const char* message) = NULL;
+void (*prof_log_error)(const char* message) = NULL;
 
-void (*_prof_win_create)(const char *filename, PROF_WIN_TAG win, WINDOW_CB input_handler) = NULL;
+void (*_prof_win_create)(const char* filename, PROF_WIN_TAG win, WINDOW_CB input_handler) = NULL;
 int (*prof_win_exists)(PROF_WIN_TAG win) = NULL;
 int (*prof_win_focus)(PROF_WIN_TAG win) = NULL;
-int (*prof_win_show)(PROF_WIN_TAG win, char *line) = NULL;
-int (*prof_win_show_themed)(PROF_WIN_TAG tag, char *group, char *key, char *def, char *line) = NULL;
-
-int (*prof_send_stanza)(char *stanza) = NULL;
-
-int (*prof_settings_boolean_get)(char *group, char *key, int def) = NULL;
-void (*prof_settings_boolean_set)(char *group, char *key, int value) = NULL;
-char* (*prof_settings_string_get)(char *group, char *key, char *def) = NULL;
-void (*prof_settings_string_set)(char *group, char *key, char *value) = NULL;
-int (*prof_settings_int_get)(char *group, char *key, int def) = NULL;
-void (*prof_settings_int_set)(char *group, char *key, int value) = NULL;
-char** (*prof_settings_string_list_get)(char *group, char *key) = NULL;
-void (*prof_settings_string_list_add)(char *group, char *key, char *value) = NULL;
-int (*prof_settings_string_list_remove)(char *group, char *key, char *value) = NULL;
-int (*prof_settings_string_list_clear)(char *group, char *key) = NULL;
-
-void (*prof_incoming_message)(char *barejid, char *resource, char *message) = NULL;
-
-void (*_prof_disco_add_feature)(const char *filename, char *feature) = NULL;
-
-void (*prof_encryption_reset)(const char *barejid) = NULL;
-
-int (*prof_chat_set_titlebar_enctext)(const char *barejid, const char *enctext) = NULL;
-int (*prof_chat_unset_titlebar_enctext)(const char *barejid) = NULL;
-int (*prof_chat_set_incoming_char)(const char *barejid, const char *ch) = NULL;
-int (*prof_chat_unset_incoming_char)(const char *barejid) = NULL;
-int (*prof_chat_set_outgoing_char)(const char *barejid, const char *ch) = NULL;
-int (*prof_chat_unset_outgoing_char)(const char *barejid) = NULL;
-int (*prof_room_set_titlebar_enctext)(const char *roomjid, const char *enctext) = NULL;
-int (*prof_room_unset_titlebar_enctext)(const char *roomjid) = NULL;
-int (*prof_room_set_message_char)(const char *roomjid, const char *ch) = NULL;
-int (*prof_room_unset_message_char)(const char *roomjid) = NULL;
-
-int (*prof_chat_show)(const char *const barejid, const char *const message) = NULL;
-int (*prof_chat_show_themed)(const char *const barejid, const char *const group, const char *const item, const char *const def,
-    const char *const ch, const char *const message) = NULL;
-
-int (*prof_room_show)(const char *const roomjid, const char *const message) = NULL;
-int (*prof_room_show_themed)(const char *const roomjid, const char *const group, const char *const item, const char *const def,
-    const char *const ch, const char *const message) = NULL;
+int (*prof_win_show)(PROF_WIN_TAG win, char* line) = NULL;
+int (*prof_win_show_themed)(PROF_WIN_TAG tag, char* group, char* key, char* def, char* line) = NULL;
+
+int (*prof_send_stanza)(char* stanza) = NULL;
+
+int (*prof_settings_boolean_get)(char* group, char* key, int def) = NULL;
+void (*prof_settings_boolean_set)(char* group, char* key, int value) = NULL;
+char* (*prof_settings_string_get)(char* group, char* key, char* def) = NULL;
+void (*prof_settings_string_set)(char* group, char* key, char* value) = NULL;
+int (*prof_settings_int_get)(char* group, char* key, int def) = NULL;
+void (*prof_settings_int_set)(char* group, char* key, int value) = NULL;
+char** (*prof_settings_string_list_get)(char* group, char* key) = NULL;
+void (*prof_settings_string_list_add)(char* group, char* key, char* value) = NULL;
+int (*prof_settings_string_list_remove)(char* group, char* key, char* value) = NULL;
+int (*prof_settings_string_list_clear)(char* group, char* key) = NULL;
+
+void (*prof_incoming_message)(char* barejid, char* resource, char* message) = NULL;
+
+void (*_prof_disco_add_feature)(const char* filename, char* feature) = NULL;
+
+void (*prof_encryption_reset)(const char* barejid) = NULL;
+
+int (*prof_chat_set_titlebar_enctext)(const char* barejid, const char* enctext) = NULL;
+int (*prof_chat_unset_titlebar_enctext)(const char* barejid) = NULL;
+int (*prof_chat_set_incoming_char)(const char* barejid, const char* ch) = NULL;
+int (*prof_chat_unset_incoming_char)(const char* barejid) = NULL;
+int (*prof_chat_set_outgoing_char)(const char* barejid, const char* ch) = NULL;
+int (*prof_chat_unset_outgoing_char)(const char* barejid) = NULL;
+int (*prof_room_set_titlebar_enctext)(const char* roomjid, const char* enctext) = NULL;
+int (*prof_room_unset_titlebar_enctext)(const char* roomjid) = NULL;
+int (*prof_room_set_message_char)(const char* roomjid, const char* ch) = NULL;
+int (*prof_room_unset_message_char)(const char* roomjid) = NULL;
+
+int (*prof_chat_show)(const char* const barejid, const char* const message) = NULL;
+int (*prof_chat_show_themed)(const char* const barejid, const char* const group, const char* const item, const char* const def,
+                             const char* const ch, const char* const message)
+    = NULL;
+
+int (*prof_room_show)(const char* const roomjid, const char* const message) = NULL;
+int (*prof_room_show_themed)(const char* const roomjid, const char* const group, const char* const item, const char* const def,
+                             const char* const ch, const char* const message)
+    = NULL;
diff --git a/src/plugins/profapi.h b/src/plugins/profapi.h
index 7e607f09..cb850c82 100644
--- a/src/plugins/profapi.h
+++ b/src/plugins/profapi.h
@@ -37,96 +37,96 @@
 #define PLUGINS_PROF_API_H
 
 #define prof_register_command(command_name, min_args, max_args, synopsis, description, arguments, examples, callback) _prof_register_command(__FILE__, command_name, min_args, max_args, synopsis, description, arguments, examples, callback)
-#define prof_register_timed(callback, interval_seconds) _prof_register_timed(__FILE__, callback, interval_seconds)
-#define prof_completer_add(key, items) _prof_completer_add(__FILE__, key, items)
-#define prof_completer_remove(key, items) _prof_completer_remove(__FILE__, key, items)
-#define prof_completer_clear(key) _prof_completer_clear(__FILE__, key)
-#define prof_filepath_completer_add(prefix) _prof_filepath_completer_add(__FILE__, prefix)
-#define prof_win_create(win, input_handler) _prof_win_create(__FILE__, win, input_handler)
-#define prof_disco_add_feature(feature) _prof_disco_add_feature(__FILE__, feature)
+#define prof_register_timed(callback, interval_seconds)                                                               _prof_register_timed(__FILE__, callback, interval_seconds)
+#define prof_completer_add(key, items)                                                                                _prof_completer_add(__FILE__, key, items)
+#define prof_completer_remove(key, items)                                                                             _prof_completer_remove(__FILE__, key, items)
+#define prof_completer_clear(key)                                                                                     _prof_completer_clear(__FILE__, key)
+#define prof_filepath_completer_add(prefix)                                                                           _prof_filepath_completer_add(__FILE__, prefix)
+#define prof_win_create(win, input_handler)                                                                           _prof_win_create(__FILE__, win, input_handler)
+#define prof_disco_add_feature(feature)                                                                               _prof_disco_add_feature(__FILE__, feature)
 
 typedef char* PROF_WIN_TAG;
-typedef void(*CMD_CB)(char **args);
-typedef void(*TIMED_CB)(void);
-typedef void(*WINDOW_CB)(PROF_WIN_TAG win, char *line);
+typedef void (*CMD_CB)(char** args);
+typedef void (*TIMED_CB)(void);
+typedef void (*WINDOW_CB)(PROF_WIN_TAG win, char* line);
 
 void (*prof_cons_alert)(void);
-int (*prof_cons_show)(const char * const message);
-int (*prof_cons_show_themed)(const char *const group, const char *const item, const char *const def, const char *const message);
-int (*prof_cons_bad_cmd_usage)(const char *const cmd);
+int (*prof_cons_show)(const char* const message);
+int (*prof_cons_show_themed)(const char* const group, const char* const item, const char* const def, const char* const message);
+int (*prof_cons_bad_cmd_usage)(const char* const cmd);
 
-void (*_prof_register_command)(const char *filename, const char *command_name, int min_args, int max_args,
-    char **synopsis, const char *description, char *arguments[][2], char **examples,
-    CMD_CB callback);
+void (*_prof_register_command)(const char* filename, const char* command_name, int min_args, int max_args,
+                               char** synopsis, const char* description, char* arguments[][2], char** examples,
+                               CMD_CB callback);
 
-void (*_prof_register_timed)(const char *filename, TIMED_CB callback, int interval_seconds);
+void (*_prof_register_timed)(const char* filename, TIMED_CB callback, int interval_seconds);
 
-void (*_prof_completer_add)(const char *filename, const char *key, char **items);
-void (*_prof_completer_remove)(const char *filename, const char *key, char **items);
-void (*_prof_completer_clear)(const char *filename, const char *key);
-void (*_prof_filepath_completer_add)(const char *filename, const char *prefix);
+void (*_prof_completer_add)(const char* filename, const char* key, char** items);
+void (*_prof_completer_remove)(const char* filename, const char* key, char** items);
+void (*_prof_completer_clear)(const char* filename, const char* key);
+void (*_prof_filepath_completer_add)(const char* filename, const char* prefix);
 
-void (*prof_notify)(const char *message, int timeout_ms, const char *category);
+void (*prof_notify)(const char* message, int timeout_ms, const char* category);
 
-void (*prof_send_line)(char *line);
+void (*prof_send_line)(char* line);
 
 char* (*prof_get_current_recipient)(void);
 char* (*prof_get_current_muc)(void);
 int (*prof_current_win_is_console)(void);
 char* (*prof_get_current_nick)(void);
-char* (*prof_get_name_from_roster)(const char *barejid);
-char* (*prof_get_barejid_from_roster)(const char *name);
+char* (*prof_get_name_from_roster)(const char* barejid);
+char* (*prof_get_barejid_from_roster)(const char* name);
 char** (*prof_get_current_occupants)(void);
 
-char* (*prof_get_room_nick)(const char *barejid);
+char* (*prof_get_room_nick)(const char* barejid);
 
-void (*prof_log_debug)(const char *message);
-void (*prof_log_info)(const char *message);
-void (*prof_log_warning)(const char *message);
-void (*prof_log_error)(const char *message);
+void (*prof_log_debug)(const char* message);
+void (*prof_log_info)(const char* message);
+void (*prof_log_warning)(const char* message);
+void (*prof_log_error)(const char* message);
 
-void (*_prof_win_create)(const char *filename, PROF_WIN_TAG win, WINDOW_CB input_handler);
+void (*_prof_win_create)(const char* filename, PROF_WIN_TAG win, WINDOW_CB input_handler);
 int (*prof_win_exists)(PROF_WIN_TAG win);
 int (*prof_win_focus)(PROF_WIN_TAG win);
-int (*prof_win_show)(PROF_WIN_TAG win, char *line);
-int (*prof_win_show_themed)(PROF_WIN_TAG tag, char *group, char *key, char *def, char *line);
-
-int (*prof_send_stanza)(char *stanza);
-
-int (*prof_settings_boolean_get)(char *group, char *key, int def);
-void (*prof_settings_boolean_set)(char *group, char *key, int value);
-char* (*prof_settings_string_get)(char *group, char *key, char *def);
-void (*prof_settings_string_set)(char *group, char *key, char *value);
-int (*prof_settings_int_get)(char *group, char *key, int def);
-void (*prof_settings_int_set)(char *group, char *key, int value);
-char** (*prof_settings_string_list_get)(char *group, char *key);
-void (*prof_settings_string_list_add)(char *group, char *key, char *value);
-int (*prof_settings_string_list_remove)(char *group, char *key, char *value);
-int (*prof_settings_string_list_clear)(char *group, char *key);
-
-void (*prof_incoming_message)(char *barejid, char *resource, char *message);
-
-void (*_prof_disco_add_feature)(const char *filename, char *feature);
-
-void (*prof_encryption_reset)(const char *barejid);
-
-int (*prof_chat_set_titlebar_enctext)(const char *barejid, const char *enctext);
-int (*prof_chat_unset_titlebar_enctext)(const char *barejid);
-int (*prof_chat_set_incoming_char)(const char *barejid, const char *ch);
-int (*prof_chat_unset_incoming_char)(const char *barejid);
-int (*prof_chat_set_outgoing_char)(const char *barejid, const char *ch);
-int (*prof_chat_unset_outgoing_char)(const char *barejid);
-int (*prof_room_set_titlebar_enctext)(const char *roomjid, const char *enctext);
-int (*prof_room_unset_titlebar_enctext)(const char *roomjid);
-int (*prof_room_set_message_char)(const char *roomjid, const char *ch);
-int (*prof_room_unset_message_char)(const char *roomjid);
-
-int (*prof_chat_show)(const char *const barejid, const char *const message);
-int (*prof_chat_show_themed)(const char *const barejid, const char *const group, const char *const item, const char *const def,
-    const char *const ch, const char *const message);
-
-int (*prof_room_show)(const char *const roomjid, const char *const message);
-int (*prof_room_show_themed)(const char *const roomjid, const char *const group, const char *const item, const char *const def,
-    const char *const ch, const char *const message);
+int (*prof_win_show)(PROF_WIN_TAG win, char* line);
+int (*prof_win_show_themed)(PROF_WIN_TAG tag, char* group, char* key, char* def, char* line);
+
+int (*prof_send_stanza)(char* stanza);
+
+int (*prof_settings_boolean_get)(char* group, char* key, int def);
+void (*prof_settings_boolean_set)(char* group, char* key, int value);
+char* (*prof_settings_string_get)(char* group, char* key, char* def);
+void (*prof_settings_string_set)(char* group, char* key, char* value);
+int (*prof_settings_int_get)(char* group, char* key, int def);
+void (*prof_settings_int_set)(char* group, char* key, int value);
+char** (*prof_settings_string_list_get)(char* group, char* key);
+void (*prof_settings_string_list_add)(char* group, char* key, char* value);
+int (*prof_settings_string_list_remove)(char* group, char* key, char* value);
+int (*prof_settings_string_list_clear)(char* group, char* key);
+
+void (*prof_incoming_message)(char* barejid, char* resource, char* message);
+
+void (*_prof_disco_add_feature)(const char* filename, char* feature);
+
+void (*prof_encryption_reset)(const char* barejid);
+
+int (*prof_chat_set_titlebar_enctext)(const char* barejid, const char* enctext);
+int (*prof_chat_unset_titlebar_enctext)(const char* barejid);
+int (*prof_chat_set_incoming_char)(const char* barejid, const char* ch);
+int (*prof_chat_unset_incoming_char)(const char* barejid);
+int (*prof_chat_set_outgoing_char)(const char* barejid, const char* ch);
+int (*prof_chat_unset_outgoing_char)(const char* barejid);
+int (*prof_room_set_titlebar_enctext)(const char* roomjid, const char* enctext);
+int (*prof_room_unset_titlebar_enctext)(const char* roomjid);
+int (*prof_room_set_message_char)(const char* roomjid, const char* ch);
+int (*prof_room_unset_message_char)(const char* roomjid);
+
+int (*prof_chat_show)(const char* const barejid, const char* const message);
+int (*prof_chat_show_themed)(const char* const barejid, const char* const group, const char* const item, const char* const def,
+                             const char* const ch, const char* const message);
+
+int (*prof_room_show)(const char* const roomjid, const char* const message);
+int (*prof_room_show_themed)(const char* const roomjid, const char* const group, const char* const item, const char* const def,
+                             const char* const ch, const char* const message);
 
 #endif
diff --git a/src/ui/inputwin.c b/src/ui/inputwin.c
index e59be8b5..453dfeac 100644
--- a/src/ui/inputwin.c
+++ b/src/ui/inputwin.c
@@ -568,12 +568,15 @@ _inp_rl_startup_hook(void)
 static void
 _inp_rl_linehandler(char* line)
 {
-    if (line && *line) {
-        if (!get_password) {
-            add_history(line);
-        }
-    }
     inp_line = line;
+    if (!line || !*line || get_password) {
+        return;
+    }
+    HISTORY_STATE* history = history_get_history_state();
+    HIST_ENTRY* last = history->length > 0 ? history->entries[history->length - 1] : NULL;
+    if (last == NULL || strcmp(last->line, line) != 0) {
+        add_history(line);
+    }
 }
 
 static gboolean shift_tab = FALSE;