Compare commits
8 Commits
merge-impr
...
fix/issue-
| Author | SHA1 | Date | |
|---|---|---|---|
| 25e9bc6e93 | |||
|
5b45b35b3e
|
|||
|
57d79ecf9c
|
|||
|
bfd7064a40
|
|||
|
3f6b8f69fd
|
|||
|
a04a8948e1
|
|||
|
c1093db090
|
|||
|
72f4f186da
|
@@ -2638,7 +2638,8 @@ static const struct cmd_t command_defs[] = {
|
|||||||
CMD_DESC(
|
CMD_DESC(
|
||||||
"Spawn external editor to edit message. "
|
"Spawn external editor to edit message. "
|
||||||
"After editing the inputline may appear empty. Press enter to send the text anyways. "
|
"After editing the inputline may appear empty. Press enter to send the text anyways. "
|
||||||
"Use /executable to set your favourite editor." )
|
"Use /executable to set your favourite editor. "
|
||||||
|
"Ctrl-Z in the editor aborts the session and returns to Profanity." )
|
||||||
},
|
},
|
||||||
|
|
||||||
{ CMD_PREAMBLE("/correct-editor",
|
{ CMD_PREAMBLE("/correct-editor",
|
||||||
|
|||||||
14
src/common.c
14
src/common.c
@@ -748,17 +748,17 @@ call_external(gchar** argv)
|
|||||||
*
|
*
|
||||||
* This function constructs an argument vector (argv) based on the provided template string, replacing placeholders ("%u" and "%p") with the provided URL and filename, respectively.
|
* This function constructs an argument vector (argv) based on the provided template string, replacing placeholders ("%u" and "%p") with the provided URL and filename, respectively.
|
||||||
*
|
*
|
||||||
* @param template The template string with placeholders.
|
* @param template_fmt The template string with placeholders.
|
||||||
* @param url The URL to replace "%u" (or NULL to skip).
|
* @param url The URL to replace "%u" (or NULL to skip).
|
||||||
* @param filename The filename to replace "%p" (or NULL to skip).
|
* @param filename The filename to replace "%p" (or NULL to skip).
|
||||||
* @return The constructed argument vector (argv) as a null-terminated array of strings.
|
* @return The constructed argument vector (argv) as a null-terminated array of strings.
|
||||||
*
|
*
|
||||||
* @note Remember to free the returned argument vector using `auto_gcharv` or `g_strfreev()`.
|
* @note Remember to free the returned argument vector using `auto_gcharv` or `g_strfreev()`.
|
||||||
*/
|
*/
|
||||||
gchar**
|
gchar**
|
||||||
format_call_external_argv(const char* template, const char* url, const char* filename)
|
format_call_external_argv(const char* template_fmt, const char* url, const char* filename)
|
||||||
{
|
{
|
||||||
gchar** argv = g_strsplit(template, " ", 0);
|
gchar** argv = g_strsplit(template_fmt, " ", 0);
|
||||||
|
|
||||||
guint num_args = 0;
|
guint num_args = 0;
|
||||||
while (argv[num_args]) {
|
while (argv[num_args]) {
|
||||||
@@ -767,7 +767,7 @@ format_call_external_argv(const char* template, const char* url, const char* fil
|
|||||||
argv[num_args] = g_strdup(url);
|
argv[num_args] = g_strdup(url);
|
||||||
} else if (0 == g_strcmp0(argv[num_args], "%p") && filename != NULL) {
|
} else if (0 == g_strcmp0(argv[num_args], "%p") && filename != NULL) {
|
||||||
g_free(argv[num_args]);
|
g_free(argv[num_args]);
|
||||||
argv[num_args] = strdup(filename);
|
argv[num_args] = g_strdup(filename);
|
||||||
}
|
}
|
||||||
num_args++;
|
num_args++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ void get_file_paths_recursive(const char* directory, GSList** contents);
|
|||||||
gchar* get_random_string(int length);
|
gchar* get_random_string(int length);
|
||||||
|
|
||||||
gboolean call_external(gchar** argv);
|
gboolean call_external(gchar** argv);
|
||||||
gchar** format_call_external_argv(const char* template, const char* url, const char* filename);
|
gchar** format_call_external_argv(const char* template_fmt, const char* url, const char* filename);
|
||||||
|
|
||||||
gchar* unique_filename_from_url(const char* url, const char* path);
|
gchar* unique_filename_from_url(const char* url, const char* path);
|
||||||
gchar* get_expanded_path(const char* path);
|
gchar* get_expanded_path(const char* path);
|
||||||
|
|||||||
@@ -178,6 +178,9 @@ _sqlite_init(ProfAccount* account)
|
|||||||
// replaced_by_db_id Inverse FK: id of the most recent correction.
|
// replaced_by_db_id Inverse FK: id of the most recent correction.
|
||||||
// Maintained by the AFTER INSERT trigger below so
|
// Maintained by the AFTER INSERT trigger below so
|
||||||
// readers can follow the chain forward in O(1).
|
// readers can follow the chain forward in O(1).
|
||||||
|
//
|
||||||
|
// NOTE: any change to these columns (add/remove/reorder) must be mirrored
|
||||||
|
// in `_migrate_to_v3`, which copies rows via an explicit column list.
|
||||||
const char* query = "CREATE TABLE IF NOT EXISTS `ChatLogs` ("
|
const char* query = "CREATE TABLE IF NOT EXISTS `ChatLogs` ("
|
||||||
"`id` INTEGER PRIMARY KEY AUTOINCREMENT, "
|
"`id` INTEGER PRIMARY KEY AUTOINCREMENT, "
|
||||||
"`from_jid` TEXT NOT NULL, "
|
"`from_jid` TEXT NOT NULL, "
|
||||||
@@ -865,11 +868,37 @@ _migrate_to_v3(void)
|
|||||||
"`replaces_db_id` INTEGER, "
|
"`replaces_db_id` INTEGER, "
|
||||||
"`replaced_by_db_id` INTEGER)",
|
"`replaced_by_db_id` INTEGER)",
|
||||||
|
|
||||||
|
// Copy rows into the deduped table. Columns are listed explicitly
|
||||||
|
// (instead of `SELECT *`) so the migration cannot silently mis-bind
|
||||||
|
// should the v2/v3 column order ever diverge — keep this list in sync
|
||||||
|
// with the `ChatLogs_v3_migration` schema above and the live `ChatLogs`
|
||||||
|
// schema. For duplicate `archive_id` groups (MAM rebroadcasts) keep the
|
||||||
|
// highest `id` deterministically ("latest insert wins") rather than
|
||||||
|
// GROUP BY's implementation-defined arbitrary pick.
|
||||||
"INSERT INTO `ChatLogs_v3_migration` "
|
"INSERT INTO `ChatLogs_v3_migration` "
|
||||||
"SELECT * FROM `ChatLogs` "
|
"(`id`, `from_jid`, `to_jid`, `from_resource`, `to_resource`, `message`, "
|
||||||
"WHERE `archive_id` IS NULL "
|
"`timestamp`, `type`, `stanza_id`, `archive_id`, `encryption`, "
|
||||||
|
"`marked_read`, `replace_id`, `replaces_db_id`, `replaced_by_db_id`) "
|
||||||
|
"SELECT `id`, `from_jid`, `to_jid`, `from_resource`, `to_resource`, `message`, "
|
||||||
|
"`timestamp`, `type`, `stanza_id`, `archive_id`, `encryption`, "
|
||||||
|
"`marked_read`, `replace_id`, `replaces_db_id`, `replaced_by_db_id` "
|
||||||
|
"FROM `ChatLogs` WHERE `archive_id` IS NULL "
|
||||||
"UNION ALL "
|
"UNION ALL "
|
||||||
"SELECT * FROM (SELECT * FROM `ChatLogs` WHERE `archive_id` IS NOT NULL GROUP BY `archive_id`)",
|
"SELECT `id`, `from_jid`, `to_jid`, `from_resource`, `to_resource`, `message`, "
|
||||||
|
"`timestamp`, `type`, `stanza_id`, `archive_id`, `encryption`, "
|
||||||
|
"`marked_read`, `replace_id`, `replaces_db_id`, `replaced_by_db_id` "
|
||||||
|
"FROM `ChatLogs` WHERE `archive_id` IS NOT NULL "
|
||||||
|
"AND `id` IN (SELECT MAX(`id`) FROM `ChatLogs` WHERE `archive_id` IS NOT NULL GROUP BY `archive_id`)",
|
||||||
|
|
||||||
|
// Dropping duplicate rows above can leave the surviving rows' correction
|
||||||
|
// back-links pointing at ids that no longer exist. NULL them out so the
|
||||||
|
// XEP-0308 (LMC) chain carries no dangling local foreign keys.
|
||||||
|
"UPDATE `ChatLogs_v3_migration` SET `replaces_db_id` = NULL "
|
||||||
|
"WHERE `replaces_db_id` IS NOT NULL "
|
||||||
|
"AND `replaces_db_id` NOT IN (SELECT `id` FROM `ChatLogs_v3_migration`)",
|
||||||
|
"UPDATE `ChatLogs_v3_migration` SET `replaced_by_db_id` = NULL "
|
||||||
|
"WHERE `replaced_by_db_id` IS NOT NULL "
|
||||||
|
"AND `replaced_by_db_id` NOT IN (SELECT `id` FROM `ChatLogs_v3_migration`)",
|
||||||
|
|
||||||
"DROP TABLE `ChatLogs` ",
|
"DROP TABLE `ChatLogs` ",
|
||||||
"ALTER TABLE `ChatLogs_v3_migration` RENAME TO `ChatLogs` ",
|
"ALTER TABLE `ChatLogs_v3_migration` RENAME TO `ChatLogs` ",
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
#ifndef EVENT_COMMON_H
|
#ifndef EVENT_COMMON_H
|
||||||
#define EVENT_COMMON_H
|
#define EVENT_COMMON_H
|
||||||
|
|
||||||
|
#include "glib.h"
|
||||||
|
|
||||||
void ev_disconnect_cleanup(void);
|
void ev_disconnect_cleanup(void);
|
||||||
void ev_inc_connection_counter(void);
|
void ev_inc_connection_counter(void);
|
||||||
void ev_reset_connection_counter(void);
|
void ev_reset_connection_counter(void);
|
||||||
|
|||||||
@@ -341,7 +341,7 @@ sv_ev_room_message(ProfMessage* message)
|
|||||||
status_bar_active(num, WIN_MUC, mucwin->roomjid);
|
status_bar_active(num, WIN_MUC, mucwin->roomjid);
|
||||||
|
|
||||||
if ((g_strcmp0(mynick, message->from_jid->resourcepart) != 0) && (prefs_get_boolean(PREF_BEEP))) {
|
if ((g_strcmp0(mynick, message->from_jid->resourcepart) != 0) && (prefs_get_boolean(PREF_BEEP))) {
|
||||||
beep();
|
ui_beep();
|
||||||
}
|
}
|
||||||
|
|
||||||
// not currently on groupchat window
|
// not currently on groupchat window
|
||||||
@@ -349,7 +349,7 @@ sv_ev_room_message(ProfMessage* message)
|
|||||||
status_bar_new(num, WIN_MUC, mucwin->roomjid);
|
status_bar_new(num, WIN_MUC, mucwin->roomjid);
|
||||||
|
|
||||||
if ((g_strcmp0(mynick, message->from_jid->resourcepart) != 0) && (prefs_get_boolean(PREF_FLASH))) {
|
if ((g_strcmp0(mynick, message->from_jid->resourcepart) != 0) && (prefs_get_boolean(PREF_FLASH))) {
|
||||||
flash();
|
ui_flash();
|
||||||
}
|
}
|
||||||
|
|
||||||
cons_show_incoming_room_message(message->from_jid->resourcepart, mucwin->roomjid, num, mention, triggers, mucwin->unread, window);
|
cons_show_incoming_room_message(message->from_jid->resourcepart, mucwin->roomjid, num, mention, triggers, mucwin->unread, window);
|
||||||
|
|||||||
@@ -804,6 +804,10 @@ omemo_on_message_send(ProfWin* win, const char* const message, gboolean request_
|
|||||||
tag_len = AES128_GCM_TAG_LENGTH;
|
tag_len = AES128_GCM_TAG_LENGTH;
|
||||||
tag = gcry_malloc_secure(tag_len);
|
tag = gcry_malloc_secure(tag_len);
|
||||||
key_tag = gcry_malloc_secure(AES128_GCM_KEY_LENGTH + AES128_GCM_TAG_LENGTH);
|
key_tag = gcry_malloc_secure(AES128_GCM_KEY_LENGTH + AES128_GCM_TAG_LENGTH);
|
||||||
|
if (!tag || !key_tag) {
|
||||||
|
log_error("[OMEMO][SEND] cannot allocate secure buffers");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
key = gcry_random_bytes_secure(AES128_GCM_KEY_LENGTH + AES128_GCM_IV_LENGTH, GCRY_VERY_STRONG_RANDOM);
|
key = gcry_random_bytes_secure(AES128_GCM_KEY_LENGTH + AES128_GCM_IV_LENGTH, GCRY_VERY_STRONG_RANDOM);
|
||||||
if (!key) {
|
if (!key) {
|
||||||
@@ -1993,10 +1997,6 @@ _cache_device_identity(const char* const jid, uint32_t device_id, ec_public_key*
|
|||||||
g_hash_table_insert(omemo_static_data.fingerprint_ac, strdup(jid), ac);
|
g_hash_table_insert(omemo_static_data.fingerprint_ac, strdup(jid), ac);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fingerprint) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char* formatted_fingerprint = omemo_format_fingerprint(fingerprint);
|
char* formatted_fingerprint = omemo_format_fingerprint(fingerprint);
|
||||||
if (formatted_fingerprint) {
|
if (formatted_fingerprint) {
|
||||||
autocomplete_add(ac, formatted_fingerprint);
|
autocomplete_add(ac, formatted_fingerprint);
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
#ifndef PGP_GPG_H
|
#ifndef PGP_GPG_H
|
||||||
#define PGP_GPG_H
|
#define PGP_GPG_H
|
||||||
|
|
||||||
|
#include "glib.h"
|
||||||
|
|
||||||
typedef struct pgp_key_t
|
typedef struct pgp_key_t
|
||||||
{
|
{
|
||||||
gchar* id;
|
gchar* id;
|
||||||
|
|||||||
@@ -70,6 +70,38 @@ static void _connect_default(const char* const account);
|
|||||||
pthread_mutex_t lock;
|
pthread_mutex_t lock;
|
||||||
static gboolean force_quit = FALSE;
|
static gboolean force_quit = FALSE;
|
||||||
|
|
||||||
|
static volatile sig_atomic_t suspend_requested = FALSE;
|
||||||
|
static volatile sig_atomic_t cont_requested = FALSE;
|
||||||
|
|
||||||
|
static void
|
||||||
|
_handle_suspend_signals(void)
|
||||||
|
{
|
||||||
|
if (cont_requested) {
|
||||||
|
cont_requested = FALSE;
|
||||||
|
if (!editor_is_active()) {
|
||||||
|
clearok(stdscr, TRUE);
|
||||||
|
ui_resize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (editor_check_stopped()) {
|
||||||
|
log_info("[Editor] stopped; aborting back to profanity");
|
||||||
|
suspend_requested = FALSE;
|
||||||
|
editor_emergency_kill();
|
||||||
|
} else if (suspend_requested) {
|
||||||
|
suspend_requested = FALSE;
|
||||||
|
if (editor_is_active()) {
|
||||||
|
log_info("[Editor] SIGTSTP from vim group; deferring to next poll");
|
||||||
|
} else {
|
||||||
|
log_info("[Suspend] dropping to shell");
|
||||||
|
if (!isendwin()) {
|
||||||
|
endwin();
|
||||||
|
}
|
||||||
|
kill(0, SIGSTOP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
prof_run(gchar* log_level, gchar* account_name, gchar* config_file, gchar* log_file, gchar* theme_name, gchar** commands)
|
prof_run(gchar* log_level, gchar* account_name, gchar* config_file, gchar* log_file, gchar* theme_name, gchar** commands)
|
||||||
{
|
{
|
||||||
@@ -93,6 +125,7 @@ prof_run(gchar* log_level, gchar* account_name, gchar* config_file, gchar* log_f
|
|||||||
int waittime = 0;
|
int waittime = 0;
|
||||||
while (cont && !force_quit) {
|
while (cont && !force_quit) {
|
||||||
log_stderr_handler();
|
log_stderr_handler();
|
||||||
|
_handle_suspend_signals();
|
||||||
session_check_autoaway();
|
session_check_autoaway();
|
||||||
|
|
||||||
line = commands ? *commands : inp_readline();
|
line = commands ? *commands : inp_readline();
|
||||||
@@ -182,6 +215,18 @@ sigterm_handler(int sig)
|
|||||||
force_quit = TRUE;
|
force_quit = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sigtstp_handler(int sig)
|
||||||
|
{
|
||||||
|
suspend_requested = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sigcont_handler(int sig)
|
||||||
|
{
|
||||||
|
cont_requested = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_init(char* log_level, char* config_file, char* log_file, char* theme_name)
|
_init(char* log_level, char* config_file, char* log_file, char* theme_name)
|
||||||
{
|
{
|
||||||
@@ -189,7 +234,8 @@ _init(char* log_level, char* config_file, char* log_file, char* theme_name)
|
|||||||
// ignore SIGPIPE
|
// ignore SIGPIPE
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
signal(SIGINT, SIG_IGN);
|
signal(SIGINT, SIG_IGN);
|
||||||
signal(SIGTSTP, SIG_IGN);
|
signal(SIGTSTP, sigtstp_handler);
|
||||||
|
signal(SIGCONT, sigcont_handler);
|
||||||
signal(SIGWINCH, ui_sigwinch_handler);
|
signal(SIGWINCH, ui_sigwinch_handler);
|
||||||
signal(SIGTERM, sigterm_handler);
|
signal(SIGTERM, sigterm_handler);
|
||||||
signal(SIGHUP, sigterm_handler);
|
signal(SIGHUP, sigterm_handler);
|
||||||
|
|||||||
@@ -10,8 +10,10 @@
|
|||||||
#ifndef BOOKMARK_IGNORE_H
|
#ifndef BOOKMARK_IGNORE_H
|
||||||
#define BOOKMARK_IGNORE_H
|
#define BOOKMARK_IGNORE_H
|
||||||
|
|
||||||
|
#include "xmpp/xmpp.h"
|
||||||
|
|
||||||
void bookmark_ignore_on_connect(const char* const barejid);
|
void bookmark_ignore_on_connect(const char* const barejid);
|
||||||
void bookmark_ignore_on_disconnect(void);
|
void bookmark_ignore_on_disconnect();
|
||||||
gboolean bookmark_ignored(Bookmark* bookmark);
|
gboolean bookmark_ignored(Bookmark* bookmark);
|
||||||
gchar** bookmark_ignore_list(gsize* len);
|
gchar** bookmark_ignore_list(gsize* len);
|
||||||
void bookmark_ignore_add(const char* const barejid);
|
void bookmark_ignore_add(const char* const barejid);
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
#include "ncurses.h"
|
#include "ncurses.h"
|
||||||
#include "ui/ui.h"
|
#include "ui/ui.h"
|
||||||
#include "xmpp/xmpp.h"
|
#include "xmpp/xmpp.h"
|
||||||
#include "ui/ui.h"
|
|
||||||
|
|
||||||
typedef struct EditorContext
|
typedef struct EditorContext
|
||||||
{
|
{
|
||||||
@@ -33,9 +32,15 @@ typedef struct EditorContext
|
|||||||
void* user_data;
|
void* user_data;
|
||||||
} EditorContext;
|
} EditorContext;
|
||||||
|
|
||||||
|
static gboolean editor_active = FALSE; // re-entrancy guard
|
||||||
|
static pid_t editor_pid = 0;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_editor_exit_cb(GPid pid, gint status, gpointer data)
|
_editor_exit_cb(GPid pid, gint status, gpointer data)
|
||||||
{
|
{
|
||||||
|
editor_active = FALSE;
|
||||||
|
editor_pid = 0;
|
||||||
|
|
||||||
EditorContext* ctx = data;
|
EditorContext* ctx = data;
|
||||||
gchar* contents = NULL;
|
gchar* contents = NULL;
|
||||||
GError* error = NULL;
|
GError* error = NULL;
|
||||||
@@ -53,8 +58,10 @@ _editor_exit_cb(GPid pid, gint status, gpointer data)
|
|||||||
cons_show_error("Could not read edited content: %s", error->message);
|
cons_show_error("Could not read edited content: %s", error->message);
|
||||||
g_error_free(error);
|
g_error_free(error);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (WIFEXITED(status)) {
|
||||||
cons_show_error("Editor exited with error status %d", WEXITSTATUS(status));
|
cons_show_error("Editor exited with status %d", WEXITSTATUS(status));
|
||||||
|
} else if (WIFSIGNALED(status)) {
|
||||||
|
cons_show("Editor session cancelled.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remove(ctx->filename) != 0) {
|
if (remove(ctx->filename) != 0) {
|
||||||
@@ -71,6 +78,11 @@ _editor_exit_cb(GPid pid, gint status, gpointer data)
|
|||||||
gboolean
|
gboolean
|
||||||
launch_editor(gchar* initial_content, void (*callback)(gchar* content, void* data), void* user_data)
|
launch_editor(gchar* initial_content, void (*callback)(gchar* content, void* data), void* user_data)
|
||||||
{
|
{
|
||||||
|
if (editor_active) {
|
||||||
|
cons_show_error("An editor session is already active.");
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
auto_gchar gchar* filename = NULL;
|
auto_gchar gchar* filename = NULL;
|
||||||
auto_gerror GError* glib_error = NULL;
|
auto_gerror GError* glib_error = NULL;
|
||||||
const char* jid = connection_get_barejid();
|
const char* jid = connection_get_barejid();
|
||||||
@@ -119,17 +131,19 @@ launch_editor(gchar* initial_content, void (*callback)(gchar* content, void* dat
|
|||||||
ctx->callback = callback;
|
ctx->callback = callback;
|
||||||
ctx->user_data = user_data;
|
ctx->user_data = user_data;
|
||||||
|
|
||||||
|
editor_active = TRUE;
|
||||||
ui_suspend();
|
ui_suspend();
|
||||||
|
|
||||||
// Ensure GLib's SIGCHLD handler is installed before forking to prevent
|
// Force GLib to install its SIGCHLD handler before forking. Creating a
|
||||||
// zombie children if the editor is launched before the main loop starts.
|
// GChildWatchSource for our own pid is the documented trigger; we never
|
||||||
GMainContext* main_ctx = g_main_context_default();
|
// attach or dispatch it, just rely on the side effect.
|
||||||
g_main_context_acquire(main_ctx);
|
GSource* sigchld_warmup = g_child_watch_source_new(getpid());
|
||||||
g_main_context_release(main_ctx);
|
g_source_unref(sigchld_warmup);
|
||||||
|
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
if (pid == -1) {
|
if (pid == -1) {
|
||||||
log_error("[Editor] Failed to fork: %s", strerror(errno));
|
log_error("[Editor] Failed to fork: %s", strerror(errno));
|
||||||
|
editor_active = FALSE;
|
||||||
ui_resume();
|
ui_resume();
|
||||||
ui_resize();
|
ui_resize();
|
||||||
cons_show_error("Failed to start editor: %s", strerror(errno));
|
cons_show_error("Failed to start editor: %s", strerror(errno));
|
||||||
@@ -140,7 +154,8 @@ launch_editor(gchar* initial_content, void (*callback)(gchar* content, void* dat
|
|||||||
} else if (pid == 0) {
|
} else if (pid == 0) {
|
||||||
// Child process: Inherits TTY from parent
|
// Child process: Inherits TTY from parent
|
||||||
|
|
||||||
// Reset signal handlers that profanity sets so the editor doesn't inherit them
|
// SIGTSTP=SIG_DFL lets vim's :stop / Ctrl-Z work; profanity catches
|
||||||
|
// the STOPPED state via editor_check_stopped() and drops to the shell.
|
||||||
signal(SIGINT, SIG_DFL);
|
signal(SIGINT, SIG_DFL);
|
||||||
signal(SIGTSTP, SIG_DFL);
|
signal(SIGTSTP, SIG_DFL);
|
||||||
signal(SIGPIPE, SIG_DFL);
|
signal(SIGPIPE, SIG_DFL);
|
||||||
@@ -152,7 +167,39 @@ launch_editor(gchar* initial_content, void (*callback)(gchar* content, void* dat
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parent process: Watch the child asynchronously
|
// Parent process: Watch the child asynchronously
|
||||||
|
editor_pid = pid;
|
||||||
g_child_watch_add((GPid)pid, _editor_exit_cb, ctx);
|
g_child_watch_add((GPid)pid, _editor_exit_cb, ctx);
|
||||||
g_strfreev(editor_argv);
|
g_strfreev(editor_argv);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
editor_emergency_kill(void)
|
||||||
|
{
|
||||||
|
if (!editor_active || editor_pid <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
log_warning("[Editor] aborting editor pid %d", editor_pid);
|
||||||
|
kill(editor_pid, SIGCONT); // wake if STOPPED; no-op otherwise
|
||||||
|
kill(editor_pid, SIGTERM);
|
||||||
|
// _editor_exit_cb will restore the UI when the child reaps.
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
editor_is_active(void)
|
||||||
|
{
|
||||||
|
return editor_active;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
editor_check_stopped(void)
|
||||||
|
{
|
||||||
|
// Poll for STOPPED without reaping (g_child_watch handles exit via its
|
||||||
|
// own WNOHANG). Lets prof_run drop the group to the shell on Ctrl-Z.
|
||||||
|
if (!editor_active || editor_pid <= 0) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
int status;
|
||||||
|
pid_t r = waitpid(editor_pid, &status, WNOHANG | WUNTRACED);
|
||||||
|
return (r == editor_pid && WIFSTOPPED(status));
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,4 +16,13 @@
|
|||||||
|
|
||||||
gboolean launch_editor(gchar* initial_content, void (*callback)(gchar* content, void* data), void* user_data);
|
gboolean launch_editor(gchar* initial_content, void (*callback)(gchar* content, void* data), void* user_data);
|
||||||
|
|
||||||
|
void editor_emergency_kill(void); // SIGCONT+SIGTERM the editor child
|
||||||
|
|
||||||
|
// TRUE if editor child is STOPPED (Ctrl-Z / :stop / gdb-attach). Does not
|
||||||
|
// reap; g_child_watch keeps handling exit.
|
||||||
|
gboolean editor_check_stopped(void);
|
||||||
|
|
||||||
|
// Editor-session flag accessor. Used by prof_run on SIGCONT resume.
|
||||||
|
gboolean editor_is_active(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -327,7 +327,7 @@ chatwin_incoming_msg(ProfChatWin* chatwin, ProfMessage* message, gboolean win_cr
|
|||||||
cons_show_incoming_message(display_name, num, chatwin->unread, window);
|
cons_show_incoming_message(display_name, num, chatwin->unread, window);
|
||||||
|
|
||||||
if (prefs_get_boolean(PREF_FLASH)) {
|
if (prefs_get_boolean(PREF_FLASH)) {
|
||||||
flash();
|
ui_flash();
|
||||||
}
|
}
|
||||||
|
|
||||||
chatwin->unread++;
|
chatwin->unread++;
|
||||||
@@ -364,7 +364,7 @@ chatwin_incoming_msg(ProfChatWin* chatwin, ProfMessage* message, gboolean win_cr
|
|||||||
wins_add_quotes_ac(window, message->plain, FALSE);
|
wins_add_quotes_ac(window, message->plain, FALSE);
|
||||||
|
|
||||||
if (prefs_get_boolean(PREF_BEEP)) {
|
if (prefs_get_boolean(PREF_BEEP)) {
|
||||||
beep();
|
ui_beep();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,8 +399,6 @@ chatwin_outgoing_msg(ProfChatWin* chatwin, const char* const message, const char
|
|||||||
win_print_outgoing((ProfWin*)chatwin, enc_char, id, replace_id, display_message);
|
win_print_outgoing((ProfWin*)chatwin, enc_char, id, replace_id, display_message);
|
||||||
}
|
}
|
||||||
|
|
||||||
plugins_post_chat_message_display(myjid->barejid, myjid->resourcepart, display_message);
|
|
||||||
|
|
||||||
// Save last id and message for LMC
|
// 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
|
// 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
|
// https://xmpp.org/extensions/xep-0308.html#rules
|
||||||
@@ -434,7 +432,6 @@ chatwin_outgoing_carbon(ProfChatWin* chatwin, ProfMessage* message)
|
|||||||
|
|
||||||
win_print_outgoing(window, enc_char, message->id, message->replace_id, message->plain);
|
win_print_outgoing(window, enc_char, message->id, message->replace_id, message->plain);
|
||||||
|
|
||||||
plugins_post_chat_message_display(message->from_jid->barejid, message->from_jid->resourcepart, message->plain);
|
|
||||||
message->plain = old_plain;
|
message->plain = old_plain;
|
||||||
|
|
||||||
int num = wins_get_num(window);
|
int num = wins_get_num(window);
|
||||||
@@ -561,7 +558,6 @@ _chatwin_history(ProfChatWin* chatwin, const char* const contact_barejid)
|
|||||||
if (plugin_msg)
|
if (plugin_msg)
|
||||||
msg->plain = plugin_msg;
|
msg->plain = plugin_msg;
|
||||||
win_print_history((ProfWin*)chatwin, msg);
|
win_print_history((ProfWin*)chatwin, msg);
|
||||||
plugins_post_chat_message_display(msg->from_jid->barejid, msg->from_jid->resourcepart, msg->plain);
|
|
||||||
msg->plain = old_plain;
|
msg->plain = old_plain;
|
||||||
curr = g_slist_next(curr);
|
curr = g_slist_next(curr);
|
||||||
}
|
}
|
||||||
@@ -601,7 +597,6 @@ chatwin_db_history(ProfChatWin* chatwin, const gchar* start_time, const gchar* e
|
|||||||
} else {
|
} else {
|
||||||
win_print_history((ProfWin*)chatwin, msg);
|
win_print_history((ProfWin*)chatwin, msg);
|
||||||
}
|
}
|
||||||
plugins_post_chat_message_display(msg->from_jid->barejid, msg->from_jid->resourcepart, msg->plain);
|
|
||||||
msg->plain = old_plain;
|
msg->plain = old_plain;
|
||||||
curr = g_slist_next(curr);
|
curr = g_slist_next(curr);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@
|
|||||||
|
|
||||||
static int inp_size;
|
static int inp_size;
|
||||||
static gboolean perform_resize = FALSE;
|
static gboolean perform_resize = FALSE;
|
||||||
|
static gboolean ui_suspended = FALSE;
|
||||||
static GTimer* ui_idle_time;
|
static GTimer* ui_idle_time;
|
||||||
static WINDOW* main_scr;
|
static WINDOW* main_scr;
|
||||||
|
|
||||||
@@ -63,6 +64,14 @@ static Display* display;
|
|||||||
|
|
||||||
static void _ui_draw_term_title(void);
|
static void _ui_draw_term_title(void);
|
||||||
|
|
||||||
|
// Fail-safe gate: authoritative flag (doesn't depend on isendwin staying
|
||||||
|
// TRUE), plus the regular endwin check for shutdown.
|
||||||
|
static gboolean
|
||||||
|
_ui_redraw_suspended(void)
|
||||||
|
{
|
||||||
|
return ui_suspended || isendwin();
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_ui_close(void)
|
_ui_close(void)
|
||||||
{
|
{
|
||||||
@@ -120,8 +129,7 @@ ui_sigwinch_handler(int sig)
|
|||||||
void
|
void
|
||||||
ui_update(void)
|
ui_update(void)
|
||||||
{
|
{
|
||||||
// UI is suspended
|
if (_ui_redraw_suspended()) {
|
||||||
if (isendwin()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,7 +146,7 @@ ui_update(void)
|
|||||||
title_bar_update_virtual();
|
title_bar_update_virtual();
|
||||||
status_bar_draw();
|
status_bar_draw();
|
||||||
inp_put_back();
|
inp_put_back();
|
||||||
doupdate();
|
prof_doupdate();
|
||||||
|
|
||||||
if (perform_resize) {
|
if (perform_resize) {
|
||||||
perform_resize = FALSE;
|
perform_resize = FALSE;
|
||||||
@@ -180,21 +188,49 @@ void
|
|||||||
ui_suspend(void)
|
ui_suspend(void)
|
||||||
{
|
{
|
||||||
inp_suspend();
|
inp_suspend();
|
||||||
|
// Flush before flipping the flag (prof_doupdate skips while suspended).
|
||||||
|
prof_doupdate();
|
||||||
|
ui_suspended = TRUE;
|
||||||
endwin();
|
endwin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ui_resume(void)
|
ui_resume(void)
|
||||||
{
|
{
|
||||||
|
ui_suspended = FALSE;
|
||||||
|
clearok(stdscr, TRUE); // ncurses can't see vim's screen clobber
|
||||||
refresh();
|
refresh();
|
||||||
inp_resume();
|
inp_resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ui_beep(void)
|
||||||
|
{
|
||||||
|
if (!isendwin()) {
|
||||||
|
beep();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ui_flash(void)
|
||||||
|
{
|
||||||
|
if (!isendwin()) {
|
||||||
|
flash();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
prof_doupdate(void)
|
||||||
|
{
|
||||||
|
if (!_ui_redraw_suspended()) {
|
||||||
|
doupdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ui_resize(void)
|
ui_resize(void)
|
||||||
{
|
{
|
||||||
// UI is suspended
|
if (_ui_redraw_suspended()) {
|
||||||
if (isendwin()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,8 +252,7 @@ ui_resize(void)
|
|||||||
void
|
void
|
||||||
ui_redraw(void)
|
ui_redraw(void)
|
||||||
{
|
{
|
||||||
// UI is suspended
|
if (_ui_redraw_suspended()) {
|
||||||
if (isendwin()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -182,7 +182,11 @@ inp_readline(void)
|
|||||||
{
|
{
|
||||||
// UI is suspended
|
// UI is suspended
|
||||||
if (is_suspended || isendwin()) {
|
if (is_suspended || isendwin()) {
|
||||||
|
// Mirror the normal-path unlock so workers aren't starved
|
||||||
|
// for the whole editor session.
|
||||||
|
pthread_mutex_unlock(&lock);
|
||||||
g_usleep(100000); // 100ms
|
g_usleep(100000); // 100ms
|
||||||
|
pthread_mutex_lock(&lock);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,11 +315,13 @@ inp_get_line(void)
|
|||||||
werase(inp_win);
|
werase(inp_win);
|
||||||
wmove(inp_win, 0, 0);
|
wmove(inp_win, 0, 0);
|
||||||
_inp_win_update_virtual();
|
_inp_win_update_virtual();
|
||||||
doupdate();
|
prof_doupdate();
|
||||||
char* line = NULL;
|
char* line = NULL;
|
||||||
while (!line) {
|
while (!line) {
|
||||||
line = inp_readline();
|
line = inp_readline();
|
||||||
ui_update();
|
ui_update();
|
||||||
|
while (g_main_context_iteration(NULL, FALSE)) // non-blocking; bounded by ready sources
|
||||||
|
;
|
||||||
}
|
}
|
||||||
status_bar_clear_prompt();
|
status_bar_clear_prompt();
|
||||||
return line;
|
return line;
|
||||||
@@ -338,12 +344,14 @@ inp_get_password(void)
|
|||||||
werase(inp_win);
|
werase(inp_win);
|
||||||
wmove(inp_win, 0, 0);
|
wmove(inp_win, 0, 0);
|
||||||
_inp_win_update_virtual();
|
_inp_win_update_virtual();
|
||||||
doupdate();
|
prof_doupdate();
|
||||||
char* password = NULL;
|
char* password = NULL;
|
||||||
get_password = TRUE;
|
get_password = TRUE;
|
||||||
while (!password) {
|
while (!password) {
|
||||||
password = inp_readline();
|
password = inp_readline();
|
||||||
ui_update();
|
ui_update();
|
||||||
|
while (g_main_context_iteration(NULL, FALSE)) // non-blocking; bounded by ready sources
|
||||||
|
;
|
||||||
}
|
}
|
||||||
get_password = FALSE;
|
get_password = FALSE;
|
||||||
status_bar_clear_prompt();
|
status_bar_clear_prompt();
|
||||||
@@ -459,7 +467,7 @@ _inp_write(char* line, int offset)
|
|||||||
_inp_win_handle_scroll();
|
_inp_win_handle_scroll();
|
||||||
|
|
||||||
_inp_win_update_virtual();
|
_inp_win_update_virtual();
|
||||||
doupdate();
|
prof_doupdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ privwin_incoming_msg(ProfPrivateWin* privatewin, ProfMessage* message)
|
|||||||
privatewin->unread++;
|
privatewin->unread++;
|
||||||
|
|
||||||
if (prefs_get_boolean(PREF_FLASH)) {
|
if (prefs_get_boolean(PREF_FLASH)) {
|
||||||
flash();
|
ui_flash();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ privwin_incoming_msg(ProfPrivateWin* privatewin, ProfMessage* message)
|
|||||||
wins_add_quotes_ac(window, message->plain, TRUE);
|
wins_add_quotes_ac(window, message->plain, TRUE);
|
||||||
|
|
||||||
if (prefs_get_boolean(PREF_BEEP)) {
|
if (prefs_get_boolean(PREF_BEEP)) {
|
||||||
beep();
|
ui_beep();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notify) {
|
if (notify) {
|
||||||
|
|||||||
@@ -170,12 +170,7 @@ status_bar_current(guint i)
|
|||||||
void
|
void
|
||||||
status_bar_inactive(const int win)
|
status_bar_inactive(const int win)
|
||||||
{
|
{
|
||||||
int true_win = win;
|
g_hash_table_remove(statusbar->tabs, GINT_TO_POINTER((win == 0) ? CONSOLE_TAB_ID : win));
|
||||||
if (true_win == 0) {
|
|
||||||
true_win = 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_hash_table_remove(statusbar->tabs, GINT_TO_POINTER(true_win));
|
|
||||||
|
|
||||||
status_bar_draw();
|
status_bar_draw();
|
||||||
}
|
}
|
||||||
@@ -183,8 +178,6 @@ status_bar_inactive(const int win)
|
|||||||
void
|
void
|
||||||
_create_tab(const int win, win_type_t wintype, char* identifier, gboolean highlight)
|
_create_tab(const int win, win_type_t wintype, char* identifier, gboolean highlight)
|
||||||
{
|
{
|
||||||
int true_win = win == 0 ? 10 : win;
|
|
||||||
|
|
||||||
StatusBarTab* tab = g_new0(StatusBarTab, 1);
|
StatusBarTab* tab = g_new0(StatusBarTab, 1);
|
||||||
tab->identifier = strdup(identifier);
|
tab->identifier = strdup(identifier);
|
||||||
tab->highlight = highlight;
|
tab->highlight = highlight;
|
||||||
@@ -214,7 +207,7 @@ _create_tab(const int win, win_type_t wintype, char* identifier, gboolean highli
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_hash_table_replace(statusbar->tabs, GINT_TO_POINTER(true_win), tab);
|
g_hash_table_replace(statusbar->tabs, GINT_TO_POINTER((win == 0) ? CONSOLE_TAB_ID : win), tab);
|
||||||
|
|
||||||
status_bar_draw();
|
status_bar_draw();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
#ifndef UI_TITLEBAR_H
|
#ifndef UI_TITLEBAR_H
|
||||||
#define UI_TITLEBAR_H
|
#define UI_TITLEBAR_H
|
||||||
|
|
||||||
|
#include "glib.h"
|
||||||
|
|
||||||
void create_title_bar(void);
|
void create_title_bar(void);
|
||||||
void free_title_bar(void);
|
void free_title_bar(void);
|
||||||
void title_bar_update_virtual(void);
|
void title_bar_update_virtual(void);
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ void ui_load_colours(void);
|
|||||||
void ui_update(void);
|
void ui_update(void);
|
||||||
void ui_redraw(void);
|
void ui_redraw(void);
|
||||||
void ui_resize(void);
|
void ui_resize(void);
|
||||||
|
// doupdate() wrapper that skips when the UI is suspended. Use this instead
|
||||||
|
// of raw doupdate() to avoid the per-site whitelist class of bug.
|
||||||
|
void prof_doupdate(void);
|
||||||
void ui_focus_win(ProfWin* window);
|
void ui_focus_win(ProfWin* window);
|
||||||
void ui_sigwinch_handler(int sig);
|
void ui_sigwinch_handler(int sig);
|
||||||
void ui_handle_otr_error(const char* const barejid, const char* const message);
|
void ui_handle_otr_error(const char* const barejid, const char* const message);
|
||||||
@@ -84,6 +87,8 @@ void ui_handle_recipient_error(const char* const recipient, const char* const er
|
|||||||
void ui_handle_error(const char* const err_msg);
|
void ui_handle_error(const char* const err_msg);
|
||||||
void ui_clear_win_title(void);
|
void ui_clear_win_title(void);
|
||||||
void ui_goodbye_title(void);
|
void ui_goodbye_title(void);
|
||||||
|
void ui_beep(void);
|
||||||
|
void ui_flash(void);
|
||||||
void ui_handle_room_configuration_form_error(const char* const roomjid, const char* const message);
|
void ui_handle_room_configuration_form_error(const char* const roomjid, const char* const message);
|
||||||
void ui_handle_room_config_submit_result(const char* const roomjid);
|
void ui_handle_room_config_submit_result(const char* const roomjid);
|
||||||
void ui_handle_room_config_submit_result_error(const char* const roomjid, const char* const message);
|
void ui_handle_room_config_submit_result_error(const char* const roomjid, const char* const message);
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
#include "ai/ai_client.h"
|
#include "ai/ai_client.h"
|
||||||
|
|
||||||
static const int PAD_MIN_HEIGHT = 100;
|
static const int PAD_MIN_HEIGHT = 100;
|
||||||
static const int PAD_THRESHOLD = 3000;
|
static const int PAD_THRESHOLD = 12000; // above buffer cap (~9000): reclaims dead pad space, never fires while scrolling
|
||||||
static gboolean _in_redraw = FALSE;
|
static gboolean _in_redraw = FALSE;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -2172,9 +2172,10 @@ win_redraw(ProfWin* window)
|
|||||||
unsigned int size = buffer_size(window->layout->buffer);
|
unsigned int size = buffer_size(window->layout->buffer);
|
||||||
_in_redraw = TRUE;
|
_in_redraw = TRUE;
|
||||||
|
|
||||||
// shrink pad back to minimum size and erase it
|
// size the pad to fit the whole buffer (plus headroom) and erase it
|
||||||
int cols = getmaxx(window->layout->win);
|
int cols = getmaxx(window->layout->win);
|
||||||
wresize(window->layout->win, PAD_MIN_HEIGHT, cols);
|
int needed = window->layout->buffer->lines + 100;
|
||||||
|
wresize(window->layout->win, MAX(needed, PAD_MIN_HEIGHT), cols);
|
||||||
werase(window->layout->win);
|
werase(window->layout->win);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < size; i++) {
|
for (unsigned int i = 0; i < size; i++) {
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
#ifndef XMPP_BLOCKING_H
|
#ifndef XMPP_BLOCKING_H
|
||||||
#define XMPP_BLOCKING_H
|
#define XMPP_BLOCKING_H
|
||||||
|
|
||||||
|
#include <strophe.h>
|
||||||
|
|
||||||
void blocking_request(void);
|
void blocking_request(void);
|
||||||
int blocked_set_handler(xmpp_stanza_t* stanza);
|
int blocked_set_handler(xmpp_stanza_t* stanza);
|
||||||
int reporting_set_handler(xmpp_stanza_t* stanza);
|
int reporting_set_handler(xmpp_stanza_t* stanza);
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
#ifndef XMPP_IQ_H
|
#ifndef XMPP_IQ_H
|
||||||
#define XMPP_IQ_H
|
#define XMPP_IQ_H
|
||||||
|
|
||||||
|
#include <strophe.h>
|
||||||
|
|
||||||
typedef int (*ProfIqCallback)(xmpp_stanza_t* const stanza, void* const userdata);
|
typedef int (*ProfIqCallback)(xmpp_stanza_t* const stanza, void* const userdata);
|
||||||
typedef void (*ProfIqFreeCallback)(void* userdata);
|
typedef void (*ProfIqFreeCallback)(void* userdata);
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "log.h"
|
||||||
#include "xmpp/jid.h"
|
#include "xmpp/jid.h"
|
||||||
|
|
||||||
#define JID_MAX_PART_LEN 1023
|
#define JID_MAX_PART_LEN 1023
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
|
* SPDX-License-Identifier: GPL-3.0-or-later WITH OpenSSL-exception
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "glib.h"
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \page OX OX Implementation
|
* \page OX OX Implementation
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -10,6 +10,9 @@
|
|||||||
#ifndef XMPP_ROSTER_H
|
#ifndef XMPP_ROSTER_H
|
||||||
#define XMPP_ROSTER_H
|
#define XMPP_ROSTER_H
|
||||||
|
|
||||||
|
#include "glib.h"
|
||||||
|
#include <strophe.h>
|
||||||
|
|
||||||
void roster_request(void);
|
void roster_request(void);
|
||||||
void roster_set_handler(xmpp_stanza_t* const stanza);
|
void roster_set_handler(xmpp_stanza_t* const stanza);
|
||||||
void roster_result_handler(xmpp_stanza_t* const stanza);
|
void roster_result_handler(xmpp_stanza_t* const stanza);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include "ui/win_types.h"
|
#include "ui/win_types.h"
|
||||||
#include "xmpp/vcard.h"
|
#include "xmpp/vcard.h"
|
||||||
|
#include <strophe.h>
|
||||||
|
|
||||||
vCard* vcard_new();
|
vCard* vcard_new();
|
||||||
void vcard_free(vCard* vcard);
|
void vcard_free(vCard* vcard);
|
||||||
|
|||||||
@@ -85,6 +85,10 @@ void
|
|||||||
ui_resize(void)
|
ui_resize(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
void
|
||||||
|
prof_doupdate(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ui_focus_win(ProfWin* win)
|
ui_focus_win(ProfWin* win)
|
||||||
@@ -1475,3 +1479,13 @@ ui_is_suspended(void)
|
|||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ui_beep(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ui_flash(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user