1
0
Fork 0
profanity/src/command/cmd_funcs.c

9667 lines
302 KiB
C

/*
* cmd_funcs.c
* vim: expandtab:ts=4:sts=4:sw=4
*
* Copyright (C) 2012 - 2019 James Booth <boothj5@gmail.com>
* Copyright (C) 2019 Michael Vetter <jubalh@iodoru.org>
* Copyright (C) 2020 William Wennerström <william@wstrm.dev>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <https://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give permission to
* link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two.
*
* You must obey the GNU General Public License in all respects for all of the
* code used other than OpenSSL. If you modify file(s) with this exception, you
* may extend this exception to your version of the file(s), but you are not
* obligated to do so. If you do not wish to do so, delete this exception
* statement from your version. If you delete this exception statement from all
* source files in the program, then also delete it here.
*
*/
#include "config.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <gio/gio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <langinfo.h>
#include <ctype.h>
// fork / execl
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <readline/readline.h>
#include "profanity.h"
#include "log.h"
#include "common.h"
#include "command/cmd_funcs.h"
#include "command/cmd_defs.h"
#include "command/cmd_ac.h"
#include "config/files.h"
#include "config/accounts.h"
#include "config/account.h"
#include "config/preferences.h"
#include "config/theme.h"
#include "config/tlscerts.h"
#include "config/scripts.h"
#include "event/client_events.h"
#include "tools/http_upload.h"
#include "tools/http_download.h"
#include "tools/autocomplete.h"
#include "tools/parser.h"
#include "tools/bookmark_ignore.h"
#include "plugins/plugins.h"
#include "ui/ui.h"
#include "ui/window_list.h"
#include "xmpp/xmpp.h"
#include "xmpp/connection.h"
#include "xmpp/contact.h"
#include "xmpp/roster_list.h"
#include "xmpp/jid.h"
#include "xmpp/muc.h"
#include "xmpp/chat_session.h"
#include "xmpp/avatar.h"
#ifdef HAVE_LIBOTR
#include "otr/otr.h"
#endif
#ifdef HAVE_LIBGPGME
#include "pgp/gpg.h"
#include "xmpp/ox.h"
#endif
#ifdef HAVE_OMEMO
#include "omemo/omemo.h"
#include "xmpp/omemo.h"
#include "tools/aesgcm_download.h"
#endif
#ifdef HAVE_GTK
#include "ui/tray.h"
#include "tools/clipboard.h"
#endif
#ifdef HAVE_PYTHON
#include "plugins/python_plugins.h"
#endif
static void _update_presence(const resource_presence_t presence,
const char* const show, gchar** args);
static void _cmd_set_boolean_preference(gchar* arg, const char* const command,
const char* const display, preference_t pref);
static void _who_room(ProfWin* window, const char* const command, gchar** args);
static void _who_roster(ProfWin* window, const char* const command, gchar** args);
static gboolean _cmd_execute(ProfWin* window, const char* const command, const char* const inp);
static gboolean _cmd_execute_default(ProfWin* window, const char* inp);
static gboolean _cmd_execute_alias(ProfWin* window, const char* const inp, gboolean* ran);
/*
* Take a line of input and process it, return TRUE if profanity is to
* continue, FALSE otherwise
*/
gboolean
cmd_process_input(ProfWin* window, char* inp)
{
log_debug("Input received: %s", inp);
gboolean result = FALSE;
g_strchomp(inp);
// just carry on if no input
if (strlen(inp) == 0) {
result = TRUE;
// handle command if input starts with a '/'
} else if (inp[0] == '/') {
char* inp_cpy = strdup(inp);
char* command = strtok(inp_cpy, " ");
char* question_mark = strchr(command, '?');
if (question_mark) {
*question_mark = '\0';
gchar* fakeinp = g_strdup_printf("/help %s", command + 1);
if (fakeinp) {
result = _cmd_execute(window, "/help", fakeinp);
g_free(fakeinp);
}
} else {
result = _cmd_execute(window, command, inp);
}
free(inp_cpy);
// call a default handler if input didn't start with '/'
} else {
result = _cmd_execute_default(window, inp);
}
return result;
}
// Command execution
void
cmd_execute_connect(ProfWin* window, const char* const account)
{
GString* command = g_string_new("/connect ");
g_string_append(command, account);
cmd_process_input(window, command->str);
g_string_free(command, TRUE);
}
gboolean
cmd_tls_certpath(ProfWin* window, const char* const command, gchar** args)
{
if (g_strcmp0(args[1], "set") == 0) {
if (args[2] == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
if (g_file_test(args[2], G_FILE_TEST_IS_DIR)) {
prefs_set_string(PREF_TLS_CERTPATH, args[2]);
cons_show("Certificate path set to: %s", args[2]);
} else {
cons_show("Directory %s does not exist.", args[2]);
}
return TRUE;
} else if (g_strcmp0(args[1], "clear") == 0) {
prefs_set_string(PREF_TLS_CERTPATH, "none");
cons_show("Certificate path cleared");
return TRUE;
} else if (g_strcmp0(args[1], "default") == 0) {
prefs_set_string(PREF_TLS_CERTPATH, NULL);
cons_show("Certificate path defaulted to finding system certpath.");
return TRUE;
} else if (args[1] == NULL) {
char* path = prefs_get_tls_certpath();
if (path) {
cons_show("Trusted certificate path: %s", path);
free(path);
} else {
cons_show("No trusted certificate path set.");
}
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
}
gboolean
cmd_tls_trust(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are currently not connected.");
return TRUE;
}
if (!connection_is_secured()) {
cons_show("No TLS connection established");
return TRUE;
}
TLSCertificate* cert = connection_get_tls_peer_cert();
if (!cert) {
cons_show("Error getting TLS certificate.");
return TRUE;
}
if (tlscerts_exists(cert->fingerprint)) {
cons_show("Certificate %s already trusted.", cert->fingerprint);
tlscerts_free(cert);
return TRUE;
}
cons_show("Adding %s to trusted certificates.", cert->fingerprint);
tlscerts_add(cert);
tlscerts_free(cert);
return TRUE;
}
gboolean
cmd_tls_trusted(ProfWin* window, const char* const command, gchar** args)
{
GList* certs = tlscerts_list();
GList* curr = certs;
if (curr) {
cons_show("Trusted certificates:");
cons_show("");
} else {
cons_show("No trusted certificates found.");
}
while (curr) {
TLSCertificate* cert = curr->data;
cons_show_tlscert_summary(cert);
cons_show("");
curr = g_list_next(curr);
}
g_list_free_full(certs, (GDestroyNotify)tlscerts_free);
return TRUE;
}
gboolean
cmd_tls_revoke(ProfWin* window, const char* const command, gchar** args)
{
if (args[1] == NULL) {
cons_bad_cmd_usage(command);
} else {
gboolean res = tlscerts_revoke(args[1]);
if (res) {
cons_show("Trusted certificate revoked: %s", args[1]);
} else {
cons_show("Could not find certificate: %s", args[1]);
}
}
return TRUE;
}
gboolean
cmd_tls_cert(ProfWin* window, const char* const command, gchar** args)
{
if (args[1]) {
TLSCertificate* cert = tlscerts_get_trusted(args[1]);
if (!cert) {
cons_show("No such certificate.");
} else {
cons_show_tlscert(cert);
tlscerts_free(cert);
}
return TRUE;
} else {
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
if (!connection_is_secured()) {
cons_show("No TLS connection established");
return TRUE;
}
TLSCertificate* cert = connection_get_tls_peer_cert();
if (!cert) {
cons_show("Error getting TLS certificate.");
return TRUE;
}
cons_show_tlscert(cert);
cons_show("");
tlscerts_free(cert);
return TRUE;
}
}
gboolean
cmd_connect(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_DISCONNECTED) {
cons_show("You are either connected already, or a login is in process.");
return TRUE;
}
gchar* opt_keys[] = { "server", "port", "tls", "auth", NULL };
gboolean parsed;
GHashTable* options = parse_options(&args[args[0] ? 1 : 0], opt_keys, &parsed);
if (!parsed) {
cons_bad_cmd_usage(command);
cons_show("");
options_destroy(options);
return TRUE;
}
char* altdomain = g_hash_table_lookup(options, "server");
char* tls_policy = g_hash_table_lookup(options, "tls");
if (tls_policy && (g_strcmp0(tls_policy, "force") != 0) && (g_strcmp0(tls_policy, "allow") != 0) && (g_strcmp0(tls_policy, "trust") != 0) && (g_strcmp0(tls_policy, "disable") != 0) && (g_strcmp0(tls_policy, "legacy") != 0)) {
cons_bad_cmd_usage(command);
cons_show("");
options_destroy(options);
return TRUE;
}
char* auth_policy = g_hash_table_lookup(options, "auth");
if (auth_policy && (g_strcmp0(auth_policy, "default") != 0) && (g_strcmp0(auth_policy, "legacy") != 0)) {
cons_bad_cmd_usage(command);
cons_show("");
options_destroy(options);
return TRUE;
}
int port = 0;
if (g_hash_table_contains(options, "port")) {
char* port_str = g_hash_table_lookup(options, "port");
char* err_msg = NULL;
gboolean res = strtoi_range(port_str, &port, 1, 65535, &err_msg);
if (!res) {
cons_show(err_msg);
cons_show("");
free(err_msg);
port = 0;
options_destroy(options);
return TRUE;
}
}
char* user = args[0];
char* def = prefs_get_string(PREF_DEFAULT_ACCOUNT);
if (!user) {
if (def) {
user = def;
cons_show("Using default account %s.", user);
} else {
cons_show("No default account.");
options_destroy(options);
return TRUE;
}
}
char* jid;
user = strdup(user);
g_free(def);
// connect with account
ProfAccount* account = accounts_get_account(user);
if (account) {
// override account options with connect options
if (altdomain != NULL)
account_set_server(account, altdomain);
if (port != 0)
account_set_port(account, port);
if (tls_policy != NULL)
account_set_tls_policy(account, tls_policy);
if (auth_policy != NULL)
account_set_auth_policy(account, auth_policy);
// use password if set
if (account->password) {
conn_status = cl_ev_connect_account(account);
// use eval_password if set
} else if (account->eval_password) {
gboolean res = account_eval_password(account);
if (res) {
conn_status = cl_ev_connect_account(account);
free(account->password);
account->password = NULL;
} else {
cons_show("Error evaluating password, see logs for details.");
account_free(account);
free(user);
options_destroy(options);
return TRUE;
}
// no account password setting, prompt
} else {
account->password = ui_ask_password(false);
conn_status = cl_ev_connect_account(account);
free(account->password);
account->password = NULL;
}
jid = account_create_connect_jid(account);
account_free(account);
// connect with JID
} else {
jid = g_utf8_strdown(user, -1);
char* passwd = ui_ask_password(false);
conn_status = cl_ev_connect_jid(jid, passwd, altdomain, port, tls_policy, auth_policy);
free(passwd);
}
if (conn_status == JABBER_DISCONNECTED) {
cons_show_error("Connection attempt for %s failed.", jid);
log_info("Connection attempt for %s failed", jid);
}
options_destroy(options);
free(jid);
free(user);
return TRUE;
}
gboolean
cmd_account_list(ProfWin* window, const char* const command, gchar** args)
{
gchar** accounts = accounts_get_list();
cons_show_account_list(accounts);
g_strfreev(accounts);
return TRUE;
}
gboolean
cmd_account_show(ProfWin* window, const char* const command, gchar** args)
{
char* account_name = args[1];
if (account_name == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
ProfAccount* account = accounts_get_account(account_name);
if (account == NULL) {
cons_show("No such account.");
cons_show("");
} else {
cons_show_account(account);
account_free(account);
}
return TRUE;
}
gboolean
cmd_account_add(ProfWin* window, const char* const command, gchar** args)
{
char* account_name = args[1];
if (account_name == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
accounts_add(account_name, NULL, 0, NULL, NULL);
cons_show("Account created.");
cons_show("");
return TRUE;
}
gboolean
cmd_account_remove(ProfWin* window, const char* const command, gchar** args)
{
char* account_name = args[1];
if (!account_name) {
cons_bad_cmd_usage(command);
return TRUE;
}
char* def = prefs_get_string(PREF_DEFAULT_ACCOUNT);
if (accounts_remove(account_name)) {
cons_show("Account %s removed.", account_name);
if (def && strcmp(def, account_name) == 0) {
prefs_set_string(PREF_DEFAULT_ACCOUNT, NULL);
cons_show("Default account removed because the corresponding account was removed.");
}
} else {
cons_show("Failed to remove account %s.", account_name);
cons_show("Either the account does not exist, or an unknown error occurred.");
}
cons_show("");
g_free(def);
return TRUE;
}
gboolean
cmd_account_enable(ProfWin* window, const char* const command, gchar** args)
{
char* account_name = args[1];
if (account_name == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
if (accounts_enable(account_name)) {
cons_show("Account enabled.");
cons_show("");
} else {
cons_show("No such account: %s", account_name);
cons_show("");
}
return TRUE;
}
gboolean
cmd_account_disable(ProfWin* window, const char* const command, gchar** args)
{
char* account_name = args[1];
if (account_name == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
if (accounts_disable(account_name)) {
cons_show("Account disabled.");
cons_show("");
} else {
cons_show("No such account: %s", account_name);
cons_show("");
}
return TRUE;
}
gboolean
cmd_account_rename(ProfWin* window, const char* const command, gchar** args)
{
if (g_strv_length(args) != 3) {
cons_bad_cmd_usage(command);
return TRUE;
}
char* account_name = args[1];
char* new_name = args[2];
if (accounts_rename(account_name, new_name)) {
cons_show("Account renamed.");
cons_show("");
} else {
cons_show("Either account %s doesn't exist, or account %s already exists.", account_name, new_name);
cons_show("");
}
return TRUE;
}
gboolean
cmd_account_default(ProfWin* window, const char* const command, gchar** args)
{
if (g_strv_length(args) == 1) {
char* def = prefs_get_string(PREF_DEFAULT_ACCOUNT);
if (def) {
cons_show("The default account is %s.", def);
free(def);
} else {
cons_show("No default account.");
}
} else if (g_strv_length(args) == 2) {
if (strcmp(args[1], "off") == 0) {
prefs_set_string(PREF_DEFAULT_ACCOUNT, NULL);
cons_show("Removed default account.");
} else {
cons_bad_cmd_usage(command);
}
} else if (g_strv_length(args) == 3) {
if (strcmp(args[1], "set") == 0) {
ProfAccount* account_p = accounts_get_account(args[2]);
if (account_p) {
prefs_set_string(PREF_DEFAULT_ACCOUNT, args[2]);
cons_show("Default account set to %s.", args[2]);
account_free(account_p);
} else {
cons_show("Account %s does not exist.", args[2]);
}
} else {
cons_bad_cmd_usage(command);
}
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}
gboolean
_account_set_jid(char* account_name, char* jid)
{
Jid* jidp = jid_create(jid);
if (jidp == NULL) {
cons_show("Malformed jid: %s", jid);
} else {
accounts_set_jid(account_name, jidp->barejid);
cons_show("Updated jid for account %s: %s", account_name, jidp->barejid);
if (jidp->resourcepart) {
accounts_set_resource(account_name, jidp->resourcepart);
cons_show("Updated resource for account %s: %s", account_name, jidp->resourcepart);
}
cons_show("");
}
jid_destroy(jidp);
return TRUE;
}
gboolean
_account_set_server(char* account_name, char* server)
{
accounts_set_server(account_name, server);
cons_show("Updated server for account %s: %s", account_name, server);
cons_show("");
return TRUE;
}
gboolean
_account_set_port(char* account_name, char* port)
{
int porti;
char* err_msg = NULL;
gboolean res = strtoi_range(port, &porti, 1, 65535, &err_msg);
if (!res) {
cons_show(err_msg);
cons_show("");
free(err_msg);
} else {
accounts_set_port(account_name, porti);
cons_show("Updated port for account %s: %s", account_name, port);
cons_show("");
}
return TRUE;
}
gboolean
_account_set_resource(char* account_name, char* resource)
{
accounts_set_resource(account_name, resource);
if (connection_get_status() == JABBER_CONNECTED) {
cons_show("Updated resource for account %s: %s, reconnect to pick up the change.", account_name, resource);
} else {
cons_show("Updated resource for account %s: %s", account_name, resource);
}
cons_show("");
return TRUE;
}
gboolean
_account_set_password(char* account_name, char* password)
{
ProfAccount* account = accounts_get_account(account_name);
if (account->eval_password) {
cons_show("Cannot set password when eval_password is set.");
} else {
accounts_set_password(account_name, password);
cons_show("Updated password for account %s", account_name);
cons_show("");
}
account_free(account);
return TRUE;
}
gboolean
_account_set_eval_password(char* account_name, char* eval_password)
{
ProfAccount* account = accounts_get_account(account_name);
if (account->password) {
cons_show("Cannot set eval_password when password is set.");
} else {
accounts_set_eval_password(account_name, eval_password);
cons_show("Updated eval_password for account %s", account_name);
cons_show("");
}
account_free(account);
return TRUE;
}
gboolean
_account_set_muc(char* account_name, char* muc)
{
accounts_set_muc_service(account_name, muc);
cons_show("Updated muc service for account %s: %s", account_name, muc);
cons_show("");
return TRUE;
}
gboolean
_account_set_nick(char* account_name, char* nick)
{
accounts_set_muc_nick(account_name, nick);
cons_show("Updated muc nick for account %s: %s", account_name, nick);
cons_show("");
return TRUE;
}
gboolean
_account_set_otr(char* account_name, char* policy)
{
if ((g_strcmp0(policy, "manual") != 0)
&& (g_strcmp0(policy, "opportunistic") != 0)
&& (g_strcmp0(policy, "always") != 0)) {
cons_show("OTR policy must be one of: manual, opportunistic or always.");
} else {
accounts_set_otr_policy(account_name, policy);
cons_show("Updated OTR policy for account %s: %s", account_name, policy);
cons_show("");
}
return TRUE;
}
gboolean
_account_set_status(char* account_name, char* status)
{
if (!valid_resource_presence_string(status) && (strcmp(status, "last") != 0)) {
cons_show("Invalid status: %s", status);
} else {
accounts_set_login_presence(account_name, status);
cons_show("Updated login status for account %s: %s", account_name, status);
}
cons_show("");
return TRUE;
}
gboolean
_account_set_pgpkeyid(char* account_name, char* pgpkeyid)
{
#ifdef HAVE_LIBGPGME
char* err_str = NULL;
if (!p_gpg_valid_key(pgpkeyid, &err_str)) {
cons_show("Invalid PGP key ID specified: %s, see /pgp keys", err_str);
} else {
accounts_set_pgp_keyid(account_name, pgpkeyid);
cons_show("Updated PGP key ID for account %s: %s", account_name, pgpkeyid);
}
free(err_str);
#else
cons_show("PGP support is not included in this build.");
#endif
cons_show("");
return TRUE;
}
gboolean
_account_set_startscript(char* account_name, char* script)
{
accounts_set_script_start(account_name, script);
cons_show("Updated start script for account %s: %s", account_name, script);
return TRUE;
}
gboolean
_account_set_theme(char* account_name, char* theme)
{
if (!theme_exists(theme)) {
cons_show("Theme does not exist: %s", theme);
return TRUE;
}
accounts_set_theme(account_name, theme);
if (connection_get_status() == JABBER_CONNECTED) {
ProfAccount* account = accounts_get_account(session_get_account_name());
if (account) {
if (g_strcmp0(account->name, account_name) == 0) {
theme_load(theme, false);
ui_load_colours();
if (prefs_get_boolean(PREF_ROSTER)) {
ui_show_roster();
} else {
ui_hide_roster();
}
if (prefs_get_boolean(PREF_OCCUPANTS)) {
ui_show_all_room_rosters();
} else {
ui_hide_all_room_rosters();
}
ui_redraw();
}
account_free(account);
}
}
cons_show("Updated theme for account %s: %s", account_name, theme);
return TRUE;
}
gboolean
_account_set_tls(char* account_name, char* policy)
{
if ((g_strcmp0(policy, "force") != 0)
&& (g_strcmp0(policy, "allow") != 0)
&& (g_strcmp0(policy, "trust") != 0)
&& (g_strcmp0(policy, "disable") != 0)
&& (g_strcmp0(policy, "legacy") != 0)) {
cons_show("TLS policy must be one of: force, allow, legacy or disable.");
} else {
accounts_set_tls_policy(account_name, policy);
cons_show("Updated TLS policy for account %s: %s", account_name, policy);
cons_show("");
}
return TRUE;
}
gboolean
_account_set_auth(char* account_name, char* policy)
{
if ((g_strcmp0(policy, "default") != 0)
&& (g_strcmp0(policy, "legacy") != 0)) {
cons_show("Auth policy must be either default or legacy.");
} else {
accounts_set_auth_policy(account_name, policy);
cons_show("Updated auth policy for account %s: %s", account_name, policy);
cons_show("");
}
return TRUE;
}
gboolean
_account_set_presence_priority(char* account_name, char* presence, char* priority)
{
int intval;
char* err_msg = NULL;
gboolean res = strtoi_range(priority, &intval, -128, 127, &err_msg);
if (!res) {
cons_show(err_msg);
free(err_msg);
return TRUE;
}
resource_presence_t presence_type = resource_presence_from_string(presence);
switch (presence_type) {
case (RESOURCE_ONLINE):
accounts_set_priority_online(account_name, intval);
break;
case (RESOURCE_CHAT):
accounts_set_priority_chat(account_name, intval);
break;
case (RESOURCE_AWAY):
accounts_set_priority_away(account_name, intval);
break;
case (RESOURCE_XA):
accounts_set_priority_xa(account_name, intval);
break;
case (RESOURCE_DND):
accounts_set_priority_dnd(account_name, intval);
break;
}
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status == JABBER_CONNECTED) {
char* connected_account = session_get_account_name();
resource_presence_t last_presence = accounts_get_last_presence(connected_account);
if (presence_type == last_presence) {
cl_ev_presence_send(last_presence, 0);
}
}
cons_show("Updated %s priority for account %s: %s", presence, account_name, priority);
cons_show("");
return TRUE;
}
gboolean
cmd_account_set(ProfWin* window, const char* const command, gchar** args)
{
if (g_strv_length(args) != 4) {
cons_bad_cmd_usage(command);
return TRUE;
}
char* account_name = args[1];
if (!accounts_account_exists(account_name)) {
cons_show("Account %s doesn't exist", account_name);
cons_show("");
return TRUE;
}
char* property = args[2];
char* value = args[3];
if (strcmp(property, "jid") == 0)
return _account_set_jid(account_name, value);
if (strcmp(property, "server") == 0)
return _account_set_server(account_name, value);
if (strcmp(property, "port") == 0)
return _account_set_port(account_name, value);
if (strcmp(property, "resource") == 0)
return _account_set_resource(account_name, value);
if (strcmp(property, "password") == 0)
return _account_set_password(account_name, value);
if (strcmp(property, "eval_password") == 0)
return _account_set_eval_password(account_name, value);
if (strcmp(property, "muc") == 0)
return _account_set_muc(account_name, value);
if (strcmp(property, "nick") == 0)
return _account_set_nick(account_name, value);
if (strcmp(property, "otr") == 0)
return _account_set_otr(account_name, value);
if (strcmp(property, "status") == 0)
return _account_set_status(account_name, value);
if (strcmp(property, "pgpkeyid") == 0)
return _account_set_pgpkeyid(account_name, value);
if (strcmp(property, "startscript") == 0)
return _account_set_startscript(account_name, value);
if (strcmp(property, "theme") == 0)
return _account_set_theme(account_name, value);
if (strcmp(property, "tls") == 0)
return _account_set_tls(account_name, value);
if (strcmp(property, "auth") == 0)
return _account_set_auth(account_name, value);
if (valid_resource_presence_string(property)) {
return _account_set_presence_priority(account_name, property, value);
}
cons_show("Invalid property: %s", property);
cons_show("");
return TRUE;
}
gboolean
cmd_account_clear(ProfWin* window, const char* const command, gchar** args)
{
if (g_strv_length(args) != 3) {
cons_bad_cmd_usage(command);
return TRUE;
}
char* account_name = args[1];
if (!accounts_account_exists(account_name)) {
cons_show("Account %s doesn't exist", account_name);
cons_show("");
return TRUE;
}
char* property = args[2];
if (strcmp(property, "password") == 0) {
accounts_clear_password(account_name);
cons_show("Removed password for account %s", account_name);
cons_show("");
} else if (strcmp(property, "eval_password") == 0) {
accounts_clear_eval_password(account_name);
cons_show("Removed eval password for account %s", account_name);
cons_show("");
} else if (strcmp(property, "server") == 0) {
accounts_clear_server(account_name);
cons_show("Removed server for account %s", account_name);
cons_show("");
} else if (strcmp(property, "port") == 0) {
accounts_clear_port(account_name);
cons_show("Removed port for account %s", account_name);
cons_show("");
} else if (strcmp(property, "otr") == 0) {
accounts_clear_otr(account_name);
cons_show("OTR policy removed for account %s", account_name);
cons_show("");
} else if (strcmp(property, "pgpkeyid") == 0) {
accounts_clear_pgp_keyid(account_name);
cons_show("Removed PGP key ID for account %s", account_name);
cons_show("");
} else if (strcmp(property, "startscript") == 0) {
accounts_clear_script_start(account_name);
cons_show("Removed start script for account %s", account_name);
cons_show("");
} else if (strcmp(property, "theme") == 0) {
accounts_clear_theme(account_name);
cons_show("Removed theme for account %s", account_name);
cons_show("");
} else if (strcmp(property, "muc") == 0) {
accounts_clear_muc(account_name);
cons_show("Removed MUC service for account %s", account_name);
cons_show("");
} else if (strcmp(property, "resource") == 0) {
accounts_clear_resource(account_name);
cons_show("Removed resource for account %s", account_name);
cons_show("");
} else {
cons_show("Invalid property: %s", property);
cons_show("");
}
return TRUE;
}
gboolean
cmd_account(ProfWin* window, const char* const command, gchar** args)
{
if (args[0] != NULL) {
cons_bad_cmd_usage(command);
cons_show("");
return TRUE;
}
if (connection_get_status() != JABBER_CONNECTED) {
cons_bad_cmd_usage(command);
return TRUE;
}
ProfAccount* account = accounts_get_account(session_get_account_name());
if (account) {
cons_show_account(account);
account_free(account);
} else {
log_error("Could not get accounts");
}
return TRUE;
}
gboolean
cmd_script(ProfWin* window, const char* const command, gchar** args)
{
if ((g_strcmp0(args[0], "run") == 0) && args[1]) {
gboolean res = scripts_exec(args[1]);
if (!res) {
cons_show("Could not find script %s", args[1]);
}
} else if (g_strcmp0(args[0], "list") == 0) {
GSList* scripts = scripts_list();
cons_show_scripts(scripts);
g_slist_free_full(scripts, g_free);
} else if ((g_strcmp0(args[0], "show") == 0) && args[1]) {
GSList* commands = scripts_read(args[1]);
cons_show_script(args[1], commands);
g_slist_free_full(commands, g_free);
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}
/* escape a string into csv and write it to the file descriptor */
static int
_writecsv(int fd, const char* const str)
{
if (!str)
return 0;
size_t len = strlen(str);
char* s = malloc(2 * len * sizeof(char));
char* c = s;
for (int i = 0; i < strlen(str); i++) {
if (str[i] != '"')
*c++ = str[i];
else {
*c++ = '"';
*c++ = '"';
len++;
}
}
if (-1 == write(fd, s, len)) {
cons_show("error: failed to write '%s' to the requested file: %s", s, strerror(errno));
return -1;
}
free(s);
return 0;
}
gboolean
cmd_export(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
cons_show("");
return TRUE;
} else {
int fd;
GSList* list = NULL;
char* path = get_expanded_path(args[0]);
fd = open(path, O_WRONLY | O_CREAT, 00600);
if (-1 == fd) {
cons_show("error: cannot open %s: %s", args[0], strerror(errno));
cons_show("");
return TRUE;
}
if (-1 == write(fd, "jid,name\n", strlen("jid,name\n")))
goto write_error;
list = roster_get_contacts(ROSTER_ORD_NAME);
if (list) {
GSList* curr = list;
while (curr) {
PContact contact = curr->data;
const char* jid = p_contact_barejid(contact);
const char* name = p_contact_name(contact);
/* write the data to the file */
if (-1 == write(fd, "\"", 1))
goto write_error;
if (-1 == _writecsv(fd, jid))
goto write_error;
if (-1 == write(fd, "\",\"", 3))
goto write_error;
if (-1 == _writecsv(fd, name))
goto write_error;
if (-1 == write(fd, "\"\n", 2))
goto write_error;
/* loop */
curr = g_slist_next(curr);
}
cons_show("Contacts exported successfully");
cons_show("");
} else {
cons_show("No contacts in roster.");
cons_show("");
}
g_slist_free(list);
close(fd);
return TRUE;
write_error:
cons_show("error: write failed: %s", strerror(errno));
cons_show("");
g_slist_free(list);
close(fd);
return TRUE;
}
}
gboolean
cmd_sub(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are currently not connected.");
return TRUE;
}
char *subcmd, *jid;
subcmd = args[0];
jid = args[1];
if (subcmd == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
if (strcmp(subcmd, "sent") == 0) {
cons_show_sent_subs();
return TRUE;
}
if (strcmp(subcmd, "received") == 0) {
cons_show_received_subs();
return TRUE;
}
if ((window->type != WIN_CHAT) && (jid == NULL)) {
cons_show("You must specify a contact.");
return TRUE;
}
if (jid == NULL) {
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
jid = chatwin->barejid;
}
Jid* jidp = jid_create(jid);
if (strcmp(subcmd, "allow") == 0) {
presence_subscription(jidp->barejid, PRESENCE_SUBSCRIBED);
cons_show("Accepted subscription for %s", jidp->barejid);
log_info("Accepted subscription for %s", jidp->barejid);
} else if (strcmp(subcmd, "deny") == 0) {
presence_subscription(jidp->barejid, PRESENCE_UNSUBSCRIBED);
cons_show("Deleted/denied subscription for %s", jidp->barejid);
log_info("Deleted/denied subscription for %s", jidp->barejid);
} else if (strcmp(subcmd, "request") == 0) {
presence_subscription(jidp->barejid, PRESENCE_SUBSCRIBE);
cons_show("Sent subscription request to %s.", jidp->barejid);
log_info("Sent subscription request to %s.", jidp->barejid);
} else if (strcmp(subcmd, "show") == 0) {
PContact contact = roster_get_contact(jidp->barejid);
if ((contact == NULL) || (p_contact_subscription(contact) == NULL)) {
if (window->type == WIN_CHAT) {
win_println(window, THEME_DEFAULT, "-", "No subscription information for %s.", jidp->barejid);
} else {
cons_show("No subscription information for %s.", jidp->barejid);
}
} else {
if (window->type == WIN_CHAT) {
if (p_contact_pending_out(contact)) {
win_println(window, THEME_DEFAULT, "-", "%s subscription status: %s, request pending.",
jidp->barejid, p_contact_subscription(contact));
} else {
win_println(window, THEME_DEFAULT, "-", "%s subscription status: %s.", jidp->barejid,
p_contact_subscription(contact));
}
} else {
if (p_contact_pending_out(contact)) {
cons_show("%s subscription status: %s, request pending.",
jidp->barejid, p_contact_subscription(contact));
} else {
cons_show("%s subscription status: %s.", jidp->barejid,
p_contact_subscription(contact));
}
}
}
} else {
cons_bad_cmd_usage(command);
}
jid_destroy(jidp);
return TRUE;
}
gboolean
cmd_disconnect(ProfWin* window, const char* const command, gchar** args)
{
if (connection_get_status() != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
cl_ev_disconnect();
ui_redraw();
return TRUE;
}
gboolean
cmd_quit(ProfWin* window, const char* const command, gchar** args)
{
log_info("Profanity is shutting down...");
exit(0);
return FALSE;
}
gboolean
cmd_wins_unread(ProfWin* window, const char* const command, gchar** args)
{
cons_show_wins(TRUE);
return TRUE;
}
gboolean
cmd_wins_attention(ProfWin* window, const char* const command, gchar** args)
{
cons_show_wins_attention();
return TRUE;
}
gboolean
cmd_wins_prune(ProfWin* window, const char* const command, gchar** args)
{
ui_prune_wins();
return TRUE;
}
gboolean
cmd_wins_swap(ProfWin* window, const char* const command, gchar** args)
{
if ((args[1] == NULL) || (args[2] == NULL)) {
cons_bad_cmd_usage(command);
return TRUE;
}
int source_win = atoi(args[1]);
int target_win = atoi(args[2]);
if ((source_win == 1) || (target_win == 1)) {
cons_show("Cannot move console window.");
return TRUE;
}
if (source_win == 10 || target_win == 10) {
cons_show("Window 10 does not exist");
return TRUE;
}
if (source_win == target_win) {
cons_show("Same source and target window supplied.");
return TRUE;
}
if (wins_get_by_num(source_win) == NULL) {
cons_show("Window %d does not exist", source_win);
return TRUE;
}
if (wins_get_by_num(target_win) == NULL) {
cons_show("Window %d does not exist", target_win);
return TRUE;
}
wins_swap(source_win, target_win);
cons_show("Swapped windows %d <-> %d", source_win, target_win);
return TRUE;
}
gboolean
cmd_wins(ProfWin* window, const char* const command, gchar** args)
{
if (args[0] != NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
cons_show_wins(FALSE);
return TRUE;
}
gboolean
cmd_close(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (g_strcmp0(args[0], "all") == 0) {
int count = ui_close_all_wins();
if (count == 0) {
cons_show("No windows to close.");
} else if (count == 1) {
cons_show("Closed 1 window.");
} else {
cons_show("Closed %d windows.", count);
}
rosterwin_roster();
return TRUE;
}
if (g_strcmp0(args[0], "read") == 0) {
int count = ui_close_read_wins();
if (count == 0) {
cons_show("No windows to close.");
} else if (count == 1) {
cons_show("Closed 1 window.");
} else {
cons_show("Closed %d windows.", count);
}
rosterwin_roster();
return TRUE;
}
gboolean is_num = TRUE;
int index = 0;
if (args[0] != NULL) {
for (int i = 0; i < strlen(args[0]); i++) {
if (!isdigit((int)args[0][i])) {
is_num = FALSE;
break;
}
}
if (is_num) {
index = atoi(args[0]);
}
} else {
index = wins_get_current_num();
}
if (is_num) {
if (index < 0 || index == 10) {
cons_show("No such window exists.");
return TRUE;
}
if (index == 1) {
cons_show("Cannot close console window.");
return TRUE;
}
ProfWin* toclose = wins_get_by_num(index);
if (!toclose) {
cons_show("Window is not open.");
return TRUE;
}
// check for unsaved form
if (ui_win_has_unsaved_form(index)) {
win_println(window, THEME_DEFAULT, "-", "You have unsaved changes, use /form submit or /form cancel");
return TRUE;
}
// handle leaving rooms, or chat
if (conn_status == JABBER_CONNECTED) {
ui_close_connected_win(index);
}
// close the window
ui_close_win(index);
cons_show("Closed window %d", index);
wins_tidy();
rosterwin_roster();
return TRUE;
} else {
if (g_strcmp0(args[0], "console") == 0) {
cons_show("Cannot close console window.");
return TRUE;
}
ProfWin* toclose = wins_get_by_string(args[0]);
if (!toclose) {
cons_show("Window \"%s\" does not exist.", args[0]);
return TRUE;
}
index = wins_get_num(toclose);
// check for unsaved form
if (ui_win_has_unsaved_form(index)) {
win_println(window, THEME_DEFAULT, "-", "You have unsaved changes, use /form submit or /form cancel");
return TRUE;
}
// handle leaving rooms, or chat
if (conn_status == JABBER_CONNECTED) {
ui_close_connected_win(index);
}
// close the window
ui_close_win(index);
cons_show("Closed window %s", args[0]);
wins_tidy();
rosterwin_roster();
return TRUE;
}
}
gboolean
cmd_win(ProfWin* window, const char* const command, gchar** args)
{
gboolean is_num = TRUE;
for (int i = 0; i < strlen(args[0]); i++) {
if (!isdigit((int)args[0][i])) {
is_num = FALSE;
break;
}
}
if (is_num) {
int num = atoi(args[0]);
ProfWin* focuswin = wins_get_by_num(num);
if (!focuswin) {
cons_show("Window %d does not exist.", num);
} else {
ui_focus_win(focuswin);
}
} else {
ProfWin* focuswin = wins_get_by_string(args[0]);
if (!focuswin) {
cons_show("Window \"%s\" does not exist.", args[0]);
} else {
ui_focus_win(focuswin);
}
}
return TRUE;
}
static void
_cmd_list_commands(GList* commands)
{
int maxlen = 0;
GList* curr = commands;
while (curr) {
gchar* cmd = curr->data;
int len = strlen(cmd);
if (len > maxlen)
maxlen = len;
curr = g_list_next(curr);
}
GString* cmds = g_string_new("");
curr = commands;
int count = 0;
while (curr) {
gchar* cmd = curr->data;
if (count == 5) {
cons_show(cmds->str);
g_string_free(cmds, TRUE);
cmds = g_string_new("");
count = 0;
}
g_string_append_printf(cmds, "%-*s", maxlen + 1, cmd);
curr = g_list_next(curr);
count++;
}
cons_show(cmds->str);
g_string_free(cmds, TRUE);
g_list_free(curr);
cons_show("");
cons_show("Use /help [command] without the leading slash, for help on a specific command");
cons_show("");
}
static void
_cmd_help_cmd_list(const char* const tag)
{
cons_show("");
ProfWin* console = wins_get_console();
if (tag) {
win_println(console, THEME_HELP_HEADER, "-", "%s commands", tag);
} else {
win_println(console, THEME_HELP_HEADER, "-", "All commands");
}
GList* ordered_commands = NULL;
if (g_strcmp0(tag, "plugins") == 0) {
GList* plugins_cmds = plugins_get_command_names();
GList* curr = plugins_cmds;
while (curr) {
ordered_commands = g_list_insert_sorted(ordered_commands, curr->data, (GCompareFunc)g_strcmp0);
curr = g_list_next(curr);
}
g_list_free(plugins_cmds);
} else {
ordered_commands = cmd_get_ordered(tag);
// add plugins if showing all commands
if (!tag) {
GList* plugins_cmds = plugins_get_command_names();
GList* curr = plugins_cmds;
while (curr) {
ordered_commands = g_list_insert_sorted(ordered_commands, curr->data, (GCompareFunc)g_strcmp0);
curr = g_list_next(curr);
}
g_list_free(plugins_cmds);
}
}
_cmd_list_commands(ordered_commands);
g_list_free(ordered_commands);
}
gboolean
cmd_help(ProfWin* window, const char* const command, gchar** args)
{
int num_args = g_strv_length(args);
if (num_args == 0) {
cons_help();
} else if (strcmp(args[0], "search_all") == 0) {
if (args[1] == NULL) {
cons_bad_cmd_usage(command);
} else {
GList* cmds = cmd_search_index_all(args[1]);
if (cmds == NULL) {
cons_show("No commands found.");
} else {
GList* curr = cmds;
GList* results = NULL;
while (curr) {
results = g_list_insert_sorted(results, curr->data, (GCompareFunc)g_strcmp0);
curr = g_list_next(curr);
}
cons_show("Search results:");
_cmd_list_commands(results);
g_list_free(results);
}
g_list_free(cmds);
}
} else if (strcmp(args[0], "search_any") == 0) {
if (args[1] == NULL) {
cons_bad_cmd_usage(command);
} else {
GList* cmds = cmd_search_index_any(args[1]);
if (cmds == NULL) {
cons_show("No commands found.");
} else {
GList* curr = cmds;
GList* results = NULL;
while (curr) {
results = g_list_insert_sorted(results, curr->data, (GCompareFunc)g_strcmp0);
curr = g_list_next(curr);
}
cons_show("Search results:");
_cmd_list_commands(results);
g_list_free(results);
}
g_list_free(cmds);
}
} else if (strcmp(args[0], "commands") == 0) {
if (args[1]) {
if (!cmd_valid_tag(args[1])) {
cons_bad_cmd_usage(command);
} else {
_cmd_help_cmd_list(args[1]);
}
} else {
_cmd_help_cmd_list(NULL);
}
} else if (strcmp(args[0], "navigation") == 0) {
cons_navigation_help();
} else {
char* cmd = args[0];
char* cmd_with_slash = g_strdup_printf("/%s", cmd);
Command* command = cmd_get(cmd_with_slash);
if (command) {
cons_show_help(cmd_with_slash, &command->help);
} else {
CommandHelp* commandHelp = plugins_get_help(cmd_with_slash);
if (commandHelp) {
cons_show_help(cmd_with_slash, commandHelp);
} else {
cons_show("No such command.");
}
}
cons_show("");
g_free(cmd_with_slash);
}
return TRUE;
}
gboolean
cmd_about(ProfWin* window, const char* const command, gchar** args)
{
cons_show("");
cons_about();
return TRUE;
}
gboolean
cmd_prefs(ProfWin* window, const char* const command, gchar** args)
{
if (args[0] == NULL) {
cons_prefs();
cons_show("Use the /account command for preferences for individual accounts.");
} else if (strcmp(args[0], "ui") == 0) {
cons_show("");
cons_show_ui_prefs();
cons_show("");
} else if (strcmp(args[0], "desktop") == 0) {
cons_show("");
cons_show_desktop_prefs();
cons_show("");
} else if (strcmp(args[0], "chat") == 0) {
cons_show("");
cons_show_chat_prefs();
cons_show("");
} else if (strcmp(args[0], "log") == 0) {
cons_show("");
cons_show_log_prefs();
cons_show("");
} else if (strcmp(args[0], "conn") == 0) {
cons_show("");
cons_show_connection_prefs();
cons_show("");
} else if (strcmp(args[0], "presence") == 0) {
cons_show("");
cons_show_presence_prefs();
cons_show("");
} else if (strcmp(args[0], "otr") == 0) {
cons_show("");
cons_show_otr_prefs();
cons_show("");
} else if (strcmp(args[0], "pgp") == 0) {
cons_show("");
cons_show_pgp_prefs();
cons_show("");
} else if (strcmp(args[0], "omemo") == 0) {
cons_show("");
cons_show_omemo_prefs();
cons_show("");
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}
gboolean
cmd_theme(ProfWin* window, const char* const command, gchar** args)
{
// 'full-load' means to load the theme including the settings (not just [colours])
gboolean fullload = (g_strcmp0(args[0], "full-load") == 0);
// list themes
if (g_strcmp0(args[0], "list") == 0) {
GSList* themes = theme_list();
cons_show_themes(themes);
g_slist_free_full(themes, g_free);
// load a theme
} else if (g_strcmp0(args[0], "load") == 0 || fullload) {
if (args[1] == NULL) {
cons_bad_cmd_usage(command);
} else if (theme_load(args[1], fullload)) {
ui_load_colours();
prefs_set_string(PREF_THEME, args[1]);
if (prefs_get_boolean(PREF_ROSTER)) {
ui_show_roster();
} else {
ui_hide_roster();
}
if (prefs_get_boolean(PREF_OCCUPANTS)) {
ui_show_all_room_rosters();
} else {
ui_hide_all_room_rosters();
}
ui_resize();
cons_show("Loaded theme: %s", args[1]);
} else {
cons_show("Couldn't find theme: %s", args[1]);
}
// show colours
} else if (g_strcmp0(args[0], "colours") == 0) {
cons_theme_colours();
} else if (g_strcmp0(args[0], "properties") == 0) {
cons_theme_properties();
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}
static void
_who_room(ProfWin* window, const char* const command, gchar** args)
{
if ((g_strv_length(args) == 2) && args[1]) {
cons_show("Argument group is not applicable to chat rooms.");
return;
}
// bad arg
if (args[0] && (g_strcmp0(args[0], "online") != 0) && (g_strcmp0(args[0], "available") != 0) && (g_strcmp0(args[0], "unavailable") != 0) && (g_strcmp0(args[0], "away") != 0) && (g_strcmp0(args[0], "chat") != 0) && (g_strcmp0(args[0], "xa") != 0) && (g_strcmp0(args[0], "dnd") != 0) && (g_strcmp0(args[0], "any") != 0) && (g_strcmp0(args[0], "moderator") != 0) && (g_strcmp0(args[0], "participant") != 0) && (g_strcmp0(args[0], "visitor") != 0) && (g_strcmp0(args[0], "owner") != 0) && (g_strcmp0(args[0], "admin") != 0) && (g_strcmp0(args[0], "member") != 0) && (g_strcmp0(args[0], "outcast") != 0)) {
cons_bad_cmd_usage(command);
return;
}
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
// presence filter
if (args[0] == NULL || (g_strcmp0(args[0], "online") == 0) || (g_strcmp0(args[0], "available") == 0) || (g_strcmp0(args[0], "unavailable") == 0) || (g_strcmp0(args[0], "away") == 0) || (g_strcmp0(args[0], "chat") == 0) || (g_strcmp0(args[0], "xa") == 0) || (g_strcmp0(args[0], "dnd") == 0) || (g_strcmp0(args[0], "any") == 0)) {
char* presence = args[0];
GList* occupants = muc_roster(mucwin->roomjid);
// no arg, show all contacts
if ((presence == NULL) || (g_strcmp0(presence, "any") == 0)) {
mucwin_roster(mucwin, occupants, NULL);
// available
} else if (strcmp("available", presence) == 0) {
GList* filtered = NULL;
while (occupants) {
Occupant* occupant = occupants->data;
if (muc_occupant_available(occupant)) {
filtered = g_list_append(filtered, occupant);
}
occupants = g_list_next(occupants);
}
mucwin_roster(mucwin, filtered, "available");
// unavailable
} else if (strcmp("unavailable", presence) == 0) {
GList* filtered = NULL;
while (occupants) {
Occupant* occupant = occupants->data;
if (!muc_occupant_available(occupant)) {
filtered = g_list_append(filtered, occupant);
}
occupants = g_list_next(occupants);
}
mucwin_roster(mucwin, filtered, "unavailable");
// show specific status
} else {
GList* filtered = NULL;
while (occupants) {
Occupant* occupant = occupants->data;
const char* presence_str = string_from_resource_presence(occupant->presence);
if (strcmp(presence_str, presence) == 0) {
filtered = g_list_append(filtered, occupant);
}
occupants = g_list_next(occupants);
}
mucwin_roster(mucwin, filtered, presence);
}
g_list_free(occupants);
// role or affiliation filter
} else {
if (g_strcmp0(args[0], "moderator") == 0) {
mucwin_show_role_list(mucwin, MUC_ROLE_MODERATOR);
return;
}
if (g_strcmp0(args[0], "participant") == 0) {
mucwin_show_role_list(mucwin, MUC_ROLE_PARTICIPANT);
return;
}
if (g_strcmp0(args[0], "visitor") == 0) {
mucwin_show_role_list(mucwin, MUC_ROLE_VISITOR);
return;
}
if (g_strcmp0(args[0], "owner") == 0) {
mucwin_show_affiliation_list(mucwin, MUC_AFFILIATION_OWNER);
return;
}
if (g_strcmp0(args[0], "admin") == 0) {
mucwin_show_affiliation_list(mucwin, MUC_AFFILIATION_ADMIN);
return;
}
if (g_strcmp0(args[0], "member") == 0) {
mucwin_show_affiliation_list(mucwin, MUC_AFFILIATION_MEMBER);
return;
}
if (g_strcmp0(args[0], "outcast") == 0) {
mucwin_show_affiliation_list(mucwin, MUC_AFFILIATION_OUTCAST);
return;
}
}
}
static void
_who_roster(ProfWin* window, const char* const command, gchar** args)
{
char* presence = args[0];
// bad arg
if (presence
&& (strcmp(presence, "online") != 0)
&& (strcmp(presence, "available") != 0)
&& (strcmp(presence, "unavailable") != 0)
&& (strcmp(presence, "offline") != 0)
&& (strcmp(presence, "away") != 0)
&& (strcmp(presence, "chat") != 0)
&& (strcmp(presence, "xa") != 0)
&& (strcmp(presence, "dnd") != 0)
&& (strcmp(presence, "any") != 0)) {
cons_bad_cmd_usage(command);
return;
}
char* group = NULL;
if ((g_strv_length(args) == 2) && args[1]) {
group = args[1];
}
cons_show("");
GSList* list = NULL;
if (group) {
list = roster_get_group(group, ROSTER_ORD_NAME);
if (list == NULL) {
cons_show("No such group: %s.", group);
return;
}
} else {
list = roster_get_contacts(ROSTER_ORD_NAME);
if (list == NULL) {
cons_show("No contacts in roster.");
return;
}
}
// no arg, show all contacts
if ((presence == NULL) || (g_strcmp0(presence, "any") == 0)) {
if (group) {
if (list == NULL) {
cons_show("No contacts in group %s.", group);
} else {
cons_show("%s:", group);
cons_show_contacts(list);
}
} else {
if (list == NULL) {
cons_show("You have no contacts.");
} else {
cons_show("All contacts:");
cons_show_contacts(list);
}
}
// available
} else if (strcmp("available", presence) == 0) {
GSList* filtered = NULL;
GSList* curr = list;
while (curr) {
PContact contact = curr->data;
if (p_contact_is_available(contact)) {
filtered = g_slist_append(filtered, contact);
}
curr = g_slist_next(curr);
}
if (group) {
if (filtered == NULL) {
cons_show("No contacts in group %s are %s.", group, presence);
} else {
cons_show("%s (%s):", group, presence);
cons_show_contacts(filtered);
}
} else {
if (filtered == NULL) {
cons_show("No contacts are %s.", presence);
} else {
cons_show("Contacts (%s):", presence);
cons_show_contacts(filtered);
}
}
g_slist_free(filtered);
// unavailable
} else if (strcmp("unavailable", presence) == 0) {
GSList* filtered = NULL;
GSList* curr = list;
while (curr) {
PContact contact = curr->data;
if (!p_contact_is_available(contact)) {
filtered = g_slist_append(filtered, contact);
}
curr = g_slist_next(curr);
}
if (group) {
if (filtered == NULL) {
cons_show("No contacts in group %s are %s.", group, presence);
} else {
cons_show("%s (%s):", group, presence);
cons_show_contacts(filtered);
}
} else {
if (filtered == NULL) {
cons_show("No contacts are %s.", presence);
} else {
cons_show("Contacts (%s):", presence);
cons_show_contacts(filtered);
}
}
g_slist_free(filtered);
// online, available resources
} else if (strcmp("online", presence) == 0) {
GSList* filtered = NULL;
GSList* curr = list;
while (curr) {
PContact contact = curr->data;
if (p_contact_has_available_resource(contact)) {
filtered = g_slist_append(filtered, contact);
}
curr = g_slist_next(curr);
}
if (group) {
if (filtered == NULL) {
cons_show("No contacts in group %s are %s.", group, presence);
} else {
cons_show("%s (%s):", group, presence);
cons_show_contacts(filtered);
}
} else {
if (filtered == NULL) {
cons_show("No contacts are %s.", presence);
} else {
cons_show("Contacts (%s):", presence);
cons_show_contacts(filtered);
}
}
g_slist_free(filtered);
// offline, no available resources
} else if (strcmp("offline", presence) == 0) {
GSList* filtered = NULL;
GSList* curr = list;
while (curr) {
PContact contact = curr->data;
if (!p_contact_has_available_resource(contact)) {
filtered = g_slist_append(filtered, contact);
}
curr = g_slist_next(curr);
}
if (group) {
if (filtered == NULL) {
cons_show("No contacts in group %s are %s.", group, presence);
} else {
cons_show("%s (%s):", group, presence);
cons_show_contacts(filtered);
}
} else {
if (filtered == NULL) {
cons_show("No contacts are %s.", presence);
} else {
cons_show("Contacts (%s):", presence);
cons_show_contacts(filtered);
}
}
g_slist_free(filtered);
// show specific status
} else {
GSList* filtered = NULL;
GSList* curr = list;
while (curr) {
PContact contact = curr->data;
if (strcmp(p_contact_presence(contact), presence) == 0) {
filtered = g_slist_append(filtered, contact);
}
curr = g_slist_next(curr);
}
if (group) {
if (filtered == NULL) {
cons_show("No contacts in group %s are %s.", group, presence);
} else {
cons_show("%s (%s):", group, presence);
cons_show_contacts(filtered);
}
} else {
if (filtered == NULL) {
cons_show("No contacts are %s.", presence);
} else {
cons_show("Contacts (%s):", presence);
cons_show_contacts(filtered);
}
}
g_slist_free(filtered);
}
g_slist_free(list);
}
gboolean
cmd_who(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
} else if (window->type == WIN_MUC) {
_who_room(window, command, args);
} else {
_who_roster(window, command, args);
}
if (window->type != WIN_CONSOLE && window->type != WIN_MUC) {
status_bar_new(1, WIN_CONSOLE, "console");
}
return TRUE;
}
static void
_cmd_msg_chatwin(const char* const barejid, const char* const msg)
{
ProfChatWin* chatwin = wins_get_chat(barejid);
if (!chatwin) {
// NOTE: This will also start the new OMEMO session and send a MAM request.
chatwin = chatwin_new(barejid);
}
ui_focus_win((ProfWin*)chatwin);
if (msg) {
// NOTE: In case the message is OMEMO encrypted, we can't be sure
// whether the key bundles of the recipient have already been
// received. In the case that *no* bundles have been received yet,
// the message won't be sent, and an error is shown to the user.
// Other cases are not handled here.
cl_ev_send_msg(chatwin, msg, NULL);
} else {
#ifdef HAVE_LIBOTR
// Start the OTR session after this (i.e. the first) message was sent
if (otr_is_secure(barejid)) {
chatwin_otr_secured(chatwin, otr_is_trusted(barejid));
}
#endif // HAVE_LIBOTR
}
}
gboolean
cmd_msg(ProfWin* window, const char* const command, gchar** args)
{
char* usr = args[0];
char* msg = args[1];
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
// send private message when in MUC room
if (window->type == WIN_MUC) {
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
Occupant* occupant = muc_roster_item(mucwin->roomjid, usr);
if (occupant) {
// in case of non-anon muc send regular chatmessage
if (muc_anonymity_type(mucwin->roomjid) == MUC_ANONYMITY_TYPE_NONANONYMOUS) {
Jid* jidp = jid_create(occupant->jid);
_cmd_msg_chatwin(jidp->barejid, msg);
win_println(window, THEME_DEFAULT, "-", "Starting direct message with occupant \"%s\" from room \"%s\" as \"%s\".", usr, mucwin->roomjid, jidp->barejid);
cons_show("Starting direct message with occupant \"%s\" from room \"%s\" as \"%s\".", usr, mucwin->roomjid, jidp->barejid);
jid_destroy(jidp);
} else {
// otherwise send mucpm
GString* full_jid = g_string_new(mucwin->roomjid);
g_string_append(full_jid, "/");
g_string_append(full_jid, usr);
ProfPrivateWin* privwin = wins_get_private(full_jid->str);
if (!privwin) {
privwin = (ProfPrivateWin*)wins_new_private(full_jid->str);
}
ui_focus_win((ProfWin*)privwin);
if (msg) {
cl_ev_send_priv_msg(privwin, msg, NULL);
}
g_string_free(full_jid, TRUE);
}
} else {
win_println(window, THEME_DEFAULT, "-", "No such participant \"%s\" in room.", usr);
}
return TRUE;
// send chat message
} else {
char* barejid = roster_barejid_from_name(usr);
if (barejid == NULL) {
barejid = usr;
}
_cmd_msg_chatwin(barejid, msg);
return TRUE;
}
}
gboolean
cmd_group(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
// list all groups
if (args[1] == NULL) {
GList* groups = roster_get_groups();
GList* curr = groups;
if (curr) {
cons_show("Groups:");
while (curr) {
cons_show(" %s", curr->data);
curr = g_list_next(curr);
}
g_list_free_full(groups, g_free);
} else {
cons_show("No groups.");
}
return TRUE;
}
// show contacts in group
if (strcmp(args[1], "show") == 0) {
char* group = args[2];
if (group == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
GSList* list = roster_get_group(group, ROSTER_ORD_NAME);
cons_show_roster_group(group, list);
return TRUE;
}
// add contact to group
if (strcmp(args[1], "add") == 0) {
char* group = args[2];
char* contact = args[3];
if ((group == NULL) || (contact == NULL)) {
cons_bad_cmd_usage(command);
return TRUE;
}
char* barejid = roster_barejid_from_name(contact);
if (barejid == NULL) {
barejid = contact;
}
PContact pcontact = roster_get_contact(barejid);
if (pcontact == NULL) {
cons_show("Contact not found in roster: %s", barejid);
return TRUE;
}
if (p_contact_in_group(pcontact, group)) {
const char* display_name = p_contact_name_or_jid(pcontact);
ui_contact_already_in_group(display_name, group);
} else {
roster_send_add_to_group(group, pcontact);
}
return TRUE;
}
// remove contact from group
if (strcmp(args[1], "remove") == 0) {
char* group = args[2];
char* contact = args[3];
if ((group == NULL) || (contact == NULL)) {
cons_bad_cmd_usage(command);
return TRUE;
}
char* barejid = roster_barejid_from_name(contact);
if (barejid == NULL) {
barejid = contact;
}
PContact pcontact = roster_get_contact(barejid);
if (pcontact == NULL) {
cons_show("Contact not found in roster: %s", barejid);
return TRUE;
}
if (!p_contact_in_group(pcontact, group)) {
const char* display_name = p_contact_name_or_jid(pcontact);
ui_contact_not_in_group(display_name, group);
} else {
roster_send_remove_from_group(group, pcontact);
}
return TRUE;
}
cons_bad_cmd_usage(command);
return TRUE;
}
gboolean
cmd_roster(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
// show roster
if (args[0] == NULL) {
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
GSList* list = roster_get_contacts(ROSTER_ORD_NAME);
cons_show_roster(list);
g_slist_free(list);
return TRUE;
// show roster, only online contacts
} else if (g_strcmp0(args[0], "online") == 0) {
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
GSList* list = roster_get_contacts_online();
cons_show_roster(list);
g_slist_free(list);
return TRUE;
// set roster size
} else if (g_strcmp0(args[0], "size") == 0) {
if (!args[1]) {
cons_bad_cmd_usage(command);
return TRUE;
}
int intval = 0;
char* err_msg = NULL;
gboolean res = strtoi_range(args[1], &intval, 1, 99, &err_msg);
if (res) {
prefs_set_roster_size(intval);
cons_show("Roster screen size set to: %d%%", intval);
if (conn_status == JABBER_CONNECTED && prefs_get_boolean(PREF_ROSTER)) {
wins_resize_all();
}
return TRUE;
} else {
cons_show(err_msg);
free(err_msg);
return TRUE;
}
// set line wrapping
} else if (g_strcmp0(args[0], "wrap") == 0) {
if (!args[1]) {
cons_bad_cmd_usage(command);
return TRUE;
} else {
_cmd_set_boolean_preference(args[1], command, "Roster panel line wrap", PREF_ROSTER_WRAP);
rosterwin_roster();
return TRUE;
}
// header settings
} else if (g_strcmp0(args[0], "header") == 0) {
if (g_strcmp0(args[1], "char") == 0) {
if (!args[2]) {
cons_bad_cmd_usage(command);
} else if (g_strcmp0(args[2], "none") == 0) {
prefs_clear_roster_header_char();
cons_show("Roster header char removed.");
rosterwin_roster();
} else {
prefs_set_roster_header_char(args[2]);
cons_show("Roster header char set to %s.", args[2]);
rosterwin_roster();
}
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
// contact settings
} else if (g_strcmp0(args[0], "contact") == 0) {
if (g_strcmp0(args[1], "char") == 0) {
if (!args[2]) {
cons_bad_cmd_usage(command);
} else if (g_strcmp0(args[2], "none") == 0) {
prefs_clear_roster_contact_char();
cons_show("Roster contact char removed.");
rosterwin_roster();
} else {
prefs_set_roster_contact_char(args[2]);
cons_show("Roster contact char set to %s.", args[2]);
rosterwin_roster();
}
} else if (g_strcmp0(args[1], "indent") == 0) {
if (!args[2]) {
cons_bad_cmd_usage(command);
} else {
int intval = 0;
char* err_msg = NULL;
gboolean res = strtoi_range(args[2], &intval, 0, 10, &err_msg);
if (res) {
prefs_set_roster_contact_indent(intval);
cons_show("Roster contact indent set to: %d", intval);
rosterwin_roster();
} else {
cons_show(err_msg);
free(err_msg);
}
}
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
// resource settings
} else if (g_strcmp0(args[0], "resource") == 0) {
if (g_strcmp0(args[1], "char") == 0) {
if (!args[2]) {
cons_bad_cmd_usage(command);
} else if (g_strcmp0(args[2], "none") == 0) {
prefs_clear_roster_resource_char();
cons_show("Roster resource char removed.");
rosterwin_roster();
} else {
prefs_set_roster_resource_char(args[2]);
cons_show("Roster resource char set to %s.", args[2]);
rosterwin_roster();
}
} else if (g_strcmp0(args[1], "indent") == 0) {
if (!args[2]) {
cons_bad_cmd_usage(command);
} else {
int intval = 0;
char* err_msg = NULL;
gboolean res = strtoi_range(args[2], &intval, 0, 10, &err_msg);
if (res) {
prefs_set_roster_resource_indent(intval);
cons_show("Roster resource indent set to: %d", intval);
rosterwin_roster();
} else {
cons_show(err_msg);
free(err_msg);
}
}
} else if (g_strcmp0(args[1], "join") == 0) {
_cmd_set_boolean_preference(args[2], command, "Roster join", PREF_ROSTER_RESOURCE_JOIN);
rosterwin_roster();
return TRUE;
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
// presence settings
} else if (g_strcmp0(args[0], "presence") == 0) {
if (g_strcmp0(args[1], "indent") == 0) {
if (!args[2]) {
cons_bad_cmd_usage(command);
} else {
int intval = 0;
char* err_msg = NULL;
gboolean res = strtoi_range(args[2], &intval, -1, 10, &err_msg);
if (res) {
prefs_set_roster_presence_indent(intval);
cons_show("Roster presence indent set to: %d", intval);
rosterwin_roster();
} else {
cons_show(err_msg);
free(err_msg);
}
}
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
// show/hide roster
} else if ((g_strcmp0(args[0], "show") == 0) || (g_strcmp0(args[0], "hide") == 0)) {
preference_t pref;
const char* pref_str;
if (args[1] == NULL) {
pref = PREF_ROSTER;
pref_str = "";
} else if (g_strcmp0(args[1], "offline") == 0) {
pref = PREF_ROSTER_OFFLINE;
pref_str = "offline";
} else if (g_strcmp0(args[1], "resource") == 0) {
pref = PREF_ROSTER_RESOURCE;
pref_str = "resource";
} else if (g_strcmp0(args[1], "presence") == 0) {
pref = PREF_ROSTER_PRESENCE;
pref_str = "presence";
} else if (g_strcmp0(args[1], "status") == 0) {
pref = PREF_ROSTER_STATUS;
pref_str = "status";
} else if (g_strcmp0(args[1], "empty") == 0) {
pref = PREF_ROSTER_EMPTY;
pref_str = "empty";
} else if (g_strcmp0(args[1], "priority") == 0) {
pref = PREF_ROSTER_PRIORITY;
pref_str = "priority";
} else if (g_strcmp0(args[1], "contacts") == 0) {
pref = PREF_ROSTER_CONTACTS;
pref_str = "contacts";
} else if (g_strcmp0(args[1], "rooms") == 0) {
pref = PREF_ROSTER_ROOMS;
pref_str = "rooms";
} else if (g_strcmp0(args[1], "unsubscribed") == 0) {
pref = PREF_ROSTER_UNSUBSCRIBED;
pref_str = "unsubscribed";
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
gboolean val;
if (g_strcmp0(args[0], "show") == 0) {
val = TRUE;
} else { // "hide"
val = FALSE;
}
cons_show("Roster%s%s %s (was %s)", strlen(pref_str) == 0 ? "" : " ", pref_str,
val == TRUE ? "enabled" : "disabled",
prefs_get_boolean(pref) == TRUE ? "enabled" : "disabled");
prefs_set_boolean(pref, val);
if (conn_status == JABBER_CONNECTED) {
if (pref == PREF_ROSTER) {
if (val == TRUE) {
ui_show_roster();
} else {
ui_hide_roster();
}
} else {
rosterwin_roster();
}
}
return TRUE;
// roster grouping
} else if (g_strcmp0(args[0], "by") == 0) {
if (g_strcmp0(args[1], "group") == 0) {
cons_show("Grouping roster by roster group");
prefs_set_string(PREF_ROSTER_BY, "group");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else if (g_strcmp0(args[1], "presence") == 0) {
cons_show("Grouping roster by presence");
prefs_set_string(PREF_ROSTER_BY, "presence");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else if (g_strcmp0(args[1], "none") == 0) {
cons_show("Roster grouping disabled");
prefs_set_string(PREF_ROSTER_BY, "none");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
// roster item order
} else if (g_strcmp0(args[0], "order") == 0) {
if (g_strcmp0(args[1], "name") == 0) {
cons_show("Ordering roster by name");
prefs_set_string(PREF_ROSTER_ORDER, "name");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else if (g_strcmp0(args[1], "presence") == 0) {
cons_show("Ordering roster by presence");
prefs_set_string(PREF_ROSTER_ORDER, "presence");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
} else if (g_strcmp0(args[0], "count") == 0) {
if (g_strcmp0(args[1], "zero") == 0) {
_cmd_set_boolean_preference(args[2], command, "Roster header zero count", PREF_ROSTER_COUNT_ZERO);
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else if (g_strcmp0(args[1], "unread") == 0) {
cons_show("Roster header count set to unread");
prefs_set_string(PREF_ROSTER_COUNT, "unread");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else if (g_strcmp0(args[1], "items") == 0) {
cons_show("Roster header count set to items");
prefs_set_string(PREF_ROSTER_COUNT, "items");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else if (g_strcmp0(args[1], "off") == 0) {
cons_show("Disabling roster header count");
prefs_set_string(PREF_ROSTER_COUNT, "off");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
} else if (g_strcmp0(args[0], "color") == 0) {
_cmd_set_boolean_preference(args[1], command, "Roster consistent colors", PREF_ROSTER_COLOR_NICK);
ui_show_roster();
return TRUE;
} else if (g_strcmp0(args[0], "unread") == 0) {
if (g_strcmp0(args[1], "before") == 0) {
cons_show("Roster unread message count: before");
prefs_set_string(PREF_ROSTER_UNREAD, "before");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else if (g_strcmp0(args[1], "after") == 0) {
cons_show("Roster unread message count: after");
prefs_set_string(PREF_ROSTER_UNREAD, "after");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else if (g_strcmp0(args[1], "off") == 0) {
cons_show("Roster unread message count: off");
prefs_set_string(PREF_ROSTER_UNREAD, "off");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
} else if (g_strcmp0(args[0], "private") == 0) {
if (g_strcmp0(args[1], "char") == 0) {
if (!args[2]) {
cons_bad_cmd_usage(command);
} else if (g_strcmp0(args[2], "none") == 0) {
prefs_clear_roster_private_char();
cons_show("Roster private room chat char removed.");
rosterwin_roster();
} else {
prefs_set_roster_private_char(args[2]);
cons_show("Roster private room chat char set to %s.", args[2]);
rosterwin_roster();
}
return TRUE;
} else if (g_strcmp0(args[1], "room") == 0) {
cons_show("Showing room private chats under room.");
prefs_set_string(PREF_ROSTER_PRIVATE, "room");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else if (g_strcmp0(args[1], "group") == 0) {
cons_show("Showing room private chats as roster group.");
prefs_set_string(PREF_ROSTER_PRIVATE, "group");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else if (g_strcmp0(args[1], "off") == 0) {
cons_show("Hiding room private chats in roster.");
prefs_set_string(PREF_ROSTER_PRIVATE, "off");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
} else if (g_strcmp0(args[0], "room") == 0) {
if (g_strcmp0(args[1], "char") == 0) {
if (!args[2]) {
cons_bad_cmd_usage(command);
} else if (g_strcmp0(args[2], "none") == 0) {
prefs_clear_roster_room_char();
cons_show("Roster room char removed.");
rosterwin_roster();
} else {
prefs_set_roster_room_char(args[2]);
cons_show("Roster room char set to %s.", args[2]);
rosterwin_roster();
}
return TRUE;
} else if (g_strcmp0(args[1], "position") == 0) {
if (g_strcmp0(args[2], "first") == 0) {
cons_show("Showing rooms first in roster.");
prefs_set_string(PREF_ROSTER_ROOMS_POS, "first");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else if (g_strcmp0(args[2], "last") == 0) {
cons_show("Showing rooms last in roster.");
prefs_set_string(PREF_ROSTER_ROOMS_POS, "last");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
} else if (g_strcmp0(args[1], "order") == 0) {
if (g_strcmp0(args[2], "name") == 0) {
cons_show("Ordering roster rooms by name");
prefs_set_string(PREF_ROSTER_ROOMS_ORDER, "name");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else if (g_strcmp0(args[2], "unread") == 0) {
cons_show("Ordering roster rooms by unread messages");
prefs_set_string(PREF_ROSTER_ROOMS_ORDER, "unread");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
} else if (g_strcmp0(args[1], "unread") == 0) {
if (g_strcmp0(args[2], "before") == 0) {
cons_show("Roster rooms unread message count: before");
prefs_set_string(PREF_ROSTER_ROOMS_UNREAD, "before");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else if (g_strcmp0(args[2], "after") == 0) {
cons_show("Roster rooms unread message count: after");
prefs_set_string(PREF_ROSTER_ROOMS_UNREAD, "after");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else if (g_strcmp0(args[2], "off") == 0) {
cons_show("Roster rooms unread message count: off");
prefs_set_string(PREF_ROSTER_ROOMS_UNREAD, "off");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
} else if (g_strcmp0(args[1], "private") == 0) {
if (g_strcmp0(args[2], "char") == 0) {
if (!args[3]) {
cons_bad_cmd_usage(command);
} else if (g_strcmp0(args[3], "none") == 0) {
prefs_clear_roster_room_private_char();
cons_show("Roster room private char removed.");
rosterwin_roster();
} else {
prefs_set_roster_room_private_char(args[3]);
cons_show("Roster room private char set to %s.", args[3]);
rosterwin_roster();
}
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
} else if (g_strcmp0(args[1], "by") == 0) {
if (g_strcmp0(args[2], "service") == 0) {
cons_show("Grouping rooms by service");
prefs_set_string(PREF_ROSTER_ROOMS_BY, "service");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else if (g_strcmp0(args[2], "none") == 0) {
cons_show("Roster room grouping disabled");
prefs_set_string(PREF_ROSTER_ROOMS_BY, "none");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
} else if (g_strcmp0(args[1], "show") == 0) {
if (g_strcmp0(args[2], "server") == 0) {
cons_show("Roster room server enabled.");
prefs_set_boolean(PREF_ROSTER_ROOMS_SERVER, TRUE);
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
} else if (g_strcmp0(args[1], "hide") == 0) {
if (g_strcmp0(args[2], "server") == 0) {
cons_show("Roster room server disabled.");
prefs_set_boolean(PREF_ROSTER_ROOMS_SERVER, FALSE);
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
} else if (g_strcmp0(args[1], "use") == 0) {
if (g_strcmp0(args[2], "jid") == 0) {
cons_show("Roster room display jid as name.");
prefs_set_string(PREF_ROSTER_ROOMS_USE_AS_NAME, "jid");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else if (g_strcmp0(args[2], "name") == 0) {
cons_show("Roster room display room name as name.");
prefs_set_string(PREF_ROSTER_ROOMS_USE_AS_NAME, "name");
if (conn_status == JABBER_CONNECTED) {
rosterwin_roster();
}
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
// add contact
} else if (strcmp(args[0], "add") == 0) {
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
char* jid = args[1];
if (jid == NULL) {
cons_bad_cmd_usage(command);
} else {
char* name = args[2];
roster_send_add_new(jid, name);
}
return TRUE;
// remove contact
} else if (strcmp(args[0], "remove") == 0) {
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
char* jid = args[1];
if (jid == NULL) {
cons_bad_cmd_usage(command);
} else {
roster_send_remove(jid);
}
return TRUE;
} else if (strcmp(args[0], "remove_all") == 0) {
if (g_strcmp0(args[1], "contacts") != 0) {
cons_bad_cmd_usage(command);
return TRUE;
}
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
GSList* all = roster_get_contacts(ROSTER_ORD_NAME);
GSList* curr = all;
while (curr) {
PContact contact = curr->data;
roster_send_remove(p_contact_barejid(contact));
curr = g_slist_next(curr);
}
g_slist_free(all);
return TRUE;
// change nickname
} else if (strcmp(args[0], "nick") == 0) {
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
char* jid = args[1];
if (jid == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
char* name = args[2];
if (name == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
// contact does not exist
PContact contact = roster_get_contact(jid);
if (contact == NULL) {
cons_show("Contact not found in roster: %s", jid);
return TRUE;
}
const char* barejid = p_contact_barejid(contact);
// TODO wait for result stanza before updating
const char* oldnick = p_contact_name(contact);
wins_change_nick(barejid, oldnick, name);
roster_change_name(contact, name);
GSList* groups = p_contact_groups(contact);
roster_send_name_change(barejid, name, groups);
cons_show("Nickname for %s set to: %s.", jid, name);
return TRUE;
// remove nickname
} else if (strcmp(args[0], "clearnick") == 0) {
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
char* jid = args[1];
if (jid == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
// contact does not exist
PContact contact = roster_get_contact(jid);
if (contact == NULL) {
cons_show("Contact not found in roster: %s", jid);
return TRUE;
}
const char* barejid = p_contact_barejid(contact);
// TODO wait for result stanza before updating
const char* oldnick = p_contact_name(contact);
wins_remove_nick(barejid, oldnick);
roster_change_name(contact, NULL);
GSList* groups = p_contact_groups(contact);
roster_send_name_change(barejid, NULL, groups);
cons_show("Nickname for %s removed.", jid);
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
}
gboolean
cmd_blocked(ProfWin* window, const char* const command, gchar** args)
{
if (connection_get_status() != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
if (!connection_supports(XMPP_FEATURE_BLOCKING)) {
cons_show("Blocking (%s) not supported by server.", XMPP_FEATURE_BLOCKING);
return TRUE;
}
blocked_report br = BLOCKED_NO_REPORT;
if (g_strcmp0(args[0], "add") == 0) {
char* jid = args[1];
if (jid == NULL && (window->type == WIN_CHAT)) {
ProfChatWin* chatwin = (ProfChatWin*)window;
jid = chatwin->barejid;
}
if (jid == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
gboolean res = blocked_add(jid, br, NULL);
if (!res) {
cons_show("User %s already blocked.", jid);
}
return TRUE;
}
if (g_strcmp0(args[0], "remove") == 0) {
if (args[1] == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
gboolean res = blocked_remove(args[1]);
if (!res) {
cons_show("User %s is not currently blocked.", args[1]);
}
return TRUE;
}
if (args[0] && strncmp(args[0], "report-", 7) == 0) {
char* jid = NULL;
char* msg = NULL;
guint argn = g_strv_length(args);
if (argn >= 2) {
jid = args[1];
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
if (argn >= 3) {
msg = args[2];
}
if (args[1] && g_strcmp0(args[0], "report-abuse") == 0) {
br = BLOCKED_REPORT_ABUSE;
} else if (args[1] && g_strcmp0(args[0], "report-spam") == 0) {
br = BLOCKED_REPORT_SPAM;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
if (!connection_supports(XMPP_FEATURE_SPAM_REPORTING)) {
cons_show("Spam reporting (%s) not supported by server.", XMPP_FEATURE_SPAM_REPORTING);
return TRUE;
}
gboolean res = blocked_add(jid, br, msg);
if (!res) {
cons_show("User %s already blocked.", args[1]);
}
return TRUE;
}
GList* blocked = blocked_list();
GList* curr = blocked;
if (curr) {
cons_show("Blocked users:");
while (curr) {
cons_show(" %s", curr->data);
curr = g_list_next(curr);
}
} else {
cons_show("No blocked users.");
}
return TRUE;
}
gboolean
cmd_resource(ProfWin* window, const char* const command, gchar** args)
{
char* cmd = args[0];
char* setting = NULL;
if (g_strcmp0(cmd, "message") == 0) {
setting = args[1];
if (!setting) {
cons_bad_cmd_usage(command);
return TRUE;
} else {
_cmd_set_boolean_preference(setting, command, "Message resource", PREF_RESOURCE_MESSAGE);
return TRUE;
}
} else if (g_strcmp0(cmd, "title") == 0) {
setting = args[1];
if (!setting) {
cons_bad_cmd_usage(command);
return TRUE;
} else {
_cmd_set_boolean_preference(setting, command, "Title resource", PREF_RESOURCE_TITLE);
return TRUE;
}
}
if (window->type != WIN_CHAT) {
cons_show("Resource can only be changed in chat windows.");
return TRUE;
}
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
ProfChatWin* chatwin = (ProfChatWin*)window;
if (g_strcmp0(cmd, "set") == 0) {
char* resource = args[1];
if (!resource) {
cons_bad_cmd_usage(command);
return TRUE;
}
#ifdef HAVE_LIBOTR
if (otr_is_secure(chatwin->barejid)) {
cons_show("Cannot choose resource during an OTR session.");
return TRUE;
}
#endif
PContact contact = roster_get_contact(chatwin->barejid);
if (!contact) {
cons_show("Cannot choose resource for contact not in roster.");
return TRUE;
}
if (!p_contact_get_resource(contact, resource)) {
cons_show("No such resource %s.", resource);
return TRUE;
}
chatwin->resource_override = strdup(resource);
chat_state_free(chatwin->state);
chatwin->state = chat_state_new();
chat_session_resource_override(chatwin->barejid, resource);
return TRUE;
} else if (g_strcmp0(cmd, "off") == 0) {
FREE_SET_NULL(chatwin->resource_override);
chat_state_free(chatwin->state);
chatwin->state = chat_state_new();
chat_session_remove(chatwin->barejid);
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
}
static void
_cmd_status_show_status(char* usr)
{
char* usr_jid = roster_barejid_from_name(usr);
if (usr_jid == NULL) {
usr_jid = usr;
}
cons_show_status(usr_jid);
}
gboolean
cmd_status_set(ProfWin* window, const char* const command, gchar** args)
{
char* state = args[1];
if (g_strcmp0(state, "online") == 0) {
_update_presence(RESOURCE_ONLINE, "online", args);
} else if (g_strcmp0(state, "away") == 0) {
_update_presence(RESOURCE_AWAY, "away", args);
} else if (g_strcmp0(state, "dnd") == 0) {
_update_presence(RESOURCE_DND, "dnd", args);
} else if (g_strcmp0(state, "chat") == 0) {
_update_presence(RESOURCE_CHAT, "chat", args);
} else if (g_strcmp0(state, "xa") == 0) {
_update_presence(RESOURCE_XA, "xa", args);
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}
gboolean
cmd_status_get(ProfWin* window, const char* const command, gchar** args)
{
char* usr = args[1];
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
switch (window->type) {
case WIN_MUC:
if (usr) {
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
Occupant* occupant = muc_roster_item(mucwin->roomjid, usr);
if (occupant) {
win_show_occupant(window, occupant);
} else {
win_println(window, THEME_DEFAULT, "-", "No such participant \"%s\" in room.", usr);
}
} else {
win_println(window, THEME_DEFAULT, "-", "You must specify a nickname.");
}
break;
case WIN_CHAT:
if (usr) {
_cmd_status_show_status(usr);
} else {
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
PContact pcontact = roster_get_contact(chatwin->barejid);
if (pcontact) {
win_show_contact(window, pcontact);
} else {
win_println(window, THEME_DEFAULT, "-", "Error getting contact info.");
}
}
break;
case WIN_PRIVATE:
if (usr) {
_cmd_status_show_status(usr);
} else {
ProfPrivateWin* privatewin = (ProfPrivateWin*)window;
assert(privatewin->memcheck == PROFPRIVATEWIN_MEMCHECK);
Jid* jid = jid_create(privatewin->fulljid);
Occupant* occupant = muc_roster_item(jid->barejid, jid->resourcepart);
if (occupant) {
win_show_occupant(window, occupant);
} else {
win_println(window, THEME_DEFAULT, "-", "Error getting contact info.");
}
jid_destroy(jid);
}
break;
case WIN_CONSOLE:
if (usr) {
_cmd_status_show_status(usr);
} else {
cons_bad_cmd_usage(command);
}
break;
default:
break;
}
return TRUE;
}
static void
_cmd_info_show_contact(char* usr)
{
char* usr_jid = roster_barejid_from_name(usr);
if (usr_jid == NULL) {
usr_jid = usr;
}
PContact pcontact = roster_get_contact(usr_jid);
if (pcontact) {
cons_show_info(pcontact);
} else {
cons_show("No such contact \"%s\" in roster.", usr);
}
}
gboolean
cmd_info(ProfWin* window, const char* const command, gchar** args)
{
char* usr = args[0];
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
switch (window->type) {
case WIN_MUC:
if (usr) {
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
Occupant* occupant = muc_roster_item(mucwin->roomjid, usr);
if (occupant) {
win_show_occupant_info(window, mucwin->roomjid, occupant);
} else {
win_println(window, THEME_DEFAULT, "-", "No such occupant \"%s\" in room.", usr);
}
} else {
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
iq_room_info_request(mucwin->roomjid, TRUE);
mucwin_info(mucwin);
return TRUE;
}
break;
case WIN_CHAT:
if (usr) {
_cmd_info_show_contact(usr);
} else {
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
PContact pcontact = roster_get_contact(chatwin->barejid);
if (pcontact) {
win_show_info(window, pcontact);
} else {
win_println(window, THEME_DEFAULT, "-", "Error getting contact info.");
}
}
break;
case WIN_PRIVATE:
if (usr) {
_cmd_info_show_contact(usr);
} else {
ProfPrivateWin* privatewin = (ProfPrivateWin*)window;
assert(privatewin->memcheck == PROFPRIVATEWIN_MEMCHECK);
Jid* jid = jid_create(privatewin->fulljid);
Occupant* occupant = muc_roster_item(jid->barejid, jid->resourcepart);
if (occupant) {
win_show_occupant_info(window, jid->barejid, occupant);
} else {
win_println(window, THEME_DEFAULT, "-", "Error getting contact info.");
}
jid_destroy(jid);
}
break;
case WIN_CONSOLE:
if (usr) {
_cmd_info_show_contact(usr);
} else {
cons_bad_cmd_usage(command);
}
break;
default:
break;
}
return TRUE;
}
gboolean
cmd_caps(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
Occupant* occupant = NULL;
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
switch (window->type) {
case WIN_MUC:
if (args[0]) {
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
occupant = muc_roster_item(mucwin->roomjid, args[0]);
if (occupant) {
Jid* jidp = jid_create_from_bare_and_resource(mucwin->roomjid, args[0]);
cons_show_caps(jidp->fulljid, occupant->presence);
jid_destroy(jidp);
} else {
cons_show("No such participant \"%s\" in room.", args[0]);
}
} else {
cons_show("No nickname supplied to /caps in chat room.");
}
break;
case WIN_CHAT:
case WIN_CONSOLE:
if (args[0]) {
Jid* jid = jid_create(args[0]);
if (jid->fulljid == NULL) {
cons_show("You must provide a full jid to the /caps command.");
} else {
PContact pcontact = roster_get_contact(jid->barejid);
if (pcontact == NULL) {
cons_show("Contact not found in roster: %s", jid->barejid);
} else {
Resource* resource = p_contact_get_resource(pcontact, jid->resourcepart);
if (resource == NULL) {
cons_show("Could not find resource %s, for contact %s", jid->barejid, jid->resourcepart);
} else {
cons_show_caps(jid->fulljid, resource->presence);
}
}
}
jid_destroy(jid);
} else {
cons_show("You must provide a jid to the /caps command.");
}
break;
case WIN_PRIVATE:
if (args[0]) {
cons_show("No parameter needed to /caps when in private chat.");
} else {
ProfPrivateWin* privatewin = (ProfPrivateWin*)window;
assert(privatewin->memcheck == PROFPRIVATEWIN_MEMCHECK);
Jid* jid = jid_create(privatewin->fulljid);
if (jid) {
occupant = muc_roster_item(jid->barejid, jid->resourcepart);
cons_show_caps(jid->resourcepart, occupant->presence);
jid_destroy(jid);
}
}
break;
default:
break;
}
return TRUE;
}
static void
_send_software_version_iq_to_fulljid(char* request)
{
char* mybarejid = connection_get_barejid();
Jid* jid = jid_create(request);
if (jid == NULL || jid->fulljid == NULL) {
cons_show("You must provide a full jid to the /software command.");
} else if (g_strcmp0(jid->barejid, mybarejid) == 0) {
cons_show("Cannot request software version for yourself.");
} else {
iq_send_software_version(jid->fulljid);
}
free(mybarejid);
jid_destroy(jid);
}
gboolean
cmd_software(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
switch (window->type) {
case WIN_MUC:
if (args[0]) {
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
Occupant* occupant = muc_roster_item(mucwin->roomjid, args[0]);
if (occupant) {
Jid* jid = jid_create_from_bare_and_resource(mucwin->roomjid, args[0]);
iq_send_software_version(jid->fulljid);
jid_destroy(jid);
} else {
cons_show("No such participant \"%s\" in room.", args[0]);
}
} else {
cons_show("No nickname supplied to /software in chat room.");
}
break;
case WIN_CHAT:
if (args[0]) {
_send_software_version_iq_to_fulljid(args[0]);
break;
} else {
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
char* resource = NULL;
ChatSession* session = chat_session_get(chatwin->barejid);
if (chatwin->resource_override) {
resource = chatwin->resource_override;
} else if (session && session->resource) {
resource = session->resource;
}
if (resource) {
GString* fulljid = g_string_new(chatwin->barejid);
g_string_append_printf(fulljid, "/%s", resource);
iq_send_software_version(fulljid->str);
g_string_free(fulljid, TRUE);
} else {
win_println(window, THEME_DEFAULT, "-", "Unknown resource for /software command. See /help resource.");
}
break;
}
case WIN_CONSOLE:
if (args[0]) {
_send_software_version_iq_to_fulljid(args[0]);
} else {
cons_show("You must provide a jid to the /software command.");
}
break;
case WIN_PRIVATE:
if (args[0]) {
cons_show("No parameter needed to /software when in private chat.");
} else {
ProfPrivateWin* privatewin = (ProfPrivateWin*)window;
assert(privatewin->memcheck == PROFPRIVATEWIN_MEMCHECK);
iq_send_software_version(privatewin->fulljid);
}
break;
default:
break;
}
return TRUE;
}
gboolean
cmd_serversoftware(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
if (args[0]) {
iq_send_software_version(args[0]);
} else {
cons_show("You must provide a jid to the /serversoftware command.");
}
return TRUE;
}
gboolean
cmd_join(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
if (args[0] == NULL) {
char* account_name = session_get_account_name();
ProfAccount* account = accounts_get_account(account_name);
if (account->muc_service) {
GString* room_str = g_string_new("");
char* uuid = connection_create_uuid();
g_string_append_printf(room_str, "private-chat-%s@%s", uuid, account->muc_service);
connection_free_uuid(uuid);
presence_join_room(room_str->str, account->muc_nick, NULL);
muc_join(room_str->str, account->muc_nick, NULL, FALSE);
g_string_free(room_str, TRUE);
account_free(account);
} else {
cons_show("Account MUC service property not found.");
}
return TRUE;
}
Jid* room_arg = jid_create(args[0]);
if (room_arg == NULL) {
cons_show_error("Specified room has incorrect format.");
cons_show("");
return TRUE;
}
char* room = NULL;
char* nick = NULL;
char* passwd = NULL;
char* account_name = session_get_account_name();
ProfAccount* account = accounts_get_account(account_name);
// full room jid supplied (room@server)
if (room_arg->localpart) {
room = g_strdup(args[0]);
// server not supplied (room), use account preference
} else if (account->muc_service) {
GString* room_str = g_string_new("");
g_string_append(room_str, args[0]);
g_string_append(room_str, "@");
g_string_append(room_str, account->muc_service);
room = room_str->str;
g_string_free(room_str, FALSE);
// no account preference
} else {
cons_show("Account MUC service property not found.");
return TRUE;
}
// Additional args supplied
gchar* opt_keys[] = { "nick", "password", NULL };
gboolean parsed;
GHashTable* options = parse_options(&args[1], opt_keys, &parsed);
if (!parsed) {
cons_bad_cmd_usage(command);
cons_show("");
g_free(room);
jid_destroy(room_arg);
return TRUE;
}
nick = g_hash_table_lookup(options, "nick");
passwd = g_hash_table_lookup(options, "password");
options_destroy(options);
// In the case that a nick wasn't provided by the optional args...
if (!nick) {
nick = account->muc_nick;
}
// When no password, check for invite with password
if (!passwd) {
passwd = muc_invite_password(room);
}
if (!muc_active(room)) {
presence_join_room(room, nick, passwd);
muc_join(room, nick, passwd, FALSE);
iq_room_affiliation_list(room, "member", false);
iq_room_affiliation_list(room, "admin", false);
iq_room_affiliation_list(room, "owner", false);
} else if (muc_roster_complete(room)) {
ui_switch_to_room(room);
}
g_free(room);
jid_destroy(room_arg);
account_free(account);
return TRUE;
}
gboolean
cmd_invite(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
if (g_strcmp0(args[0], "send") == 0) {
char* contact = args[1];
char* reason = args[2];
if (window->type != WIN_MUC) {
cons_show("You must be in a chat room to send an invite.");
return TRUE;
}
char* usr_jid = roster_barejid_from_name(contact);
if (usr_jid == NULL) {
usr_jid = contact;
}
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
message_send_invite(mucwin->roomjid, usr_jid, reason);
if (reason) {
cons_show("Room invite sent, contact: %s, room: %s, reason: \"%s\".",
contact, mucwin->roomjid, reason);
} else {
cons_show("Room invite sent, contact: %s, room: %s.",
contact, mucwin->roomjid);
}
} else if (g_strcmp0(args[0], "list") == 0) {
GList* invites = muc_invites();
cons_show_room_invites(invites);
g_list_free_full(invites, g_free);
} else if (g_strcmp0(args[0], "decline") == 0) {
if (!muc_invites_contain(args[1])) {
cons_show("No such invite exists.");
} else {
muc_invites_remove(args[1]);
cons_show("Declined invite to %s.", args[1]);
}
}
return TRUE;
}
gboolean
cmd_form_field(ProfWin* window, char* tag, gchar** args)
{
if (window->type != WIN_CONFIG) {
return TRUE;
}
ProfConfWin* confwin = (ProfConfWin*)window;
DataForm* form = confwin->form;
if (form) {
if (!form_tag_exists(form, tag)) {
win_println(window, THEME_DEFAULT, "-", "Form does not contain a field with tag %s", tag);
return TRUE;
}
form_field_type_t field_type = form_get_field_type(form, tag);
char* cmd = NULL;
char* value = NULL;
gboolean valid = FALSE;
gboolean added = FALSE;
gboolean removed = FALSE;
switch (field_type) {
case FIELD_BOOLEAN:
value = args[0];
if (g_strcmp0(value, "on") == 0) {
form_set_value(form, tag, "1");
win_println(window, THEME_DEFAULT, "-", "Field updated...");
confwin_show_form_field(confwin, form, tag);
} else if (g_strcmp0(value, "off") == 0) {
form_set_value(form, tag, "0");
win_println(window, THEME_DEFAULT, "-", "Field updated...");
confwin_show_form_field(confwin, form, tag);
} else {
win_println(window, THEME_DEFAULT, "-", "Invalid command, usage:");
confwin_field_help(confwin, tag);
win_println(window, THEME_DEFAULT, "-", "");
}
break;
case FIELD_TEXT_PRIVATE:
case FIELD_TEXT_SINGLE:
case FIELD_JID_SINGLE:
value = args[0];
if (value == NULL) {
win_println(window, THEME_DEFAULT, "-", "Invalid command, usage:");
confwin_field_help(confwin, tag);
win_println(window, THEME_DEFAULT, "-", "");
} else {
form_set_value(form, tag, value);
win_println(window, THEME_DEFAULT, "-", "Field updated...");
confwin_show_form_field(confwin, form, tag);
}
break;
case FIELD_LIST_SINGLE:
value = args[0];
if ((value == NULL) || !form_field_contains_option(form, tag, value)) {
win_println(window, THEME_DEFAULT, "-", "Invalid command, usage:");
confwin_field_help(confwin, tag);
win_println(window, THEME_DEFAULT, "-", "");
} else {
form_set_value(form, tag, value);
win_println(window, THEME_DEFAULT, "-", "Field updated...");
confwin_show_form_field(confwin, form, tag);
}
break;
case FIELD_TEXT_MULTI:
cmd = args[0];
if (cmd) {
value = args[1];
}
if ((g_strcmp0(cmd, "add") != 0) && (g_strcmp0(cmd, "remove"))) {
win_println(window, THEME_DEFAULT, "-", "Invalid command, usage:");
confwin_field_help(confwin, tag);
win_println(window, THEME_DEFAULT, "-", "");
break;
}
if (value == NULL) {
win_println(window, THEME_DEFAULT, "-", "Invalid command, usage:");
confwin_field_help(confwin, tag);
win_println(window, THEME_DEFAULT, "-", "");
break;
}
if (g_strcmp0(cmd, "add") == 0) {
form_add_value(form, tag, value);
win_println(window, THEME_DEFAULT, "-", "Field updated...");
confwin_show_form_field(confwin, form, tag);
break;
}
if (g_strcmp0(args[0], "remove") == 0) {
if (!g_str_has_prefix(value, "val")) {
win_println(window, THEME_DEFAULT, "-", "Invalid command, usage:");
confwin_field_help(confwin, tag);
win_println(window, THEME_DEFAULT, "-", "");
break;
}
if (strlen(value) < 4) {
win_println(window, THEME_DEFAULT, "-", "Invalid command, usage:");
confwin_field_help(confwin, tag);
win_println(window, THEME_DEFAULT, "-", "");
break;
}
int index = strtol(&value[3], NULL, 10);
if ((index < 1) || (index > form_get_value_count(form, tag))) {
win_println(window, THEME_DEFAULT, "-", "Invalid command, usage:");
confwin_field_help(confwin, tag);
win_println(window, THEME_DEFAULT, "-", "");
break;
}
removed = form_remove_text_multi_value(form, tag, index);
if (removed) {
win_println(window, THEME_DEFAULT, "-", "Field updated...");
confwin_show_form_field(confwin, form, tag);
} else {
win_println(window, THEME_DEFAULT, "-", "Could not remove %s from %s", value, tag);
}
}
break;
case FIELD_LIST_MULTI:
cmd = args[0];
if (cmd) {
value = args[1];
}
if ((g_strcmp0(cmd, "add") != 0) && (g_strcmp0(cmd, "remove"))) {
win_println(window, THEME_DEFAULT, "-", "Invalid command, usage:");
confwin_field_help(confwin, tag);
win_println(window, THEME_DEFAULT, "-", "");
break;
}
if (value == NULL) {
win_println(window, THEME_DEFAULT, "-", "Invalid command, usage:");
confwin_field_help(confwin, tag);
win_println(window, THEME_DEFAULT, "-", "");
break;
}
if (g_strcmp0(args[0], "add") == 0) {
valid = form_field_contains_option(form, tag, value);
if (valid) {
added = form_add_unique_value(form, tag, value);
if (added) {
win_println(window, THEME_DEFAULT, "-", "Field updated...");
confwin_show_form_field(confwin, form, tag);
} else {
win_println(window, THEME_DEFAULT, "-", "Value %s already selected for %s", value, tag);
}
} else {
win_println(window, THEME_DEFAULT, "-", "Invalid command, usage:");
confwin_field_help(confwin, tag);
win_println(window, THEME_DEFAULT, "-", "");
}
break;
}
if (g_strcmp0(args[0], "remove") == 0) {
valid = form_field_contains_option(form, tag, value);
if (valid == TRUE) {
removed = form_remove_value(form, tag, value);
if (removed) {
win_println(window, THEME_DEFAULT, "-", "Field updated...");
confwin_show_form_field(confwin, form, tag);
} else {
win_println(window, THEME_DEFAULT, "-", "Value %s is not currently set for %s", value, tag);
}
} else {
win_println(window, THEME_DEFAULT, "-", "Invalid command, usage:");
confwin_field_help(confwin, tag);
win_println(window, THEME_DEFAULT, "-", "");
}
}
break;
case FIELD_JID_MULTI:
cmd = args[0];
if (cmd) {
value = args[1];
}
if ((g_strcmp0(cmd, "add") != 0) && (g_strcmp0(cmd, "remove"))) {
win_println(window, THEME_DEFAULT, "-", "Invalid command, usage:");
confwin_field_help(confwin, tag);
win_println(window, THEME_DEFAULT, "-", "");
break;
}
if (value == NULL) {
win_println(window, THEME_DEFAULT, "-", "Invalid command, usage:");
confwin_field_help(confwin, tag);
win_println(window, THEME_DEFAULT, "-", "");
break;
}
if (g_strcmp0(args[0], "add") == 0) {
added = form_add_unique_value(form, tag, value);
if (added) {
win_println(window, THEME_DEFAULT, "-", "Field updated...");
confwin_show_form_field(confwin, form, tag);
} else {
win_println(window, THEME_DEFAULT, "-", "JID %s already exists in %s", value, tag);
}
break;
}
if (g_strcmp0(args[0], "remove") == 0) {
removed = form_remove_value(form, tag, value);
if (removed) {
win_println(window, THEME_DEFAULT, "-", "Field updated...");
confwin_show_form_field(confwin, form, tag);
} else {
win_println(window, THEME_DEFAULT, "-", "Field %s does not contain %s", tag, value);
}
}
break;
default:
break;
}
}
return TRUE;
}
gboolean
cmd_form(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
if (window->type != WIN_CONFIG) {
cons_show("Command '/form' does not apply to this window.");
return TRUE;
}
if ((g_strcmp0(args[0], "submit") != 0) && (g_strcmp0(args[0], "cancel") != 0) && (g_strcmp0(args[0], "show") != 0) && (g_strcmp0(args[0], "help") != 0)) {
cons_bad_cmd_usage(command);
return TRUE;
}
ProfConfWin* confwin = (ProfConfWin*)window;
assert(confwin->memcheck == PROFCONFWIN_MEMCHECK);
if (g_strcmp0(args[0], "show") == 0) {
confwin_show_form(confwin);
return TRUE;
}
if (g_strcmp0(args[0], "help") == 0) {
char* tag = args[1];
if (tag) {
confwin_field_help(confwin, tag);
} else {
confwin_form_help(confwin);
gchar** help_text = NULL;
Command* command = cmd_get("/form");
if (command) {
help_text = command->help.synopsis;
}
ui_show_lines((ProfWin*)confwin, help_text);
}
win_println(window, THEME_DEFAULT, "-", "");
return TRUE;
}
if (g_strcmp0(args[0], "submit") == 0 && confwin->submit != NULL) {
confwin->submit(confwin);
}
if (g_strcmp0(args[0], "cancel") == 0 && confwin->cancel != NULL) {
confwin->cancel(confwin);
}
if ((g_strcmp0(args[0], "submit") == 0) || (g_strcmp0(args[0], "cancel") == 0)) {
if (confwin->form) {
cmd_ac_remove_form_fields(confwin->form);
}
int num = wins_get_num(window);
ProfWin* new_current = (ProfWin*)wins_get_muc(confwin->roomjid);
if (!new_current) {
new_current = wins_get_console();
}
ui_focus_win(new_current);
wins_close_by_num(num);
wins_tidy();
}
return TRUE;
}
gboolean
cmd_kick(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
if (window->type != WIN_MUC) {
cons_show("Command '/kick' only applies in chat rooms.");
return TRUE;
}
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
char* nick = args[0];
if (nick) {
if (muc_roster_contains_nick(mucwin->roomjid, nick)) {
char* reason = args[1];
iq_room_kick_occupant(mucwin->roomjid, nick, reason);
} else {
win_println(window, THEME_DEFAULT, "!", "Occupant does not exist: %s", nick);
}
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}
gboolean
cmd_ban(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
if (window->type != WIN_MUC) {
cons_show("Command '/ban' only applies in chat rooms.");
return TRUE;
}
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
char* jid = args[0];
if (jid) {
char* reason = args[1];
iq_room_affiliation_set(mucwin->roomjid, jid, "outcast", reason);
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}
gboolean
cmd_subject(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
if (window->type != WIN_MUC) {
cons_show("Command '/room' does not apply to this window.");
return TRUE;
}
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
if (args[0] == NULL) {
char* subject = muc_subject(mucwin->roomjid);
if (subject) {
win_print(window, THEME_ROOMINFO, "!", "Room subject: ");
win_appendln(window, THEME_DEFAULT, "%s", subject);
} else {
win_println(window, THEME_ROOMINFO, "!", "Room has no subject");
}
return TRUE;
}
if (g_strcmp0(args[0], "set") == 0) {
if (args[1]) {
message_send_groupchat_subject(mucwin->roomjid, args[1]);
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}
if (g_strcmp0(args[0], "edit") == 0) {
if (args[1]) {
message_send_groupchat_subject(mucwin->roomjid, args[1]);
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}
if (g_strcmp0(args[0], "prepend") == 0) {
if (args[1]) {
char* old_subject = muc_subject(mucwin->roomjid);
if (old_subject) {
GString* new_subject = g_string_new(args[1]);
g_string_append(new_subject, old_subject);
message_send_groupchat_subject(mucwin->roomjid, new_subject->str);
g_string_free(new_subject, TRUE);
} else {
win_print(window, THEME_ROOMINFO, "!", "Room does not have a subject, use /subject set <subject>");
}
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}
if (g_strcmp0(args[0], "append") == 0) {
if (args[1]) {
char* old_subject = muc_subject(mucwin->roomjid);
if (old_subject) {
GString* new_subject = g_string_new(old_subject);
g_string_append(new_subject, args[1]);
message_send_groupchat_subject(mucwin->roomjid, new_subject->str);
g_string_free(new_subject, TRUE);
} else {
win_print(window, THEME_ROOMINFO, "!", "Room does not have a subject, use /subject set <subject>");
}
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}
if (g_strcmp0(args[0], "clear") == 0) {
message_send_groupchat_subject(mucwin->roomjid, NULL);
return TRUE;
}
cons_bad_cmd_usage(command);
return TRUE;
}
gboolean
cmd_affiliation(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
if (window->type != WIN_MUC) {
cons_show("Command '/affiliation' does not apply to this window.");
return TRUE;
}
char* cmd = args[0];
if (cmd == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
char* affiliation = args[1];
if (affiliation && (g_strcmp0(affiliation, "owner") != 0) && (g_strcmp0(affiliation, "admin") != 0) && (g_strcmp0(affiliation, "member") != 0) && (g_strcmp0(affiliation, "none") != 0) && (g_strcmp0(affiliation, "outcast") != 0)) {
cons_bad_cmd_usage(command);
return TRUE;
}
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
if (g_strcmp0(cmd, "list") == 0) {
if (!affiliation) {
iq_room_affiliation_list(mucwin->roomjid, "owner", true);
iq_room_affiliation_list(mucwin->roomjid, "admin", true);
iq_room_affiliation_list(mucwin->roomjid, "member", true);
iq_room_affiliation_list(mucwin->roomjid, "outcast", true);
} else if (g_strcmp0(affiliation, "none") == 0) {
win_println(window, THEME_DEFAULT, "!", "Cannot list users with no affiliation.");
} else {
iq_room_affiliation_list(mucwin->roomjid, affiliation, true);
}
return TRUE;
}
if (g_strcmp0(cmd, "set") == 0) {
if (!affiliation) {
cons_bad_cmd_usage(command);
return TRUE;
}
char* jid = args[2];
if (jid == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
} else {
char* reason = args[3];
iq_room_affiliation_set(mucwin->roomjid, jid, affiliation, reason);
return TRUE;
}
}
if (g_strcmp0(cmd, "request") == 0) {
message_request_voice(mucwin->roomjid);
return TRUE;
}
if (g_strcmp0(cmd, "register") == 0) {
iq_muc_register_nick(mucwin->roomjid);
return TRUE;
}
cons_bad_cmd_usage(command);
return TRUE;
}
gboolean
cmd_role(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
if (window->type != WIN_MUC) {
cons_show("Command '/role' does not apply to this window.");
return TRUE;
}
char* cmd = args[0];
if (cmd == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
char* role = args[1];
if (role && (g_strcmp0(role, "visitor") != 0) && (g_strcmp0(role, "participant") != 0) && (g_strcmp0(role, "moderator") != 0) && (g_strcmp0(role, "none") != 0)) {
cons_bad_cmd_usage(command);
return TRUE;
}
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
if (g_strcmp0(cmd, "list") == 0) {
if (!role) {
iq_room_role_list(mucwin->roomjid, "moderator");
iq_room_role_list(mucwin->roomjid, "participant");
iq_room_role_list(mucwin->roomjid, "visitor");
} else if (g_strcmp0(role, "none") == 0) {
win_println(window, THEME_DEFAULT, "!", "Cannot list users with no role.");
} else {
iq_room_role_list(mucwin->roomjid, role);
}
return TRUE;
}
if (g_strcmp0(cmd, "set") == 0) {
if (!role) {
cons_bad_cmd_usage(command);
return TRUE;
}
char* nick = args[2];
if (nick == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
} else {
char* reason = args[3];
iq_room_role_set(mucwin->roomjid, nick, role, reason);
return TRUE;
}
}
cons_bad_cmd_usage(command);
return TRUE;
}
gboolean
cmd_room(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
if (window->type != WIN_MUC) {
cons_show("Command '/room' does not apply to this window.");
return TRUE;
}
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
if (g_strcmp0(args[0], "accept") == 0) {
gboolean requires_config = muc_requires_config(mucwin->roomjid);
if (!requires_config) {
win_println(window, THEME_ROOMINFO, "!", "Current room does not require configuration.");
return TRUE;
} else {
iq_confirm_instant_room(mucwin->roomjid);
muc_set_requires_config(mucwin->roomjid, FALSE);
win_println(window, THEME_ROOMINFO, "!", "Room unlocked.");
return TRUE;
}
} else if (g_strcmp0(args[0], "destroy") == 0) {
iq_destroy_room(mucwin->roomjid);
return TRUE;
} else if (g_strcmp0(args[0], "config") == 0) {
ProfConfWin* confwin = wins_get_conf(mucwin->roomjid);
if (confwin) {
ui_focus_win((ProfWin*)confwin);
} else {
iq_request_room_config_form(mucwin->roomjid);
}
return TRUE;
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}
gboolean
cmd_occupants(ProfWin* window, const char* const command, gchar** args)
{
if (g_strcmp0(args[0], "size") == 0) {
if (!args[1]) {
cons_bad_cmd_usage(command);
return TRUE;
} else {
int intval = 0;
char* err_msg = NULL;
gboolean res = strtoi_range(args[1], &intval, 1, 99, &err_msg);
if (res) {
prefs_set_occupants_size(intval);
cons_show("Occupants screen size set to: %d%%", intval);
wins_resize_all();
return TRUE;
} else {
cons_show(err_msg);
free(err_msg);
return TRUE;
}
}
}
if (g_strcmp0(args[0], "indent") == 0) {
if (!args[1]) {
cons_bad_cmd_usage(command);
return TRUE;
} else {
int intval = 0;
char* err_msg = NULL;
gboolean res = strtoi_range(args[1], &intval, 0, 10, &err_msg);
if (res) {
prefs_set_occupants_indent(intval);
cons_show("Occupants indent set to: %d", intval);
occupantswin_occupants_all();
} else {
cons_show(err_msg);
free(err_msg);
}
return TRUE;
}
}
if (g_strcmp0(args[0], "wrap") == 0) {
if (!args[1]) {
cons_bad_cmd_usage(command);
return TRUE;
} else {
_cmd_set_boolean_preference(args[1], command, "Occupants panel line wrap", PREF_OCCUPANTS_WRAP);
occupantswin_occupants_all();
return TRUE;
}
}
if (g_strcmp0(args[0], "char") == 0) {
if (!args[1]) {
cons_bad_cmd_usage(command);
} else if (g_strcmp0(args[1], "none") == 0) {
prefs_clear_occupants_char();
cons_show("Occupants char removed.");
occupantswin_occupants_all();
} else {
prefs_set_occupants_char(args[1]);
cons_show("Occupants char set to %s.", args[1]);
occupantswin_occupants_all();
}
return TRUE;
}
if (g_strcmp0(args[0], "color") == 0) {
_cmd_set_boolean_preference(args[1], command, "Occupants consistent colors", PREF_OCCUPANTS_COLOR_NICK);
occupantswin_occupants_all();
return TRUE;
}
if (g_strcmp0(args[0], "default") == 0) {
if (g_strcmp0(args[1], "show") == 0) {
if (g_strcmp0(args[2], "jid") == 0) {
cons_show("Occupant jids enabled.");
prefs_set_boolean(PREF_OCCUPANTS_JID, TRUE);
} else if (g_strcmp0(args[2], "offline") == 0) {
cons_show("Occupants offline enabled.");
prefs_set_boolean(PREF_OCCUPANTS_OFFLINE, TRUE);
} else {
cons_show("Occupant list enabled.");
prefs_set_boolean(PREF_OCCUPANTS, TRUE);
}
return TRUE;
} else if (g_strcmp0(args[1], "hide") == 0) {
if (g_strcmp0(args[2], "jid") == 0) {
cons_show("Occupant jids disabled.");
prefs_set_boolean(PREF_OCCUPANTS_JID, FALSE);
} else if (g_strcmp0(args[2], "offline") == 0) {
cons_show("Occupants offline disabled.");
prefs_set_boolean(PREF_OCCUPANTS_OFFLINE, FALSE);
} else {
cons_show("Occupant list disabled.");
prefs_set_boolean(PREF_OCCUPANTS, FALSE);
}
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
}
// header settings
if (g_strcmp0(args[0], "header") == 0) {
if (g_strcmp0(args[1], "char") == 0) {
if (!args[2]) {
cons_bad_cmd_usage(command);
} else if (g_strcmp0(args[2], "none") == 0) {
prefs_clear_occupants_header_char();
cons_show("Occupants header char removed.");
occupantswin_occupants_all();
} else {
prefs_set_occupants_header_char(args[2]);
cons_show("Occupants header char set to %s.", args[2]);
occupantswin_occupants_all();
}
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
if (window->type != WIN_MUC) {
cons_show("Cannot apply setting when not in chat room.");
return TRUE;
}
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
if (g_strcmp0(args[0], "show") == 0) {
if (g_strcmp0(args[1], "jid") == 0) {
mucwin->showjid = TRUE;
mucwin_update_occupants(mucwin);
} else if (g_strcmp0(args[1], "offline") == 0) {
mucwin->showoffline = TRUE;
mucwin_update_occupants(mucwin);
} else {
mucwin_show_occupants(mucwin);
}
} else if (g_strcmp0(args[0], "hide") == 0) {
if (g_strcmp0(args[1], "jid") == 0) {
mucwin->showjid = FALSE;
mucwin_update_occupants(mucwin);
} else if (g_strcmp0(args[1], "offline") == 0) {
mucwin->showoffline = FALSE;
mucwin_update_occupants(mucwin);
} else {
mucwin_hide_occupants(mucwin);
}
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}
gboolean
cmd_rooms(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
gchar* service = NULL;
gchar* filter = NULL;
if (args[0] != NULL) {
if (g_strcmp0(args[0], "service") == 0) {
if (args[1] == NULL) {
cons_bad_cmd_usage(command);
cons_show("");
return TRUE;
}
service = g_strdup(args[1]);
} else if (g_strcmp0(args[0], "filter") == 0) {
if (args[1] == NULL) {
cons_bad_cmd_usage(command);
cons_show("");
return TRUE;
}
filter = g_strdup(args[1]);
} else if (g_strcmp0(args[0], "cache") == 0) {
if (g_strv_length(args) != 2) {
cons_bad_cmd_usage(command);
cons_show("");
return TRUE;
} else if (g_strcmp0(args[1], "on") == 0) {
prefs_set_boolean(PREF_ROOM_LIST_CACHE, TRUE);
cons_show("Rooms list cache enabled.");
return TRUE;
} else if (g_strcmp0(args[1], "off") == 0) {
prefs_set_boolean(PREF_ROOM_LIST_CACHE, FALSE);
cons_show("Rooms list cache disabled.");
return TRUE;
} else if (g_strcmp0(args[1], "clear") == 0) {
iq_rooms_cache_clear();
cons_show("Rooms list cache cleared.");
return TRUE;
} else {
cons_bad_cmd_usage(command);
cons_show("");
return TRUE;
}
} else {
cons_bad_cmd_usage(command);
cons_show("");
return TRUE;
}
}
if (g_strv_length(args) >= 3) {
if (g_strcmp0(args[2], "service") == 0) {
if (args[3] == NULL) {
cons_bad_cmd_usage(command);
cons_show("");
g_free(service);
g_free(filter);
return TRUE;
}
g_free(service);
service = g_strdup(args[3]);
} else if (g_strcmp0(args[2], "filter") == 0) {
if (args[3] == NULL) {
cons_bad_cmd_usage(command);
cons_show("");
g_free(service);
g_free(filter);
return TRUE;
}
g_free(filter);
filter = g_strdup(args[3]);
} else {
cons_bad_cmd_usage(command);
cons_show("");
g_free(service);
g_free(filter);
return TRUE;
}
}
if (service == NULL) {
ProfAccount* account = accounts_get_account(session_get_account_name());
if (account->muc_service) {
service = g_strdup(account->muc_service);
account_free(account);
} else {
cons_show("Account MUC service property not found.");
account_free(account);
g_free(service);
g_free(filter);
return TRUE;
}
}
cons_show("");
if (filter) {
cons_show("Room list request sent: %s, filter: '%s'", service, filter);
} else {
cons_show("Room list request sent: %s", service);
}
iq_room_list_request(service, filter);
g_free(service);
g_free(filter);
return TRUE;
}
gboolean
cmd_bookmark(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
cons_alert(NULL);
return TRUE;
}
int num_args = g_strv_length(args);
gchar* cmd = args[0];
if (window->type == WIN_MUC
&& num_args < 2
&& (cmd == NULL || g_strcmp0(cmd, "add") == 0)) {
// default to current nickname, password, and autojoin "on"
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
char* nick = muc_nick(mucwin->roomjid);
char* password = muc_password(mucwin->roomjid);
gboolean added = bookmark_add(mucwin->roomjid, nick, password, "on", NULL);
if (added) {
win_println(window, THEME_DEFAULT, "!", "Bookmark added for %s.", mucwin->roomjid);
} else {
win_println(window, THEME_DEFAULT, "!", "Bookmark already exists for %s.", mucwin->roomjid);
}
return TRUE;
}
if (window->type == WIN_MUC
&& num_args < 2
&& g_strcmp0(cmd, "remove") == 0) {
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
gboolean removed = bookmark_remove(mucwin->roomjid);
if (removed) {
win_println(window, THEME_DEFAULT, "!", "Bookmark removed for %s.", mucwin->roomjid);
} else {
win_println(window, THEME_DEFAULT, "!", "Bookmark does not exist for %s.", mucwin->roomjid);
}
return TRUE;
}
if (cmd == NULL) {
cons_bad_cmd_usage(command);
cons_alert(NULL);
return TRUE;
}
if (strcmp(cmd, "invites") == 0) {
if (g_strcmp0(args[1], "on") == 0) {
prefs_set_boolean(PREF_BOOKMARK_INVITE, TRUE);
cons_show("Auto bookmarking accepted invites enabled.");
} else if (g_strcmp0(args[1], "off") == 0) {
prefs_set_boolean(PREF_BOOKMARK_INVITE, FALSE);
cons_show("Auto bookmarking accepted invites disabled.");
} else {
cons_bad_cmd_usage(command);
cons_show("");
}
cons_alert(NULL);
return TRUE;
}
if (strcmp(cmd, "list") == 0) {
char* bookmark_jid = args[1];
if (bookmark_jid == NULL) {
// list all bookmarks
GList* bookmarks = bookmark_get_list();
cons_show_bookmarks(bookmarks);
g_list_free(bookmarks);
} else {
// list one bookmark
Bookmark* bookmark = bookmark_get_by_jid(bookmark_jid);
cons_show_bookmark(bookmark);
}
return TRUE;
}
char* jid = args[1];
if (jid == NULL) {
cons_bad_cmd_usage(command);
cons_show("");
cons_alert(NULL);
return TRUE;
}
if (strchr(jid, '@') == NULL) {
cons_show("Invalid room, must be of the form room@domain.tld");
cons_show("");
cons_alert(NULL);
return TRUE;
}
if (strcmp(cmd, "remove") == 0) {
gboolean removed = bookmark_remove(jid);
if (removed) {
cons_show("Bookmark removed for %s.", jid);
} else {
cons_show("No bookmark exists for %s.", jid);
}
cons_alert(NULL);
return TRUE;
}
if (strcmp(cmd, "join") == 0) {
gboolean joined = bookmark_join(jid);
if (!joined) {
cons_show("No bookmark exists for %s.", jid);
}
cons_alert(NULL);
return TRUE;
}
gchar* opt_keys[] = { "autojoin", "nick", "password", "name", NULL };
gboolean parsed;
GHashTable* options = parse_options(&args[2], opt_keys, &parsed);
if (!parsed) {
cons_bad_cmd_usage(command);
cons_show("");
cons_alert(NULL);
return TRUE;
}
char* autojoin = g_hash_table_lookup(options, "autojoin");
if (autojoin && ((strcmp(autojoin, "on") != 0) && (strcmp(autojoin, "off") != 0))) {
cons_bad_cmd_usage(command);
cons_show("");
options_destroy(options);
cons_alert(NULL);
return TRUE;
}
char* nick = g_hash_table_lookup(options, "nick");
char* password = g_hash_table_lookup(options, "password");
char* name = g_hash_table_lookup(options, "name");
if (strcmp(cmd, "add") == 0) {
gboolean added = bookmark_add(jid, nick, password, autojoin, name);
if (added) {
cons_show("Bookmark added for %s.", jid);
} else {
cons_show("Bookmark already exists, use /bookmark update to edit.");
}
options_destroy(options);
cons_alert(NULL);
return TRUE;
}
if (strcmp(cmd, "update") == 0) {
gboolean updated = bookmark_update(jid, nick, password, autojoin, name);
if (updated) {
cons_show("Bookmark updated.");
} else {
cons_show("No bookmark exists for %s.", jid);
}
options_destroy(options);
cons_alert(NULL);
return TRUE;
}
cons_bad_cmd_usage(command);
options_destroy(options);
cons_alert(NULL);
return TRUE;
}
gboolean
cmd_bookmark_ignore(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
cons_alert(NULL);
return TRUE;
}
// `/bookmark ignore` lists them
if (args[1] == NULL) {
gsize len = 0;
gchar** list = bookmark_ignore_list(&len);
cons_show_bookmarks_ignore(list, len);
g_strfreev(list);
return TRUE;
}
if (strcmp(args[1], "add") == 0 && args[2] != NULL) {
bookmark_ignore_add(args[2]);
cons_show("Autojoin for bookmark %s added to ignore list.", args[2]);
return TRUE;
}
if (strcmp(args[1], "remove") == 0 && args[2] != NULL) {
bookmark_ignore_remove(args[2]);
cons_show("Autojoin for bookmark %s removed from ignore list.", args[2]);
return TRUE;
}
cons_bad_cmd_usage(command);
return TRUE;
}
gboolean
cmd_disco(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
GString* jid = g_string_new("");
if (args[1]) {
jid = g_string_append(jid, args[1]);
} else {
Jid* jidp = jid_create(connection_get_fulljid());
jid = g_string_append(jid, jidp->domainpart);
jid_destroy(jidp);
}
if (g_strcmp0(args[0], "info") == 0) {
iq_disco_info_request(jid->str);
} else {
iq_disco_items_request(jid->str);
}
g_string_free(jid, TRUE);
return TRUE;
}
// TODO: Move this into its own tools such as HTTPUpload or AESGCMDownload.
#ifdef HAVE_OMEMO
char*
_add_omemo_stream(int* fd, FILE** fh, char** err)
{
// Create temporary file for writing ciphertext.
int tmpfd;
char* tmpname = NULL;
if ((tmpfd = g_file_open_tmp("profanity.XXXXXX", &tmpname, NULL)) == -1) {
*err = "Unable to create temporary file for encrypted transfer.";
return NULL;
}
FILE* tmpfh = fdopen(tmpfd, "w+b");
// The temporary ciphertext file should be removed after it has
// been closed.
remove(tmpname);
free(tmpname);
int crypt_res;
char* fragment;
fragment = omemo_encrypt_file(*fh, tmpfh, file_size(*fd), &crypt_res);
if (crypt_res != 0) {
fclose(tmpfh);
return NULL;
}
// Force flush as the upload will read from the same stream.
fflush(tmpfh);
rewind(tmpfh);
fclose(*fh); // Also closes descriptor.
// Switch original stream with temporary ciphertext stream.
*fd = tmpfd;
*fh = tmpfh;
return fragment;
}
#endif
gboolean
cmd_sendfile(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
gchar* filename;
char* alt_scheme = NULL;
char* alt_fragment = NULL;
// expand ~ to $HOME
filename = get_expanded_path(args[0]);
if (access(filename, R_OK) != 0) {
cons_show_error("Uploading '%s' failed: File not found!", filename);
goto out;
}
if (!is_regular_file(filename)) {
cons_show_error("Uploading '%s' failed: Not a file!", filename);
goto out;
}
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
goto out;
}
if (window->type != WIN_CHAT && window->type != WIN_PRIVATE && window->type != WIN_MUC) {
cons_show_error("Unsupported window for file transmission.");
goto out;
}
int fd;
if ((fd = open(filename, O_RDONLY)) == -1) {
cons_show_error("Unable to open file descriptor for '%s'.", filename);
goto out;
}
FILE* fh = fdopen(fd, "rb");
gboolean omemo_enabled = FALSE;
gboolean sendfile_enabled = TRUE;
switch (window->type) {
case WIN_MUC:
{
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
omemo_enabled = mucwin->is_omemo == TRUE;
break;
}
case WIN_CHAT:
{
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
omemo_enabled = chatwin->is_omemo == TRUE;
sendfile_enabled = !((chatwin->pgp_send == TRUE && !prefs_get_boolean(PREF_PGP_SENDFILE))
|| (chatwin->is_otr == TRUE && !prefs_get_boolean(PREF_OTR_SENDFILE)));
break;
}
case WIN_PRIVATE: // We don't support encryption in private MUC windows.
default:
cons_show_error("Unsupported window for file transmission.");
goto out;
}
if (!sendfile_enabled) {
cons_show_error("Uploading unencrypted files disabled. See /otr sendfile or /pgp sendfile.");
win_println(window, THEME_ERROR, "-", "Sending encrypted files via http_upload is not possible yet.");
goto out;
}
if (omemo_enabled) {
#ifdef HAVE_OMEMO
char* err = NULL;
alt_scheme = OMEMO_AESGCM_URL_SCHEME;
alt_fragment = _add_omemo_stream(&fd, &fh, &err);
if (err != NULL) {
cons_show_error(err);
win_println(window, THEME_ERROR, "-", err);
goto out;
}
#endif
}
HTTPUpload* upload = malloc(sizeof(HTTPUpload));
upload->window = window;
upload->filename = strdup(filename);
upload->filehandle = fh;
upload->filesize = file_size(fd);
upload->mime_type = file_mime_type(filename);
if (alt_scheme != NULL) {
upload->alt_scheme = strdup(alt_scheme);
} else {
upload->alt_scheme = NULL;
}
if (alt_fragment != NULL) {
upload->alt_fragment = strdup(alt_fragment);
} else {
upload->alt_fragment = NULL;
}
iq_http_upload_request(upload);
out:
#ifdef HAVE_OMEMO
if (alt_fragment != NULL)
omemo_free(alt_fragment);
#endif
if (filename != NULL)
free(filename);
return TRUE;
}
gboolean
cmd_lastactivity(ProfWin* window, const char* const command, gchar** args)
{
if ((g_strcmp0(args[0], "set") == 0)) {
if ((g_strcmp0(args[1], "on") == 0) || (g_strcmp0(args[1], "off") == 0)) {
_cmd_set_boolean_preference(args[1], command, "Last activity", PREF_LASTACTIVITY);
if (g_strcmp0(args[1], "on") == 0) {
caps_add_feature(XMPP_FEATURE_LASTACTIVITY);
}
if (g_strcmp0(args[1], "off") == 0) {
caps_remove_feature(XMPP_FEATURE_LASTACTIVITY);
}
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
}
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
if ((g_strcmp0(args[0], "get") == 0)) {
if (args[1] == NULL) {
Jid* jidp = jid_create(connection_get_fulljid());
GString* jid = g_string_new(jidp->domainpart);
iq_last_activity_request(jid->str);
g_string_free(jid, TRUE);
jid_destroy(jidp);
return TRUE;
} else {
iq_last_activity_request(args[1]);
return TRUE;
}
}
cons_bad_cmd_usage(command);
return TRUE;
}
gboolean
cmd_nick(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
if (window->type != WIN_MUC) {
cons_show("You can only change your nickname in a chat room window.");
return TRUE;
}
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
char* nick = args[0];
presence_change_room_nick(mucwin->roomjid, nick);
return TRUE;
}
gboolean
cmd_alias(ProfWin* window, const char* const command, gchar** args)
{
char* subcmd = args[0];
if (strcmp(subcmd, "add") == 0) {
char* alias = args[1];
if (alias == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
} else {
char* alias_p = alias;
GString* ac_value = g_string_new("");
if (alias[0] == '/') {
g_string_append(ac_value, alias);
alias_p = &alias[1];
} else {
g_string_append(ac_value, "/");
g_string_append(ac_value, alias);
}
char* value = args[2];
if (value == NULL) {
cons_bad_cmd_usage(command);
g_string_free(ac_value, TRUE);
return TRUE;
} else if (cmd_ac_exists(ac_value->str)) {
cons_show("Command or alias '%s' already exists.", ac_value->str);
g_string_free(ac_value, TRUE);
return TRUE;
} else {
prefs_add_alias(alias_p, value);
cmd_ac_add(ac_value->str);
cmd_ac_add_alias_value(alias_p);
cons_show("Command alias added %s -> %s", ac_value->str, value);
g_string_free(ac_value, TRUE);
return TRUE;
}
}
} else if (strcmp(subcmd, "remove") == 0) {
char* alias = args[1];
if (alias == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
} else {
if (alias[0] == '/') {
alias = &alias[1];
}
gboolean removed = prefs_remove_alias(alias);
if (!removed) {
cons_show("No such command alias /%s", alias);
} else {
GString* ac_value = g_string_new("/");
g_string_append(ac_value, alias);
cmd_ac_remove(ac_value->str);
cmd_ac_remove_alias_value(alias);
g_string_free(ac_value, TRUE);
cons_show("Command alias removed -> /%s", alias);
}
return TRUE;
}
} else if (strcmp(subcmd, "list") == 0) {
GList* aliases = prefs_get_aliases();
cons_show_aliases(aliases);
prefs_free_aliases(aliases);
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
}
gboolean
cmd_clear(ProfWin* window, const char* const command, gchar** args)
{
if (args[0] == NULL) {
win_clear(window);
return TRUE;
} else {
if ((g_strcmp0(args[0], "persist_history") == 0)) {
if (args[1] != NULL) {
if ((g_strcmp0(args[1], "on") == 0) || (g_strcmp0(args[1], "off") == 0)) {
_cmd_set_boolean_preference(args[1], command, "Persistent history", PREF_CLEAR_PERSIST_HISTORY);
return TRUE;
}
} else {
if (prefs_get_boolean(PREF_CLEAR_PERSIST_HISTORY)) {
win_println(window, THEME_DEFAULT, "!", " Persistently clear screen : ON");
} else {
win_println(window, THEME_DEFAULT, "!", " Persistently clear screen : OFF");
}
return TRUE;
}
}
}
cons_bad_cmd_usage(command);
return TRUE;
}
gboolean
cmd_privileges(ProfWin* window, const char* const command, gchar** args)
{
_cmd_set_boolean_preference(args[0], command, "MUC privileges", PREF_MUC_PRIVILEGES);
ui_redraw_all_room_rosters();
return TRUE;
}
gboolean
cmd_charset(ProfWin* window, const char* const command, gchar** args)
{
char* codeset = nl_langinfo(CODESET);
char* lang = getenv("LANG");
cons_show("Charset information:");
if (lang) {
cons_show(" LANG: %s", lang);
}
if (codeset) {
cons_show(" CODESET: %s", codeset);
}
cons_show(" MB_CUR_MAX: %d", MB_CUR_MAX);
cons_show(" MB_LEN_MAX: %d", MB_LEN_MAX);
return TRUE;
}
gboolean
cmd_beep(ProfWin* window, const char* const command, gchar** args)
{
_cmd_set_boolean_preference(args[0], command, "Sound", PREF_BEEP);
return TRUE;
}
gboolean
cmd_console(ProfWin* window, const char* const command, gchar** args)
{
gboolean isMuc = (g_strcmp0(args[0], "muc") == 0);
if ((g_strcmp0(args[0], "chat") != 0) && !isMuc && (g_strcmp0(args[0], "private") != 0)) {
cons_bad_cmd_usage(command);
return TRUE;
}
gchar* setting = args[1];
if ((g_strcmp0(setting, "all") != 0) && (g_strcmp0(setting, "first") != 0) && (g_strcmp0(setting, "none") != 0)) {
if (!(isMuc && (g_strcmp0(setting, "mention") == 0))) {
cons_bad_cmd_usage(command);
return TRUE;
}
}
if (g_strcmp0(args[0], "chat") == 0) {
prefs_set_string(PREF_CONSOLE_CHAT, setting);
cons_show("Console chat messages set: %s", setting);
return TRUE;
}
if (g_strcmp0(args[0], "muc") == 0) {
prefs_set_string(PREF_CONSOLE_MUC, setting);
cons_show("Console MUC messages set: %s", setting);
return TRUE;
}
if (g_strcmp0(args[0], "private") == 0) {
prefs_set_string(PREF_CONSOLE_PRIVATE, setting);
cons_show("Console private room messages set: %s", setting);
return TRUE;
}
return TRUE;
}
gboolean
cmd_presence(ProfWin* window, const char* const command, gchar** args)
{
if (strcmp(args[0], "console") != 0 && strcmp(args[0], "chat") != 0 && strcmp(args[0], "room") != 0 && strcmp(args[0], "titlebar") != 0) {
cons_bad_cmd_usage(command);
return TRUE;
}
if (strcmp(args[0], "titlebar") == 0) {
_cmd_set_boolean_preference(args[1], command, "Contact presence", PREF_PRESENCE);
return TRUE;
}
if (strcmp(args[1], "all") != 0 && strcmp(args[1], "online") != 0 && strcmp(args[1], "none") != 0) {
cons_bad_cmd_usage(command);
return TRUE;
}
if (strcmp(args[0], "console") == 0) {
prefs_set_string(PREF_STATUSES_CONSOLE, args[1]);
if (strcmp(args[1], "all") == 0) {
cons_show("All presence updates will appear in the console.");
} else if (strcmp(args[1], "online") == 0) {
cons_show("Only online/offline presence updates will appear in the console.");
} else {
cons_show("Presence updates will not appear in the console.");
}
}
if (strcmp(args[0], "chat") == 0) {
prefs_set_string(PREF_STATUSES_CHAT, args[1]);
if (strcmp(args[1], "all") == 0) {
cons_show("All presence updates will appear in chat windows.");
} else if (strcmp(args[1], "online") == 0) {
cons_show("Only online/offline presence updates will appear in chat windows.");
} else {
cons_show("Presence updates will not appear in chat windows.");
}
}
if (strcmp(args[0], "room") == 0) {
prefs_set_string(PREF_STATUSES_MUC, args[1]);
if (strcmp(args[1], "all") == 0) {
cons_show("All presence updates will appear in chat room windows.");
} else if (strcmp(args[1], "online") == 0) {
cons_show("Only join/leave presence updates will appear in chat room windows.");
} else {
cons_show("Presence updates will not appear in chat room windows.");
}
}
return TRUE;
}
gboolean
cmd_wrap(ProfWin* window, const char* const command, gchar** args)
{
_cmd_set_boolean_preference(args[0], command, "Word wrap", PREF_WRAP);
wins_resize_all();
return TRUE;
}
gboolean
cmd_time(ProfWin* window, const char* const command, gchar** args)
{
if (g_strcmp0(args[0], "lastactivity") == 0) {
if (args[1] == NULL) {
char* format = prefs_get_string(PREF_TIME_LASTACTIVITY);
cons_show("Last activity time format: '%s'.", format);
g_free(format);
return TRUE;
} else if (g_strcmp0(args[1], "set") == 0 && args[2] != NULL) {
prefs_set_string(PREF_TIME_LASTACTIVITY, args[2]);
cons_show("Last activity time format set to '%s'.", args[2]);
ui_redraw();
return TRUE;
} else if (g_strcmp0(args[1], "off") == 0) {
cons_show("Last activity time cannot be disabled.");
ui_redraw();
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
} else if (g_strcmp0(args[0], "statusbar") == 0) {
if (args[1] == NULL) {
char* format = prefs_get_string(PREF_TIME_STATUSBAR);
cons_show("Status bar time format: '%s'.", format);
g_free(format);
return TRUE;
} else if (g_strcmp0(args[1], "set") == 0 && args[2] != NULL) {
prefs_set_string(PREF_TIME_STATUSBAR, args[2]);
cons_show("Status bar time format set to '%s'.", args[2]);
ui_redraw();
return TRUE;
} else if (g_strcmp0(args[1], "off") == 0) {
prefs_set_string(PREF_TIME_STATUSBAR, "off");
cons_show("Status bar time display disabled.");
ui_redraw();
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
} else if (g_strcmp0(args[0], "console") == 0) {
if (args[1] == NULL) {
char* format = prefs_get_string(PREF_TIME_CONSOLE);
cons_show("Console time format: '%s'.", format);
g_free(format);
return TRUE;
} else if (g_strcmp0(args[1], "set") == 0 && args[2] != NULL) {
prefs_set_string(PREF_TIME_CONSOLE, args[2]);
cons_show("Console time format set to '%s'.", args[2]);
wins_resize_all();
return TRUE;
} else if (g_strcmp0(args[1], "off") == 0) {
prefs_set_string(PREF_TIME_CONSOLE, "off");
cons_show("Console time display disabled.");
wins_resize_all();
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
} else if (g_strcmp0(args[0], "chat") == 0) {
if (args[1] == NULL) {
char* format = prefs_get_string(PREF_TIME_CHAT);
cons_show("Chat time format: '%s'.", format);
g_free(format);
return TRUE;
} else if (g_strcmp0(args[1], "set") == 0 && args[2] != NULL) {
prefs_set_string(PREF_TIME_CHAT, args[2]);
cons_show("Chat time format set to '%s'.", args[2]);
wins_resize_all();
return TRUE;
} else if (g_strcmp0(args[1], "off") == 0) {
prefs_set_string(PREF_TIME_CHAT, "off");
cons_show("Chat time display disabled.");
wins_resize_all();
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
} else if (g_strcmp0(args[0], "muc") == 0) {
if (args[1] == NULL) {
char* format = prefs_get_string(PREF_TIME_MUC);
cons_show("MUC time format: '%s'.", format);
g_free(format);
return TRUE;
} else if (g_strcmp0(args[1], "set") == 0 && args[2] != NULL) {
prefs_set_string(PREF_TIME_MUC, args[2]);
cons_show("MUC time format set to '%s'.", args[2]);
wins_resize_all();
return TRUE;
} else if (g_strcmp0(args[1], "off") == 0) {
prefs_set_string(PREF_TIME_MUC, "off");
cons_show("MUC time display disabled.");
wins_resize_all();
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
} else if (g_strcmp0(args[0], "config") == 0) {
if (args[1] == NULL) {
char* format = prefs_get_string(PREF_TIME_CONFIG);
cons_show("config time format: '%s'.", format);
g_free(format);
return TRUE;
} else if (g_strcmp0(args[1], "set") == 0 && args[2] != NULL) {
prefs_set_string(PREF_TIME_CONFIG, args[2]);
cons_show("config time format set to '%s'.", args[2]);
wins_resize_all();
return TRUE;
} else if (g_strcmp0(args[1], "off") == 0) {
prefs_set_string(PREF_TIME_CONFIG, "off");
cons_show("config time display disabled.");
wins_resize_all();
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
} else if (g_strcmp0(args[0], "private") == 0) {
if (args[1] == NULL) {
char* format = prefs_get_string(PREF_TIME_PRIVATE);
cons_show("Private chat time format: '%s'.", format);
g_free(format);
return TRUE;
} else if (g_strcmp0(args[1], "set") == 0 && args[2] != NULL) {
prefs_set_string(PREF_TIME_PRIVATE, args[2]);
cons_show("Private chat time format set to '%s'.", args[2]);
wins_resize_all();
return TRUE;
} else if (g_strcmp0(args[1], "off") == 0) {
prefs_set_string(PREF_TIME_PRIVATE, "off");
cons_show("Private chat time display disabled.");
wins_resize_all();
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
} else if (g_strcmp0(args[0], "xml") == 0) {
if (args[1] == NULL) {
char* format = prefs_get_string(PREF_TIME_XMLCONSOLE);
cons_show("XML Console time format: '%s'.", format);
g_free(format);
return TRUE;
} else if (g_strcmp0(args[1], "set") == 0 && args[2] != NULL) {
prefs_set_string(PREF_TIME_XMLCONSOLE, args[2]);
cons_show("XML Console time format set to '%s'.", args[2]);
wins_resize_all();
return TRUE;
} else if (g_strcmp0(args[1], "off") == 0) {
prefs_set_string(PREF_TIME_XMLCONSOLE, "off");
cons_show("XML Console time display disabled.");
wins_resize_all();
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
} else if (g_strcmp0(args[0], "all") == 0) {
if (args[1] == NULL) {
cons_time_setting();
return TRUE;
} else if (g_strcmp0(args[1], "set") == 0 && args[2] != NULL) {
prefs_set_string(PREF_TIME_CONSOLE, args[2]);
cons_show("Console time format set to '%s'.", args[2]);
prefs_set_string(PREF_TIME_CHAT, args[2]);
cons_show("Chat time format set to '%s'.", args[2]);
prefs_set_string(PREF_TIME_MUC, args[2]);
cons_show("MUC time format set to '%s'.", args[2]);
prefs_set_string(PREF_TIME_CONFIG, args[2]);
cons_show("config time format set to '%s'.", args[2]);
prefs_set_string(PREF_TIME_PRIVATE, args[2]);
cons_show("Private chat time format set to '%s'.", args[2]);
prefs_set_string(PREF_TIME_XMLCONSOLE, args[2]);
cons_show("XML Console time format set to '%s'.", args[2]);
wins_resize_all();
return TRUE;
} else if (g_strcmp0(args[1], "off") == 0) {
prefs_set_string(PREF_TIME_CONSOLE, "off");
cons_show("Console time display disabled.");
prefs_set_string(PREF_TIME_CHAT, "off");
cons_show("Chat time display disabled.");
prefs_set_string(PREF_TIME_MUC, "off");
cons_show("MUC time display disabled.");
prefs_set_string(PREF_TIME_CONFIG, "off");
cons_show("config time display disabled.");
prefs_set_string(PREF_TIME_PRIVATE, "off");
cons_show("config time display disabled.");
prefs_set_string(PREF_TIME_XMLCONSOLE, "off");
cons_show("XML Console time display disabled.");
ui_redraw();
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
}
gboolean
cmd_states(ProfWin* window, const char* const command, gchar** args)
{
if (args[0] == NULL) {
return FALSE;
}
_cmd_set_boolean_preference(args[0], command, "Sending chat states", PREF_STATES);
// if disabled, disable outtype and gone
if (strcmp(args[0], "off") == 0) {
prefs_set_boolean(PREF_OUTTYPE, FALSE);
prefs_set_gone(0);
}
return TRUE;
}
gboolean
cmd_wintitle(ProfWin* window, const char* const command, gchar** args)
{
if (g_strcmp0(args[0], "show") != 0 && g_strcmp0(args[0], "goodbye") != 0) {
cons_bad_cmd_usage(command);
return TRUE;
}
if (g_strcmp0(args[0], "show") == 0 && g_strcmp0(args[1], "off") == 0) {
ui_clear_win_title();
}
if (g_strcmp0(args[0], "show") == 0) {
_cmd_set_boolean_preference(args[1], command, "Window title show", PREF_WINTITLE_SHOW);
} else {
_cmd_set_boolean_preference(args[1], command, "Window title goodbye", PREF_WINTITLE_GOODBYE);
}
return TRUE;
}
gboolean
cmd_outtype(ProfWin* window, const char* const command, gchar** args)
{
if (args[0] == NULL) {
return FALSE;
}
_cmd_set_boolean_preference(args[0], command, "Sending typing notifications", PREF_OUTTYPE);
// if enabled, enable states
if (strcmp(args[0], "on") == 0) {
prefs_set_boolean(PREF_STATES, TRUE);
}
return TRUE;
}
gboolean
cmd_gone(ProfWin* window, const char* const command, gchar** args)
{
char* value = args[0];
gint period = atoi(value);
prefs_set_gone(period);
if (period == 0) {
cons_show("Automatic leaving conversations after period disabled.");
} else if (period == 1) {
cons_show("Leaving conversations after 1 minute of inactivity.");
} else {
cons_show("Leaving conversations after %d minutes of inactivity.", period);
}
// if enabled, enable states
if (period > 0) {
prefs_set_boolean(PREF_STATES, TRUE);
}
return TRUE;
}
gboolean
cmd_notify(ProfWin* window, const char* const command, gchar** args)
{
if (!args[0]) {
ProfWin* current = wins_get_current();
if (current->type == WIN_MUC) {
win_println(current, THEME_DEFAULT, "-", "");
ProfMucWin* mucwin = (ProfMucWin*)current;
win_println(window, THEME_DEFAULT, "!", "Notification settings for %s:", mucwin->roomjid);
if (prefs_has_room_notify(mucwin->roomjid)) {
if (prefs_get_room_notify(mucwin->roomjid)) {
win_println(window, THEME_DEFAULT, "!", " Message : ON");
} else {
win_println(window, THEME_DEFAULT, "!", " Message : OFF");
}
} else {
if (prefs_get_boolean(PREF_NOTIFY_ROOM)) {
win_println(window, THEME_DEFAULT, "!", " Message : ON (global setting)");
} else {
win_println(window, THEME_DEFAULT, "!", " Message : OFF (global setting)");
}
}
if (prefs_has_room_notify_mention(mucwin->roomjid)) {
if (prefs_get_room_notify_mention(mucwin->roomjid)) {
win_println(window, THEME_DEFAULT, "!", " Mention : ON");
} else {
win_println(window, THEME_DEFAULT, "!", " Mention : OFF");
}
} else {
if (prefs_get_boolean(PREF_NOTIFY_ROOM_MENTION)) {
win_println(window, THEME_DEFAULT, "!", " Mention : ON (global setting)");
} else {
win_println(window, THEME_DEFAULT, "!", " Mention : OFF (global setting)");
}
}
if (prefs_has_room_notify_trigger(mucwin->roomjid)) {
if (prefs_get_room_notify_trigger(mucwin->roomjid)) {
win_println(window, THEME_DEFAULT, "!", " Triggers : ON");
} else {
win_println(window, THEME_DEFAULT, "!", " Triggers : OFF");
}
} else {
if (prefs_get_boolean(PREF_NOTIFY_ROOM_TRIGGER)) {
win_println(window, THEME_DEFAULT, "!", " Triggers : ON (global setting)");
} else {
win_println(window, THEME_DEFAULT, "!", " Triggers : OFF (global setting)");
}
}
win_println(current, THEME_DEFAULT, "-", "");
} else {
cons_show("");
cons_notify_setting();
cons_bad_cmd_usage(command);
}
return TRUE;
}
// chat settings
if (g_strcmp0(args[0], "chat") == 0) {
if (g_strcmp0(args[1], "on") == 0) {
cons_show("Chat notifications enabled.");
prefs_set_boolean(PREF_NOTIFY_CHAT, TRUE);
} else if (g_strcmp0(args[1], "off") == 0) {
cons_show("Chat notifications disabled.");
prefs_set_boolean(PREF_NOTIFY_CHAT, FALSE);
} else if (g_strcmp0(args[1], "current") == 0) {
if (g_strcmp0(args[2], "on") == 0) {
cons_show("Current window chat notifications enabled.");
prefs_set_boolean(PREF_NOTIFY_CHAT_CURRENT, TRUE);
} else if (g_strcmp0(args[2], "off") == 0) {
cons_show("Current window chat notifications disabled.");
prefs_set_boolean(PREF_NOTIFY_CHAT_CURRENT, FALSE);
} else {
cons_show("Usage: /notify chat current on|off");
}
} else if (g_strcmp0(args[1], "text") == 0) {
if (g_strcmp0(args[2], "on") == 0) {
cons_show("Showing text in chat notifications enabled.");
prefs_set_boolean(PREF_NOTIFY_CHAT_TEXT, TRUE);
} else if (g_strcmp0(args[2], "off") == 0) {
cons_show("Showing text in chat notifications disabled.");
prefs_set_boolean(PREF_NOTIFY_CHAT_TEXT, FALSE);
} else {
cons_show("Usage: /notify chat text on|off");
}
}
// chat room settings
} else if (g_strcmp0(args[0], "room") == 0) {
if (g_strcmp0(args[1], "on") == 0) {
cons_show("Room notifications enabled.");
prefs_set_boolean(PREF_NOTIFY_ROOM, TRUE);
} else if (g_strcmp0(args[1], "off") == 0) {
cons_show("Room notifications disabled.");
prefs_set_boolean(PREF_NOTIFY_ROOM, FALSE);
} else if (g_strcmp0(args[1], "mention") == 0) {
if (g_strcmp0(args[2], "on") == 0) {
cons_show("Room notifications with mention enabled.");
prefs_set_boolean(PREF_NOTIFY_ROOM_MENTION, TRUE);
} else if (g_strcmp0(args[2], "off") == 0) {
cons_show("Room notifications with mention disabled.");
prefs_set_boolean(PREF_NOTIFY_ROOM_MENTION, FALSE);
} else if (g_strcmp0(args[2], "case_sensitive") == 0) {
cons_show("Room mention matching set to case sensitive.");
prefs_set_boolean(PREF_NOTIFY_MENTION_CASE_SENSITIVE, TRUE);
} else if (g_strcmp0(args[2], "case_insensitive") == 0) {
cons_show("Room mention matching set to case insensitive.");
prefs_set_boolean(PREF_NOTIFY_MENTION_CASE_SENSITIVE, FALSE);
} else if (g_strcmp0(args[2], "word_whole") == 0) {
cons_show("Room mention matching set to whole word.");
prefs_set_boolean(PREF_NOTIFY_MENTION_WHOLE_WORD, TRUE);
} else if (g_strcmp0(args[2], "word_part") == 0) {
cons_show("Room mention matching set to partial word.");
prefs_set_boolean(PREF_NOTIFY_MENTION_WHOLE_WORD, FALSE);
} else {
cons_show("Usage: /notify room mention on|off");
}
} else if (g_strcmp0(args[1], "current") == 0) {
if (g_strcmp0(args[2], "on") == 0) {
cons_show("Current window chat room message notifications enabled.");
prefs_set_boolean(PREF_NOTIFY_ROOM_CURRENT, TRUE);
} else if (g_strcmp0(args[2], "off") == 0) {
cons_show("Current window chat room message notifications disabled.");
prefs_set_boolean(PREF_NOTIFY_ROOM_CURRENT, FALSE);
} else {
cons_show("Usage: /notify room current on|off");
}
} else if (g_strcmp0(args[1], "text") == 0) {
if (g_strcmp0(args[2], "on") == 0) {
cons_show("Showing text in chat room message notifications enabled.");
prefs_set_boolean(PREF_NOTIFY_ROOM_TEXT, TRUE);
} else if (g_strcmp0(args[2], "off") == 0) {
cons_show("Showing text in chat room message notifications disabled.");
prefs_set_boolean(PREF_NOTIFY_ROOM_TEXT, FALSE);
} else {
cons_show("Usage: /notify room text on|off");
}
} else if (g_strcmp0(args[1], "trigger") == 0) {
if (g_strcmp0(args[2], "add") == 0) {
if (!args[3]) {
cons_bad_cmd_usage(command);
} else {
gboolean res = prefs_add_room_notify_trigger(args[3]);
if (res) {
cons_show("Adding room notification trigger: %s", args[3]);
} else {
cons_show("Room notification trigger already exists: %s", args[3]);
}
}
} else if (g_strcmp0(args[2], "remove") == 0) {
if (!args[3]) {
cons_bad_cmd_usage(command);
} else {
gboolean res = prefs_remove_room_notify_trigger(args[3]);
if (res) {
cons_show("Removing room notification trigger: %s", args[3]);
} else {
cons_show("Room notification trigger does not exist: %s", args[3]);
}
}
} else if (g_strcmp0(args[2], "list") == 0) {
GList* triggers = prefs_get_room_notify_triggers();
GList* curr = triggers;
if (curr) {
cons_show("Room notification triggers:");
} else {
cons_show("No room notification triggers");
}
while (curr) {
cons_show(" %s", curr->data);
curr = g_list_next(curr);
}
g_list_free_full(triggers, free);
} else if (g_strcmp0(args[2], "on") == 0) {
cons_show("Enabling room notification triggers");
prefs_set_boolean(PREF_NOTIFY_ROOM_TRIGGER, TRUE);
} else if (g_strcmp0(args[2], "off") == 0) {
cons_show("Disabling room notification triggers");
prefs_set_boolean(PREF_NOTIFY_ROOM_TRIGGER, FALSE);
} else {
cons_bad_cmd_usage(command);
}
} else {
cons_show("Usage: /notify room on|off|mention");
}
// typing settings
} else if (g_strcmp0(args[0], "typing") == 0) {
if (g_strcmp0(args[1], "on") == 0) {
cons_show("Typing notifications enabled.");
prefs_set_boolean(PREF_NOTIFY_TYPING, TRUE);
} else if (g_strcmp0(args[1], "off") == 0) {
cons_show("Typing notifications disabled.");
prefs_set_boolean(PREF_NOTIFY_TYPING, FALSE);
} else if (g_strcmp0(args[1], "current") == 0) {
if (g_strcmp0(args[2], "on") == 0) {
cons_show("Current window typing notifications enabled.");
prefs_set_boolean(PREF_NOTIFY_TYPING_CURRENT, TRUE);
} else if (g_strcmp0(args[2], "off") == 0) {
cons_show("Current window typing notifications disabled.");
prefs_set_boolean(PREF_NOTIFY_TYPING_CURRENT, FALSE);
} else {
cons_show("Usage: /notify typing current on|off");
}
} else {
cons_show("Usage: /notify typing on|off");
}
// invite settings
} else if (g_strcmp0(args[0], "invite") == 0) {
if (g_strcmp0(args[1], "on") == 0) {
cons_show("Chat room invite notifications enabled.");
prefs_set_boolean(PREF_NOTIFY_INVITE, TRUE);
} else if (g_strcmp0(args[1], "off") == 0) {
cons_show("Chat room invite notifications disabled.");
prefs_set_boolean(PREF_NOTIFY_INVITE, FALSE);
} else {
cons_show("Usage: /notify invite on|off");
}
// subscription settings
} else if (g_strcmp0(args[0], "sub") == 0) {
if (g_strcmp0(args[1], "on") == 0) {
cons_show("Subscription notifications enabled.");
prefs_set_boolean(PREF_NOTIFY_SUB, TRUE);
} else if (g_strcmp0(args[1], "off") == 0) {
cons_show("Subscription notifications disabled.");
prefs_set_boolean(PREF_NOTIFY_SUB, FALSE);
} else {
cons_show("Usage: /notify sub on|off");
}
// remind settings
} else if (g_strcmp0(args[0], "remind") == 0) {
if (!args[1]) {
cons_bad_cmd_usage(command);
} else {
gint period = atoi(args[1]);
prefs_set_notify_remind(period);
if (period == 0) {
cons_show("Message reminders disabled.");
} else if (period == 1) {
cons_show("Message reminder period set to 1 second.");
} else {
cons_show("Message reminder period set to %d seconds.", period);
}
}
// current chat room settings
} else if (g_strcmp0(args[0], "on") == 0) {
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
} else {
ProfWin* window = wins_get_current();
if (window->type != WIN_MUC) {
cons_show("You must be in a chat room.");
} else {
ProfMucWin* mucwin = (ProfMucWin*)window;
prefs_set_room_notify(mucwin->roomjid, TRUE);
win_println(window, THEME_DEFAULT, "!", "Notifications enabled for %s", mucwin->roomjid);
}
}
} else if (g_strcmp0(args[0], "off") == 0) {
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
} else {
ProfWin* window = wins_get_current();
if (window->type != WIN_MUC) {
cons_show("You must be in a chat room.");
} else {
ProfMucWin* mucwin = (ProfMucWin*)window;
prefs_set_room_notify(mucwin->roomjid, FALSE);
win_println(window, THEME_DEFAULT, "!", "Notifications disabled for %s", mucwin->roomjid);
}
}
} else if (g_strcmp0(args[0], "mention") == 0) {
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
} else {
if (g_strcmp0(args[1], "on") == 0) {
ProfWin* window = wins_get_current();
if (window->type != WIN_MUC) {
cons_show("You must be in a chat room.");
} else {
ProfMucWin* mucwin = (ProfMucWin*)window;
prefs_set_room_notify_mention(mucwin->roomjid, TRUE);
win_println(window, THEME_DEFAULT, "!", "Mention notifications enabled for %s", mucwin->roomjid);
}
} else if (g_strcmp0(args[1], "off") == 0) {
ProfWin* window = wins_get_current();
if (window->type != WIN_MUC) {
cons_show("You must be in a chat rooms.");
} else {
ProfMucWin* mucwin = (ProfMucWin*)window;
prefs_set_room_notify_mention(mucwin->roomjid, FALSE);
win_println(window, THEME_DEFAULT, "!", "Mention notifications disabled for %s", mucwin->roomjid);
}
} else {
cons_bad_cmd_usage(command);
}
}
} else if (g_strcmp0(args[0], "trigger") == 0) {
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
} else {
if (g_strcmp0(args[1], "on") == 0) {
ProfWin* window = wins_get_current();
if (window->type != WIN_MUC) {
cons_show("You must be in a chat room.");
} else {
ProfMucWin* mucwin = (ProfMucWin*)window;
prefs_set_room_notify_trigger(mucwin->roomjid, TRUE);
win_println(window, THEME_DEFAULT, "!", "Custom trigger notifications enabled for %s", mucwin->roomjid);
}
} else if (g_strcmp0(args[1], "off") == 0) {
ProfWin* window = wins_get_current();
if (window->type != WIN_MUC) {
cons_show("You must be in a chat rooms.");
} else {
ProfMucWin* mucwin = (ProfMucWin*)window;
prefs_set_room_notify_trigger(mucwin->roomjid, FALSE);
win_println(window, THEME_DEFAULT, "!", "Custom trigger notifications disabled for %s", mucwin->roomjid);
}
} else {
cons_bad_cmd_usage(command);
}
}
} else if (g_strcmp0(args[0], "reset") == 0) {
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
} else {
ProfWin* window = wins_get_current();
if (window->type != WIN_MUC) {
cons_show("You must be in a chat room.");
} else {
ProfMucWin* mucwin = (ProfMucWin*)window;
gboolean res = prefs_reset_room_notify(mucwin->roomjid);
if (res) {
win_println(window, THEME_DEFAULT, "!", "Notification settings set to global defaults for %s", mucwin->roomjid);
} else {
win_println(window, THEME_DEFAULT, "!", "No custom notification settings for %s", mucwin->roomjid);
}
}
}
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}
gboolean
cmd_inpblock(ProfWin* window, const char* const command, gchar** args)
{
char* subcmd = args[0];
char* value = args[1];
if (g_strcmp0(subcmd, "timeout") == 0) {
if (value == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
int intval = 0;
char* err_msg = NULL;
gboolean res = strtoi_range(value, &intval, 1, 1000, &err_msg);
if (res) {
cons_show("Input blocking set to %d milliseconds.", intval);
prefs_set_inpblock(intval);
inp_nonblocking(FALSE);
} else {
cons_show(err_msg);
free(err_msg);
}
return TRUE;
}
if (g_strcmp0(subcmd, "dynamic") == 0) {
if (value == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
if (g_strcmp0(value, "on") != 0 && g_strcmp0(value, "off") != 0) {
cons_show("Dynamic must be one of 'on' or 'off'");
return TRUE;
}
_cmd_set_boolean_preference(value, command, "Dynamic input blocking", PREF_INPBLOCK_DYNAMIC);
return TRUE;
}
cons_bad_cmd_usage(command);
return TRUE;
}
gboolean
cmd_titlebar(ProfWin* window, const char* const command, gchar** args)
{
if (g_strcmp0(args[0], "up") == 0) {
gboolean result = prefs_titlebar_pos_up();
if (result) {
ui_resize();
cons_show("Title bar moved up.");
} else {
cons_show("Could not move title bar up.");
}
return TRUE;
}
if (g_strcmp0(args[0], "down") == 0) {
gboolean result = prefs_titlebar_pos_down();
if (result) {
ui_resize();
cons_show("Title bar moved down.");
} else {
cons_show("Could not move title bar down.");
}
return TRUE;
}
cons_bad_cmd_usage(command);
return TRUE;
}
gboolean
cmd_titlebar_show_hide(ProfWin* window, const char* const command, gchar** args)
{
if (args[1] != NULL) {
if (g_strcmp0(args[0], "show") == 0) {
if (g_strcmp0(args[1], "tls") == 0) {
cons_show("TLS titlebar indicator enabled.");
prefs_set_boolean(PREF_TLS_SHOW, TRUE);
} else if (g_strcmp0(args[1], "encwarn") == 0) {
cons_show("Encryption warning titlebar indicator enabled.");
prefs_set_boolean(PREF_ENC_WARN, TRUE);
} else if (g_strcmp0(args[1], "resource") == 0) {
cons_show("Showing resource in titlebar enabled.");
prefs_set_boolean(PREF_RESOURCE_TITLE, TRUE);
} else if (g_strcmp0(args[1], "presence") == 0) {
cons_show("Showing contact presence in titlebar enabled.");
prefs_set_boolean(PREF_PRESENCE, TRUE);
} else if (g_strcmp0(args[1], "jid") == 0) {
cons_show("Showing MUC JID in titlebar as title enabled.");
prefs_set_boolean(PREF_TITLEBAR_MUC_TITLE_JID, TRUE);
} else if (g_strcmp0(args[1], "name") == 0) {
cons_show("Showing MUC name in titlebar as title enabled.");
prefs_set_boolean(PREF_TITLEBAR_MUC_TITLE_NAME, TRUE);
} else {
cons_bad_cmd_usage(command);
}
} else if (g_strcmp0(args[0], "hide") == 0) {
if (g_strcmp0(args[1], "tls") == 0) {
cons_show("TLS titlebar indicator disabled.");
prefs_set_boolean(PREF_TLS_SHOW, FALSE);
} else if (g_strcmp0(args[1], "encwarn") == 0) {
cons_show("Encryption warning titlebar indicator disabled.");
prefs_set_boolean(PREF_ENC_WARN, FALSE);
} else if (g_strcmp0(args[1], "resource") == 0) {
cons_show("Showing resource in titlebar disabled.");
prefs_set_boolean(PREF_RESOURCE_TITLE, FALSE);
} else if (g_strcmp0(args[1], "presence") == 0) {
cons_show("Showing contact presence in titlebar disabled.");
prefs_set_boolean(PREF_PRESENCE, FALSE);
} else if (g_strcmp0(args[1], "jid") == 0) {
cons_show("Showing MUC JID in titlebar as title disabled.");
prefs_set_boolean(PREF_TITLEBAR_MUC_TITLE_JID, FALSE);
} else if (g_strcmp0(args[1], "name") == 0) {
cons_show("Showing MUC name in titlebar as title disabled.");
prefs_set_boolean(PREF_TITLEBAR_MUC_TITLE_NAME, FALSE);
} else {
cons_bad_cmd_usage(command);
}
} else {
cons_bad_cmd_usage(command);
}
}
return TRUE;
}
gboolean
cmd_mainwin(ProfWin* window, const char* const command, gchar** args)
{
if (g_strcmp0(args[0], "up") == 0) {
gboolean result = prefs_mainwin_pos_up();
if (result) {
ui_resize();
cons_show("Main window moved up.");
} else {
cons_show("Could not move main window up.");
}
return TRUE;
}
if (g_strcmp0(args[0], "down") == 0) {
gboolean result = prefs_mainwin_pos_down();
if (result) {
ui_resize();
cons_show("Main window moved down.");
} else {
cons_show("Could not move main window down.");
}
return TRUE;
}
cons_bad_cmd_usage(command);
return TRUE;
}
gboolean
cmd_statusbar(ProfWin* window, const char* const command, gchar** args)
{
if (g_strcmp0(args[0], "show") == 0) {
if (g_strcmp0(args[1], "name") == 0) {
prefs_set_boolean(PREF_STATUSBAR_SHOW_NAME, TRUE);
cons_show("Enabled showing tab names.");
ui_resize();
return TRUE;
}
if (g_strcmp0(args[1], "number") == 0) {
prefs_set_boolean(PREF_STATUSBAR_SHOW_NUMBER, TRUE);
cons_show("Enabled showing tab numbers.");
ui_resize();
return TRUE;
}
if (g_strcmp0(args[1], "read") == 0) {
prefs_set_boolean(PREF_STATUSBAR_SHOW_READ, TRUE);
cons_show("Enabled showing inactive tabs.");
ui_resize();
return TRUE;
}
cons_bad_cmd_usage(command);
return TRUE;
}
if (g_strcmp0(args[0], "hide") == 0) {
if (g_strcmp0(args[1], "name") == 0) {
if (prefs_get_boolean(PREF_STATUSBAR_SHOW_NUMBER) == FALSE) {
cons_show("Cannot disable both names and numbers in statusbar.");
cons_show("Use '/statusbar maxtabs 0' to hide tabs.");
return TRUE;
}
prefs_set_boolean(PREF_STATUSBAR_SHOW_NAME, FALSE);
cons_show("Disabled showing tab names.");
ui_resize();
return TRUE;
}
if (g_strcmp0(args[1], "number") == 0) {
if (prefs_get_boolean(PREF_STATUSBAR_SHOW_NAME) == FALSE) {
cons_show("Cannot disable both names and numbers in statusbar.");
cons_show("Use '/statusbar maxtabs 0' to hide tabs.");
return TRUE;
}
prefs_set_boolean(PREF_STATUSBAR_SHOW_NUMBER, FALSE);
cons_show("Disabled showing tab numbers.");
ui_resize();
return TRUE;
}
if (g_strcmp0(args[1], "read") == 0) {
prefs_set_boolean(PREF_STATUSBAR_SHOW_READ, FALSE);
cons_show("Disabled showing inactive tabs.");
ui_resize();
return TRUE;
}
cons_bad_cmd_usage(command);
return TRUE;
}
if (g_strcmp0(args[0], "maxtabs") == 0) {
if (args[1] == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
char* value = args[1];
int intval = 0;
char* err_msg = NULL;
gboolean res = strtoi_range(value, &intval, 0, INT_MAX, &err_msg);
if (res) {
if (intval < 0 || intval > 10) {
cons_bad_cmd_usage(command);
return TRUE;
}
prefs_set_statusbartabs(intval);
if (intval == 0) {
cons_show("Status bar tabs disabled.");
} else {
cons_show("Status bar tabs set to %d.", intval);
}
ui_resize();
return TRUE;
} else {
cons_show(err_msg);
cons_bad_cmd_usage(command);
free(err_msg);
return TRUE;
}
}
if (g_strcmp0(args[0], "tablen") == 0) {
if (args[1] == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
char* value = args[1];
int intval = 0;
char* err_msg = NULL;
gboolean res = strtoi_range(value, &intval, 0, INT_MAX, &err_msg);
if (res) {
if (intval < 0) {
cons_bad_cmd_usage(command);
return TRUE;
}
prefs_set_statusbartablen(intval);
if (intval == 0) {
cons_show("Maximum tab length disabled.");
} else {
cons_show("Maximum tab length set to %d.", intval);
}
ui_resize();
return TRUE;
} else {
cons_show(err_msg);
cons_bad_cmd_usage(command);
free(err_msg);
return TRUE;
}
}
if (g_strcmp0(args[0], "self") == 0) {
if (g_strcmp0(args[1], "barejid") == 0) {
prefs_set_string(PREF_STATUSBAR_SELF, "barejid");
cons_show("Using barejid for statusbar title.");
ui_resize();
return TRUE;
}
if (g_strcmp0(args[1], "fulljid") == 0) {
prefs_set_string(PREF_STATUSBAR_SELF, "fulljid");
cons_show("Using fulljid for statusbar title.");
ui_resize();
return TRUE;
}
if (g_strcmp0(args[1], "user") == 0) {
prefs_set_string(PREF_STATUSBAR_SELF, "user");
cons_show("Using user for statusbar title.");
ui_resize();
return TRUE;
}
if (g_strcmp0(args[1], "off") == 0) {
prefs_set_string(PREF_STATUSBAR_SELF, "off");
cons_show("Disabling statusbar title.");
ui_resize();
return TRUE;
}
cons_bad_cmd_usage(command);
return TRUE;
}
if (g_strcmp0(args[0], "chat") == 0) {
if (g_strcmp0(args[1], "jid") == 0) {
prefs_set_string(PREF_STATUSBAR_CHAT, "jid");
cons_show("Using jid for chat tabs.");
ui_resize();
return TRUE;
}
if (g_strcmp0(args[1], "user") == 0) {
prefs_set_string(PREF_STATUSBAR_CHAT, "user");
cons_show("Using user for chat tabs.");
ui_resize();
return TRUE;
}
cons_bad_cmd_usage(command);
return TRUE;
}
if (g_strcmp0(args[0], "room") == 0) {
if (g_strcmp0(args[1], "jid") == 0) {
prefs_set_string(PREF_STATUSBAR_ROOM, "jid");
cons_show("Using jid for room tabs.");
ui_resize();
return TRUE;
}
if (g_strcmp0(args[1], "room") == 0) {
prefs_set_string(PREF_STATUSBAR_ROOM, "room");
cons_show("Using room name for room tabs.");
ui_resize();
return TRUE;
}
cons_bad_cmd_usage(command);
return TRUE;
}
if (g_strcmp0(args[0], "up") == 0) {
gboolean result = prefs_statusbar_pos_up();
if (result) {
ui_resize();
cons_show("Status bar moved up");
} else {
cons_show("Could not move status bar up.");
}
return TRUE;
}
if (g_strcmp0(args[0], "down") == 0) {
gboolean result = prefs_statusbar_pos_down();
if (result) {
ui_resize();
cons_show("Status bar moved down.");
} else {
cons_show("Could not move status bar down.");
}
return TRUE;
}
cons_bad_cmd_usage(command);
return TRUE;
}
gboolean
cmd_inputwin(ProfWin* window, const char* const command, gchar** args)
{
if (g_strcmp0(args[0], "up") == 0) {
gboolean result = prefs_inputwin_pos_up();
if (result) {
ui_resize();
cons_show("Input window moved up.");
} else {
cons_show("Could not move input window up.");
}
return TRUE;
}
if (g_strcmp0(args[0], "down") == 0) {
gboolean result = prefs_inputwin_pos_down();
if (result) {
ui_resize();
cons_show("Input window moved down.");
} else {
cons_show("Could not move input window down.");
}
return TRUE;
}
cons_bad_cmd_usage(command);
return TRUE;
}
gboolean
cmd_log(ProfWin* window, const char* const command, gchar** args)
{
char* subcmd = args[0];
char* value = args[1];
if (strcmp(subcmd, "maxsize") == 0) {
if (value == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
int intval = 0;
char* err_msg = NULL;
gboolean res = strtoi_range(value, &intval, PREFS_MIN_LOG_SIZE, INT_MAX, &err_msg);
if (res) {
prefs_set_max_log_size(intval);
cons_show("Log maximum size set to %d bytes", intval);
} else {
cons_show(err_msg);
free(err_msg);
}
return TRUE;
}
if (strcmp(subcmd, "rotate") == 0) {
if (value == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
_cmd_set_boolean_preference(value, command, "Log rotate", PREF_LOG_ROTATE);
return TRUE;
}
if (strcmp(subcmd, "shared") == 0) {
if (value == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
_cmd_set_boolean_preference(value, command, "Shared log", PREF_LOG_SHARED);
cons_show("Setting only takes effect after saving and restarting Profanity.");
return TRUE;
}
if (strcmp(subcmd, "where") == 0) {
cons_show("Log file: %s", get_log_file_location());
return TRUE;
}
cons_bad_cmd_usage(command);
/* TODO: make 'level' subcommand for debug level */
return TRUE;
}
gboolean
cmd_reconnect(ProfWin* window, const char* const command, gchar** args)
{
char* value = args[0];
int intval = 0;
char* err_msg = NULL;
gboolean res = strtoi_range(value, &intval, 0, INT_MAX, &err_msg);
if (res) {
prefs_set_reconnect(intval);
if (intval == 0) {
cons_show("Reconnect disabled.", intval);
} else {
cons_show("Reconnect interval set to %d seconds.", intval);
}
} else {
cons_show(err_msg);
cons_bad_cmd_usage(command);
free(err_msg);
}
return TRUE;
}
gboolean
cmd_autoping(ProfWin* window, const char* const command, gchar** args)
{
char* cmd = args[0];
char* value = args[1];
if (g_strcmp0(cmd, "set") == 0) {
int intval = 0;
char* err_msg = NULL;
gboolean res = strtoi_range(value, &intval, 0, INT_MAX, &err_msg);
if (res) {
prefs_set_autoping(intval);
iq_set_autoping(intval);
if (intval == 0) {
cons_show("Autoping disabled.");
} else {
cons_show("Autoping interval set to %d seconds.", intval);
}
} else {
cons_show(err_msg);
cons_bad_cmd_usage(command);
free(err_msg);
}
} else if (g_strcmp0(cmd, "timeout") == 0) {
int intval = 0;
char* err_msg = NULL;
gboolean res = strtoi_range(value, &intval, 0, INT_MAX, &err_msg);
if (res) {
prefs_set_autoping_timeout(intval);
if (intval == 0) {
cons_show("Autoping timeout disabled.");
} else {
cons_show("Autoping timeout set to %d seconds.", intval);
}
} else {
cons_show(err_msg);
cons_bad_cmd_usage(command);
free(err_msg);
}
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}
gboolean
cmd_ping(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
if (args[0] == NULL && connection_supports(XMPP_FEATURE_PING) == FALSE) {
cons_show("Server does not support ping requests (%s).", XMPP_FEATURE_PING);
return TRUE;
}
if (args[0] != NULL && caps_jid_has_feature(args[0], XMPP_FEATURE_PING) == FALSE) {
cons_show("%s does not support ping requests.", args[0]);
return TRUE;
}
iq_send_ping(args[0]);
if (args[0] == NULL) {
cons_show("Pinged server...");
} else {
cons_show("Pinged %s...", args[0]);
}
return TRUE;
}
gboolean
cmd_autoaway(ProfWin* window, const char* const command, gchar** args)
{
if ((g_strcmp0(args[0], "mode") != 0) && (g_strcmp0(args[0], "time") != 0) && (g_strcmp0(args[0], "message") != 0) && (g_strcmp0(args[0], "check") != 0)) {
cons_show("Setting must be one of 'mode', 'time', 'message' or 'check'");
return TRUE;
}
if (g_strcmp0(args[0], "mode") == 0) {
if ((g_strcmp0(args[1], "idle") != 0) && (g_strcmp0(args[1], "away") != 0) && (g_strcmp0(args[1], "off") != 0)) {
cons_show("Mode must be one of 'idle', 'away' or 'off'");
} else {
prefs_set_string(PREF_AUTOAWAY_MODE, args[1]);
cons_show("Auto away mode set to: %s.", args[1]);
}
return TRUE;
}
if ((g_strcmp0(args[0], "time") == 0) && (args[2] != NULL)) {
if (g_strcmp0(args[1], "away") == 0) {
int minutesval = 0;
char* err_msg = NULL;
gboolean res = strtoi_range(args[2], &minutesval, 1, INT_MAX, &err_msg);
if (res) {
prefs_set_autoaway_time(minutesval);
if (minutesval == 1) {
cons_show("Auto away time set to: 1 minute.");
} else {
cons_show("Auto away time set to: %d minutes.", minutesval);
}
} else {
cons_show(err_msg);
free(err_msg);
}
return TRUE;
} else if (g_strcmp0(args[1], "xa") == 0) {
int minutesval = 0;
char* err_msg = NULL;
gboolean res = strtoi_range(args[2], &minutesval, 0, INT_MAX, &err_msg);
if (res) {
int away_time = prefs_get_autoaway_time();
if (minutesval != 0 && minutesval <= away_time) {
cons_show("Auto xa time must be larger than auto away time.");
} else {
prefs_set_autoxa_time(minutesval);
if (minutesval == 0) {
cons_show("Auto xa time disabled.");
} else if (minutesval == 1) {
cons_show("Auto xa time set to: 1 minute.");
} else {
cons_show("Auto xa time set to: %d minutes.", minutesval);
}
}
} else {
cons_show(err_msg);
free(err_msg);
}
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
if (g_strcmp0(args[0], "message") == 0) {
if (g_strcmp0(args[1], "away") == 0 && args[2] != NULL) {
if (g_strcmp0(args[2], "off") == 0) {
prefs_set_string(PREF_AUTOAWAY_MESSAGE, NULL);
cons_show("Auto away message cleared.");
} else {
prefs_set_string(PREF_AUTOAWAY_MESSAGE, args[2]);
cons_show("Auto away message set to: \"%s\".", args[2]);
}
return TRUE;
} else if (g_strcmp0(args[1], "xa") == 0) {
if (g_strcmp0(args[2], "off") == 0) {
prefs_set_string(PREF_AUTOXA_MESSAGE, NULL);
cons_show("Auto xa message cleared.");
} else {
prefs_set_string(PREF_AUTOXA_MESSAGE, args[2]);
cons_show("Auto xa message set to: \"%s\".", args[2]);
}
return TRUE;
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
}
if (g_strcmp0(args[0], "check") == 0) {
_cmd_set_boolean_preference(args[1], command, "Online check", PREF_AUTOAWAY_CHECK);
return TRUE;
}
return TRUE;
}
gboolean
cmd_priority(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
char* value = args[0];
int intval = 0;
char* err_msg = NULL;
gboolean res = strtoi_range(value, &intval, -128, 127, &err_msg);
if (res) {
accounts_set_priority_all(session_get_account_name(), intval);
resource_presence_t last_presence = accounts_get_last_presence(session_get_account_name());
cl_ev_presence_send(last_presence, 0);
cons_show("Priority set to %d.", intval);
} else {
cons_show(err_msg);
free(err_msg);
}
return TRUE;
}
gboolean
cmd_vercheck(ProfWin* window, const char* const command, gchar** args)
{
int num_args = g_strv_length(args);
if (num_args == 0) {
cons_check_version(TRUE);
return TRUE;
} else {
_cmd_set_boolean_preference(args[0], command, "Version checking", PREF_VERCHECK);
return TRUE;
}
}
gboolean
cmd_xmlconsole(ProfWin* window, const char* const command, gchar** args)
{
ProfXMLWin* xmlwin = wins_get_xmlconsole();
if (xmlwin) {
ui_focus_win((ProfWin*)xmlwin);
} else {
ProfWin* window = wins_new_xmlconsole();
ui_focus_win(window);
}
return TRUE;
}
gboolean
cmd_flash(ProfWin* window, const char* const command, gchar** args)
{
_cmd_set_boolean_preference(args[0], command, "Screen flash", PREF_FLASH);
return TRUE;
}
gboolean
cmd_tray(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_GTK
if (g_strcmp0(args[0], "timer") == 0) {
if (args[1] == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
if (prefs_get_boolean(PREF_TRAY) == FALSE) {
cons_show("Tray icon not currently enabled, see /help tray");
return TRUE;
}
int intval = 0;
char* err_msg = NULL;
gboolean res = strtoi_range(args[1], &intval, 1, 10, &err_msg);
if (res) {
if (intval == 1) {
cons_show("Tray timer set to 1 second.");
} else {
cons_show("Tray timer set to %d seconds.", intval);
}
prefs_set_tray_timer(intval);
if (prefs_get_boolean(PREF_TRAY)) {
tray_set_timer(intval);
}
} else {
cons_show(err_msg);
free(err_msg);
}
return TRUE;
} else if (g_strcmp0(args[0], "read") == 0) {
if (prefs_get_boolean(PREF_TRAY) == FALSE) {
cons_show("Tray icon not currently enabled, see /help tray");
} else if (g_strcmp0(args[1], "on") == 0) {
prefs_set_boolean(PREF_TRAY_READ, TRUE);
cons_show("Tray icon enabled when no unread messages.");
} else if (g_strcmp0(args[1], "off") == 0) {
prefs_set_boolean(PREF_TRAY_READ, FALSE);
cons_show("Tray icon disabled when no unread messages.");
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
} else {
gboolean old = prefs_get_boolean(PREF_TRAY);
_cmd_set_boolean_preference(args[0], command, "Tray icon", PREF_TRAY);
gboolean new = prefs_get_boolean(PREF_TRAY);
if (old != new) {
if (new) {
tray_enable();
} else {
tray_disable();
}
}
return TRUE;
}
#else
cons_show("This version of Profanity has not been built with GTK Tray Icon support enabled");
return TRUE;
#endif
}
gboolean
cmd_intype(ProfWin* window, const char* const command, gchar** args)
{
if (g_strcmp0(args[0], "console") == 0) {
_cmd_set_boolean_preference(args[1], command, "Show contact typing in console", PREF_INTYPE_CONSOLE);
} else if (g_strcmp0(args[0], "titlebar") == 0) {
_cmd_set_boolean_preference(args[1], command, "Show contact typing in titlebar", PREF_INTYPE);
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}
gboolean
cmd_splash(ProfWin* window, const char* const command, gchar** args)
{
_cmd_set_boolean_preference(args[0], command, "Splash screen", PREF_SPLASH);
return TRUE;
}
gboolean
cmd_autoconnect(ProfWin* window, const char* const command, gchar** args)
{
if (strcmp(args[0], "off") == 0) {
prefs_set_string(PREF_CONNECT_ACCOUNT, NULL);
cons_show("Autoconnect account disabled.");
} else if (strcmp(args[0], "set") == 0) {
if (args[1] == NULL || strlen(args[1]) == 0) {
cons_bad_cmd_usage(command);
} else {
if (accounts_account_exists(args[1])) {
prefs_set_string(PREF_CONNECT_ACCOUNT, args[1]);
cons_show("Autoconnect account set to: %s.", args[1]);
} else {
cons_show_error("Account '%s' does not exist.", args[1]);
}
}
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}
gboolean
cmd_logging(ProfWin* window, const char* const command, gchar** args)
{
if (args[0] == NULL) {
cons_logging_setting();
return TRUE;
}
if (strcmp(args[0], "chat") == 0 && args[1] != NULL) {
_cmd_set_boolean_preference(args[1], command, "Chat logging", PREF_CHLOG);
// if set to off, disable history
if (strcmp(args[1], "off") == 0) {
prefs_set_boolean(PREF_HISTORY, FALSE);
}
return TRUE;
} else if (g_strcmp0(args[0], "group") == 0 && args[1] != NULL) {
if (g_strcmp0(args[1], "on") == 0 || g_strcmp0(args[1], "off") == 0) {
_cmd_set_boolean_preference(args[1], command, "Groupchat logging", PREF_GRLOG);
return TRUE;
}
}
cons_bad_cmd_usage(command);
return TRUE;
}
gboolean
cmd_history(ProfWin* window, const char* const command, gchar** args)
{
if (args[0] == NULL) {
return FALSE;
}
_cmd_set_boolean_preference(args[0], command, "Chat history", PREF_HISTORY);
// if set to on, set chlog (/logging chat on)
if (strcmp(args[0], "on") == 0) {
prefs_set_boolean(PREF_CHLOG, TRUE);
}
return TRUE;
}
gboolean
cmd_carbons(ProfWin* window, const char* const command, gchar** args)
{
if (args[0] == NULL) {
return FALSE;
}
_cmd_set_boolean_preference(args[0], command, "Message carbons preference", PREF_CARBONS);
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status == JABBER_CONNECTED) {
// enable carbons
if (strcmp(args[0], "on") == 0) {
iq_enable_carbons();
} else if (strcmp(args[0], "off") == 0) {
iq_disable_carbons();
}
}
return TRUE;
}
gboolean
cmd_receipts(ProfWin* window, const char* const command, gchar** args)
{
if (g_strcmp0(args[0], "send") == 0) {
_cmd_set_boolean_preference(args[1], command, "Send delivery receipts", PREF_RECEIPTS_SEND);
if (g_strcmp0(args[1], "on") == 0) {
caps_add_feature(XMPP_FEATURE_RECEIPTS);
}
if (g_strcmp0(args[1], "off") == 0) {
caps_remove_feature(XMPP_FEATURE_RECEIPTS);
}
} else if (g_strcmp0(args[0], "request") == 0) {
_cmd_set_boolean_preference(args[1], command, "Request delivery receipts", PREF_RECEIPTS_REQUEST);
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}
gboolean
cmd_plugins_install(ProfWin* window, const char* const command, gchar** args)
{
char* path = NULL;
if (args[1] == NULL) {
cons_show("Please provide a path to the plugin file or directory, see /help plugins");
return TRUE;
}
// take whole path or build it in case it's just the plugin name
if (strchr(args[1], '/')) {
path = get_expanded_path(args[1]);
} else {
if (g_str_has_suffix(args[1], ".py")) {
path = g_strdup_printf("%s/%s", GLOBAL_PYTHON_PLUGINS_PATH, args[1]);
} else if (g_str_has_suffix(args[1], ".so")) {
path = g_strdup_printf("%s/%s", GLOBAL_C_PLUGINS_PATH, args[1]);
} else {
cons_show("Plugins must have one of the following extensions: '.py' '.so'");
return TRUE;
}
}
if (access(path, R_OK) != 0) {
cons_show("Cannot access: %s", path);
free(path);
return TRUE;
}
if (is_regular_file(path)) {
if (!g_str_has_suffix(path, ".py") && !g_str_has_suffix(path, ".so")) {
cons_show("Plugins must have one of the following extensions: '.py' '.so'");
free(path);
return TRUE;
}
GString* error_message = g_string_new(NULL);
gchar* plugin_name = g_path_get_basename(path);
gboolean result = plugins_install(plugin_name, path, error_message);
if (result) {
cons_show("Plugin installed and loaded: %s", plugin_name);
} else {
cons_show("Failed to install plugin: %s. %s", plugin_name, error_message->str);
}
g_free(plugin_name);
g_string_free(error_message, TRUE);
free(path);
return TRUE;
} else if (is_dir(path)) {
PluginsInstallResult* result = plugins_install_all(path);
if (result->installed || result->failed) {
if (result->installed) {
cons_show("");
cons_show("Installed and loaded plugins:");
GSList* curr = result->installed;
while (curr) {
cons_show(" %s", curr->data);
curr = g_slist_next(curr);
}
}
if (result->failed) {
cons_show("");
cons_show("Failed installs:");
GSList* curr = result->failed;
while (curr) {
cons_show(" %s", curr->data);
curr = g_slist_next(curr);
}
}
} else {
cons_show("No plugins found in: %s", path);
}
free(path);
plugins_free_install_result(result);
return TRUE;
} else {
cons_show("Argument must be a file or directory.");
}
free(path);
return TRUE;
}
gboolean
cmd_plugins_update(ProfWin* window, const char* const command, gchar** args)
{
char* path;
if (args[1] == NULL) {
cons_show("Please provide a path to the plugin file, see /help plugins");
return TRUE;
} else {
path = get_expanded_path(args[1]);
}
if (access(path, R_OK) != 0) {
cons_show("File not found: %s", path);
free(path);
return TRUE;
}
if (is_regular_file(path)) {
if (!g_str_has_suffix(path, ".py") && !g_str_has_suffix(path, ".so")) {
cons_show("Plugins must have one of the following extensions: '.py' '.so'");
free(path);
return TRUE;
}
GString* error_message = g_string_new(NULL);
gchar* plugin_name = g_path_get_basename(path);
if (plugins_unload(plugin_name)) {
if (plugins_uninstall(plugin_name)) {
if (plugins_install(plugin_name, path, error_message)) {
cons_show("Plugin installed: %s", plugin_name);
} else {
cons_show("Failed to install plugin: %s. %s", plugin_name, error_message->str);
}
} else {
cons_show("Failed to uninstall plugin: %s.", plugin_name);
}
} else {
cons_show("Failed to unload plugin: %s.", plugin_name);
}
g_free(plugin_name);
g_string_free(error_message, TRUE);
free(path);
return TRUE;
}
free(path);
cons_show("Argument must be a file.");
return TRUE;
}
gboolean
cmd_plugins_uninstall(ProfWin* window, const char* const command, gchar** args)
{
if (args[1] == NULL) {
return FALSE;
}
gboolean res = plugins_uninstall(args[1]);
if (res) {
cons_show("Uninstalled plugin: %s", args[1]);
} else {
cons_show("Failed to uninstall plugin: %s", args[1]);
}
return TRUE;
}
gboolean
cmd_plugins_load(ProfWin* window, const char* const command, gchar** args)
{
if (args[1] == NULL) {
GSList* loaded = plugins_load_all();
if (loaded) {
cons_show("Loaded plugins:");
GSList* curr = loaded;
while (curr) {
cons_show(" %s", curr->data);
curr = g_slist_next(curr);
}
g_slist_free_full(loaded, g_free);
} else {
cons_show("No plugins loaded.");
}
return TRUE;
}
GString* error_message = g_string_new(NULL);
gboolean res = plugins_load(args[1], error_message);
if (res) {
cons_show("Loaded plugin: %s", args[1]);
} else {
cons_show("Failed to load plugin: %s. %s", args[1], error_message->str);
}
g_string_free(error_message, TRUE);
return TRUE;
}
gboolean
cmd_plugins_unload(ProfWin* window, const char* const command, gchar** args)
{
if (args[1] == NULL) {
gboolean res = plugins_unload_all();
if (res) {
cons_show("Unloaded all plugins.");
} else {
cons_show("No plugins unloaded.");
}
return TRUE;
}
gboolean res = plugins_unload(args[1]);
if (res) {
cons_show("Unloaded plugin: %s", args[1]);
} else {
cons_show("Failed to unload plugin: %s", args[1]);
}
return TRUE;
}
gboolean
cmd_plugins_reload(ProfWin* window, const char* const command, gchar** args)
{
if (args[1] == NULL) {
plugins_reload_all();
cons_show("Reloaded all plugins");
return TRUE;
}
GString* error_message = g_string_new(NULL);
gboolean res = plugins_reload(args[1], error_message);
if (res) {
cons_show("Reloaded plugin: %s", args[1]);
} else {
cons_show("Failed to reload plugin: %s, %s", args[1], error_message);
}
g_string_free(error_message, TRUE);
return TRUE;
}
gboolean
cmd_plugins_python_version(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_PYTHON
const char* version = python_get_version_string();
cons_show("Python version:");
cons_show("%s", version);
#else
cons_show("This build does not support python plugins.");
#endif
return TRUE;
}
gboolean
cmd_plugins(ProfWin* window, const char* const command, gchar** args)
{
GDir* global_pyp_dir = NULL;
GDir* global_cp_dir = NULL;
if (access(GLOBAL_PYTHON_PLUGINS_PATH, R_OK) == 0) {
GError* error = NULL;
global_pyp_dir = g_dir_open(GLOBAL_PYTHON_PLUGINS_PATH, 0, &error);
if (error) {
log_warning("Error when trying to open global plugins path: %s", GLOBAL_PYTHON_PLUGINS_PATH);
g_error_free(error);
return TRUE;
}
}
if (access(GLOBAL_C_PLUGINS_PATH, R_OK) == 0) {
GError* error = NULL;
global_cp_dir = g_dir_open(GLOBAL_C_PLUGINS_PATH, 0, &error);
if (error) {
log_warning("Error when trying to open global plugins path: %s", GLOBAL_C_PLUGINS_PATH);
g_error_free(error);
return TRUE;
}
}
if (global_pyp_dir) {
const gchar* filename;
cons_show("The following Python plugins are available globally and can be installed:");
while ((filename = g_dir_read_name(global_pyp_dir))) {
cons_show(" %s", filename);
}
}
if (global_cp_dir) {
const gchar* filename;
cons_show("The following C plugins are available globally and can be installed:");
while ((filename = g_dir_read_name(global_cp_dir))) {
cons_show(" %s", filename);
}
}
GList* plugins = plugins_loaded_list();
if (plugins == NULL) {
cons_show("No plugins installed.");
return TRUE;
}
GList* curr = plugins;
cons_show("Installed plugins:");
while (curr) {
cons_show(" %s", curr->data);
curr = g_list_next(curr);
}
g_list_free(plugins);
return TRUE;
}
gboolean
cmd_pgp(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_LIBGPGME
if (args[0] == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
if (strcmp(args[0], "char") == 0) {
if (args[1] == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
} else if (g_utf8_strlen(args[1], 4) == 1) {
if (prefs_set_pgp_char(args[1])) {
cons_show("PGP char set to %s.", args[1]);
} else {
cons_show_error("Could not set PGP char: %s.", args[1]);
}
return TRUE;
}
cons_bad_cmd_usage(command);
return TRUE;
} else if (g_strcmp0(args[0], "log") == 0) {
char* choice = args[1];
if (g_strcmp0(choice, "on") == 0) {
prefs_set_string(PREF_PGP_LOG, "on");
cons_show("PGP messages will be logged as plaintext.");
if (!prefs_get_boolean(PREF_CHLOG)) {
cons_show("Chat logging is currently disabled, use '/logging chat on' to enable.");
}
} else if (g_strcmp0(choice, "off") == 0) {
prefs_set_string(PREF_PGP_LOG, "off");
cons_show("PGP message logging disabled.");
} else if (g_strcmp0(choice, "redact") == 0) {
prefs_set_string(PREF_PGP_LOG, "redact");
cons_show("PGP messages will be logged as '[redacted]'.");
if (!prefs_get_boolean(PREF_CHLOG)) {
cons_show("Chat logging is currently disabled, use '/logging chat on' to enable.");
}
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}
if (g_strcmp0(args[0], "keys") == 0) {
GHashTable* keys = p_gpg_list_keys();
if (!keys || g_hash_table_size(keys) == 0) {
cons_show("No keys found");
return TRUE;
}
cons_show("PGP keys:");
GList* keylist = g_hash_table_get_keys(keys);
GList* curr = keylist;
while (curr) {
ProfPGPKey* key = g_hash_table_lookup(keys, curr->data);
cons_show(" %s", key->name);
cons_show(" ID : %s", key->id);
char* format_fp = p_gpg_format_fp_str(key->fp);
cons_show(" Fingerprint : %s", format_fp);
free(format_fp);
if (key->secret) {
cons_show(" Type : PUBLIC, PRIVATE");
} else {
cons_show(" Type : PUBLIC");
}
curr = g_list_next(curr);
}
g_list_free(keylist);
p_gpg_free_keys(keys);
return TRUE;
}
if (g_strcmp0(args[0], "setkey") == 0) {
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
char* jid = args[1];
if (!args[1]) {
cons_bad_cmd_usage(command);
return TRUE;
}
char* keyid = args[2];
if (!args[2]) {
cons_bad_cmd_usage(command);
return TRUE;
}
gboolean res = p_gpg_addkey(jid, keyid);
if (!res) {
cons_show("Key ID not found.");
} else {
cons_show("Key %s set for %s.", keyid, jid);
}
return TRUE;
}
if (g_strcmp0(args[0], "contacts") == 0) {
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
GHashTable* pubkeys = p_gpg_pubkeys();
GList* jids = g_hash_table_get_keys(pubkeys);
if (!jids) {
cons_show("No contacts found with PGP public keys assigned.");
return TRUE;
}
cons_show("Assigned PGP public keys:");
GList* curr = jids;
while (curr) {
char* jid = curr->data;
ProfPGPPubKeyId* pubkeyid = g_hash_table_lookup(pubkeys, jid);
if (pubkeyid->received) {
cons_show(" %s: %s (received)", jid, pubkeyid->id);
} else {
cons_show(" %s: %s (stored)", jid, pubkeyid->id);
}
curr = g_list_next(curr);
}
g_list_free(jids);
return TRUE;
}
if (g_strcmp0(args[0], "libver") == 0) {
const char* libver = p_gpg_libver();
if (!libver) {
cons_show("Could not get libgpgme version");
return TRUE;
}
GString* fullstr = g_string_new("Using libgpgme version ");
g_string_append(fullstr, libver);
cons_show("%s", fullstr->str);
g_string_free(fullstr, TRUE);
return TRUE;
}
if (g_strcmp0(args[0], "start") == 0) {
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You must be connected to start PGP encrpytion.");
return TRUE;
}
if (window->type != WIN_CHAT && args[1] == NULL) {
cons_show("You must be in a regular chat window to start PGP encrpytion.");
return TRUE;
}
ProfChatWin* chatwin = NULL;
if (args[1]) {
char* contact = args[1];
char* barejid = roster_barejid_from_name(contact);
if (barejid == NULL) {
barejid = contact;
}
chatwin = wins_get_chat(barejid);
if (!chatwin) {
chatwin = chatwin_new(barejid);
}
ui_focus_win((ProfWin*)chatwin);
} else {
chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
}
if (chatwin->is_otr) {
win_println(window, THEME_DEFAULT, "!", "You must end the OTR session to start PGP encryption.");
return TRUE;
}
if (chatwin->pgp_send) {
win_println(window, THEME_DEFAULT, "!", "You have already started PGP encryption.");
return TRUE;
}
if (chatwin->is_omemo) {
win_println(window, THEME_DEFAULT, "!", "You must disable OMEMO before starting an PGP encrypted session.");
return TRUE;
}
ProfAccount* account = accounts_get_account(session_get_account_name());
char* err_str = NULL;
if (!p_gpg_valid_key(account->pgp_keyid, &err_str)) {
win_println(window, THEME_DEFAULT, "!", "Invalid PGP key ID %s: %s, cannot start PGP encryption.", account->pgp_keyid, err_str);
free(err_str);
account_free(account);
return TRUE;
}
free(err_str);
account_free(account);
if (!p_gpg_available(chatwin->barejid)) {
win_println(window, THEME_DEFAULT, "!", "No PGP key found for %s.", chatwin->barejid);
return TRUE;
}
chatwin->pgp_send = TRUE;
win_println(window, THEME_DEFAULT, "!", "PGP encryption enabled.");
return TRUE;
}
if (g_strcmp0(args[0], "end") == 0) {
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
if (window->type != WIN_CHAT) {
cons_show("You must be in a regular chat window to end PGP encrpytion.");
return TRUE;
}
ProfChatWin* chatwin = (ProfChatWin*)window;
if (chatwin->pgp_send == FALSE) {
win_println(window, THEME_DEFAULT, "!", "PGP encryption is not currently enabled.");
return TRUE;
}
chatwin->pgp_send = FALSE;
win_println(window, THEME_DEFAULT, "!", "PGP encryption disabled.");
return TRUE;
}
if (g_strcmp0(args[0], "sendfile") == 0) {
_cmd_set_boolean_preference(args[1], command, "Sending unencrypted files using /sendfile while otherwise using PGP", PREF_PGP_SENDFILE);
return TRUE;
}
cons_bad_cmd_usage(command);
return TRUE;
#else
cons_show("This version of Profanity has not been built with PGP support enabled");
return TRUE;
#endif
}
#ifdef HAVE_LIBGPGME
/*!
* \brief Command for XEP-0373: OpenPGP for XMPP
*
*/
gboolean
cmd_ox(ProfWin* window, const char* const command, gchar** args)
{
if (args[0] == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
if (strcmp(args[0], "char") == 0) {
if (args[1] == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
} else if (g_utf8_strlen(args[1], 4) == 1) {
if (prefs_set_ox_char(args[1])) {
cons_show("OX char set to %s.", args[1]);
} else {
cons_show_error("Could not set OX char: %s.", args[1]);
}
return TRUE;
}
cons_bad_cmd_usage(command);
return TRUE;
}
// The '/ox keys' command - same like in pgp
// Should we move this to a common command
// e.g. '/openpgp keys'?.
else if (g_strcmp0(args[0], "keys") == 0) {
GHashTable* keys = p_gpg_list_keys();
if (!keys || g_hash_table_size(keys) == 0) {
cons_show("No keys found");
return TRUE;
}
cons_show("OpenPGP keys:");
GList* keylist = g_hash_table_get_keys(keys);
GList* curr = keylist;
while (curr) {
ProfPGPKey* key = g_hash_table_lookup(keys, curr->data);
cons_show(" %s", key->name);
cons_show(" ID : %s", key->id);
char* format_fp = p_gpg_format_fp_str(key->fp);
cons_show(" Fingerprint : %s", format_fp);
free(format_fp);
if (key->secret) {
cons_show(" Type : PUBLIC, PRIVATE");
} else {
cons_show(" Type : PUBLIC");
}
curr = g_list_next(curr);
}
g_list_free(keylist);
p_gpg_free_keys(keys);
return TRUE;
}
else if (g_strcmp0(args[0], "contacts") == 0) {
GHashTable* keys = ox_gpg_public_keys();
cons_show("OpenPGP keys:");
GList* keylist = g_hash_table_get_keys(keys);
GList* curr = keylist;
GSList* roster_list = NULL;
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
} else {
roster_list = roster_get_contacts(ROSTER_ORD_NAME);
}
while (curr) {
ProfPGPKey* key = g_hash_table_lookup(keys, curr->data);
PContact contact = NULL;
if (roster_list) {
GSList* curr_c = roster_list;
while (!contact && curr_c) {
contact = curr_c->data;
const char* jid = p_contact_barejid(contact);
GString* xmppuri = g_string_new("xmpp:");
g_string_append(xmppuri, jid);
if (g_strcmp0(key->name, xmppuri->str)) {
contact = NULL;
}
curr_c = g_slist_next(curr_c);
}
}
if (contact) {
cons_show("%s - %s", key->fp, key->name);
} else {
cons_show("%s - %s (not in roster)", key->fp, key->name);
}
curr = g_list_next(curr);
}
} else if (g_strcmp0(args[0], "start") == 0) {
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You must be connected to start OX encrpytion.");
return TRUE;
}
if (window->type != WIN_CHAT && args[1] == NULL) {
cons_show("You must be in a regular chat window to start OX encrpytion.");
return TRUE;
}
ProfChatWin* chatwin = NULL;
if (args[1]) {
char* contact = args[1];
char* barejid = roster_barejid_from_name(contact);
if (barejid == NULL) {
barejid = contact;
}
chatwin = wins_get_chat(barejid);
if (!chatwin) {
chatwin = chatwin_new(barejid);
}
ui_focus_win((ProfWin*)chatwin);
} else {
chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
}
if (chatwin->is_otr) {
win_println(window, THEME_DEFAULT, "!", "You must end the OTR session to start OX encryption.");
return TRUE;
}
if (chatwin->pgp_send) {
win_println(window, THEME_DEFAULT, "!", "You must end the PGP session to start OX encryption.");
return TRUE;
}
if (chatwin->is_ox) {
win_println(window, THEME_DEFAULT, "!", "You have already started OX encryption.");
return TRUE;
}
ProfAccount* account = accounts_get_account(session_get_account_name());
if (!ox_is_private_key_available(account->jid)) {
win_println(window, THEME_DEFAULT, "!", "No private OpenPGP found, cannot start OX encryption.");
account_free(account);
return TRUE;
}
account_free(account);
if (!ox_is_public_key_available(chatwin->barejid)) {
win_println(window, THEME_DEFAULT, "!", "No OX-OpenPGP key found for %s.", chatwin->barejid);
return TRUE;
}
chatwin->is_ox = TRUE;
win_println(window, THEME_DEFAULT, "!", "OX encryption enabled.");
return TRUE;
} else if (g_strcmp0(args[0], "announce") == 0) {
if (args[1]) {
ox_announce_public_key(args[1]);
} else {
cons_show("Filename is required");
}
} else if (g_strcmp0(args[0], "discover") == 0) {
if (args[1]) {
ox_discover_public_key(args[1]);
} else {
cons_show("To discover the OpenPGP keys of an user, the JID is required");
}
} else if (g_strcmp0(args[0], "request") == 0) {
if (args[1] && args[2]) {
ox_request_public_key(args[1], args[2]);
} else {
cons_show("JID and OpenPGP Key ID are required");
}
} else {
cons_show("OX not implemented");
}
return TRUE;
}
#endif // HAVE_LIBGPGME
gboolean
cmd_otr_char(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_LIBOTR
if (args[1] == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
} else if (g_utf8_strlen(args[1], 4) == 1) {
if (prefs_set_otr_char(args[1])) {
cons_show("OTR char set to %s.", args[1]);
} else {
cons_show_error("Could not set OTR char: %s.", args[1]);
}
return TRUE;
}
cons_bad_cmd_usage(command);
#else
cons_show("This version of Profanity has not been built with OTR support enabled");
#endif
return TRUE;
}
gboolean
cmd_otr_log(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_LIBOTR
char* choice = args[1];
if (g_strcmp0(choice, "on") == 0) {
prefs_set_string(PREF_OTR_LOG, "on");
cons_show("OTR messages will be logged as plaintext.");
if (!prefs_get_boolean(PREF_CHLOG)) {
cons_show("Chat logging is currently disabled, use '/logging chat on' to enable.");
}
} else if (g_strcmp0(choice, "off") == 0) {
prefs_set_string(PREF_OTR_LOG, "off");
cons_show("OTR message logging disabled.");
} else if (g_strcmp0(choice, "redact") == 0) {
prefs_set_string(PREF_OTR_LOG, "redact");
cons_show("OTR messages will be logged as '[redacted]'.");
if (!prefs_get_boolean(PREF_CHLOG)) {
cons_show("Chat logging is currently disabled, use '/logging chat on' to enable.");
}
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
#else
cons_show("This version of Profanity has not been built with OTR support enabled");
return TRUE;
#endif
}
gboolean
cmd_otr_libver(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_LIBOTR
char* version = otr_libotr_version();
cons_show("Using libotr version %s", version);
return TRUE;
#else
cons_show("This version of Profanity has not been built with OTR support enabled");
return TRUE;
#endif
}
gboolean
cmd_otr_policy(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_LIBOTR
if (args[1] == NULL) {
char* policy = prefs_get_string(PREF_OTR_POLICY);
cons_show("OTR policy is now set to: %s", policy);
g_free(policy);
return TRUE;
}
char* choice = args[1];
if ((g_strcmp0(choice, "manual") != 0) && (g_strcmp0(choice, "opportunistic") != 0) && (g_strcmp0(choice, "always") != 0)) {
cons_show("OTR policy can be set to: manual, opportunistic or always.");
return TRUE;
}
char* contact = args[2];
if (contact == NULL) {
prefs_set_string(PREF_OTR_POLICY, choice);
cons_show("OTR policy is now set to: %s", choice);
return TRUE;
}
if (connection_get_status() != JABBER_CONNECTED) {
cons_show("You must be connected to set the OTR policy for a contact.");
return TRUE;
}
char* contact_jid = roster_barejid_from_name(contact);
if (contact_jid == NULL) {
contact_jid = contact;
}
accounts_add_otr_policy(session_get_account_name(), contact_jid, choice);
cons_show("OTR policy for %s set to: %s", contact_jid, choice);
return TRUE;
#else
cons_show("This version of Profanity has not been built with OTR support enabled");
return TRUE;
#endif
}
gboolean
cmd_otr_gen(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_LIBOTR
if (connection_get_status() != JABBER_CONNECTED) {
cons_show("You must be connected with an account to load OTR information.");
return TRUE;
}
ProfAccount* account = accounts_get_account(session_get_account_name());
otr_keygen(account);
account_free(account);
return TRUE;
#else
cons_show("This version of Profanity has not been built with OTR support enabled");
return TRUE;
#endif
}
gboolean
cmd_otr_myfp(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_LIBOTR
if (connection_get_status() != JABBER_CONNECTED) {
cons_show("You must be connected with an account to load OTR information.");
return TRUE;
}
if (!otr_key_loaded()) {
win_println(window, THEME_DEFAULT, "!", "You have not generated or loaded a private key, use '/otr gen'");
return TRUE;
}
char* fingerprint = otr_get_my_fingerprint();
win_println(window, THEME_DEFAULT, "!", "Your OTR fingerprint: %s", fingerprint);
free(fingerprint);
return TRUE;
#else
cons_show("This version of Profanity has not been built with OTR support enabled");
return TRUE;
#endif
}
gboolean
cmd_otr_theirfp(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_LIBOTR
if (connection_get_status() != JABBER_CONNECTED) {
cons_show("You must be connected with an account to load OTR information.");
return TRUE;
}
if (window->type != WIN_CHAT) {
win_println(window, THEME_DEFAULT, "-", "You must be in a regular chat window to view a recipient's fingerprint.");
return TRUE;
}
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
if (chatwin->is_otr == FALSE) {
win_println(window, THEME_DEFAULT, "!", "You are not currently in an OTR session.");
return TRUE;
}
char* fingerprint = otr_get_their_fingerprint(chatwin->barejid);
win_println(window, THEME_DEFAULT, "!", "%s's OTR fingerprint: %s", chatwin->barejid, fingerprint);
free(fingerprint);
return TRUE;
#else
cons_show("This version of Profanity has not been built with OTR support enabled");
return TRUE;
#endif
}
gboolean
cmd_otr_start(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_LIBOTR
if (connection_get_status() != JABBER_CONNECTED) {
cons_show("You must be connected with an account to load OTR information.");
return TRUE;
}
// recipient supplied
if (args[1]) {
char* contact = args[1];
char* barejid = roster_barejid_from_name(contact);
if (barejid == NULL) {
barejid = contact;
}
ProfChatWin* chatwin = wins_get_chat(barejid);
if (!chatwin) {
chatwin = chatwin_new(barejid);
}
ui_focus_win((ProfWin*)chatwin);
if (chatwin->pgp_send) {
win_println(window, THEME_DEFAULT, "!", "You must disable PGP encryption before starting an OTR session.");
return TRUE;
}
if (chatwin->is_omemo) {
win_println(window, THEME_DEFAULT, "!", "You must disable OMEMO before starting an OTR session.");
return TRUE;
}
if (chatwin->is_otr) {
win_println(window, THEME_DEFAULT, "!", "You are already in an OTR session.");
return TRUE;
}
if (!otr_key_loaded()) {
win_println(window, THEME_DEFAULT, "!", "You have not generated or loaded a private key, use '/otr gen'");
return TRUE;
}
if (!otr_is_secure(barejid)) {
char* otr_query_message = otr_start_query();
char* id = message_send_chat_otr(barejid, otr_query_message, FALSE, NULL);
free(id);
return TRUE;
}
chatwin_otr_secured(chatwin, otr_is_trusted(barejid));
return TRUE;
// no recipient, use current chat
} else {
if (window->type != WIN_CHAT) {
win_println(window, THEME_DEFAULT, "-", "You must be in a regular chat window to start an OTR session.");
return TRUE;
}
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
if (chatwin->pgp_send) {
win_println(window, THEME_DEFAULT, "!", "You must disable PGP encryption before starting an OTR session.");
return TRUE;
}
if (chatwin->is_otr) {
win_println(window, THEME_DEFAULT, "!", "You are already in an OTR session.");
return TRUE;
}
if (!otr_key_loaded()) {
win_println(window, THEME_DEFAULT, "!", "You have not generated or loaded a private key, use '/otr gen'");
return TRUE;
}
char* otr_query_message = otr_start_query();
char* id = message_send_chat_otr(chatwin->barejid, otr_query_message, FALSE, NULL);
free(id);
return TRUE;
}
#else
cons_show("This version of Profanity has not been built with OTR support enabled");
return TRUE;
#endif
}
gboolean
cmd_otr_end(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_LIBOTR
if (connection_get_status() != JABBER_CONNECTED) {
cons_show("You must be connected with an account to load OTR information.");
return TRUE;
}
if (window->type != WIN_CHAT) {
win_println(window, THEME_DEFAULT, "-", "You must be in a regular chat window to use OTR.");
return TRUE;
}
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
if (chatwin->is_otr == FALSE) {
win_println(window, THEME_DEFAULT, "!", "You are not currently in an OTR session.");
return TRUE;
}
chatwin_otr_unsecured(chatwin);
otr_end_session(chatwin->barejid);
return TRUE;
#else
cons_show("This version of Profanity has not been built with OTR support enabled");
return TRUE;
#endif
}
gboolean
cmd_otr_trust(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_LIBOTR
if (connection_get_status() != JABBER_CONNECTED) {
cons_show("You must be connected with an account to load OTR information.");
return TRUE;
}
if (window->type != WIN_CHAT) {
win_println(window, THEME_DEFAULT, "-", "You must be in an OTR session to trust a recipient.");
return TRUE;
}
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
if (chatwin->is_otr == FALSE) {
win_println(window, THEME_DEFAULT, "!", "You are not currently in an OTR session.");
return TRUE;
}
chatwin_otr_trust(chatwin);
otr_trust(chatwin->barejid);
return TRUE;
#else
cons_show("This version of Profanity has not been built with OTR support enabled");
return TRUE;
#endif
}
gboolean
cmd_otr_untrust(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_LIBOTR
if (connection_get_status() != JABBER_CONNECTED) {
cons_show("You must be connected with an account to load OTR information.");
return TRUE;
}
if (window->type != WIN_CHAT) {
win_println(window, THEME_DEFAULT, "-", "You must be in an OTR session to untrust a recipient.");
return TRUE;
}
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
if (chatwin->is_otr == FALSE) {
win_println(window, THEME_DEFAULT, "!", "You are not currently in an OTR session.");
return TRUE;
}
chatwin_otr_untrust(chatwin);
otr_untrust(chatwin->barejid);
return TRUE;
#else
cons_show("This version of Profanity has not been built with OTR support enabled");
return TRUE;
#endif
}
gboolean
cmd_otr_secret(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_LIBOTR
if (connection_get_status() != JABBER_CONNECTED) {
cons_show("You must be connected with an account to load OTR information.");
return TRUE;
}
if (window->type != WIN_CHAT) {
win_println(window, THEME_DEFAULT, "-", "You must be in an OTR session to trust a recipient.");
return TRUE;
}
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
if (chatwin->is_otr == FALSE) {
win_println(window, THEME_DEFAULT, "!", "You are not currently in an OTR session.");
return TRUE;
}
char* secret = args[1];
if (secret == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
otr_smp_secret(chatwin->barejid, secret);
return TRUE;
#else
cons_show("This version of Profanity has not been built with OTR support enabled");
return TRUE;
#endif
}
gboolean
cmd_otr_question(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_LIBOTR
if (connection_get_status() != JABBER_CONNECTED) {
cons_show("You must be connected with an account to load OTR information.");
return TRUE;
}
char* question = args[1];
char* answer = args[2];
if (question == NULL || answer == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
if (window->type != WIN_CHAT) {
win_println(window, THEME_DEFAULT, "-", "You must be in an OTR session to trust a recipient.");
return TRUE;
}
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
if (chatwin->is_otr == FALSE) {
win_println(window, THEME_DEFAULT, "!", "You are not currently in an OTR session.");
return TRUE;
}
otr_smp_question(chatwin->barejid, question, answer);
return TRUE;
#else
cons_show("This version of Profanity has not been built with OTR support enabled");
return TRUE;
#endif
}
gboolean
cmd_otr_answer(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_LIBOTR
if (connection_get_status() != JABBER_CONNECTED) {
cons_show("You must be connected with an account to load OTR information.");
return TRUE;
}
if (window->type != WIN_CHAT) {
win_println(window, THEME_DEFAULT, "-", "You must be in an OTR session to trust a recipient.");
return TRUE;
}
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
if (chatwin->is_otr == FALSE) {
win_println(window, THEME_DEFAULT, "!", "You are not currently in an OTR session.");
return TRUE;
}
char* answer = args[1];
if (answer == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
otr_smp_answer(chatwin->barejid, answer);
return TRUE;
#else
cons_show("This version of Profanity has not been built with OTR support enabled");
return TRUE;
#endif
}
gboolean
cmd_otr_sendfile(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_LIBOTR
_cmd_set_boolean_preference(args[1], command, "Sending unencrypted files in an OTR session via /sendfile", PREF_OTR_SENDFILE);
return TRUE;
#else
cons_show("This version of Profanity has not been built with OTR support enabled");
return TRUE;
#endif
}
gboolean
cmd_command_list(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
if (connection_supports(XMPP_FEATURE_COMMANDS) == FALSE) {
cons_show("Server does not support ad hoc commands (%s).", XMPP_FEATURE_COMMANDS);
return TRUE;
}
char* jid = args[1];
if (jid == NULL) {
switch (window->type) {
case WIN_MUC:
{
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
jid = mucwin->roomjid;
break;
}
case WIN_CHAT:
{
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
jid = chatwin->barejid;
break;
}
case WIN_PRIVATE:
{
ProfPrivateWin* privatewin = (ProfPrivateWin*)window;
assert(privatewin->memcheck == PROFPRIVATEWIN_MEMCHECK);
jid = privatewin->fulljid;
break;
}
case WIN_CONSOLE:
{
jid = connection_get_domain();
break;
}
default:
cons_show("Cannot send ad hoc commands.");
return TRUE;
}
}
iq_command_list(jid);
cons_show("List available ad hoc commands");
return TRUE;
}
gboolean
cmd_command_exec(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
if (connection_supports(XMPP_FEATURE_COMMANDS) == FALSE) {
cons_show("Server does not support ad hoc commands (%s).", XMPP_FEATURE_COMMANDS);
return TRUE;
}
if (args[1] == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
char* jid = args[2];
if (jid == NULL) {
switch (window->type) {
case WIN_MUC:
{
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
jid = mucwin->roomjid;
break;
}
case WIN_CHAT:
{
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
jid = chatwin->barejid;
break;
}
case WIN_PRIVATE:
{
ProfPrivateWin* privatewin = (ProfPrivateWin*)window;
assert(privatewin->memcheck == PROFPRIVATEWIN_MEMCHECK);
jid = privatewin->fulljid;
break;
}
case WIN_CONSOLE:
{
jid = connection_get_domain();
break;
}
default:
cons_show("Cannot send ad hoc commands.");
return TRUE;
}
}
iq_command_exec(jid, args[1]);
cons_show("Execute %s...", args[1]);
return TRUE;
}
static gboolean
_cmd_execute(ProfWin* window, const char* const command, const char* const inp)
{
if (g_str_has_prefix(command, "/field") && window->type == WIN_CONFIG) {
gboolean result = FALSE;
gchar** args = parse_args_with_freetext(inp, 1, 2, &result);
if (!result) {
win_println(window, THEME_DEFAULT, "!", "Invalid command, see /form help");
result = TRUE;
} else {
gchar** tokens = g_strsplit(inp, " ", 2);
char* field = tokens[0] + 1;
result = cmd_form_field(window, field, args);
g_strfreev(tokens);
}
g_strfreev(args);
return result;
}
Command* cmd = cmd_get(command);
gboolean result = FALSE;
if (cmd) {
gchar** args = cmd->parser(inp, cmd->min_args, cmd->max_args, &result);
if (result == FALSE) {
ui_invalid_command_usage(cmd->cmd, cmd->setting_func);
return TRUE;
}
if (args[0] && cmd->sub_funcs[0][0]) {
int i = 0;
while (cmd->sub_funcs[i][0]) {
if (g_strcmp0(args[0], (char*)cmd->sub_funcs[i][0]) == 0) {
gboolean (*func)(ProfWin * window, const char* const command, gchar** args) = cmd->sub_funcs[i][1];
gboolean result = func(window, command, args);
g_strfreev(args);
return result;
}
i++;
}
}
if (!cmd->func) {
ui_invalid_command_usage(cmd->cmd, cmd->setting_func);
return TRUE;
}
gboolean result = cmd->func(window, command, args);
g_strfreev(args);
return result;
} else if (plugins_run_command(inp)) {
return TRUE;
} else {
gboolean ran_alias = FALSE;
gboolean alias_result = _cmd_execute_alias(window, inp, &ran_alias);
if (!ran_alias) {
return _cmd_execute_default(window, inp);
} else {
return alias_result;
}
}
}
static gboolean
_cmd_execute_default(ProfWin* window, const char* inp)
{
// handle escaped commands - treat as normal message
if (g_str_has_prefix(inp, "//")) {
inp++;
// handle unknown commands
} else if ((inp[0] == '/') && (!g_str_has_prefix(inp, "/me "))) {
cons_show("Unknown command: %s", inp);
cons_alert(NULL);
return TRUE;
}
// handle non commands in non chat or plugin windows
if (window->type != WIN_CHAT && window->type != WIN_MUC && window->type != WIN_PRIVATE && window->type != WIN_PLUGIN && window->type != WIN_XML) {
cons_show("Unknown command: %s", inp);
cons_alert(NULL);
return TRUE;
}
// handle plugin window
if (window->type == WIN_PLUGIN) {
ProfPluginWin* pluginwin = (ProfPluginWin*)window;
plugins_win_process_line(pluginwin->tag, inp);
return TRUE;
}
jabber_conn_status_t status = connection_get_status();
if (status != JABBER_CONNECTED) {
win_println(window, THEME_DEFAULT, "-", "You are not currently connected.");
return TRUE;
}
switch (window->type) {
case WIN_CHAT:
{
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
cl_ev_send_msg(chatwin, inp, NULL);
break;
}
case WIN_PRIVATE:
{
ProfPrivateWin* privatewin = (ProfPrivateWin*)window;
assert(privatewin->memcheck == PROFPRIVATEWIN_MEMCHECK);
cl_ev_send_priv_msg(privatewin, inp, NULL);
break;
}
case WIN_MUC:
{
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
cl_ev_send_muc_msg(mucwin, inp, NULL);
break;
}
case WIN_XML:
{
connection_send_stanza(inp);
break;
}
default:
break;
}
return TRUE;
}
static gboolean
_cmd_execute_alias(ProfWin* window, const char* const inp, gboolean* ran)
{
if (inp[0] != '/') {
*ran = FALSE;
return TRUE;
}
char* alias = strdup(inp + 1);
char* value = prefs_get_alias(alias);
free(alias);
if (value) {
*ran = TRUE;
gboolean result = cmd_process_input(window, value);
g_free(value);
return result;
}
*ran = FALSE;
return TRUE;
}
// helper function for status change commands
static void
_update_presence(const resource_presence_t resource_presence,
const char* const show, gchar** args)
{
char* msg = NULL;
int num_args = g_strv_length(args);
// if no message, use status as message
if (num_args == 2) {
msg = args[1];
} else {
msg = args[2];
}
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
} else {
connection_set_presence_msg(msg);
cl_ev_presence_send(resource_presence, 0);
ui_update_presence(resource_presence, msg, show);
}
}
// helper function for boolean preference commands
static void
_cmd_set_boolean_preference(gchar* arg, const char* const command,
const char* const display, preference_t pref)
{
if (arg == NULL) {
cons_bad_cmd_usage(command);
} else if (strcmp(arg, "on") == 0) {
GString* enabled = g_string_new(display);
g_string_append(enabled, " enabled.");
cons_show(enabled->str);
prefs_set_boolean(pref, TRUE);
g_string_free(enabled, TRUE);
} else if (strcmp(arg, "off") == 0) {
GString* disabled = g_string_new(display);
g_string_append(disabled, " disabled.");
cons_show(disabled->str);
prefs_set_boolean(pref, FALSE);
g_string_free(disabled, TRUE);
} else {
cons_bad_cmd_usage(command);
}
}
gboolean
cmd_omemo_gen(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_OMEMO
if (connection_get_status() != JABBER_CONNECTED) {
cons_show("You must be connected with an account to initialize OMEMO.");
return TRUE;
}
if (omemo_loaded()) {
cons_show("OMEMO crytographic materials have already been generated.");
return TRUE;
}
cons_show("Generating OMEMO crytographic materials, it may take a while...");
ui_update();
ProfAccount* account = accounts_get_account(session_get_account_name());
omemo_generate_crypto_materials(account);
cons_show("OMEMO crytographic materials generated. Your Device ID is %d.", omemo_device_id());
return TRUE;
#else
cons_show("This version of Profanity has not been built with OMEMO support enabled");
return TRUE;
#endif
}
gboolean
cmd_omemo_start(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_OMEMO
if (connection_get_status() != JABBER_CONNECTED) {
cons_show("You must be connected with an account to load OMEMO information.");
return TRUE;
}
if (!omemo_loaded()) {
win_println(window, THEME_DEFAULT, "!", "You have not generated or loaded a cryptographic materials, use '/omemo gen'");
return TRUE;
}
ProfChatWin* chatwin = NULL;
// recipient supplied
if (args[1]) {
char* contact = args[1];
char* barejid = roster_barejid_from_name(contact);
if (barejid == NULL) {
barejid = contact;
}
chatwin = wins_get_chat(barejid);
if (!chatwin) {
chatwin = chatwin_new(barejid);
}
ui_focus_win((ProfWin*)chatwin);
} else {
if (window->type == WIN_CHAT) {
chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
}
}
if (chatwin) {
if (chatwin->pgp_send) {
win_println((ProfWin*)chatwin, THEME_DEFAULT, "!", "You must disable PGP encryption before starting an OMEMO session.");
return TRUE;
}
if (chatwin->is_otr) {
win_println((ProfWin*)chatwin, THEME_DEFAULT, "!", "You must disable OTR encryption before starting an OMEMO session.");
return TRUE;
}
if (chatwin->is_omemo) {
win_println((ProfWin*)chatwin, THEME_DEFAULT, "!", "You are already in an OMEMO session.");
return TRUE;
}
accounts_add_omemo_state(session_get_account_name(), chatwin->barejid, TRUE);
omemo_start_session(chatwin->barejid);
chatwin->is_omemo = TRUE;
} else if (window->type == WIN_MUC) {
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
if (muc_anonymity_type(mucwin->roomjid) == MUC_ANONYMITY_TYPE_NONANONYMOUS
&& muc_member_type(mucwin->roomjid) == MUC_MEMBER_TYPE_MEMBERS_ONLY) {
accounts_add_omemo_state(session_get_account_name(), mucwin->roomjid, TRUE);
omemo_start_muc_sessions(mucwin->roomjid);
mucwin->is_omemo = TRUE;
} else {
win_println(window, THEME_DEFAULT, "!", "MUC must be non-anonymous (i.e. be configured to present real jid to anyone) and members-only in order to support OMEMO.");
}
} else {
win_println(window, THEME_DEFAULT, "-", "You must be in a regular chat window to start an OMEMO session.");
}
return TRUE;
#else
cons_show("This version of Profanity has not been built with OMEMO support enabled");
return TRUE;
#endif
}
gboolean
cmd_omemo_trust_mode(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_OMEMO
if (!args[1]) {
cons_show("Current trust mode is %s", prefs_get_string(PREF_OMEMO_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("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("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("ALL OMEMO fingerprints will be trusted automatically");
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
prefs_set_string(PREF_OMEMO_TRUST_MODE, args[1]);
#else
cons_show("This version of Profanity has not been built with OMEMO support enabled");
#endif
return TRUE;
}
gboolean
cmd_omemo_char(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_OMEMO
if (args[1] == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
} else if (g_utf8_strlen(args[1], 4) == 1) {
if (prefs_set_omemo_char(args[1])) {
cons_show("OMEMO char set to %s.", args[1]);
} else {
cons_show_error("Could not set OMEMO char: %s.", args[1]);
}
return TRUE;
}
cons_bad_cmd_usage(command);
#else
cons_show("This version of Profanity has not been built with OMEMO support enabled");
#endif
return TRUE;
}
gboolean
cmd_omemo_log(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_OMEMO
char* choice = args[1];
if (g_strcmp0(choice, "on") == 0) {
prefs_set_string(PREF_OMEMO_LOG, "on");
cons_show("OMEMO messages will be logged as plaintext.");
if (!prefs_get_boolean(PREF_CHLOG)) {
cons_show("Chat logging is currently disabled, use '/logging chat on' to enable.");
}
} else if (g_strcmp0(choice, "off") == 0) {
prefs_set_string(PREF_OMEMO_LOG, "off");
cons_show("OMEMO message logging disabled.");
} else if (g_strcmp0(choice, "redact") == 0) {
prefs_set_string(PREF_OMEMO_LOG, "redact");
cons_show("OMEMO messages will be logged as '[redacted]'.");
if (!prefs_get_boolean(PREF_CHLOG)) {
cons_show("Chat logging is currently disabled, use '/logging chat on' to enable.");
}
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
#else
cons_show("This version of Profanity has not been built with OMEMO support enabled");
return TRUE;
#endif
}
gboolean
cmd_omemo_end(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_OMEMO
if (connection_get_status() != JABBER_CONNECTED) {
cons_show("You must be connected with an account to load OMEMO information.");
return TRUE;
}
if (window->type == WIN_CHAT) {
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
if (!chatwin->is_omemo) {
win_println(window, THEME_DEFAULT, "!", "You are not currently in an OMEMO session.");
return TRUE;
}
chatwin->is_omemo = FALSE;
accounts_add_omemo_state(session_get_account_name(), chatwin->barejid, FALSE);
} else if (window->type == WIN_MUC) {
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
if (!mucwin->is_omemo) {
win_println(window, THEME_DEFAULT, "!", "You are not currently in an OMEMO session.");
return TRUE;
}
mucwin->is_omemo = FALSE;
accounts_add_omemo_state(session_get_account_name(), mucwin->roomjid, FALSE);
} else {
win_println(window, THEME_DEFAULT, "-", "You must be in a regular chat window to start an OMEMO session.");
return TRUE;
}
return TRUE;
#else
cons_show("This version of Profanity has not been built with OMEMO support enabled");
return TRUE;
#endif
}
gboolean
cmd_omemo_fingerprint(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_OMEMO
if (connection_get_status() != JABBER_CONNECTED) {
cons_show("You must be connected with an account to load OMEMO information.");
return TRUE;
}
if (!omemo_loaded()) {
win_println(window, THEME_DEFAULT, "!", "You have not generated or loaded a cryptographic materials, use '/omemo gen'");
return TRUE;
}
Jid* jid;
if (!args[1]) {
if (window->type == WIN_CONSOLE) {
char* fingerprint = omemo_own_fingerprint(TRUE);
cons_show("Your OMEMO fingerprint: %s", fingerprint);
free(fingerprint);
jid = jid_create(connection_get_fulljid());
} else if (window->type == WIN_CHAT) {
ProfChatWin* chatwin = (ProfChatWin*)window;
jid = jid_create(chatwin->barejid);
} else {
win_println(window, THEME_DEFAULT, "-", "You must be in a regular chat window to print fingerprint without providing the contact.");
return TRUE;
}
} else {
char* barejid = roster_barejid_from_name(args[1]);
if (barejid) {
jid = jid_create(barejid);
} else {
jid = jid_create(args[1]);
if (!jid) {
cons_show("%s is not a valid jid", args[1]);
return TRUE;
}
}
}
GList* fingerprints = omemo_known_device_identities(jid->barejid);
if (!fingerprints) {
win_println(window, THEME_DEFAULT, "-", "There is no known fingerprints for %s", jid->barejid);
return TRUE;
}
for (GList* fingerprint = fingerprints; fingerprint != NULL; fingerprint = fingerprint->next) {
char* formatted_fingerprint = omemo_format_fingerprint(fingerprint->data);
gboolean trusted = omemo_is_trusted_identity(jid->barejid, fingerprint->data);
win_println(window, THEME_DEFAULT, "-", "%s's OMEMO fingerprint: %s%s", jid->barejid, formatted_fingerprint, trusted ? " (trusted)" : "");
free(formatted_fingerprint);
}
g_list_free(fingerprints);
win_println(window, THEME_DEFAULT, "-", "You can trust it with '/omemo trust <fingerprint>'");
win_println(window, THEME_DEFAULT, "-", "You can untrust it with '/omemo untrust <fingerprint>'");
return TRUE;
#else
cons_show("This version of Profanity has not been built with OMEMO support enabled");
return TRUE;
#endif
}
gboolean
cmd_omemo_trust(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_OMEMO
if (connection_get_status() != JABBER_CONNECTED) {
cons_show("You must be connected with an account to load OMEMO information.");
return TRUE;
}
if (!args[1]) {
cons_bad_cmd_usage(command);
return TRUE;
}
if (!omemo_loaded()) {
win_println(window, THEME_DEFAULT, "!", "You have not generated or loaded a cryptographic materials, use '/omemo gen'");
return TRUE;
}
char* fingerprint;
char* barejid;
/* Contact not provided */
if (!args[2]) {
fingerprint = args[1];
if (window->type != WIN_CHAT) {
win_println(window, THEME_DEFAULT, "-", "You must be in a regular chat window to trust a device without providing the contact.");
return TRUE;
}
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
barejid = chatwin->barejid;
} else {
fingerprint = args[2];
char* contact = args[1];
barejid = roster_barejid_from_name(contact);
if (barejid == NULL) {
barejid = contact;
}
}
omemo_trust(barejid, fingerprint);
char* unformatted_fingerprint = malloc(strlen(fingerprint));
int i;
int j;
for (i = 0, j = 0; fingerprint[i] != '\0'; i++) {
if (!g_ascii_isxdigit(fingerprint[i])) {
continue;
}
unformatted_fingerprint[j++] = fingerprint[i];
}
unformatted_fingerprint[j] = '\0';
gboolean trusted = omemo_is_trusted_identity(barejid, unformatted_fingerprint);
win_println(window, THEME_DEFAULT, "-", "%s's OMEMO fingerprint: %s%s", barejid, fingerprint, trusted ? " (trusted)" : "");
free(unformatted_fingerprint);
return TRUE;
#else
cons_show("This version of Profanity has not been built with OMEMO support enabled");
return TRUE;
#endif
}
gboolean
cmd_omemo_untrust(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_OMEMO
if (connection_get_status() != JABBER_CONNECTED) {
cons_show("You must be connected with an account to load OMEMO information.");
return TRUE;
}
if (!args[1]) {
cons_bad_cmd_usage(command);
return TRUE;
}
if (!omemo_loaded()) {
win_println(window, THEME_DEFAULT, "!", "You have not generated or loaded a cryptographic materials, use '/omemo gen'");
return TRUE;
}
char* fingerprint;
char* barejid;
/* Contact not provided */
if (!args[2]) {
fingerprint = args[1];
if (window->type != WIN_CHAT) {
win_println(window, THEME_DEFAULT, "-", "You must be in a regular chat window to trust a device without providing the contact.");
return TRUE;
}
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
barejid = chatwin->barejid;
} else {
fingerprint = args[2];
char* contact = args[1];
barejid = roster_barejid_from_name(contact);
if (barejid == NULL) {
barejid = contact;
}
}
omemo_untrust(barejid, fingerprint);
char* unformatted_fingerprint = malloc(strlen(fingerprint));
int i, j;
for (i = 0, j = 0; fingerprint[i] != '\0'; i++) {
if (!g_ascii_isxdigit(fingerprint[i])) {
continue;
}
unformatted_fingerprint[j++] = fingerprint[i];
}
unformatted_fingerprint[j] = '\0';
gboolean trusted = omemo_is_trusted_identity(barejid, unformatted_fingerprint);
win_println(window, THEME_DEFAULT, "-", "%s's OMEMO fingerprint: %s%s", barejid, fingerprint, trusted ? " (trusted)" : "");
free(unformatted_fingerprint);
return TRUE;
#else
cons_show("This version of Profanity has not been built with OMEMO support enabled");
return TRUE;
#endif
}
gboolean
cmd_omemo_clear_device_list(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_OMEMO
if (connection_get_status() != JABBER_CONNECTED) {
cons_show("You must be connected with an account to initialize OMEMO.");
return TRUE;
}
omemo_devicelist_publish(NULL);
cons_show("Cleared OMEMO device list");
return TRUE;
#else
cons_show("This version of Profanity has not been built with OMEMO support enabled");
return TRUE;
#endif
}
gboolean
cmd_omemo_policy(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_OMEMO
if (args[1] == NULL) {
char* policy = prefs_get_string(PREF_OMEMO_POLICY);
cons_show("OMEMO policy is now set to: %s", policy);
g_free(policy);
return TRUE;
}
char* choice = args[1];
if ((g_strcmp0(choice, "manual") != 0) && (g_strcmp0(choice, "automatic") != 0) && (g_strcmp0(choice, "always") != 0)) {
cons_show("OMEMO policy can be set to: manual, automatic or always.");
return TRUE;
}
prefs_set_string(PREF_OMEMO_POLICY, choice);
cons_show("OMEMO policy is now set to: %s", choice);
return TRUE;
#else
cons_show("This version of Profanity has not been built with OMEMO support enabled");
return TRUE;
#endif
}
gboolean
cmd_save(ProfWin* window, const char* const command, gchar** args)
{
log_info("Saving preferences to configuration file");
cons_show("Saving preferences.");
prefs_save();
return TRUE;
}
gboolean
cmd_reload(ProfWin* window, const char* const command, gchar** args)
{
log_info("Reloading preferences");
cons_show("Reloading preferences.");
prefs_reload();
return TRUE;
}
gboolean
cmd_paste(ProfWin* window, const char* const command, gchar** args)
{
#ifdef HAVE_GTK
char* clipboard_buffer = clipboard_get();
if (clipboard_buffer) {
switch (window->type) {
case WIN_MUC:
{
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
cl_ev_send_muc_msg(mucwin, clipboard_buffer, NULL);
break;
}
case WIN_CHAT:
{
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
cl_ev_send_msg(chatwin, clipboard_buffer, NULL);
break;
}
case WIN_PRIVATE:
{
ProfPrivateWin* privatewin = (ProfPrivateWin*)window;
assert(privatewin->memcheck == PROFPRIVATEWIN_MEMCHECK);
cl_ev_send_priv_msg(privatewin, clipboard_buffer, NULL);
break;
}
case WIN_CONSOLE:
case WIN_XML:
default:
cons_bad_cmd_usage(command);
break;
}
free(clipboard_buffer);
}
#else
cons_show("This version of Profanity has not been built with GTK support enabled. It is needed for the clipboard feature to work.");
#endif
return TRUE;
}
gboolean
cmd_color(ProfWin* window, const char* const command, gchar** args)
{
if (g_strcmp0(args[0], "on") == 0) {
prefs_set_string(PREF_COLOR_NICK, "true");
} else if (g_strcmp0(args[0], "off") == 0) {
prefs_set_string(PREF_COLOR_NICK, "false");
} else if (g_strcmp0(args[0], "redgreen") == 0) {
prefs_set_string(PREF_COLOR_NICK, "redgreen");
} else if (g_strcmp0(args[0], "blue") == 0) {
prefs_set_string(PREF_COLOR_NICK, "blue");
} else if (g_strcmp0(args[0], "own") == 0) {
if (g_strcmp0(args[1], "on") == 0) {
_cmd_set_boolean_preference(args[1], command, "Color generation for own nick", PREF_COLOR_NICK_OWN);
}
} else {
cons_bad_cmd_usage(command);
return TRUE;
}
cons_show("Consistent color generation for nicks set to: %s", args[0]);
char* theme = prefs_get_string(PREF_THEME);
if (theme) {
gboolean res = theme_load(theme, false);
if (res) {
cons_show("Theme reloaded: %s", theme);
} else {
theme_load("default", false);
}
g_free(theme);
}
return TRUE;
}
gboolean
cmd_avatar(ProfWin* window, const char* const command, gchar** args)
{
if (args[1] == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
if (g_strcmp0(args[0], "get") == 0) {
avatar_get_by_nick(args[1], false);
} else if (g_strcmp0(args[0], "open") == 0) {
avatar_get_by_nick(args[1], true);
} else if (g_strcmp0(args[0], "cmd") == 0) {
prefs_set_string(PREF_AVATAR_CMD, args[1]);
cons_show("Avatar cmd set to: %s", args[1]);
}
return TRUE;
}
gboolean
cmd_os(ProfWin* window, const char* const command, gchar** args)
{
_cmd_set_boolean_preference(args[0], command, "Revealing OS name", PREF_REVEAL_OS);
return TRUE;
}
gboolean
cmd_correction(ProfWin* window, const char* const command, gchar** args)
{
// enable/disable
if (g_strcmp0(args[0], "on") == 0) {
_cmd_set_boolean_preference(args[0], command, "Last Message Correction", PREF_CORRECTION_ALLOW);
caps_add_feature(XMPP_FEATURE_LAST_MESSAGE_CORRECTION);
return TRUE;
} else if (g_strcmp0(args[0], "off") == 0) {
_cmd_set_boolean_preference(args[0], command, "Last Message Correction", PREF_CORRECTION_ALLOW);
caps_remove_feature(XMPP_FEATURE_LAST_MESSAGE_CORRECTION);
return TRUE;
}
// char
if (g_strcmp0(args[0], "char") == 0) {
if (args[1] == NULL) {
cons_bad_cmd_usage(command);
} else if (strlen(args[1]) != 1) {
cons_bad_cmd_usage(command);
} else {
prefs_set_correction_char(args[1][0]);
cons_show("LMC char set to %c.", args[1][0]);
}
}
return TRUE;
}
gboolean
_can_correct(ProfWin* window)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are currently not connected.");
return FALSE;
} else if (!prefs_get_boolean(PREF_CORRECTION_ALLOW)) {
win_println(window, THEME_DEFAULT, "!", "Corrections not enabled. See /help correction.");
return FALSE;
} else if (window->type == WIN_CHAT) {
ProfChatWin* chatwin = (ProfChatWin*)window;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);
if (chatwin->last_msg_id == NULL || chatwin->last_message == NULL) {
win_println(window, THEME_DEFAULT, "!", "No last message to correct.");
return FALSE;
}
} else if (window->type == WIN_MUC) {
ProfMucWin* mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
if (mucwin->last_msg_id == NULL || mucwin->last_message == NULL) {
win_println(window, THEME_DEFAULT, "!", "No last message to correct.");
return FALSE;
}
} else {
win_println(window, THEME_DEFAULT, "!", "Command /correct-editor only valid in regular chat windows.");
return FALSE;
}
return TRUE;
}
gboolean
cmd_correct(ProfWin* window, const char* const command, gchar** args)
{
if (!_can_correct(window)) {
return TRUE;
}
if (window->type == WIN_CHAT) {
ProfChatWin* chatwin = (ProfChatWin*)window;
// send message again, with replace flag
gchar* message = g_strjoinv(" ", args);
cl_ev_send_msg_correct(chatwin, message, FALSE, TRUE);
free(message);
} else if (window->type == WIN_MUC) {
ProfMucWin* mucwin = (ProfMucWin*)window;
// send message again, with replace flag
gchar* message = g_strjoinv(" ", args);
cl_ev_send_muc_msg_corrected(mucwin, message, FALSE, TRUE);
free(message);
}
return TRUE;
}
gboolean
cmd_slashguard(ProfWin* window, const char* const command, gchar** args)
{
if (args[0] == NULL) {
return FALSE;
}
_cmd_set_boolean_preference(args[0], command, "Slashguard", PREF_SLASH_GUARD);
return TRUE;
}
#ifdef HAVE_OMEMO
void
_url_aesgcm_method(ProfWin* window, const char* cmd_template, const char* url, const char* filename)
{
AESGCMDownload* download = malloc(sizeof(AESGCMDownload));
download->window = window;
download->url = strdup(url);
download->filename = strdup(filename);
if (cmd_template != NULL) {
download->cmd_template = strdup(cmd_template);
} else {
download->cmd_template = NULL;
}
pthread_create(&(download->worker), NULL, &aesgcm_file_get, download);
aesgcm_download_add_download(download);
}
#endif
void
_url_http_method(ProfWin* window, const char* cmd_template, const char* url, const char* filename)
{
HTTPDownload* download = malloc(sizeof(HTTPDownload));
download->window = window;
download->url = strdup(url);
download->filename = strdup(filename);
if (cmd_template != NULL) {
download->cmd_template = strdup(cmd_template);
} else {
download->cmd_template = NULL;
}
pthread_create(&(download->worker), NULL, &http_file_get, download);
http_download_add_download(download);
}
void
_url_external_method(const char* cmd_template, const char* url, const char* filename)
{
gchar** argv = format_call_external_argv(cmd_template, url, filename);
if (!call_external(argv, NULL, NULL)) {
cons_show_error("Unable to call external executable for url: check the logs for more information.");
} else {
cons_show("URL '%s' has been called with '%s'.", url, cmd_template);
}
g_strfreev(argv);
}
gboolean
cmd_url_open(ProfWin* window, const char* const command, gchar** args)
{
if (window->type != WIN_CHAT && window->type != WIN_MUC && window->type != WIN_PRIVATE) {
cons_show_error("url open not supported in this window");
return TRUE;
}
gchar* url = args[1];
if (url == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
gchar* scheme = NULL;
char* cmd_template = NULL;
char* filename = NULL;
scheme = g_uri_parse_scheme(url);
if (scheme == NULL) {
cons_show_error("URL '%s' is not valid.", args[1]);
goto out;
}
cmd_template = prefs_get_string(PREF_URL_OPEN_CMD);
if (cmd_template == NULL) {
cons_show_error("No default `url open` command found in executables preferences.");
goto out;
}
#ifdef HAVE_OMEMO
// OMEMO URLs (aesgcm://) must be saved and decrypted before being opened.
if (g_strcmp0(scheme, "aesgcm") == 0) {
// Ensure that the downloads directory exists for saving cleartexts.
gchar* downloads_dir = files_get_data_path(DIR_DOWNLOADS);
if (g_mkdir_with_parents(downloads_dir, S_IRWXU) != 0) {
cons_show_error("Failed to create download directory "
"at '%s' with error '%s'",
downloads_dir, strerror(errno));
g_free(downloads_dir);
goto out;
}
// Generate an unique filename from the URL that should be stored in the
// downloads directory.
filename = unique_filename_from_url(url, downloads_dir);
g_free(downloads_dir);
// Download, decrypt and open the cleartext version of the AESGCM
// encrypted file.
_url_aesgcm_method(window, cmd_template, url, filename);
goto out;
}
#endif
_url_external_method(cmd_template, url, NULL);
out:
free(cmd_template);
free(filename);
g_free(scheme);
return TRUE;
}
gboolean
cmd_url_save(ProfWin* window, const char* const command, gchar** args)
{
if (window->type != WIN_CHAT && window->type != WIN_MUC && window->type != WIN_PRIVATE) {
cons_show_error("`/url save` is not supported in this window.");
return TRUE;
}
if (args[1] == NULL) {
cons_bad_cmd_usage(command);
return TRUE;
}
gchar* url = args[1];
gchar* path = g_strdup(args[2]);
gchar* scheme = NULL;
char* filename = NULL;
char* cmd_template = NULL;
scheme = g_uri_parse_scheme(url);
if (scheme == NULL) {
cons_show_error("URL '%s' is not valid.", args[1]);
goto out;
}
filename = unique_filename_from_url(url, path);
if (filename == NULL) {
cons_show_error("Failed to generate unique filename"
"from URL '%s' for path '%s'",
url, path);
goto out;
}
cmd_template = prefs_get_string(PREF_URL_SAVE_CMD);
if (cmd_template == NULL && (g_strcmp0(scheme, "http") == 0 || g_strcmp0(scheme, "https") == 0)) {
_url_http_method(window, cmd_template, url, filename);
#ifdef HAVE_OMEMO
} else if (g_strcmp0(scheme, "aesgcm") == 0) {
_url_aesgcm_method(window, cmd_template, url, filename);
#endif
} else if (cmd_template != NULL) {
_url_external_method(cmd_template, url, filename);
} else {
cons_show_error("No download method defined for the scheme '%s'.", scheme);
}
out:
free(filename);
free(cmd_template);
g_free(scheme);
g_free(path);
return TRUE;
}
gboolean
cmd_executable_avatar(ProfWin* window, const char* const command, gchar** args)
{
prefs_set_string(PREF_AVATAR_CMD, args[1]);
cons_show("`avatar` command set to invoke '%s'", args[1]);
return TRUE;
}
gboolean
cmd_executable_urlopen(ProfWin* window, const char* const command, gchar** args)
{
guint num_args = g_strv_length(args);
if (num_args < 2) {
cons_bad_cmd_usage(command);
return TRUE;
}
if (g_strcmp0(args[1], "set") == 0 && num_args >= 3) {
gchar* str = g_strjoinv(" ", &args[2]);
prefs_set_string(PREF_URL_OPEN_CMD, str);
cons_show("`url open` command set to invoke '%s'", str);
g_free(str);
} else if (g_strcmp0(args[1], "default") == 0) {
prefs_set_string(PREF_URL_OPEN_CMD, NULL);
gchar* def = prefs_get_string(PREF_URL_OPEN_CMD);
cons_show("`url open` command set to invoke %s (default)", def);
g_free(def);
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}
gboolean
cmd_executable_urlsave(ProfWin* window, const char* const command, gchar** args)
{
guint num_args = g_strv_length(args);
if (num_args < 2) {
cons_bad_cmd_usage(command);
return TRUE;
}
if (g_strcmp0(args[1], "set") == 0 && num_args >= 3) {
gchar* str = g_strjoinv(" ", &args[2]);
prefs_set_string(PREF_URL_SAVE_CMD, str);
cons_show("`url save` command set to invoke '%s'", str);
g_free(str);
} else if (g_strcmp0(args[1], "default") == 0) {
prefs_set_string(PREF_URL_SAVE_CMD, NULL);
cons_show("`url save` will use built-in download method (default)");
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}
gboolean
cmd_executable_editor(ProfWin* window, const char* const command, gchar** args)
{
guint num_args = g_strv_length(args);
if (g_strcmp0(args[1], "set") == 0 && num_args >= 3) {
prefs_set_string(PREF_COMPOSE_EDITOR, args[2]);
cons_show("`editor` command set to invoke '%s'", args[2]);
} else {
cons_bad_cmd_usage(command);
}
return TRUE;
}
gboolean
cmd_mam(ProfWin* window, const char* const command, gchar** args)
{
_cmd_set_boolean_preference(args[0], command, "Message Archive Management", PREF_MAM);
return TRUE;
}
gboolean
cmd_change_password(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
char* user = connection_get_user();
char* passwd = ui_ask_password(false);
char* confirm_passwd = ui_ask_password(true);
if (g_strcmp0(passwd, confirm_passwd) == 0) {
iq_register_change_password(user, passwd);
} else {
cons_show("Aborted! The new password and the confirmed password do not match.");
}
free(user);
free(passwd);
free(confirm_passwd);
return TRUE;
}
// Returns true if an error occured
gboolean
_get_message_from_editor(gchar* message, gchar** returned_message)
{
// create editor dir if not present
char* jid = connection_get_barejid();
gchar* path = files_get_account_data_path(DIR_EDITOR, jid);
free(jid);
if (g_mkdir_with_parents(path, S_IRWXU) != 0) {
cons_show_error("Failed to create directory at '%s' with error '%s'", path, strerror(errno));
g_free(path);
return TRUE;
}
// build temp file name. Example: /home/user/.local/share/profanity/editor/jid/compose.md
char* filename = g_strdup_printf("%s/compose.md", path);
g_free(path);
GError* creation_error = NULL;
GFile* file = g_file_new_for_path(filename);
GFileOutputStream* fos = g_file_create(file, G_FILE_CREATE_PRIVATE, NULL, &creation_error);
free(filename);
if (message != NULL && strlen(message) > 0) {
int fd_output_file = open(g_file_get_path(file), O_WRONLY);
if (fd_output_file < 0) {
cons_show_error("Editor: Could not open file '%s': %s", file, strerror(errno));
return TRUE;
}
if (-1 == write(fd_output_file, message, strlen(message))) {
cons_show_error("Editor: failed to write '%s' to file: %s", message, strerror(errno));
return TRUE;
}
close(fd_output_file);
}
if (creation_error) {
cons_show_error("Editor: could not create temp file");
return TRUE;
}
g_object_unref(fos);
char* editor = prefs_get_string(PREF_COMPOSE_EDITOR);
// Fork / exec
pid_t pid = fork();
if (pid == 0) {
int x = execlp(editor, editor, g_file_get_path(file), (char*)NULL);
if (x == -1) {
cons_show_error("Editor:Failed to exec %s", editor);
}
_exit(EXIT_FAILURE);
} else {
if (pid == -1) {
return TRUE;
}
int status = 0;
waitpid(pid, &status, 0);
int fd_input_file = open(g_file_get_path(file), O_RDONLY);
const size_t COUNT = 8192;
char buf[COUNT];
ssize_t size_read = read(fd_input_file, buf, COUNT);
if (size_read > 0 && size_read <= COUNT) {
buf[size_read - 1] = '\0';
GString* text = g_string_new(buf);
*returned_message = g_strdup(text->str);
g_string_free(text, TRUE);
}
close(fd_input_file);
GError* deletion_error = NULL;
g_file_delete(file, NULL, &deletion_error);
if (deletion_error) {
cons_show("Editor: error during file deletion");
return TRUE;
}
g_object_unref(file);
}
return FALSE;
}
gboolean
cmd_editor(ProfWin* window, const char* const command, gchar** args)
{
jabber_conn_status_t conn_status = connection_get_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are currently not connected.");
return TRUE;
}
gchar* message = NULL;
if (_get_message_from_editor(NULL, &message)) {
return TRUE;
}
rl_insert_text(message);
ui_resize();
rl_point = rl_end;
rl_forced_update_display();
g_free(message);
return TRUE;
}
gboolean
cmd_correct_editor(ProfWin* window, const char* const command, gchar** args)
{
if (!_can_correct(window)) {
return TRUE;
}
gchar* initial_message = win_get_last_sent_message(window);
gchar* message = NULL;
if (_get_message_from_editor(initial_message, &message)) {
return TRUE;
}
if (window->type == WIN_CHAT) {
ProfChatWin* chatwin = (ProfChatWin*)window;
cl_ev_send_msg_correct(chatwin, message, FALSE, TRUE);
} else if (window->type == WIN_MUC) {
ProfMucWin* mucwin = (ProfMucWin*)window;
cl_ev_send_muc_msg_corrected(mucwin, message, FALSE, TRUE);
}
g_free(message);
return TRUE;
}
gboolean
cmd_silence(ProfWin* window, const char* const command, gchar** args)
{
_cmd_set_boolean_preference(args[0], command, "Block all messages from JIDs that are not in the roster", PREF_SILENCE_NON_ROSTER);
return TRUE;
}
gboolean
cmd_register(ProfWin* window, const char* const command, gchar** args)
{
gchar* opt_keys[] = { "port", "tls", "auth", NULL };
gboolean parsed;
GHashTable* options = parse_options(&args[2], opt_keys, &parsed);
if (!parsed) {
cons_bad_cmd_usage(command);
cons_show("");
options_destroy(options);
return TRUE;
}
char* tls_policy = g_hash_table_lookup(options, "tls");
if (tls_policy && (g_strcmp0(tls_policy, "force") != 0) && (g_strcmp0(tls_policy, "allow") != 0) && (g_strcmp0(tls_policy, "trust") != 0) && (g_strcmp0(tls_policy, "disable") != 0) && (g_strcmp0(tls_policy, "legacy") != 0)) {
cons_bad_cmd_usage(command);
cons_show("");
options_destroy(options);
return TRUE;
}
int port = 0;
if (g_hash_table_contains(options, "port")) {
char* port_str = g_hash_table_lookup(options, "port");
char* err_msg = NULL;
gboolean res = strtoi_range(port_str, &port, 1, 65535, &err_msg);
if (!res) {
cons_show(err_msg);
cons_show("");
free(err_msg);
port = 0;
options_destroy(options);
return TRUE;
}
}
char* username = args[0];
char* server = args[1];
char* passwd = ui_ask_password(false);
char* confirm_passwd = ui_ask_password(true);
if (g_strcmp0(passwd, confirm_passwd) == 0) {
log_info("Attempting to register account %s on server %s.", username, server);
connection_register(server, port, tls_policy, username, passwd);
} else {
cons_show("The two passwords do not match.");
}
if (connection_get_status() == JABBER_DISCONNECTED) {
cons_show_error("Connection attempt to server %s port %d failed.", server, port);
log_info("Connection attempt to server %s port %d failed.", server, port);
return TRUE;
}
free(passwd);
free(confirm_passwd);
options_destroy(options);
log_info("we are leaving the registration process");
return TRUE;
}
gboolean
cmd_mood(ProfWin* window, const char* const command, gchar** args)
{
if (g_strcmp0(args[0], "set") == 0) {
if (args[1]) {
cons_show("Your mood: %s", args[1]);
if (args[2]) {
publish_user_mood(args[1], args[2]);
} else {
publish_user_mood(args[1], args[1]);
}
}
} else if (g_strcmp0(args[0], "clear") == 0) {
cons_show("Clearing the user mood.");
publish_user_mood(NULL, NULL);
}
return TRUE;
}