diff options
author | Will Song <incertia9474@gmail.com> | 2015-05-29 19:53:37 -0500 |
---|---|---|
committer | Will Song <incertia9474@gmail.com> | 2015-05-29 19:53:37 -0500 |
commit | 9463c6719036957c8468e1363a48afbfe751fd3e (patch) | |
tree | aed6ccd050fc182a0d4d111bef6f743d28a42a73 | |
parent | 7f436d614b11d72893d856f1c3d817ab34b0b9eb (diff) | |
parent | 304e08a9c0bfa27ed84dc1ff0a2e2d32b36529f8 (diff) | |
download | profani-tty-9463c6719036957c8468e1363a48afbfe751fd3e.tar.gz |
fix conflicts
138 files changed, 7295 insertions, 6044 deletions
diff --git a/.gitignore b/.gitignore index be11f141..ba909849 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ # *.[oa] # *~ profanity +profanity.sh *.o *.log *.swp @@ -25,7 +26,7 @@ configure.scan stamp-h1 *~ *dirstamp -valgrind.out +valgrind*.out* core bugs/ TODO @@ -64,3 +65,7 @@ profanity.workspace m4/ test.sh clean-test.sh +callgrind.out.* +gen_docs.sh +main_fragment.html +toc_fragment.html diff --git a/.travis.yml b/.travis.yml index c87d68b7..e546d8b3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: c install: - sudo apt-get update - - sudo apt-get -y install libssl-dev libexpat1-dev libncursesw5-dev libglib2.0-dev libnotify-dev libcurl3-dev libxss-dev libotr2-dev + - sudo apt-get -y install libssl-dev libexpat1-dev libncursesw5-dev libglib2.0-dev libnotify-dev libcurl3-dev libxss-dev libotr2-dev uuid-dev - git clone git://github.com/strophe/libstrophe.git - cd libstrophe - mkdir m4 @@ -11,15 +11,15 @@ install: - sudo make install - cd .. - rm -rf libstrophe - - wget https://open.cryptomilk.org/attachments/download/42/cmocka-0.4.1.tar.xz - - tar -xvf cmocka-0.4.1.tar.xz - - cd cmocka-0.4.1 + - wget https://cmocka.org/files/1.0/cmocka-1.0.0.tar.xz + - tar -xvf cmocka-1.0.0.tar.xz + - cd cmocka-1.0.0 - mkdir build - cd build - cmake -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug .. - make - sudo make install - cd ../.. - - rm -rf cmocka-0.4.1 + - rm -rf cmocka-1.0.0 - ./bootstrap.sh script: ./configure && make && make check diff --git a/CHANGELOG b/CHANGELOG index 815f6e55..519660db 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,16 +1,26 @@ +0.4.7 +===== + +- GNU Readline +- Message Carbons (xep-0280) +- Message Delivery Receipts (xep-0184) +- MUC Mediated Invitation support + 0.4.6 ===== -- 16 colour support +- 16 colour support (/theme colours) - UI preferences included in themes -- Word wrapping (/wrap) -- Show hide time (/time) -- Show or hide and customise roster panel (/roster) +- /wrap - Word wrapping +- /time - Show/hide time in main window, and configure precision +- /roster - Show/hide and customise roster panel +- /roster and /occupants panel size settings (% of screen width) +- /account default - Set default account for /connect - /account remove -- Added default account for /connect -- Additional readline style shortcuts -- Improved chat session handling -- Override resource during chat and resource display settings (/resource) -- Disable terminal title by default, additonal title on exit -- Dynamic input blocking timeout to use less CPU -- eval_password property on accounts for retrieving password from keyring/keychain +- /presence - Show/hide contact presence in titlebar +- /resource - Override resource during chat, resource display settings +- Improved chat session handling <http://xmpp.org/rfcs/rfc6121.html#message-chat> +- Lower CPU usage with dynamic input blocking timeout +- Keychain/keyring integration using account eval_password property +- Disable term window title by default +- Fixed remote code execution bug on OSX when desktop notifications configured to show message text diff --git a/LICENSE.txt b/LICENSE.txt index 609ce80c..e1990985 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,5 +1,5 @@ Profanity -Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> +Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> Profanity is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/Makefile.am b/Makefile.am index d9fa9729..372b60f3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -13,7 +13,9 @@ core_sources = \ src/xmpp/roster.c src/xmpp/roster.h \ src/xmpp/bookmark.c src/xmpp/bookmark.h \ src/xmpp/form.c src/xmpp/form.h \ - src/server_events.c src/server_events.h \ + src/event/server_events.c src/event/server_events.h \ + src/event/client_events.c src/event/client_events.h \ + src/event/ui_events.c src/event/ui_events.h \ src/ui/ui.h src/ui/window.c src/ui/window.h src/ui/core.c \ src/ui/titlebar.c src/ui/statusbar.c src/ui/inputwin.c \ src/ui/titlebar.h src/ui/statusbar.h src/ui/inputwin.h \ @@ -27,7 +29,6 @@ core_sources = \ src/tools/parser.h \ src/tools/p_sha1.h src/tools/p_sha1.c \ src/tools/autocomplete.c src/tools/autocomplete.h \ - src/tools/history.c src/tools/history.h \ src/tools/tinyurl.c src/tools/tinyurl.h \ src/config/accounts.c src/config/accounts.h \ src/config/account.c src/config/account.h \ @@ -44,13 +45,13 @@ tests_sources = \ src/roster_list.c src/roster_list.h \ src/xmpp/xmpp.h src/xmpp/form.c \ src/ui/ui.h \ + src/otr/otr.h \ src/command/command.h src/command/command.c \ src/command/commands.h src/command/commands.c \ src/tools/parser.c \ src/tools/parser.h \ src/tools/p_sha1.h src/tools/p_sha1.c \ src/tools/autocomplete.c src/tools/autocomplete.h \ - src/tools/history.c src/tools/history.h \ src/tools/tinyurl.c src/tools/tinyurl.h \ src/config/accounts.h \ src/config/account.c src/config/account.h \ @@ -61,9 +62,10 @@ tests_sources = \ src/ui/buffer.c \ src/ui/titlebar.c src/ui/statusbar.c src/ui/inputwin.c \ src/ui/titlebar.h src/ui/statusbar.h src/ui/inputwin.h \ - src/server_events.c src/server_events.h \ + src/event/server_events.c src/event/server_events.h \ + src/event/client_events.c src/event/client_events.h \ + src/event/ui_events.c src/event/ui_events.h \ tests/xmpp/stub_xmpp.c \ - tests/otr/stub_otr.c \ tests/ui/stub_ui.c \ tests/log/stub_log.c \ tests/config/stub_accounts.c \ @@ -78,12 +80,10 @@ tests_sources = \ tests/test_cmd_roster.c tests/test_cmd_roster.h \ tests/test_cmd_statuses.c tests/test_cmd_statuses.h \ tests/test_cmd_sub.c tests/test_cmd_sub.h \ - tests/test_cmd_win.c tests/test_cmd_win.h \ tests/test_cmd_disconnect.c tests/test_cmd_disconnect.h \ tests/test_common.c tests/test_common.h \ tests/test_contact.c tests/test_contact.h \ tests/test_form.c tests/test_form.h \ - tests/test_history.c tests/test_history.h \ tests/test_jid.c tests/test_jid.h \ tests/test_muc.c tests/test_muc.h \ tests/test_parser.c tests/test_parser.h \ @@ -104,6 +104,9 @@ otr3_sources = \ otr4_sources = \ src/otr/otrlib.h src/otr/otrlibv4.c src/otr/otr.h src/otr/otr.c +otr_test_sources = \ + tests/otr/stub_otr.c + themes_sources = themes/* script_sources = bootstrap.sh configure-debug install-all.sh @@ -111,6 +114,7 @@ script_sources = bootstrap.sh configure-debug install-all.sh man_sources = docs/profanity.1 if BUILD_OTR +tests_sources += $(otr_test_sources) if BUILD_OTR3 core_sources += $(otr3_sources) endif diff --git a/configure.ac b/configure.ac index 7369f112..1e2c6173 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. -AC_INIT([profanity], [0.4.6], [boothj5web@gmail.com]) +AC_INIT([profanity], [0.4.7], [boothj5web@gmail.com]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([src/main.c]) AC_CONFIG_HEADERS([src/config.h]) @@ -34,6 +34,8 @@ AC_DEFINE_UNQUOTED([PACKAGE_STATUS], ["$PACKAGE_STATUS"], [Status of this build] AS_IF([test "x$PLATFORM" = xcygwin], [AC_DEFINE([PLATFORM_CYGWIN], [1], [Cygwin])]) +AS_IF([test "x$PLATFORM" = xosx], + [AC_DEFINE([PLATFORM_OSX], [1], [OSx])]) ### Options AC_ARG_ENABLE([notifications], @@ -134,10 +136,23 @@ PKG_CHECK_MODULES([glib], [glib-2.0 >= 2.26], [], PKG_CHECK_MODULES([curl], [libcurl], [], [AC_MSG_ERROR([libcurl is required for profanity])]) +AS_IF([test "x$PLATFORM" != xosx], + [AC_CHECK_LIB([readline], [main], [], + [AC_MSG_ERROR([libreadline is required for profanity])])], + [AC_CHECK_FILE([/usr/local/opt/readline/lib], + [LIBS="-lreadline $LIBS" + AM_CPPFLAGS="-I/usr/local/opt/readline/include $AM_CPPFLAGS" + AM_LDFLAGS="-L/usr/local/opt/readline/lib $AM_LDFLAGS" + AC_SUBST(AM_LDFLAGS)], + [AC_MSG_ERROR([libreadline is required for profanity])])]) + +AC_CHECK_LIB([uuid], [uuid_generate], [], + [AC_MSG_ERROR([libuuid is required for profanity])]) + AS_IF([test "x$PLATFORM" = xosx], [LIBS="-lcurl $LIBS"]) ### Check for desktop notification support -### Linux requires libnotify +### Linux/FreeBSD require libnotify ### Windows uses native OS calls ### OSX requires terminal-notifier @@ -150,7 +165,7 @@ AS_IF([test "x$PLATFORM" = xosx], [AC_MSG_ERROR([terminal-notifier not found, required for desktop notifications.])], [AC_MSG_NOTICE([Desktop notifications not supported.])])], [AC_DEFINE([HAVE_OSXNOTIFY], [1], [terminal notifier])])])], - [test "x$PLATFORM" = xnix], + [test "x$PLATFORM" = xnix -o "x$PLATFORM" = xfreebsd], [AS_IF([test "x$enable_notifications" != xno], [PKG_CHECK_MODULES([libnotify], [libnotify], [AC_DEFINE([HAVE_LIBNOTIFY], [1], [libnotify module])], diff --git a/docs/profanity.1 b/docs/profanity.1 index a65281fb..63cd0677 100644 --- a/docs/profanity.1 +++ b/docs/profanity.1 @@ -1,9 +1,9 @@ -.TH Profanity 1 "March 2014" "Profanity XMPP client" +.TH Profanity 1 "February 2015" "Profanity XMPP client" .SH NAME Profanity \- a simple console based XMPP chat client. .SH SYNOPSIS .B profanity -[\-vhd] [\-l level] +[\-vhd] [\-l level] [\-a account] .SH DESCRIPTION .B Profanity is a simple lightweight console based XMPP chat client. Its emphasis is @@ -15,19 +15,21 @@ at: .SH OPTIONS .TP .BI "\-v, \-\-version" -Show version information. +Show version and build information. .TP .BI "\-h, \-\-help" Show help on command line arguments. .TP -.BI "\-a, \-\-account" -Auto connect to an account on startup. +.BI "\-a, \-\-account "ACCOUNT +Auto connect to an account on startup, +.I ACCOUNT +must be an existing account. .TP .BI "\-d, \-\-disable\-tls" Disable TLS for servers that either don't support it, or claim to but do not complete the handshake. .TP -.BI "\-l, \-\-log="LEVEL +.BI "\-l, \-\-log "LEVEL Set the logging level, .I LEVEL may be set to DEBUG, INFO (the default), WARN or ERROR. @@ -45,10 +47,10 @@ is stored in , details on configuring Profanity can be found at <http://www.profanity.im/configuration.html>. .PP .SH BUGS -Bugs can either be reported by sending a mail directly to: +Bugs can either be reported by raising an issue at the Github issue tracker: .br .PP -<boothj5web@gmail.com> +<https://github.com/boothj5/profanity/issues> .br .PP or to the mailing list at: @@ -57,12 +59,14 @@ or to the mailing list at: <https://groups.google.com/forum/#!forum/profanitydev> .br .PP -or with a Github account by logging issues on the issue tracker at: +or by sending a mail directly to: +.br +.PP +<boothj5web@gmail.com> .br .PP -<https://github.com/boothj5/profanity> .SH LICENSE -Copyright (C) 2012 \- 2014 James Booth <boothj5web@gmail.com>. +Copyright (C) 2012 \- 2015 James Booth <boothj5web@gmail.com>. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software; you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. diff --git a/install-all.sh b/install-all.sh index cc32d8fd..4ffc5999 100755 --- a/install-all.sh +++ b/install-all.sh @@ -24,7 +24,7 @@ debian_prepare() echo echo Profanity installer... installing dependencies echo - sudo apt-get -y install git automake autoconf libssl-dev libexpat1-dev libncursesw5-dev libglib2.0-dev libnotify-dev libcurl3-dev libxss-dev libotr5-dev libtool + sudo apt-get -y install git automake autoconf libssl-dev libexpat1-dev libncursesw5-dev libglib2.0-dev libnotify-dev libcurl3-dev libxss-dev libotr5-dev libreadline-dev libtool uuid-dev } @@ -36,7 +36,7 @@ fedora_prepare() ARCH=`arch` - sudo yum -y install gcc git autoconf automake openssl-devel.$ARCH expat-devel.$ARCH ncurses-devel.$ARCH glib2-devel.$ARCH libnotify-devel.$ARCH libcurl-devel.$ARCH libXScrnSaver-devel.$ARCH libotr3-devel.$ARCH libtool + sudo yum -y install gcc git autoconf automake openssl-devel.$ARCH expat-devel.$ARCH ncurses-devel.$ARCH glib2-devel.$ARCH libnotify-devel.$ARCH libcurl-devel.$ARCH libXScrnSaver-devel.$ARCH libotr3-devel.$ARCH readline-devel.$ARCH libtool uuid-devel.$ARCH } opensuse_prepare() @@ -44,7 +44,7 @@ opensuse_prepare() echo echo Profanity installer...installing dependencies echo - sudo zypper -n in gcc git automake make autoconf libopenssl-devel expat libexpat-devel ncurses-devel glib2-devel libnotify-devel libcurl-devel libXScrnSaver-devel libotr-devel libtool + sudo zypper -n in gcc git automake make autoconf libopenssl-devel expat libexpat-devel ncurses-devel glib2-devel libnotify-devel libcurl-devel libXScrnSaver-devel libotr-devel readline-devel libtool libuuid-devel } cygwin_prepare() @@ -60,9 +60,9 @@ cygwin_prepare() mv apt-cyg /usr/local/bin/ if [ -n "$CYG_MIRROR" ]; then - apt-cyg -m $CYG_MIRROR install git make gcc-core m4 automake autoconf pkg-config openssl-devel libexpat-devel zlib-devel libncursesw-devel libglib2.0-devel libcurl-devel libidn-devel libssh2-devel libkrb5-devel openldap-devel libgcrypt-devel libtool + apt-cyg -m $CYG_MIRROR install git make gcc-core m4 automake autoconf pkg-config openssl-devel libexpat-devel zlib-devel libncursesw-devel libglib2.0-devel libcurl-devel libidn-devel libssh2-devel libkrb5-devel openldap-devel libgcrypt-devel libreadline-devel libtool libuuid-devel else - apt-cyg install git make gcc-core m4 automake autoconf pkg-config openssl-devel libexpat-devel zlib-devel libncursesw-devel libglib2.0-devel libcurl-devel libidn-devel libssh2-devel libkrb5-devel openldap-devel libgcrypt-devel libtool + apt-cyg install git make gcc-core m4 automake autoconf pkg-config openssl-devel libexpat-devel zlib-devel libncursesw-devel libglib2.0-devel libcurl-devel libidn-devel libssh2-devel libkrb5-devel openldap-devel libgcrypt-devel libreadline-devel libtool libuuid-devel fi } diff --git a/src/chat_session.c b/src/chat_session.c index fbe06f76..2758d603 100644 --- a/src/chat_session.c +++ b/src/chat_session.c @@ -1,7 +1,7 @@ /* * chat_session.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -64,7 +64,7 @@ _chat_session_new(const char * const barejid, const char * const resource, static void _chat_session_free(ChatSession *session) { - if (session != NULL) { + if (session) { free(session->barejid); free(session->resource); free(session); @@ -81,7 +81,7 @@ chat_sessions_init(void) void chat_sessions_clear(void) { - if (sessions != NULL) + if (sessions) g_hash_table_remove_all(sessions); } @@ -141,7 +141,7 @@ chat_session_recipient_active(const char * const barejid, const char * const res // session exists with resource, update chat_states if (g_strcmp0(session->resource, resource) == 0) { session->send_states = send_states; - // session exists with differet resource and no override, replace + // session exists with different resource and no override, replace } else if (!session->resource_override) { _chat_session_new(barejid, resource, FALSE, send_states); } diff --git a/src/chat_session.h b/src/chat_session.h index 585a523b..f51a8341 100644 --- a/src/chat_session.h +++ b/src/chat_session.h @@ -1,7 +1,7 @@ /* * chat_session.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/chat_state.c b/src/chat_state.c index 99a83f43..8ddb6f1e 100644 --- a/src/chat_state.c +++ b/src/chat_state.c @@ -1,7 +1,7 @@ /* * chat_state.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/chat_state.h b/src/chat_state.h index ba394a56..7f0d8832 100644 --- a/src/chat_state.h +++ b/src/chat_state.h @@ -1,7 +1,7 @@ /* * chat_state.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/command/command.c b/src/command/command.c index 1441ef46..1871ea6c 100644 --- a/src/command/command.c +++ b/src/command/command.c @@ -1,7 +1,7 @@ /* * command.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -36,6 +36,7 @@ #include <errno.h> #include <limits.h> #include <stdlib.h> +#include <stdio.h> #include <string.h> #include <glib.h> @@ -70,8 +71,6 @@ typedef char*(*autocompleter)(char*, int*); static gboolean _cmd_execute(const char * const command, const char * const inp); -static gboolean _cmd_execute_default(const char * inp); -static gboolean _cmd_execute_alias(const char * const inp, gboolean *ran); static char * _cmd_complete_parameters(const char * const input); @@ -101,6 +100,8 @@ static char * _role_autocomplete(const char * const input); static char * _resource_autocomplete(const char * const input); static char * _titlebar_autocomplete(const char * const input); static char * _inpblock_autocomplete(const char * const input); +static char * _time_autocomplete(const char * const input); +static char * _receipts_autocomplete(const char * const input); GHashTable *commands = NULL; @@ -111,18 +112,19 @@ static struct cmd_t command_defs[] = { { "/help", cmd_help, parse_args, 0, 1, NULL, - { "/help [area|command]", "Get help on using Profanity.", + { "/help [area|command]", "Help on using Profanity.", { "/help [area|command]", - "-------------------------", - "Use with no arguments to get a help summary.", - "Supply an area to see help for commands related to specific features.", - "Supply a command (without the leading slash) to see help for that command.", + "--------------------", + "Help on using Profanity.", + "", + "area : Summary help for commands in a certain area of functionality.", + "command : Full help for a specific command, for example '/help connect'.", "", - "Example : /help commands", - "Example : /help presence", - "Example : /help who", + "Use with no arguments to see a list of areas.", "", - "For more detailed help, see the user guide at http://www.profanity.im/userguide.html.", + "Example: /help commands", + "Example: /help presence", + "Example: /help who", NULL } } }, { "/about", @@ -135,15 +137,17 @@ static struct cmd_t command_defs[] = { "/connect", cmd_connect, parse_args, 0, 5, NULL, - { "/connect [account] [server value] [port value]", "Login to a chat service.", + { "/connect [account] [server value] [port value]", "Account login.", { "/connect [account] [server value] [port value]", "----------------------------------------------", - "Connect to an XMPP service using the specified account.", - "Use the server property to specify a server if required.", - "Change the default port (5222, or 5223 for SSL) with the port property.", - "An account is automatically created if one does not exist.", - "If no account is specified, then the default account is used." - "See the /account command for more details.", + "Login to a chat service.", + "", + "account : The local account you wish to connect with, or a JID if connecting for the first time.", + "server value : Supply a server if it is different to the domain part of your JID.", + "port value : The port to use if different to the default (5222, or 5223 for SSL).", + "", + "If no account is specified, the default is used if one is configured.", + "A local account is created with the JID as it's name if it doesn't already exist.", "", "Example: /connect", "Example: /connect myuser@gmail.com", @@ -162,48 +166,57 @@ static struct cmd_t command_defs[] = { "/msg", cmd_msg, parse_args_with_freetext, 1, 2, NULL, - { "/msg contact|nick [message]", "Start chat with user.", + { "/msg contact|nick [message]", "Start chat with a user.", { "/msg contact|nick [message]", "---------------------------", - "Open a chat window for the contact and send the message if one is supplied.", - "When in a chat room, supply a nickname to start private chat with a room member.", + "Send a one to one chat message, or a private message to a chat room occupant.", + "", + "contact : The contact's JID, or nickname if one has been set in your roster.", + "nick : A chat room occupant, to whom you wish to send a private message.", + "message : The message to send", + "", + "If the message is omitted, a new chat window will be opened without sending a message.", "Use quotes if the nickname includes spaces.", "", - "Example : /msg myfriend@server.com Hey, here's a message!", - "Example : /msg otherfriend@server.com", - "Example : /msg Bob Here is a private message", - "Example : /msg \"My Friend\" Hi, how are you?", + "Example: /msg myfriend@server.com Hey, here's a message!", + "Example: /msg otherfriend@server.com", + "Example: /msg Bob Here is a private message", + "Example: /msg \"My Friend\" Hi, how are you?", NULL } } }, { "/roster", cmd_roster, parse_args_with_freetext, 0, 3, NULL, - { "/roster [online|show|hide|by|size|add|remove|nick|clearnick] [offline|resource] [percent] [group|presence|none] [jid] [nickname]", "Manage your roster.", - { "/roster [online|show|hide|by|size|add|remove|nick|clearnick] [offline|resource] [percent] [group|presence|none] [jid] [nickname]", - "-------------------------------------------------------------------------------------------------------------------------", - "View, add to, and remove from your roster.", + { "/roster [command] [args..]", "Manage your roster.", + { "/roster [command] [args..]", + "--------------------------", + "Manage your roster, and roster display settings.", + "", + "command - online|show|hide|by|size|add|remove|nick|clearnick", + "", + "online : Show all online contacts in your roster.", + "show : Show the roster panel.", + "show offline : Show offline contacts in the roster panel.", + "show resource : Show contact's connected resources in the roster panel.", + "hide : Hide the roster panel.", + "hide offline : Hide offline contacts in the roster panel.", + "hide resource : Hide contact's connected resources in the roster panel.", + "by group : Group contacts in the roster panel by roster group.", + "by presence : Group contacts in the roster panel by presence.", + "by none : No grouping in the roster panel.", + "size : Percentage of the screen taken up by the roster (1-99).", + "add jid [nick] : Add a new item to the roster.", + "remove jid : Removes an item from the roster.", + "nick jid nick : Change a contacts nickname.", + "clearnick jid : Removes the current nickname.", + "", "Passing no arguments lists all contacts in your roster.", - "online - Show all online contacts in your roster.", - "show - Show the roster panel in the console window.", - "hide - Hide the roster panel.", - "show offline - Show offline contacts in the roster panel.", - "hide offline - Hide offline contacts in the roster panel.", - "show resource - Show contact's connected resources in the roster panel.", - "hide resource - Hide contact's connected resources in the roster panel.", - "by group - Group contacts in the roster panel by roster group.", - "by presence - Group contacts in the roster panel by presence.", - "by none - No grouping in the roster panel.", - "size - Percentage of the screen taken up by the roster (1-99).", - "add - Add a new item, jid is required, nickname is optional.", - "remove - Removes a contact, jid is required.", - "nick - Changes a contacts nickname, both jid and nickname are required,", - "clearnick - Removes the current nickname, jid is required.", - "", - "Example : /roster (show your roster)", - "Example : /roster add someone@contacts.org (add the contact)", - "Example : /roster add someone@contacts.org Buddy (add the contact with nickname 'Buddy')", - "Example : /roster remove someone@contacts.org (remove the contact)", - "Example : /roster nick myfriend@chat.org My Friend", - "Example : /roster clearnick kai@server.com (clears nickname)", + "", + "Example: /roster (show your roster)", + "Example: /roster add someone@contacts.org (add the contact)", + "Example: /roster add someone@contacts.org Buddy (add the contact with nickname 'Buddy')", + "Example: /roster remove someone@contacts.org (remove the contact)", + "Example: /roster nick myfriend@chat.org My Friend", + "Example: /roster clearnick kai@server.com (clears nickname)", NULL } } }, { "/group", @@ -212,31 +225,35 @@ static struct cmd_t command_defs[] = { "/group [show|add|remove] [group] [contact]", "------------------------------------------", "View, add to, and remove from roster groups.", + "", + "show group : List all roster items a group.", + "add group contact : Added a contact to a group.", + "remove group contact : Remove a contact from a group.", + "", "Passing no argument will list all roster groups.", - "The 'show' command takes 'group' as an argument, and lists all roster items in that group.", - "The 'add' command takes 'group' and 'contact' arguments, and adds the contact to the group.", - "The 'remove' command takes 'group' and 'contact' arguments and removes the contact from the group,", "", - "Example : /group", - "Example : /group show friends", - "Example : /group add friends newfriend@server.org", - "Example : /group add family Brother (using contacts nickname)", - "Example : /group remove colleagues boss@work.com", + "Example: /group", + "Example: /group show friends", + "Example: /group add friends newfriend@server.org", + "Example: /group add family Brother (using contacts nickname)", + "Example: /group remove colleagues boss@work.com", NULL } } }, { "/info", cmd_info, parse_args, 0, 1, NULL, - { "/info [contact|nick]", "Show basic information about a contact, room, or room member.", + { "/info [contact|nick]", "Show information about a contact, room, or room member.", { "/info [contact|nick]", "--------------------", - "Show basic information about a contact, room, or room member.", - "If in the console, a contact must be specified.", - "If in a chat window the parameter is not required, the current recipient will be used.", - "If in a chat room, providing no arguments will display information about the room.", - "If in a chat room, supplying a nick will show information about the occupant.", + "Show information about a contact, room, or room member.", "", - "Example : /info mybuddy@chat.server.org", - "Example : /info kai", + "contact : The contact you wish to view information about.", + "nick : When in a chat room, the occupant you wish to view information about.", + "", + "Passing no argument in a chat window will use the current recipient.", + "Passing no argument in a chat room will display information about the room.", + "", + "Example: /info mybuddy@chat.server.org", + "Example: /info kai", NULL } } }, { "/caps", @@ -244,14 +261,16 @@ static struct cmd_t command_defs[] = { "/caps [fulljid|nick]", "Find out a contacts client software capabilities.", { "/caps [fulljid|nick]", "--------------------", - "Find out a contact, or room members client software capabilities.", - "If in the console window or a regular chat window, a full JID is required.", - "If in a chat room, the nickname is required.", - "If in private chat, no parameter is required.", + "Find out a contacts, or room members client software capabilities.", + "", + "fulljid : If in the console or a chat window, the full JID for which you wish to see capabilities.", + "nick : If in a chat room, nickname for which you wish to see capabilities.", + "", + "If in private chat initiated from a chat room, no parameter is required.", "", - "Example : /caps mybuddy@chat.server.org/laptop (contact's laptop resource)", - "Example : /caps mybuddy@chat.server.org/phone (contact's phone resource)", - "Example : /caps bruce (room member)", + "Example: /caps mybuddy@chat.server.org/laptop (contact's laptop resource)", + "Example: /caps mybuddy@chat.server.org/phone (contact's phone resource)", + "Example: /caps bruce (room member)", NULL } } }, { "/software", @@ -259,15 +278,17 @@ static struct cmd_t command_defs[] = { "/software [fulljid|nick]", "Find out software version information about a contacts resource.", { "/software [fulljid|nick]", "------------------------", - "Find out a contact, or room members software version information, if such requests are supported.", - "If in the console window or a regular chat window, a full JID is required.", - "If in a chat room, the nickname is required.", - "If in private chat, no parameter is required.", + "Find out a contact, or room members software version information.", + "", + "fulljid : If in the console or a chat window, the full JID for which you wish to see software information.", + "nick : If in a chat room, nickname for which you wish to see software information.", + "", + "If in private chat initiated from a chat room, no parameter is required.", "If the contact's software does not support software version requests, nothing will be displayed.", "", - "Example : /software mybuddy@chat.server.org/laptop (contact's laptop resource)", - "Example : /software mybuddy@chat.server.org/phone (contact's phone resource)", - "Example : /software bruce (room member)", + "Example: /software mybuddy@chat.server.org/laptop (contact's laptop resource)", + "Example: /software mybuddy@chat.server.org/phone (contact's phone resource)", + "Example: /software bruce (room member)", NULL } } }, { "/status", @@ -276,39 +297,49 @@ static struct cmd_t command_defs[] = { "/status [contact|nick]", "----------------------", "Find out a contact, or room members presence information.", + "", + "contact : The contact who's presence you which to see.", + "nick : If in a chat room, the occupant who's presence you wish to see.", + "", "If in a chat window the parameter is not required, the current recipient will be used.", "", - "Example : /status buddy@server.com", - "Example : /status jon", + "Example: /status buddy@server.com", + "Example: /status jon", NULL } } }, { "/resource", cmd_resource, parse_args, 1, 2, &cons_resource_setting, - { "/resource set|off|title|message [resource]", "Set the contact's resource.", + { "/resource set|off|title|message [resource]", "Set the contact's resource, display settings.", { "/resource set|off|title|message [resource]", "------------------------------------------", - "Set the resource to use when chatting to a contact and manage resource display settings.", - "set resource - Set the resource.", - "off - Let the server choose which resource to route messages to.", - "title on|off - Show or hide the current resource in the titlebar.", - "message on|off - Show or hide the resource from which a message was recieved.", + "Override chat session resource, and manage resource display settings.", + "", + "set resource : Set the resource to which messages will be sent.", + "off : Let the server choose which resource to route messages to.", + "title on|off : Show or hide the current resource in the titlebar.", + "message on|off : Show or hide the resource when showing an incoming message.", NULL } } }, { "/join", - cmd_join, parse_args, 1, 5, NULL, - { "/join room[@server] [nick value] [password value]", "Join a chat room.", - { "/join room[@server] [nick value] [password value]", - "-------------------------------------------------", + cmd_join, parse_args, 0, 5, NULL, + { "/join [room] [nick value] [password value]", "Join a chat room.", + { "/join [room] [nick value] [password value]", + "-----------------------------------------", "Join a chat room at the conference server.", - "If nick is specified you will join with this nickname.", - "Otherwise the account preference 'muc.nick' will be used which by default is the localpart of your JID (before the @).", - "If no server is supplied, the account preference 'muc.service' is used, which is 'conference.<domain-part>' by default.", + "", + "room : Bare room JID (the chat server is determined by the 'muc.service' account property) or full room jid." + "nick value : Nickname to use in the room", + "password value : Password if the room requires it.", + "", + "If no room is supplied, a generated name will be used with the format private-chat-[UUID].", + "If no nickname is specified the account preference 'muc.nick' will be used which by default is the localpart of your JID.", "If the room doesn't exist, and the server allows it, a new one will be created.", "", - "Example : /join jdev@conference.jabber.org", - "Example : /join jdev@conference.jabber.org nick mynick", - "Example : /join private@conference.jabber.org nick mynick password mypassword", - "Example : /join jdev (as user@jabber.org will join jdev@conference.jabber.org)", + "Example: /join", + "Example: /join jdev@conference.jabber.org", + "Example: /join jdev@conference.jabber.org nick mynick", + "Example: /join private@conference.jabber.org nick mynick password mypassword", + "Example: /join jdev (as user@jabber.org will join jdev@conference.jabber.org)", NULL } } }, { "/leave", @@ -324,8 +355,10 @@ static struct cmd_t command_defs[] = { "/invite contact [message]", "Invite contact to chat room.", { "/invite contact [message]", "-------------------------", - "Send a direct invite to the specified contact to the current chat room.", - "If a message is supplied it will be sent as the reason for the invite.", + "Send a direct invite to the current chat room.", + "", + "contact : The contact you wish to invite", + "message : An optional message to send with the invite.", NULL } } }, { "/invites", @@ -333,9 +366,7 @@ static struct cmd_t command_defs[] = { "/invites", "Show outstanding chat room invites.", { "/invites", "--------", - "Show all rooms that you have been invited to, and have not yet been accepted or declind.", - "Use \"/join <room>\" to accept a room invitation.", - "Use \"/decline <room>\" to decline a room invitation.", + "Show all rooms that you have been invited to, and not accepted or declined.", NULL } } }, { "/decline", @@ -343,7 +374,9 @@ static struct cmd_t command_defs[] = { "/decline room", "Decline a chat room invite.", { "/decline room", "-------------", - "Decline invitation to a chat room, the room will no longer be in the list of outstanding invites.", + "Decline a chat room invitation.", + "", + "room : The room for the invite you wish to decline.", NULL } } }, { "/room", @@ -351,9 +384,11 @@ static struct cmd_t command_defs[] = { "/room accept|destroy|config", "Room configuration.", { "/room accept|destroy|config", "---------------------------", - "accept - Accept default room configuration.", - "destroy - Reject default room configuration.", - "config - Edit room configuration.", + "Chat room configuration.", + "", + "accept : Accept default room configuration.", + "destroy : Reject default room configuration.", + "config : Edit room configuration.", NULL } } }, { "/kick", @@ -361,8 +396,10 @@ static struct cmd_t command_defs[] = { "/kick nick [reason]", "Kick occupants from chat rooms.", { "/kick nick [reason]", "-------------------", - "nick - Nickname of the occupant to kick from the room.", - "reason - Optional reason for kicking the occupant.", + "Kick occupants from chat rooms.", + "", + "nick : Nickname of the occupant to kick from the room.", + "reason : Optional reason for kicking the occupant.", NULL } } }, { "/ban", @@ -370,8 +407,10 @@ static struct cmd_t command_defs[] = { "/ban jid [reason]", "Ban users from chat rooms.", { "/ban jid [reason]", "-----------------", - "jid - Bare JID of the user to ban from the room.", - "reason - Optional reason for banning the user.", + "Ban users from chat rooms.", + "", + "jid : Bare JID of the user to ban from the room.", + "reason : Optional reason for banning the user.", NULL } } }, { "/subject", @@ -379,8 +418,10 @@ static struct cmd_t command_defs[] = { "/subject set|clear [subject]", "Set or clear room subject.", { "/subject set|clear [subject]", "----------------------------", - "set subject - Set the room subject.", - "clear - Clear the room subject.", + "Set or clear room subject.", + "", + "set subject : Set the room subject.", + "clear : Clear the room subject.", NULL } } }, { "/affiliation", @@ -388,8 +429,11 @@ static struct cmd_t command_defs[] = { "/affiliation set|list [affiliation] [jid] [reason]", "Manage room affiliations.", { "/affiliation set|list [affiliation] [jid] [reason]", "--------------------------------------------------", - "set affiliation jid [reason]- Set the affiliation of user with jid, with an optional reason.", - "list [affiliation] - List all users with the specified affiliation, or all if none specified.", + "Manage room affiliations.", + "", + "set affiliation jid [reason]: Set the affiliation of user with jid, with an optional reason.", + "list [affiliation] : List all users with the specified affiliation, or all if none specified.", + "", "The affiliation may be one of owner, admin, member, outcast or none.", NULL } } }, @@ -398,20 +442,28 @@ static struct cmd_t command_defs[] = { "/role set|list [role] [nick] [reason]", "Manage room roles.", { "/role set|list [role] [nick] [reason]", "-------------------------------------", - "set role nick [reason] - Set the role of occupant with nick, with an optional reason.", - "list [role] - List all occupants with the specified role, or all if none specified.", + "Manage room roles.", + "", + "set role nick [reason] : Set the role of occupant with nick, with an optional reason.", + "list [role] : List all occupants with the specified role, or all if none specified.", + "", "The role may be one of moderator, participant, visitor or none.", NULL } } }, { "/occupants", - cmd_occupants, parse_args, 1, 2, cons_occupants_setting, - { "/occupants show|hide|default|size [show|hide] [percent]", "Show or hide room occupants.", - { "/occupants show|hide|default|size [show|hide] [percent]", - "-------------------------------------------------------", - "show - Show the occupants panel in chat rooms.", - "hide - Hide the occupants panel in chat rooms.", - "default - Whether occupants are shown by default in new rooms, 'show' or 'hide'", - "size - Percentage of the screen taken by the occupants list in rooms (1-99).", + cmd_occupants, parse_args, 1, 3, cons_occupants_setting, + { "/occupants show|hide|default|size [jid|show|hide|percent] [jid]", "Show or hide room occupants.", + { "/occupants show|hide|default|size [jid|show|hide|percent] [jid]", + "---------------------------------------------------------------", + "Show or hide room occupants, and occupants panel display settings.", + "", + "show : Show the occupants panel in current room.", + "hide : Hide the occupants panel in current room.", + "show jid : Show jid in the occupants panel in current room.", + "hide jid : Hide jid in the occupants panel in current room.", + "default show|hide : Whether occupants are shown by default in new rooms.", + "default show|hide jid : Whether occupants jids are shown by default in new rooms.", + "size percent : Percentage of the screen taken by the occupants list in rooms (1-99).", NULL } } }, { "/form", @@ -419,10 +471,12 @@ static struct cmd_t command_defs[] = { "/form show|submit|cancel|help [tag]", "Form handling.", { "/form show|submit|cancel|help [tag]", "-----------------------------------", - "show - Show the current form.", - "submit - Submit the current form.", - "cancel - Cancel changes to the current form.", - "help [tag] - Display help for form, or a specific field.", + "Form configuration.", + "", + "show : Show the current form.", + "submit : Submit the current form.", + "cancel : Cancel changes to the current form.", + "help [tag] : Display help for form, or a specific field.", NULL } } }, { "/rooms", @@ -431,45 +485,51 @@ static struct cmd_t command_defs[] = { "/rooms [conference-service]", "---------------------------", "List the chat rooms available at the specified conference service", - "If no argument is supplied, the account preference 'muc.service' is used, which is 'conference.<domain-part>' by default.", "", - "Example : /rooms conference.jabber.org", - "Example : /rooms (if logged in as me@server.org, is equivalent to /rooms conference.server.org)", + "conference-service : The conference service to query.", + "", + "If no argument is supplied, the account preference 'muc.service' is used, 'conference.<domain-part>' by default.", + "", + "Example: /rooms conference.jabber.org", + "Example: /rooms (if logged in as me@server.org, is equivalent to /rooms conference.server.org)", NULL } } }, { "/bookmark", cmd_bookmark, parse_args, 0, 8, NULL, - { "/bookmark [list|add|update|remove|join] [room@server] [nick value] [password value] [autojoin on|off]", "Manage bookmarks.", - { "/bookmark [list|add|update|remove|join] [room@server] [nick value] [password value] [autojoin on|off]", - "---------------------------------------------------------------------------------------------------", - "Manage bookmarks.", - "list: List all bookmarks.", - "add: Add a bookmark for room@server with the following optional properties:", - " nick: Nickname used in the chat room", - " password: Password for private rooms, note this may be stored in plaintext on your server", - " autojoin: Whether to join the room automatically on login \"on\" or \"off\".", - "update: Update any of the above properties associated with the bookmark.", - "remove: Remove the bookmark for room@server.", - "join: Join room@server using the properties associated with the bookmark.", - "When in a chat room, the /bookmark command with no arguments will bookmark the current room with the current settings, and set autojoin to \"on\".", + { "/bookmark [command] [args..]", "Manage bookmarks.", + { "/bookmark [command] [args..]", + "----------------------------", + "Manage bookmarks and join bookmarked rooms.", + "", + "command : list|add|update|remove|join", + "", + "list : List all bookmarks.", + "add room@server [prop value..] : Add a bookmark for room@server with the following optional properties:", + " nick value : Nickname used in the chat room", + " password value : Password if required, may be stored in plaintext on your server", + " autojoin on|off : Whether to join the room automatically on login.", + "update room@server [prop value..] : Update any of the above properties associated with the bookmark.", + "remove room@server : Remove the bookmark for room@server.", + "join room@server : Join room using the properties associated with the bookmark.", + "", + "In a chat room, /bookmark with no arguments will bookmark the current room, setting autojoin to \"on\".", NULL } } }, { "/disco", cmd_disco, parse_args, 1, 2, NULL, - { "/disco command entity", "Service discovery.", - { "/disco command entity", + { "/disco info|items entity", "Service discovery.", + { "/disco info|items entity", "---------------------", "Find out information about an entities supported services.", - "Command may be one of:", - "info: List protocols and features supported by an entity.", - "items: List items associated with an entity.", "", - "The entity must be a Jabber ID.", + "info : List protocols and features supported by an entity.", + "items : List items associated with an entity.", + "entity : Jabber ID.", "", - "Example : /disco info myserver.org", - "Example : /disco items myserver.org", - "Example : /disco items conference.jabber.org", - "Example : /disco info myfriend@server.com/laptop", + "Example: /disco info myserver.org", + "Example: /disco items myserver.org", + "Example: /disco items conference.jabber.org", + "Example: /disco info myfriend@server.com/laptop", NULL } } }, { "/nick", @@ -478,47 +538,52 @@ static struct cmd_t command_defs[] = { "/nick nickname", "--------------", "Change the name by which other members of a chat room see you.", - "This command is only valid when called within a chat room window.", "", - "Example : /nick kai hansen", - "Example : /nick bob", + "nickname : The new nickname.", + "", + "Example: /nick kai hansen", + "Example: /nick bob", NULL } } }, { "/win", cmd_win, parse_args, 1, 1, NULL, { "/win num", "View a window.", { "/win num", - "------------------", + "--------", "Show the contents of a specific window in the main window area.", + "", + "num - Window number to display.", NULL } } }, { "/wins", cmd_wins, parse_args, 0, 3, NULL, - { "/wins [tidy|prune|swap] [source] [target]", "List or tidy active windows.", - { "/wins [tidy|prune|swap] [source] [target]", - "-----------------------------------------", - "Passing no argument will list all currently active windows and information about their usage.", - "tidy : Shuffle windows so there are no gaps.", + { "/wins [tidy|prune|swap] [source target]", "List or tidy active windows.", + { "/wins [tidy|prune|swap] [source target]", + "---------------------------------------", + "Show a list of windows, or tidy or swap.", + "", + "tidy : Move windows so there are no gaps.", "prune : Close all windows with no unread messages, and then tidy as above.", "swap source target : Swap windows, target may be an empty position.", + "", + "Passing no argument will list all currently active windows and information about their usage.", NULL } } }, { "/sub", cmd_sub, parse_args, 1, 2, NULL, - { "/sub command [jid]", "Manage subscriptions.", - { "/sub command [jid]", - "------------------", - "command : One of the following,", - "request : Send a subscription request to the user to be informed of their", - " : presence.", - "allow : Approve a contact's subscription reqeust to see your presence.", - "deny : Remove subscription for a contact, or deny a request", - "show : Show subscriprion status for a contact.", - "sent : Show all sent subscription requests pending a response.", - "received : Show all received subscription requests awaiting your response.", - "", - "The optional 'jid' parameter only applys to 'request', 'allow', 'deny' and 'show'", - "If it is omitted the contact of the current window is used.", + { "/sub request|allow|deny|show|sent|received [jid]", "Manage subscriptions.", + { "/sub request|allow|deny|show|sent|received [jid]", + "------------------------------------------------", + "Manage subscriptions to contact presence.", + "", + "request [jid] : Send a subscription request to the user.", + "allow [jid] : Approve a contact's subscription request.", + "deny [jid] : Remove subscription for a contact, or deny a request", + "show [jid] : Show subscription status for a contact.", + "sent : Show all sent subscription requests pending a response.", + "received : Show all received subscription requests awaiting your response.", + "", + "If jid is omitted, the contact of the current window is used.", "", "Example: /sub request myfriend@jabber.org", "Example: /sub allow myfriend@jabber.org", @@ -531,9 +596,11 @@ static struct cmd_t command_defs[] = { "/tiny url", "Send url as tinyurl in current chat.", { "/tiny url", "---------", - "Send the url as a tiny url.", + "Send url as tinyurl in current chat.", + "", + "url : The url to make tiny.", "", - "Example : /tiny http://www.profanity.im", + "Example: /tiny http://www.profanity.im", NULL } } }, { "/who", @@ -541,31 +608,30 @@ static struct cmd_t command_defs[] = { "/who [status|role|affiliation] [group]", "Show contacts/room occupants with chosen status, role or affiliation", { "/who [status|role|affiliation] [group]", "--------------------------------------", - "Normal usage:", - "Status may be one of - online, offline, away, dnd, xa, chat, available, unavailable, or any where:", - "online : Contacts that are online, chat, away, xa, dnd", - "available : Contacts that are available for chat - online, chat.", - "unavailable : Contacts that are not available for chat - offline, away, xa, dnd.", - "any : Contacts with any status (same as calling with no argument).", + "Show contacts/room occupants with chosen status, role or affiliation", "", - "The group argument filters the list by that group.", - "", - "In a chat room, a role or affiliation may also be supplied instead of status.", - "Roles: moderator, participant, visitor", - "Affiliations: owner, admin, member", + "status : online|offline|away|dnd|xa|chat|available|unavailable|any", + " online : Contacts that are online, chat, away, xa, dnd", + " available : Contacts that are available for chat - online, chat.", + " unavailable : Contacts that are not available for chat - offline, away, xa, dnd.", + " any : Contacts with any status (same as calling with no argument).", + "role : moderator|participant|visitor", + "affiliation : owner|admin|member", + "group : Filter the results by the specified group.", NULL } } }, { "/close", cmd_close, parse_args, 0, 1, NULL, - { "/close [win|read|all]", "Close windows.", - { "/close [win|read|all]", + { "/close [num|read|all]", "Close windows.", + { "/close [num|read|all]", "---------------------", + "Close the current window, or a number of windows.", + "", + "num : Close the specified window.", + "all : Close all windows.", + "read : Close all windows that have no new messages.", + "", "Passing no argument will close the current window.", - "2,3,4,5,6,7,8,9 or 0 : Close the specified window.", - "all : Close all currently open windows.", - "read : Close all windows that have no new messages.", - "The console window cannot be closed.", - "If in a chat room, you will leave the room.", NULL } } }, { "/clear", @@ -588,8 +654,8 @@ static struct cmd_t command_defs[] = cmd_privileges, parse_args, 1, 1, &cons_privileges_setting, { "/privileges on|off", "Show occupant privileges in chat rooms.", { "/privileges on|off", - "---------------------------", - "If enabled the room roster will be broken down my role, and role information will be showin in the room.", + "------------------", + "If enabled the room occupants panel will be grouped by role, and role information will be shown in the room.", NULL } } }, { "/beep", @@ -607,7 +673,7 @@ static struct cmd_t command_defs[] = { "/presence on|off", "Show the contacts presence in the titlebar.", { "/presence on|off", "----------------", - "Switch display of the contacts presence on or off.", + "Switch display of the contacts presence in the titlebar on or off.", NULL } } }, { "/wrap", @@ -615,71 +681,61 @@ static struct cmd_t command_defs[] = { "/wrap on|off", "Word wrapping.", { "/wrap on|off", "------------", - "Enable or disable word wrapping.", + "Enable or disable word wrapping in the main window.", NULL } } }, { "/time", - cmd_time, parse_args, 1, 1, &cons_time_setting, - { "/time <format>", "Time display.", - { "/time <format>", - "---------------------", - "Configure the time format for the main window.", + cmd_time, parse_args, 1, 3, &cons_time_setting, + { "/time main|statusbar set|off [format]", "Time display.", + { "/time main|statusbar set|off [format]", + "---------------------------------", + "Configure time display preferences.", + "", + "main set <format> : Change strftime format to <format> in main window.", + "main off : Do not show time in main window.", + "statusbar set <format> : Change strftime format to <format> in statusbar.", + "statusbar off : Do not show time in status bar.", NULL } } }, { "/inpblock", cmd_inpblock, parse_args, 2, 2, &cons_inpblock_setting, - { "/inpblock timeout|dynamic [millis|on|off]", "Input blocking delay (dynamic or static).", + { "/inpblock timeout|dynamic [millis|on|off]", "Configure input blocking.", { "/inpblock timeout|dynamic [millis|on|off]", "-----------------------------------------", "How long to wait for input before checking for new messages or checking for state changes such as 'idle'.", - "timeout : Time to wait in milliseconds before reading input from the terminal buffer, defaults to 500.", - " : Valid values are 1-1000.", - "dynamic : Start with a 0 timeout and increase the value dynamically up to the specified 'timeout'.", - " : on|off", - "A higher timeout will result in less CPU usage, but a noticable delay for response to input.", - "A lower timeout will result in higher CPU usage, but faster response to input.", - "Using the dynamic setting, higher CPU usage will occur during activity, but over time the CPU usage will decrease whilst there is no activity.", + "", + "timeout millis : Time to wait (1-1000) in milliseconds before reading input from the terminal buffer, default: 1000.", + "dynamic on|off : Start with 0 millis and dynamically increase up to timeout when no activity, default: on.", NULL } } }, { "/notify", cmd_notify, parse_args, 2, 3, &cons_notify_setting, - { "/notify [type value]|[type setting value]", "Control various desktop noficiations.", + { "/notify [type value]|[type setting value]", "Control various desktop notifications.", { "/notify [type value]|[type setting value]", "-----------------------------------------", - "Settings for various desktop notifications where type is one of:", - "message : Notificaitons for regular messages.", - " : on|off", - "message current : Whether messages in the current window trigger notifications.", - " : on|off", - "message text : Show message text in message notifications.", - " : on|off", - "room : Notificaitons for chat room messages.", - " : on|off|mention", - "room current : Whether chat room messages in the current window trigger notifications.", - " : on|off", - "room text : Show message test in chat room message notifications.", - " : on|off", - "remind : Notification reminders of unread messages.", - " : where value is the reminder period in seconds,", - " : use 0 to disable.", - "typing : Notifications when contacts are typing.", - " : on|off", - "typing current : Whether typing notifications are triggerd for the current window.", - " : on|off", - "invite : Notifications for chat room invites.", - " : on|off", - "sub : Notifications for subscription requests.", - " : on|off", - "", - "Example : /notify message on (enable message notifications)", - "Example : /notify message text on (show message text in notifications)", - "Example : /notify room mention (enable chat room notifications only on mention)", - "Example : /notify room current off (disable room message notifications when window visible)", - "Example : /notify room text off (do not show message text in chat room notifications)", - "Example : /notify remind 10 (remind every 10 seconds)", - "Example : /notify remind 0 (switch off reminders)", - "Example : /notify typing on (enable typing notifications)", - "Example : /notify invite on (enable chat room invite notifications)", + "Settings for various kinds of desktop notifications.", + "", + "message on|off : Notifications for regular messages.", + "message current on|off : Whether messages in the current window trigger notifications.", + "message text on|off : Show message text in message notifications.", + "room on|off|mention : Notifications for chat room messages.", + "room current on|off : Whether chat room messages in the current window trigger notifications.", + "room text on|off : Show message text in chat room message notifications.", + "remind seconds : Notification reminder period for unread messages, use 0 to disable.", + "typing on|off : Notifications when contacts are typing.", + "typing current of|off : Whether typing notifications are triggered for the current window.", + "invite on|off : Notifications for chat room invites.", + "sub on|off : Notifications for subscription requests.", + "", + "Example: /notify message on (enable message notifications)", + "Example: /notify message text on (show message text in notifications)", + "Example: /notify room mention (enable chat room notifications only on mention)", + "Example: /notify room current off (disable room message notifications when window visible)", + "Example: /notify room text off (do not show message text in chat room notifications)", + "Example: /notify remind 10 (remind every 10 seconds)", + "Example: /notify remind 0 (switch off reminders)", + "Example: /notify typing on (enable typing notifications)", + "Example: /notify invite on (enable chat room invite notifications)", NULL } } }, { "/flash", @@ -687,8 +743,7 @@ static struct cmd_t command_defs[] = { "/flash on|off", "Terminal flash on new messages.", { "/flash on|off", "-------------", - "Make the terminal flash when incoming messages are received.", - "The flash will only occur if you are not in the chat window associated with the user sending the message.", + "Make the terminal flash when incoming messages are received in another window.", "If the terminal doesn't support flashing, it may attempt to beep.", NULL } } }, @@ -717,7 +772,7 @@ static struct cmd_t command_defs[] = "The setting can be overridden by the -a (--account) command line option.", "", "Example: /autoconnect set jc@stuntteam.org (autoconnect with the specified account).", - "Example: /autoconnect off (disable autoconnect).", + "Example: /autoconnect off (disable autoconnect).", NULL } } }, { "/vercheck", @@ -725,18 +780,18 @@ static struct cmd_t command_defs[] = { "/vercheck [on|off]", "Check for a new release.", { "/vercheck [on|off]", "------------------", - "Without a parameter will check for a new release.", - "Switching on or off will enable/disable a version check when Profanity starts, and each time the /about command is run.", + "Enable/disable a version check when Profanity starts, and each time the /about command is run.", NULL } } }, { "/titlebar", cmd_titlebar, parse_args, 2, 2, &cons_titlebar_setting, { "/titlebar show|goodbye on|off", "Manage the terminal window title.", { "/titlebar show|goodbye on|off", - "---------------------", + "-----------------------------", "Show or hide a title and exit message in the terminal window title.", - "show - Show current logged in user, and unread messages in the title.", - "goodbye - Show a message in the title when exiting profanity.", + "", + "show : Show current logged in user, and unread messages in the title.", + "goodbye : Show a message in the title when exiting profanity.", NULL } } }, { "/mouse", @@ -744,12 +799,7 @@ static struct cmd_t command_defs[] = { "/mouse on|off", "Use profanity mouse handling.", { "/mouse on|off", "-------------", - "If set to 'on', profanity will handle mouse actions, which enables scrolling the main window with the mouse wheel.", - "To select text, use the shift key while selcting an area.", - "If set to 'off', profanity leaves mouse handling to the terminal implementation.", - "This feature is experimental, certain mouse click events may occasionally freeze", - "Profanity until a key is pressed or another mouse event is received", - "The default is 'off'.", + "This feature is experimental, default is 'off'.", NULL } } }, { "/alias", @@ -758,12 +808,17 @@ static struct cmd_t command_defs[] = { "/alias add|remove|list [name value]", "-----------------------------------", "Add, remove or show command aliases.", - "The alias will be available as a command, the leading '/' will be added if not supplied.", - "Example : /alias add friends /who online friends", - "Example : /alias add /q /quit", - "Example : /alias a /away \"I'm in a meeting.\"", - "Example : /alias remove q", - "Example : /alias list", + "", + "add name value : Add a new command alias.", + "remove name : Remove a command alias.", + "list : List all aliases.", + "", + "Example: /alias add friends /who online friends", + "Example: /alias add /q /quit", + "Example: /alias a /away \"I'm in a meeting.\"", + "Example: /alias remove q", + "Example: /alias list", + "", "The above aliases will be available as /friends and /a", NULL } } }, @@ -792,29 +847,30 @@ static struct cmd_t command_defs[] = { "/states on|off", "Send chat states during a chat session.", { "/states on|off", "--------------", - "Sending of chat state notifications during chat sessions.", - "Such as whether you have become inactive, or have closed the chat window.", + "Send chat state notifications during chat sessions.", NULL } } }, { "/otr", cmd_otr, parse_args, 1, 3, NULL, - { "/otr gen|myfp|theirfp|start|end|trust|untrust|log|warn|libver|policy|secret|question|answer", "Off The Record encryption commands.", - { "/otr gen|myfp|theirfp|start|end|trust|untrust|log|warn|libver|policy|secret|question|answer", - "-------------------------------------------------------------------------------------------", - "gen - Generate your private key.", - "myfp - Show your fingerprint.", - "theirfp - Show contacts fingerprint.", - "start [contact] - Start an OTR session with the contact, or the current recipient if in a chat window and no argument supplied.", - "end - End the current OTR session,", - "trust - Indicate that you have verified the contact's fingerprint.", - "untrust - Indicate the the contact's fingerprint is not verified,", - "log - How to log OTR messages, options are 'on', 'off' and 'redact', with redaction being the default.", - "warn - Show when unencrypted messaging is being used in the title bar, options are 'on' and 'off' with 'on' being the default.", - "libver - Show which version of the libotr library is being used.", - "policy - manual, opportunistic or always.", - "secret [secret]- Verify a contacts identity using a shared secret.", - "question [question] [answer] - Verify a contacts identity using a question and expected anwser, if the question has spaces, surround with double quotes.", - "answer [answer] - Respond to a question answer verification request with your answer.", + { "/otr command [args..]", "Off The Record encryption commands.", + { "/otr command [args..]", + "---------------------", + "Off The Record encryption commands.", + "", + "gen : Generate your private key.", + "myfp : Show your fingerprint.", + "theirfp : Show contacts fingerprint.", + "start [contact] : Start an OTR session with contact, or current recipient if omitted.", + "end : End the current OTR session,", + "trust : Indicate that you have verified the contact's fingerprint.", + "untrust : Indicate the the contact's fingerprint is not verified,", + "log on|off|redact : OTR message logging, default: redact.", + "warn on|off : Show in the titlebar when unencrypted messaging is being used.", + "libver : Show which version of the libotr library is being used.", + "policy manual|opportunistic|always : Set the global OTR policy.", + "secret [secret] : Verify a contacts identity using a shared secret.", + "question [question] [answer] : Verify a contacts identity using a question and expected answer.", + "answer [answer] : Respond to a question answer verification request with your answer.", NULL } } }, { "/outtype", @@ -822,8 +878,7 @@ static struct cmd_t command_defs[] = { "/outtype on|off", "Send typing notification to recipient.", { "/outtype on|off", "---------------", - "Send an indication that you are typing to the chat recipient.", - "Chat states (/states) will be enabled if this setting is set.", + "Send typing notifications, chat states (/states) will be enabled if this setting is set.", NULL } } }, { "/gone", @@ -831,8 +886,7 @@ static struct cmd_t command_defs[] = { "/gone minutes", "Send 'gone' state to recipient after a period.", { "/gone minutes", "-------------", - "Send a 'gone' state to the recipient after the specified number of minutes." - "This indicates to the recipient's client that you have left the conversation.", + "Send a 'gone' state to the recipient after the specified number of minutes.", "A value of 0 will disable sending this chat state.", "Chat states (/states) will be enabled if this setting is set.", NULL } } }, @@ -848,15 +902,36 @@ static struct cmd_t command_defs[] = { "/log", cmd_log, parse_args, 1, 2, &cons_log_setting, - { "/log [property] [value]", "Manage system logging settings.", - { "/log [property] [value]", - "-----------------------", - "where : Show the current log file location.", - "Property may be one of:", - "rotate : Rotate log, accepts 'on' or 'off', defaults to 'on'.", - "maxsize : With rotate enabled, specifies the max log size, defaults to 1048580 (1MB).", - "shared : Share logs between all instances, accepts 'on' or 'off', defaults to 'on'.", - NULL } } }, + { "/log where|rotate|maxsize|shared [value]", "Manage system logging settings.", + { "/log where|rotate|maxsize|shared [value]", + "----------------------------------------", + "Manage profanity logging settings.", + "", + "where : Show the current log file location.", + "rotate on|off : Rotate log, default on.", + "maxsize bytes : With rotate enabled, specifies the max log size, defaults to 1048580 (1MB).", + "shared on|off : Share logs between all instances, default: on.", + NULL } } }, + + { "/carbons", + cmd_carbons, parse_args, 1, 1, &cons_carbons_setting, + { "/carbons on|off", "Message carbons.", + { "/carbons on|off", + "---------------", + "Enable or disable message carbons.", + "The message carbons feature ensures that both sides of all conversations are shared with all the user's clients that implement this protocol.", + NULL } } }, + + { "/receipts", + cmd_receipts, parse_args, 2, 2, &cons_receipts_setting, + { "/receipts send|request on|off", "Message delivery receipts.", + { "/receipts send|request on|off", + "-----------------------------", + "Enable or disable message delivery receipts. The interface will indicate when a message has been received.", + "", + "send on|off : Enable or disable sending of delivery receipts.", + "request on|off : Enable or disable sending of delivery receipt requests.", + NULL } } }, { "/reconnect", cmd_reconnect, parse_args, 1, 1, &cons_reconnect_setting, @@ -879,26 +954,25 @@ static struct cmd_t command_defs[] = { "/ping", cmd_ping, parse_args, 0, 1, NULL, { "/ping [target]", "Send ping IQ request.", - { "/ping [rarget]", + { "/ping [target]", "--------------", - "Sends an IQ ping stanza to the specificed target.", - "If no target is supplied, your chat server will be used.", + "Sends an IQ ping stanza to the specified target.", + "If no target is supplied, your chat server will be pinged.", NULL } } }, { "/autoaway", cmd_autoaway, parse_args_with_freetext, 2, 2, &cons_autoaway_setting, - { "/autoaway setting value", "Set auto idle/away properties.", - { "/autoaway setting value", - "-----------------------", - "'setting' may be one of 'mode', 'time', 'message' or 'check', with the following values:", - "", - "mode : idle - Sends idle time, whilst your status remains online.", - " away - Sends an away presence.", - " off - Disabled (default).", - "time : Number of minutes before the presence change is sent, the default is 15.", - "message : Optional message to send with the presence change.", - " : off - Disable message (default).", - "check : on|off, when enabled, checks for activity and sends online presence, default is 'on'.", + { "/autoaway mode|time|message|check value", "Set auto idle/away properties.", + { "/autoaway mode|time|message|check value", + "---------------------------------------", + "Manage autoway properties.", + "", + "mode idle : Sends idle time, status remains online.", + "mode away : Sends an away presence.", + "mode off : Disabled (default).", + "time minutes : Number of minutes before the presence change is sent, default: 15.", + "message text|off : Optional message to send with the presence change, default: off (disabled).", + "check on|off : When enabled, checks for activity and sends online presence, default: on.", "", "Example: /autoaway mode idle", "Example: /autoaway time 30", @@ -911,9 +985,11 @@ static struct cmd_t command_defs[] = { "/priority value", "Set priority for the current account.", { "/priority value", "---------------", - "Set priority for the current account, presence will be sent when calling this command.", - "See the /account command for more specific priority settings per presence status.", - "value : Number between -128 and 127. Default value is 0.", + "Set priority for the current account.", + "", + "value : Number between -128 and 127, default: 0.", + "", + "See the /account command for specific priority settings per presence status.", NULL } } }, { "/account", @@ -922,6 +998,7 @@ static struct cmd_t command_defs[] = { "/account [command] [account] [property] [value]", "-----------------------------------------------", "Commands for creating and managing accounts.", + "", "list : List all accounts.", "show account : Show information about an account.", "enable account : Enable the account, it will be used for autocomplete.", @@ -933,43 +1010,38 @@ static struct cmd_t command_defs[] = "set account property value : Set 'property' of 'account' to 'value'.", "clear account property value : Clear 'property' of 'account'.", "", - "When connected, the /account command can be called with no arguments, to show current account settings.", - "", - "The set command may use one of the following for 'property'.", - "jid : The Jabber ID of the account, the account name will be used if this property is not set.", - "server : The chat server, if different to the domainpart of the JID.", - "port : The port used for connecting if not the default (5222, or 5223 for SSL).", - "status : The presence status to use on login, use 'last' to use whatever your last status was.", - "online|chat|away", - "|xa|dnd : Priority for the specified presence.", - "resource : The resource to be used.", - "password : Password for the account, note this is currently stored in plaintext if set.", - "eval_password : Shell command evaluated to retrieve password for the account. Can be used to retrieve password from keyring.", - "muc : The default MUC chat service to use.", - "nick : The default nickname to use when joining chat rooms.", - "otr : Override global OTR policy for this account: manual, opportunistic or always.", - "", - "The clear command works for password, port and server", - "", - "Example : /account add work", - " : /account set work jid me@chatty", - " : /account set work server talk.chat.com", - " : /account set work port 5111", - " : /account set work resource desktop", - " : /account set work muc chatservice.mycompany.com", - " : /account set work nick dennis", - " : /account set work status dnd", - " : /account set work dnd -1", - " : /account set work online 10", - " : /account rename work gtalk", + "Account properties.", + "", + "jid : The Jabber ID of the account, account name will be used if not set.", + "server : The chat server, if different to the domainpart of the JID.", + "port : The port used for connecting if not the default (5222, or 5223 for SSL).", + "status : The presence status to use on login, use 'last' to use your last status before logging out.", + "online|chat|away|xa|dnd : Priority for the specified presence.", + "resource : The resource to be used.", + "password : Password for the account, note this is currently stored in plaintext if set.", + "eval_password : Shell command evaluated to retrieve password for the account. Can be used to retrieve password from keyring.", + "muc : The default MUC chat service to use.", + "nick : The default nickname to use when joining chat rooms.", + "otr : Override global OTR policy for this account: manual, opportunistic or always.", + "", + "Example: /account add me", + "Example: /account set me jid me@chatty", + "Example: /account set me server talk.chat.com", + "Example: /account set me port 5111", + "Example: /account set me muc chatservice.mycompany.com", + "Example: /account set me nick dennis", + "Example: /account set me status dnd", + "Example: /account set me dnd -1", + "Example: /account rename me gtalk", NULL } } }, { "/prefs", cmd_prefs, parse_args, 0, 1, NULL, - { "/prefs [area]", "Show configuration.", - { "/prefs [area]", - "-------------", - "Area is one of:", + { "/prefs [ui|desktop|chat|log|conn|presence]", "Show configuration.", + { "/prefs [ui|desktop|chat|log|conn|presence]", + "------------------------------------------", + "Show preferences for different areas of functionality.", + "", "ui : User interface preferences.", "desktop : Desktop notification preferences.", "chat : Chat state preferences.", @@ -977,22 +1049,22 @@ static struct cmd_t command_defs[] = "conn : Connection handling preferences.", "presence : Chat presence preferences.", "", - "No argument shows all categories.", + "No argument shows all preferences.", NULL } } }, { "/theme", cmd_theme, parse_args, 1, 2, &cons_theme_setting, - { "/theme list|set|colours [theme-name]", "Change colour theme.", - { "/theme list|set|colours [theme-name]", - "------------------------------------", - "Change the colour settings used.", + { "/theme list|load|colours [theme-name]", "Change colour theme.", + { "/theme list|load|colours [theme-name]", + "-------------------------------------", + "Load a theme, includes colours and UI options.", "", - "list : List all available themes.", - "set theme-name : Load the named theme.\"default\" will reset to the default colours.", - "colours : Show the colour values as rendered by the terminal.", + "list : List all available themes.", + "load theme-name : Load the named theme. 'default' will reset to the default theme.", + "colours : Show the colour values as rendered by the terminal.", "", - "Example : /theme list", - "Example : /theme set mycooltheme", + "Example: /theme list", + "Example: /theme load mycooltheme", NULL } } }, @@ -1001,12 +1073,23 @@ static struct cmd_t command_defs[] = { "/statuses console|chat|muc setting", "Set preferences for presence change messages.", { "/statuses console|chat|muc setting", "----------------------------------", - "Configure how presence changes are displayed in various windows.", - "Settings:", - " all - Show all presence changes.", - " online - Show only online/offline changes.", - " none - Don't show any presence changes.", + "Configure which presence changes are displayed in various windows.", + "", + "console : Configure what is displayed in the console window.", + "chat : Configure what is displayed in chat windows.", + "muc : Configure what is displayed in chat room windows.", + "", + "Available options are:", + "", + "all : Show all presence changes.", + "online : Show only online/offline changes.", + "none : Don't show any presence changes.", + "", "The default is 'all' for all windows.", + "", + "Example: /statuses console none", + "Example: /statuses chat online", + "Example: /statuses muc all", NULL } } }, { "/xmlconsole", @@ -1019,57 +1102,52 @@ static struct cmd_t command_defs[] = { "/away", cmd_away, parse_args_with_freetext, 0, 1, NULL, - { "/away [msg]", "Set status to away.", - { "/away [msg]", - "-----------", + { "/away [message]", "Set status to away.", + { "/away [message]", + "---------------", "Set your status to 'away' with the optional message.", - "Your current status can be found in the top right of the screen.", "", - "Example : /away Gone for lunch", + "Example: /away Gone for lunch", NULL } } }, { "/chat", cmd_chat, parse_args_with_freetext, 0, 1, NULL, - { "/chat [msg]", "Set status to chat (available for chat).", - { "/chat [msg]", - "-----------", + { "/chat [message]", "Set status to chat (available for chat).", + { "/chat [message]", + "---------------", "Set your status to 'chat', meaning 'available for chat', with the optional message.", - "Your current status can be found in the top right of the screen.", "", - "Example : /chat Please talk to me!", + "Example: /chat Please talk to me!", NULL } } }, { "/dnd", cmd_dnd, parse_args_with_freetext, 0, 1, NULL, - { "/dnd [msg]", "Set status to dnd (do not disturb).", - { "/dnd [msg]", - "----------", + { "/dnd [message]", "Set status to dnd (do not disturb).", + { "/dnd [message]", + "--------------", "Set your status to 'dnd', meaning 'do not disturb', with the optional message.", - "Your current status can be found in the top right of the screen.", "", - "Example : /dnd I'm in the zone", + "Example: /dnd I'm in the zone", NULL } } }, { "/online", cmd_online, parse_args_with_freetext, 0, 1, NULL, - { "/online [msg]", "Set status to online.", - { "/online [msg]", - "-------------", + { "/online [message]", "Set status to online.", + { "/online [message]", + "-----------------", "Set your status to 'online' with the optional message.", - "Your current status can be found in the top right of the screen.", "", - "Example : /online Up the Irons!", + "Example: /online Up the Irons!", NULL } } }, { "/xa", cmd_xa, parse_args_with_freetext, 0, 1, NULL, - { "/xa [msg]", "Set status to xa (extended away).", - { "/xa [msg]", - "---------", + { "/xa [message]", "Set status to xa (extended away).", + { "/xa [message]", + "-------------", "Set your status to 'xa', meaning 'extended away', with the optional message.", - "Your current status can be found in the top right of the screen.", "", - "Example : /xa This meeting is going to be a long one", + "Example: /xa This meeting is going to be a long one", NULL } } }, }; @@ -1121,8 +1199,12 @@ static Autocomplete form_ac; static Autocomplete form_field_multi_ac; static Autocomplete occupants_ac; static Autocomplete occupants_default_ac; +static Autocomplete occupants_show_ac; +static Autocomplete time_ac; +static Autocomplete time_statusbar_ac; static Autocomplete resource_ac; static Autocomplete inpblock_ac; +static Autocomplete receipts_ac; /* * Initialise command autocompleter and history @@ -1140,7 +1222,7 @@ cmd_init(void) autocomplete_add(help_ac, "basic"); autocomplete_add(help_ac, "chatting"); autocomplete_add(help_ac, "groupchat"); - autocomplete_add(help_ac, "presence"); + autocomplete_add(help_ac, "presences"); autocomplete_add(help_ac, "contacts"); autocomplete_add(help_ac, "service"); autocomplete_add(help_ac, "settings"); @@ -1163,7 +1245,7 @@ cmd_init(void) // load aliases GList *aliases = prefs_get_aliases(); GList *curr = aliases; - while (curr != NULL) { + while (curr) { ProfAlias *alias = curr->data; GString *ac_alias = g_string_new("/"); g_string_append(ac_alias, alias->name); @@ -1243,8 +1325,8 @@ cmd_init(void) autocomplete_add(autoconnect_ac, "off"); theme_ac = autocomplete_new(); + autocomplete_add(theme_ac, "load"); autocomplete_add(theme_ac, "list"); - autocomplete_add(theme_ac, "set"); autocomplete_add(theme_ac, "colours"); disco_ac = autocomplete_new(); @@ -1460,6 +1542,20 @@ cmd_init(void) autocomplete_add(occupants_default_ac, "show"); autocomplete_add(occupants_default_ac, "hide"); + occupants_show_ac = autocomplete_new(); + autocomplete_add(occupants_show_ac, "jid"); + + time_ac = autocomplete_new(); + autocomplete_add(time_ac, "minutes"); + autocomplete_add(time_ac, "seconds"); + autocomplete_add(time_ac, "off"); + autocomplete_add(time_ac, "statusbar"); + + time_statusbar_ac = autocomplete_new(); + autocomplete_add(time_statusbar_ac, "minutes"); + autocomplete_add(time_statusbar_ac, "seconds"); + autocomplete_add(time_statusbar_ac, "off"); + resource_ac = autocomplete_new(); autocomplete_add(resource_ac, "set"); autocomplete_add(resource_ac, "off"); @@ -1469,6 +1565,10 @@ cmd_init(void) inpblock_ac = autocomplete_new(); autocomplete_add(inpblock_ac, "timeout"); autocomplete_add(inpblock_ac, "dynamic"); + + receipts_ac = autocomplete_new(); + autocomplete_add(receipts_ac, "send"); + autocomplete_add(receipts_ac, "request"); } void @@ -1522,8 +1622,12 @@ cmd_uninit(void) autocomplete_free(form_field_multi_ac); autocomplete_free(occupants_ac); autocomplete_free(occupants_default_ac); + autocomplete_free(occupants_show_ac); + autocomplete_free(time_ac); + autocomplete_free(time_statusbar_ac); autocomplete_free(resource_ac); autocomplete_free(inpblock_ac); + autocomplete_free(receipts_ac); } gboolean @@ -1539,7 +1643,7 @@ cmd_exists(char *cmd) void cmd_autocomplete_add(char *value) { - if (commands_ac != NULL) { + if (commands_ac) { autocomplete_add(commands_ac, value); } } @@ -1547,41 +1651,45 @@ cmd_autocomplete_add(char *value) void cmd_autocomplete_add_form_fields(DataForm *form) { - if (form) { - GSList *fields = autocomplete_create_list(form->tag_ac); - GSList *curr_field = fields; - while (curr_field) { - GString *field_str = g_string_new("/"); - g_string_append(field_str, curr_field->data); - cmd_autocomplete_add(field_str->str); - g_string_free(field_str, TRUE); - curr_field = g_slist_next(curr_field); - } - g_slist_free_full(fields, free); + if (form == NULL) { + return; } + + GSList *fields = autocomplete_create_list(form->tag_ac); + GSList *curr_field = fields; + while (curr_field) { + GString *field_str = g_string_new("/"); + g_string_append(field_str, curr_field->data); + cmd_autocomplete_add(field_str->str); + g_string_free(field_str, TRUE); + curr_field = g_slist_next(curr_field); + } + g_slist_free_full(fields, free); } void cmd_autocomplete_remove_form_fields(DataForm *form) { - if (form) { - GSList *fields = autocomplete_create_list(form->tag_ac); - GSList *curr_field = fields; - while (curr_field) { - GString *field_str = g_string_new("/"); - g_string_append(field_str, curr_field->data); - cmd_autocomplete_remove(field_str->str); - g_string_free(field_str, TRUE); - curr_field = g_slist_next(curr_field); - } - g_slist_free_full(fields, free); + if (form == NULL) { + return; } + + GSList *fields = autocomplete_create_list(form->tag_ac); + GSList *curr_field = fields; + while (curr_field) { + GString *field_str = g_string_new("/"); + g_string_append(field_str, curr_field->data); + cmd_autocomplete_remove(field_str->str); + g_string_free(field_str, TRUE); + curr_field = g_slist_next(curr_field); + } + g_slist_free_full(fields, free); } void cmd_autocomplete_remove(char *value) { - if (commands_ac != NULL) { + if (commands_ac) { autocomplete_remove(commands_ac, value); } } @@ -1589,7 +1697,7 @@ cmd_autocomplete_remove(char *value) void cmd_alias_add(char *value) { - if (aliases_ac != NULL) { + if (aliases_ac) { autocomplete_add(aliases_ac, value); } } @@ -1597,7 +1705,7 @@ cmd_alias_add(char *value) void cmd_alias_remove(char *value) { - if (aliases_ac != NULL) { + if (aliases_ac) { autocomplete_remove(aliases_ac, value); } } @@ -1610,7 +1718,7 @@ cmd_autocomplete(const char * const input) if ((strncmp(input, "/", 1) == 0) && (!str_contains(input, strlen(input), ' '))) { char *found = NULL; found = autocomplete_complete(commands_ac, input, TRUE); - if (found != NULL) { + if (found) { return found; } @@ -1650,8 +1758,8 @@ cmd_reset_autocomplete() autocomplete_reset(autoaway_mode_ac); autocomplete_reset(autoconnect_ac); autocomplete_reset(theme_ac); - if (theme_load_ac != NULL) { - autocomplete_reset(theme_load_ac); + if (theme_load_ac) { + autocomplete_free(theme_load_ac); theme_load_ac = NULL; } autocomplete_reset(account_ac); @@ -1686,8 +1794,12 @@ cmd_reset_autocomplete() autocomplete_reset(form_field_multi_ac); autocomplete_reset(occupants_ac); autocomplete_reset(occupants_default_ac); + autocomplete_reset(occupants_show_ac); + autocomplete_reset(time_ac); + autocomplete_reset(time_statusbar_ac); autocomplete_reset(resource_ac); autocomplete_reset(inpblock_ac); + autocomplete_reset(receipts_ac); if (ui_current_win_type() == WIN_CHAT) { ProfChatWin *chatwin = wins_get_current_chat(); @@ -1724,11 +1836,6 @@ cmd_process_input(char *inp) gboolean result = FALSE; g_strstrip(inp); - // add line to history if something typed - if (strlen(inp) > 0) { - ui_inp_history_append(inp); - } - // just carry on if no input if (strlen(inp) == 0) { result = TRUE; @@ -1742,7 +1849,7 @@ cmd_process_input(char *inp) // call a default handler if input didn't start with '/' } else { - result = _cmd_execute_default(inp); + result = cmd_execute_default(inp); } return result; @@ -1782,7 +1889,7 @@ _cmd_execute(const char * const command, const char * const inp) Command *cmd = g_hash_table_lookup(commands, command); gboolean result = FALSE; - if (cmd != NULL) { + if (cmd) { gchar **args = cmd->parser(inp, cmd->min_args, cmd->max_args, &result); if (result == FALSE) { ui_invalid_command_usage(cmd->help.usage, cmd->setting_func); @@ -1794,145 +1901,15 @@ _cmd_execute(const char * const command, const char * const inp) } } else { gboolean ran_alias = FALSE; - gboolean alias_result = _cmd_execute_alias(inp, &ran_alias); + gboolean alias_result = cmd_execute_alias(inp, &ran_alias); if (!ran_alias) { - return _cmd_execute_default(inp); + return cmd_execute_default(inp); } else { return alias_result; } } } -static gboolean -_cmd_execute_alias(const char * const inp, gboolean *ran) -{ - if (inp[0] != '/') { - ran = FALSE; - return TRUE; - } else { - char *alias = strdup(inp+1); - char *value = prefs_get_alias(alias); - free(alias); - if (value != NULL) { - *ran = TRUE; - return cmd_process_input(value); - } else { - *ran = FALSE; - return TRUE; - } - } -} - -static gboolean -_cmd_execute_default(const char * inp) -{ - jabber_conn_status_t status = jabber_get_connection_status(); - - // 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(); - return TRUE; - } - - win_type_t win_type = ui_current_win_type(); - switch (win_type) - { - case WIN_MUC: - if (status != JABBER_CONNECTED) { - ui_current_print_line("You are not currently connected."); - } else { - ProfMucWin *mucwin = wins_get_current_muc(); - message_send_groupchat(mucwin->roomjid, inp); - } - break; - - case WIN_CHAT: - if (status != JABBER_CONNECTED) { - ui_current_print_line("You are not currently connected."); - } else { - ProfWin *current = wins_get_current(); - ProfChatWin *chatwin = (ProfChatWin*)current; - assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); -#ifdef HAVE_LIBOTR - prof_otrpolicy_t policy = otr_get_policy(chatwin->barejid); - if (policy == PROF_OTRPOLICY_ALWAYS && !otr_is_secure(chatwin->barejid)) { - cons_show_error("Failed to send message. Please check OTR policy"); - return TRUE; - } - if (otr_is_secure(chatwin->barejid)) { - char *encrypted = otr_encrypt_message(chatwin->barejid, inp); - if (encrypted != NULL) { - message_send_chat(chatwin->barejid, encrypted); - otr_free_message(encrypted); - if (prefs_get_boolean(PREF_CHLOG)) { - const char *jid = jabber_get_fulljid(); - Jid *jidp = jid_create(jid); - char *pref_otr_log = prefs_get_string(PREF_OTR_LOG); - if (strcmp(pref_otr_log, "on") == 0) { - chat_log_chat(jidp->barejid, chatwin->barejid, inp, PROF_OUT_LOG, NULL); - } else if (strcmp(pref_otr_log, "redact") == 0) { - chat_log_chat(jidp->barejid, chatwin->barejid, "[redacted]", PROF_OUT_LOG, NULL); - } - prefs_free_string(pref_otr_log); - jid_destroy(jidp); - } - - ui_outgoing_chat_msg("me", chatwin->barejid, inp); - } else { - cons_show_error("Failed to send message."); - } - } else { - message_send_chat(chatwin->barejid, inp); - if (prefs_get_boolean(PREF_CHLOG)) { - const char *jid = jabber_get_fulljid(); - Jid *jidp = jid_create(jid); - chat_log_chat(jidp->barejid, chatwin->barejid, inp, PROF_OUT_LOG, NULL); - jid_destroy(jidp); - } - - ui_outgoing_chat_msg("me", chatwin->barejid, inp); - } -#else - message_send_chat(chatwin->barejid, inp); - if (prefs_get_boolean(PREF_CHLOG)) { - const char *jid = jabber_get_fulljid(); - Jid *jidp = jid_create(jid); - chat_log_chat(jidp->barejid, chatwin->barejid, inp, PROF_OUT_LOG, NULL); - jid_destroy(jidp); - } - - ui_outgoing_chat_msg("me", chatwin->barejid, inp); -#endif - } - break; - - case WIN_PRIVATE: - if (status != JABBER_CONNECTED) { - ui_current_print_line("You are not currently connected."); - } else { - ProfPrivateWin *privatewin = wins_get_current_private(); - message_send_private(privatewin->fulljid, inp); - ui_outgoing_private_msg("me", privatewin->fulljid, inp); - } - break; - - case WIN_CONSOLE: - case WIN_XML: - cons_show("Unknown command: %s", inp); - break; - - default: - break; - } - - return TRUE; -} - static char * _cmd_complete_parameters(const char * const input) { @@ -1942,7 +1919,7 @@ _cmd_complete_parameters(const char * const input) // autocomplete boolean settings gchar *boolean_choices[] = { "/beep", "/intype", "/states", "/outtype", "/flash", "/splash", "/chlog", "/grlog", "/mouse", "/history", - "/vercheck", "/privileges", "/presence", "/wrap" }; + "/vercheck", "/privileges", "/presence", "/wrap", "/carbons" }; for (i = 0; i < ARRAY_SIZE(boolean_choices); i++) { result = autocomplete_param_with_func(input, boolean_choices[i], prefs_autocomplete_boolean_choice); @@ -1958,23 +1935,31 @@ _cmd_complete_parameters(const char * const input) if (nick_ac) { gchar *nick_choices[] = { "/msg", "/info", "/caps", "/status", "/software" } ; + // Remove quote character before and after names when doing autocomplete + char *unquoted = strip_arg_quotes(input); for (i = 0; i < ARRAY_SIZE(nick_choices); i++) { - result = autocomplete_param_with_ac(input, nick_choices[i], nick_ac, TRUE); + result = autocomplete_param_with_ac(unquoted, nick_choices[i], nick_ac, TRUE); if (result) { + free(unquoted); return result; } } + free(unquoted); } // otherwise autocomplete using roster } else { gchar *contact_choices[] = { "/msg", "/info", "/status" }; + // Remove quote character before and after names when doing autocomplete + char *unquoted = strip_arg_quotes(input); for (i = 0; i < ARRAY_SIZE(contact_choices); i++) { - result = autocomplete_param_with_func(input, contact_choices[i], roster_contact_autocomplete); + result = autocomplete_param_with_func(unquoted, contact_choices[i], roster_contact_autocomplete); if (result) { + free(unquoted); return result; } } + free(unquoted); gchar *resource_choices[] = { "/caps", "/software", "/ping" }; for (i = 0; i < ARRAY_SIZE(resource_choices); i++) { @@ -1998,8 +1983,8 @@ _cmd_complete_parameters(const char * const input) } } - gchar *cmds[] = { "/help", "/prefs", "/disco", "/close", "/wins", "/subject", "/room", }; - Autocomplete completers[] = { help_ac, prefs_ac, disco_ac, close_ac, wins_ac, subject_ac, room_ac, }; + gchar *cmds[] = { "/help", "/prefs", "/disco", "/close", "/wins", "/subject", "/room" }; + Autocomplete completers[] = { help_ac, prefs_ac, disco_ac, close_ac, wins_ac, subject_ac, room_ac }; for (i = 0; i < ARRAY_SIZE(cmds); i++) { result = autocomplete_param_with_ac(input, cmds[i], completers[i], TRUE); @@ -2034,6 +2019,8 @@ _cmd_complete_parameters(const char * const input) g_hash_table_insert(ac_funcs, "/resource", _resource_autocomplete); g_hash_table_insert(ac_funcs, "/titlebar", _titlebar_autocomplete); g_hash_table_insert(ac_funcs, "/inpblock", _inpblock_autocomplete); + g_hash_table_insert(ac_funcs, "/time", _time_autocomplete); + g_hash_table_insert(ac_funcs, "/receipts", _receipts_autocomplete); int len = strlen(input); char parsed[len+1]; @@ -2049,7 +2036,7 @@ _cmd_complete_parameters(const char * const input) parsed[i] = '\0'; char * (*ac_func)(const char * const) = g_hash_table_lookup(ac_funcs, parsed); - if (ac_func != NULL) { + if (ac_func) { result = ac_func(input); if (result) { g_hash_table_destroy(ac_funcs); @@ -2073,15 +2060,15 @@ _sub_autocomplete(const char * const input) { char *result = NULL; result = autocomplete_param_with_func(input, "/sub allow", presence_sub_request_find); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_func(input, "/sub deny", presence_sub_request_find); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_ac(input, "/sub", sub_ac, TRUE); - if (result != NULL) { + if (result) { return result; } @@ -2096,7 +2083,7 @@ _who_autocomplete(const char * const input) if (win_type == WIN_MUC) { result = autocomplete_param_with_ac(input, "/who", who_room_ac, TRUE); - if (result != NULL) { + if (result) { return result; } } else { @@ -2107,13 +2094,13 @@ _who_autocomplete(const char * const input) for (i = 0; i < ARRAY_SIZE(group_commands); i++) { result = autocomplete_param_with_func(input, group_commands[i], roster_group_autocomplete); - if (result != NULL) { + if (result) { return result; } } result = autocomplete_param_with_ac(input, "/who", who_roster_ac, TRUE); - if (result != NULL) { + if (result) { return result; } } @@ -2126,31 +2113,31 @@ _roster_autocomplete(const char * const input) { char *result = NULL; result = autocomplete_param_with_func(input, "/roster nick", roster_barejid_autocomplete); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_func(input, "/roster clearnick", roster_barejid_autocomplete); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_func(input, "/roster remove", roster_barejid_autocomplete); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_ac(input, "/roster show", roster_option_ac, TRUE); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_ac(input, "/roster hide", roster_option_ac, TRUE); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_ac(input, "/roster by", roster_by_ac, TRUE); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_ac(input, "/roster", roster_ac, TRUE); - if (result != NULL) { + if (result) { return result; } @@ -2162,28 +2149,28 @@ _group_autocomplete(const char * const input) { char *result = NULL; result = autocomplete_param_with_func(input, "/group show", roster_group_autocomplete); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_no_with_func(input, "/group add", 4, roster_contact_autocomplete); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_no_with_func(input, "/group remove", 4, roster_contact_autocomplete); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_func(input, "/group add", roster_group_autocomplete); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_func(input, "/group remove", roster_group_autocomplete); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_ac(input, "/group", group_ac, TRUE); - if (result != NULL) { + if (result) { return result; } @@ -2244,7 +2231,7 @@ _bookmark_autocomplete(const char * const input) found = autocomplete_param_with_ac(input, beginning->str, bookmark_property_ac, TRUE); } g_string_free(beginning, TRUE); - if (found != NULL) { + if (found) { g_strfreev(args); return found; } @@ -2253,15 +2240,15 @@ _bookmark_autocomplete(const char * const input) g_strfreev(args); found = autocomplete_param_with_func(input, "/bookmark remove", bookmark_find); - if (found != NULL) { + if (found) { return found; } found = autocomplete_param_with_func(input, "/bookmark join", bookmark_find); - if (found != NULL) { + if (found) { return found; } found = autocomplete_param_with_func(input, "/bookmark update", bookmark_find); - if (found != NULL) { + if (found) { return found; } @@ -2276,42 +2263,42 @@ _notify_autocomplete(const char * const input) char *result = NULL; result = autocomplete_param_with_func(input, "/notify room current", prefs_autocomplete_boolean_choice); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_func(input, "/notify message current", prefs_autocomplete_boolean_choice); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_func(input, "/notify typing current", prefs_autocomplete_boolean_choice); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_func(input, "/notify room text", prefs_autocomplete_boolean_choice); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_func(input, "/notify message text", prefs_autocomplete_boolean_choice); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_ac(input, "/notify room", notify_room_ac, TRUE); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_ac(input, "/notify message", notify_message_ac, TRUE); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_ac(input, "/notify typing", notify_typing_ac, TRUE); - if (result != NULL) { + if (result) { return result; } @@ -2319,13 +2306,13 @@ _notify_autocomplete(const char * const input) for (i = 0; i < ARRAY_SIZE(boolean_choices); i++) { result = autocomplete_param_with_func(input, boolean_choices[i], prefs_autocomplete_boolean_choice); - if (result != NULL) { + if (result) { return result; } } result = autocomplete_param_with_ac(input, "/notify", notify_ac, TRUE); - if (result != NULL) { + if (result) { return result; } @@ -2338,16 +2325,16 @@ _autoaway_autocomplete(const char * const input) char *result = NULL; result = autocomplete_param_with_ac(input, "/autoaway mode", autoaway_mode_ac, TRUE); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_func(input, "/autoaway check", prefs_autocomplete_boolean_choice); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_ac(input, "/autoaway", autoaway_ac, TRUE); - if (result != NULL) { + if (result) { return result; } @@ -2361,16 +2348,16 @@ _log_autocomplete(const char * const input) result = autocomplete_param_with_func(input, "/log rotate", prefs_autocomplete_boolean_choice); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_func(input, "/log shared", prefs_autocomplete_boolean_choice); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_ac(input, "/log", log_ac, TRUE); - if (result != NULL) { + if (result) { return result; } @@ -2383,12 +2370,12 @@ _autoconnect_autocomplete(const char * const input) char *result = NULL; result = autocomplete_param_with_func(input, "/autoconnect set", accounts_find_enabled); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_ac(input, "/autoconnect", autoconnect_ac, TRUE); - if (result != NULL) { + if (result) { return result; } @@ -2401,12 +2388,12 @@ _otr_autocomplete(const char * const input) char *found = NULL; found = autocomplete_param_with_func(input, "/otr start", roster_contact_autocomplete); - if (found != NULL) { + if (found) { return found; } found = autocomplete_param_with_ac(input, "/otr log", otr_log_ac, TRUE); - if (found != NULL) { + if (found) { return found; } @@ -2421,7 +2408,7 @@ _otr_autocomplete(const char * const input) found = autocomplete_param_with_func(input, beginning->str, roster_contact_autocomplete); g_string_free(beginning, TRUE); - if (found != NULL) { + if (found) { g_strfreev(args); return found; } @@ -2430,18 +2417,18 @@ _otr_autocomplete(const char * const input) g_strfreev(args); found = autocomplete_param_with_ac(input, "/otr policy", otr_policy_ac, TRUE); - if (found != NULL) { + if (found) { return found; } found = autocomplete_param_with_func(input, "/otr warn", prefs_autocomplete_boolean_choice); - if (found != NULL) { + if (found) { return found; } found = autocomplete_param_with_ac(input, "/otr", otr_ac, TRUE); - if (found != NULL) { + if (found) { return found; } @@ -2452,24 +2439,25 @@ static char * _theme_autocomplete(const char * const input) { char *result = NULL; - if ((strncmp(input, "/theme set ", 11) == 0) && (strlen(input) > 11)) { + if ((strncmp(input, "/theme load ", 12) == 0) && (strlen(input) > 12)) { if (theme_load_ac == NULL) { theme_load_ac = autocomplete_new(); GSList *themes = theme_list(); - while (themes != NULL) { - autocomplete_add(theme_load_ac, themes->data); - themes = g_slist_next(themes); + GSList *curr = themes; + while (curr) { + autocomplete_add(theme_load_ac, curr->data); + curr = g_slist_next(curr); } - g_slist_free(themes); + g_slist_free_full(themes, g_free); autocomplete_add(theme_load_ac, "default"); } - result = autocomplete_param_with_ac(input, "/theme set", theme_load_ac, TRUE); - if (result != NULL) { + result = autocomplete_param_with_ac(input, "/theme load", theme_load_ac, TRUE); + if (result) { return result; } } result = autocomplete_param_with_ac(input, "/theme", theme_ac, TRUE); - if (result != NULL) { + if (result) { return result; } @@ -2488,24 +2476,24 @@ _resource_autocomplete(const char * const input) if (contact) { Autocomplete ac = p_contact_resource_ac(contact); found = autocomplete_param_with_ac(input, "/resource set", ac, FALSE); - if (found != NULL) { + if (found) { return found; } } } found = autocomplete_param_with_func(input, "/resource title", prefs_autocomplete_boolean_choice); - if (found != NULL) { + if (found) { return found; } found = autocomplete_param_with_func(input, "/resource message", prefs_autocomplete_boolean_choice); - if (found != NULL) { + if (found) { return found; } found = autocomplete_param_with_ac(input, "/resource", resource_ac, FALSE); - if (found != NULL) { + if (found) { return found; } @@ -2518,17 +2506,17 @@ _titlebar_autocomplete(const char * const input) char *found = NULL; found = autocomplete_param_with_func(input, "/titlebar show", prefs_autocomplete_boolean_choice); - if (found != NULL) { + if (found) { return found; } found = autocomplete_param_with_func(input, "/titlebar goodbye", prefs_autocomplete_boolean_choice); - if (found != NULL) { + if (found) { return found; } found = autocomplete_param_with_ac(input, "/titlebar", titlebar_ac, FALSE); - if (found != NULL) { + if (found) { return found; } @@ -2541,12 +2529,12 @@ _inpblock_autocomplete(const char * const input) char *found = NULL; found = autocomplete_param_with_func(input, "/inpblock dynamic", prefs_autocomplete_boolean_choice); - if (found != NULL) { + if (found) { return found; } found = autocomplete_param_with_ac(input, "/inpblock", inpblock_ac, FALSE); - if (found != NULL) { + if (found) { return found; } @@ -2567,13 +2555,13 @@ _form_autocomplete(const char * const input) DataForm *form = confwin->form; if (form) { found = autocomplete_param_with_ac(input, "/form help", form->tag_ac, TRUE); - if (found != NULL) { + if (found) { return found; } } found = autocomplete_param_with_ac(input, "/form", form_ac, TRUE); - if (found != NULL) { + if (found) { return found; } @@ -2656,13 +2644,51 @@ _occupants_autocomplete(const char * const input) { char *found = NULL; + found = autocomplete_param_with_ac(input, "/occupants default show", occupants_show_ac, TRUE); + if (found) { + return found; + } + + found = autocomplete_param_with_ac(input, "/occupants default hide", occupants_show_ac, TRUE); + if (found) { + return found; + } + found = autocomplete_param_with_ac(input, "/occupants default", occupants_default_ac, TRUE); - if (found != NULL) { + if (found) { + return found; + } + + found = autocomplete_param_with_ac(input, "/occupants show", occupants_show_ac, TRUE); + if (found) { + return found; + } + + found = autocomplete_param_with_ac(input, "/occupants hide", occupants_show_ac, TRUE); + if (found) { return found; } found = autocomplete_param_with_ac(input, "/occupants", occupants_ac, TRUE); - if (found != NULL) { + if (found) { + return found; + } + + return NULL; +} + +static char * +_time_autocomplete(const char * const input) +{ + char *found = NULL; + + found = autocomplete_param_with_ac(input, "/time statusbar", time_statusbar_ac, TRUE); + if (found) { + return found; + } + + found = autocomplete_param_with_ac(input, "/time", time_ac, TRUE); + if (found) { return found; } @@ -2678,9 +2704,9 @@ _kick_autocomplete(const char * const input) ProfMucWin *mucwin = wins_get_current_muc(); Autocomplete nick_ac = muc_roster_ac(mucwin->roomjid); - if (nick_ac != NULL) { + if (nick_ac) { result = autocomplete_param_with_ac(input, "/kick", nick_ac, TRUE); - if (result != NULL) { + if (result) { return result; } } @@ -2698,9 +2724,9 @@ _ban_autocomplete(const char * const input) ProfMucWin *mucwin = wins_get_current_muc(); Autocomplete jid_ac = muc_roster_jid_ac(mucwin->roomjid); - if (jid_ac != NULL) { + if (jid_ac) { result = autocomplete_param_with_ac(input, "/ban", jid_ac, TRUE); - if (result != NULL) { + if (result) { return result; } } @@ -2729,7 +2755,7 @@ _affiliation_autocomplete(const char * const input) result = autocomplete_param_with_ac(input, beginning->str, jid_ac, TRUE); g_string_free(beginning, TRUE); - if (result != NULL) { + if (result) { g_strfreev(args); return result; } @@ -2739,17 +2765,17 @@ _affiliation_autocomplete(const char * const input) } result = autocomplete_param_with_ac(input, "/affiliation set", affiliation_ac, TRUE); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_ac(input, "/affiliation list", affiliation_ac, TRUE); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_ac(input, "/affiliation", privilege_cmd_ac, TRUE); - if (result != NULL) { + if (result) { return result; } @@ -2776,7 +2802,7 @@ _role_autocomplete(const char * const input) result = autocomplete_param_with_ac(input, beginning->str, nick_ac, TRUE); g_string_free(beginning, TRUE); - if (result != NULL) { + if (result) { g_strfreev(args); return result; } @@ -2786,17 +2812,17 @@ _role_autocomplete(const char * const input) } result = autocomplete_param_with_ac(input, "/role set", role_ac, TRUE); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_ac(input, "/role list", role_ac, TRUE); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_ac(input, "/role", privilege_cmd_ac, TRUE); - if (result != NULL) { + if (result) { return result; } @@ -2809,22 +2835,45 @@ _statuses_autocomplete(const char * const input) char *result = NULL; result = autocomplete_param_with_ac(input, "/statuses console", statuses_setting_ac, TRUE); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_ac(input, "/statuses chat", statuses_setting_ac, TRUE); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_ac(input, "/statuses muc", statuses_setting_ac, TRUE); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_ac(input, "/statuses", statuses_ac, TRUE); - if (result != NULL) { + if (result) { + return result; + } + + return NULL; +} + +static char * +_receipts_autocomplete(const char * const input) +{ + char *result = NULL; + + result = autocomplete_param_with_func(input, "/receipts send", prefs_autocomplete_boolean_choice); + if (result) { + return result; + } + + result = autocomplete_param_with_func(input, "/receipts request", prefs_autocomplete_boolean_choice); + if (result) { + return result; + } + + result = autocomplete_param_with_ac(input, "/receipts", receipts_ac, TRUE); + if (result) { return result; } @@ -2837,12 +2886,12 @@ _alias_autocomplete(const char * const input) char *result = NULL; result = autocomplete_param_with_ac(input, "/alias remove", aliases_ac, TRUE); - if (result != NULL) { + if (result) { return result; } result = autocomplete_param_with_ac(input, "/alias", alias_ac, TRUE); - if (result != NULL) { + if (result) { return result; } @@ -2860,7 +2909,7 @@ _connect_autocomplete(const char * const input) if ((strncmp(input, "/connect", 8) == 0) && (result == TRUE)) { GString *beginning = g_string_new("/connect "); g_string_append(beginning, args[0]); - if (args[1] != NULL && args[2] != NULL) { + if (args[1] && args[2]) { g_string_append(beginning, " "); g_string_append(beginning, args[1]); g_string_append(beginning, " "); @@ -2868,7 +2917,7 @@ _connect_autocomplete(const char * const input) } found = autocomplete_param_with_ac(input, beginning->str, connect_property_ac, TRUE); g_string_free(beginning, TRUE); - if (found != NULL) { + if (found) { g_strfreev(args); return found; } @@ -2877,7 +2926,7 @@ _connect_autocomplete(const char * const input) g_strfreev(args); found = autocomplete_param_with_func(input, "/connect", accounts_find_enabled); - if (found != NULL) { + if (found) { return found; } @@ -2891,7 +2940,7 @@ _join_autocomplete(const char * const input) gboolean result = FALSE; found = autocomplete_param_with_func(input, "/join", bookmark_find); - if (found != NULL) { + if (found) { return found; } @@ -2900,7 +2949,7 @@ _join_autocomplete(const char * const input) if ((strncmp(input, "/join", 5) == 0) && (result == TRUE)) { GString *beginning = g_string_new("/join "); g_string_append(beginning, args[0]); - if (args[1] != NULL && args[2] != NULL) { + if (args[1] && args[2]) { g_string_append(beginning, " "); g_string_append(beginning, args[1]); g_string_append(beginning, " "); @@ -2908,7 +2957,7 @@ _join_autocomplete(const char * const input) } found = autocomplete_param_with_ac(input, beginning->str, join_property_ac, TRUE); g_string_free(beginning, TRUE); - if (found != NULL) { + if (found) { g_strfreev(args); return found; } @@ -2935,14 +2984,14 @@ _account_autocomplete(const char * const input) g_string_append(beginning, args[2]); found = autocomplete_param_with_ac(input, beginning->str, otr_policy_ac, TRUE); g_string_free(beginning, TRUE); - if (found != NULL) { + if (found) { g_strfreev(args); return found; } } else { found = autocomplete_param_with_ac(input, beginning->str, account_set_ac, TRUE); g_string_free(beginning, TRUE); - if (found != NULL) { + if (found) { g_strfreev(args); return found; } @@ -2954,7 +3003,7 @@ _account_autocomplete(const char * const input) g_string_append(beginning, args[1]); found = autocomplete_param_with_ac(input, beginning->str, account_clear_ac, TRUE); g_string_free(beginning, TRUE); - if (found != NULL) { + if (found) { g_strfreev(args); return found; } @@ -2974,7 +3023,7 @@ _account_autocomplete(const char * const input) for (i = 0; i < ARRAY_SIZE(account_choice); i++) { found = autocomplete_param_with_func(input, account_choice[i], accounts_find_all); - if (found != NULL) { + if (found) { return found; } } @@ -2982,3 +3031,55 @@ _account_autocomplete(const char * const input) found = autocomplete_param_with_ac(input, "/account", account_ac, TRUE); return found; } + +static int +_cmp_command(Command *cmd1, Command *cmd2) +{ + return g_strcmp0(cmd1->cmd, cmd2->cmd); +} + +void +command_docgen(void) +{ + GList *cmds = NULL; + unsigned int i; + for (i = 0; i < ARRAY_SIZE(command_defs); i++) { + Command *pcmd = command_defs+i; + cmds = g_list_insert_sorted(cmds, pcmd, (GCompareFunc)_cmp_command); + } + + FILE *toc_fragment = fopen("toc_fragment.html", "w"); + FILE *main_fragment = fopen("main_fragment.html", "w"); + + fputs("<ul><li><ul><li>\n", toc_fragment); + fputs("<hr>\n", main_fragment); + + GList *curr = cmds; + while (curr) { + Command *pcmd = curr->data; + + fprintf(toc_fragment, "<a href=\"#%s\">%s</a>,\n", &pcmd->cmd[1], pcmd->cmd); + + fprintf(main_fragment, "<a name=\"%s\"></a>\n", &pcmd->cmd[1]); + fprintf(main_fragment, "<h4>%s</h4>\n", pcmd->cmd); + fputs("<p>Usage:</p>\n", main_fragment); + fprintf(main_fragment, "<p><pre><code>%s</code></pre></p>\n", pcmd->help.usage); + + fputs("<p>Details:</p>\n", main_fragment); + fputs("<p><pre><code>", main_fragment); + int i = 2; + while (pcmd->help.long_help[i]) { + fprintf(main_fragment, "%s\n", pcmd->help.long_help[i++]); + } + fputs("</code></pre></p>\n<a href=\"#top\"><h5>back to top</h5></a><br><hr>\n", main_fragment); + fputs("\n", main_fragment); + + curr = g_list_next(curr); + } + + fputs("</ul></ul>\n", toc_fragment); + + fclose(toc_fragment); + fclose(main_fragment); + g_list_free(cmds); +} diff --git a/src/command/command.h b/src/command/command.h index ffbccfa4..b500404b 100644 --- a/src/command/command.h +++ b/src/command/command.h @@ -1,7 +1,7 @@ /* * command.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -66,4 +66,6 @@ void cmd_history_append(char *inp); char *cmd_history_previous(char *inp); char *cmd_history_next(char *inp); +void command_docgen(void); + #endif diff --git a/src/command/commands.c b/src/command/commands.c index 02910f99..c5350519 100644 --- a/src/command/commands.c +++ b/src/command/commands.c @@ -1,7 +1,7 @@ /* * commands.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -38,10 +38,8 @@ #include <stdlib.h> #include <errno.h> #include <assert.h> +#include <uuid/uuid.h> #include <glib.h> -#ifdef HAVE_LIBOTR -#include <libotr/proto.h> -#endif #include "chat_session.h" #include "command/commands.h" @@ -67,12 +65,13 @@ #include "xmpp/bookmark.h" #include "ui/ui.h" #include "ui/windows.h" +#include "event/client_events.h" +#include "event/ui_events.h" static void _update_presence(const resource_presence_t presence, const char * const show, gchar **args); static gboolean _cmd_set_boolean_preference(gchar *arg, struct cmd_help_t help, const char * const display, preference_t pref); -static int _strtoi(char *str, int *saveptr, int min, int max); static void _cmd_show_filtered_help(char *heading, gchar *cmd_filter[], int filter_size); static gint _compare_commands(Command *a, Command *b); static void _who_room(gchar **args, struct cmd_help_t help); @@ -81,115 +80,178 @@ static void _who_roster(gchar **args, struct cmd_help_t help); extern GHashTable *commands; gboolean -cmd_connect(gchar **args, struct cmd_help_t help) +cmd_execute_default(const char * inp) { - gboolean result = FALSE; + // handle escaped commands - treat as normal message + if (g_str_has_prefix(inp, "//")) { + inp++; - jabber_conn_status_t conn_status = jabber_get_connection_status(); + // handle unknown commands + } else if ((inp[0] == '/') && (!g_str_has_prefix(inp, "/me "))) { + cons_show("Unknown command: %s", inp); + cons_alert(); + return TRUE; + } + + // handle non commands in non chat windows + ProfWin *current = wins_get_current(); + if (current->type != WIN_CHAT && current->type != WIN_MUC && current->type != WIN_PRIVATE) { + cons_show("Unknown command: %s", inp); + return TRUE; + } + + jabber_conn_status_t status = jabber_get_connection_status(); + if (status != JABBER_CONNECTED) { + ui_current_print_line("You are not currently connected."); + return TRUE; + } + + switch (current->type) { + case WIN_CHAT: + { + ProfChatWin *chatwin = wins_get_current_chat(); + cl_ev_send_msg(chatwin, inp); + break; + } + case WIN_PRIVATE: + { + ProfPrivateWin *privatewin = wins_get_current_private(); + cl_ev_send_priv_msg(privatewin, inp); + break; + } + case WIN_MUC: + { + ProfMucWin *mucwin = wins_get_current_muc(); + cl_ev_send_muc_msg(mucwin, inp); + break; + } + default: + break; + } + + return TRUE; +} + +gboolean +cmd_execute_alias(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; + return cmd_process_input(value); + } + *ran = FALSE; + return TRUE; +} + +gboolean +cmd_connect(gchar **args, struct cmd_help_t help) +{ + jabber_conn_status_t conn_status = jabber_get_connection_status(); if ((conn_status != JABBER_DISCONNECTED) && (conn_status != JABBER_STARTED)) { cons_show("You are either connected already, or a login is in process."); - result = TRUE; - } else { - gchar *opt_keys[] = { "server", "port", NULL }; - gboolean parsed; + return TRUE; + } - GHashTable *options = parse_options(&args[args[0] ? 1 : 0], opt_keys, &parsed); - if (!parsed) { - cons_show("Usage: %s", help.usage); + gchar *opt_keys[] = { "server", "port", NULL }; + gboolean parsed; + + GHashTable *options = parse_options(&args[args[0] ? 1 : 0], opt_keys, &parsed); + if (!parsed) { + cons_show("Usage: %s", help.usage); + cons_show(""); + return TRUE; + } + + char *altdomain = g_hash_table_lookup(options, "server"); + + 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; return TRUE; } + } - char *altdomain = g_hash_table_lookup(options, "server"); - - int port = 0; - if (g_hash_table_contains(options, "port")) { - char *port_str = g_hash_table_lookup(options, "port"); - if (_strtoi(port_str, &port, 1, 65535) != 0) { - port = 0; - cons_show(""); - 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."); + g_free(def); + 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); + char *lower = g_utf8_strdown(user, -1); + char *jid; + g_free(def); + + // connect with account + ProfAccount *account = accounts_get_account(lower); + if (account) { + // 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("No default account."); - g_free(def); + cons_show("Error evaluating password, see logs for details."); + g_free(lower); return TRUE; } - } - char *lower = g_utf8_strdown(user, -1); - char *jid; - g_free(def); - def = NULL; - - ProfAccount *account = accounts_get_account(lower); - if (account != NULL) { - jid = account_create_full_jid(account); - if(account->eval_password){ - // Evaluate as shell command to retrieve password - GString *cmd = g_string_append(g_string_new(account->eval_password), " 2>/dev/null"); - FILE *stream = popen(cmd->str, "r"); - g_string_free(cmd, TRUE); - if(stream){ - // Limit to READ_BUF_SIZE bytes to prevent overflows in the case of a poorly chosen command - account->password = g_malloc(READ_BUF_SIZE); - if(!account->password){ - log_error("Failed to allocate enough memory to read eval_password output"); - cons_show("Error evaluating password, see logs for details."); - return TRUE; - } - account->password = fgets(account->password, READ_BUF_SIZE, stream); - pclose(stream); - if(!account->password){ - log_error("No result from eval_password."); - cons_show("Error evaluating password, see logs for details."); - return TRUE; - } - g_strstrip(account->password); - } else { - log_error("popen failed when running eval_password."); - cons_show("Error evaluating password, see logs for details."); - return TRUE; - } - } else if (!account->password) { - account->password = ui_ask_password(); - } - cons_show("Connecting with account %s as %s", account->name, jid); - if(g_hash_table_contains(options, "port") || g_hash_table_contains(options, "server")) - cons_show("Ignoring extra connect options. Please set them with /account set"); - conn_status = jabber_connect_with_account(account); - account_free(account); + // no account password setting, prompt } else { - char *passwd = ui_ask_password(); - jid = strdup(lower); - cons_show("Connecting as %s", jid); - conn_status = jabber_connect_with_details(jid, passwd, altdomain, port); - free(passwd); - } - g_free(lower); - - if (conn_status == JABBER_DISCONNECTED) { - cons_show_error("Connection attempt for %s failed.", jid); - log_info("Connection attempt for %s failed", jid); + account->password = ui_ask_password(); + conn_status = cl_ev_connect_account(account); + free(account->password); + account->password = NULL; } - options_destroy(options); + jid = account_create_full_jid(account); - free(jid); + // connect with JID + } else { + jid = strdup(lower); + char *passwd = ui_ask_password(); + conn_status = cl_ev_connect_jid(jid, passwd, altdomain, port); + free(passwd); + } - result = TRUE; + if (conn_status == JABBER_DISCONNECTED) { + cons_show_error("Connection attempt for %s failed.", jid); + log_info("Connection attempt for %s failed", jid); } - return result; + options_destroy(options); + g_free(lower); + free(jid); + + return TRUE; } gboolean @@ -342,7 +404,7 @@ cmd_account(gchar **args, struct cmd_help_t help) } else { accounts_set_jid(account_name, jid->barejid); cons_show("Updated jid for account %s: %s", account_name, jid->barejid); - if (jid->resourcepart != NULL) { + if (jid->resourcepart) { accounts_set_resource(account_name, jid->resourcepart); cons_show("Updated resource for account %s: %s", account_name, jid->resourcepart); } @@ -355,8 +417,12 @@ cmd_account(gchar **args, struct cmd_help_t help) cons_show(""); } else if (strcmp(property, "port") == 0) { int port; - if (_strtoi(value, &port, 1, 65535) != 0) { + char *err_msg = NULL; + gboolean res = strtoi_range(value, &port, 1, 65535, &err_msg); + if (!res) { + cons_show(err_msg); cons_show(""); + free(err_msg); return TRUE; } else { accounts_set_port(account_name, port); @@ -368,7 +434,7 @@ cmd_account(gchar **args, struct cmd_help_t help) cons_show("Updated resource for account %s: %s", account_name, value); cons_show(""); } else if (strcmp(property, "password") == 0) { - if(accounts_get_account(account_name)->eval_password != NULL) { + if(accounts_get_account(account_name)->eval_password) { cons_show("Cannot set password when eval_password is set."); } else { accounts_set_password(account_name, value); @@ -376,7 +442,7 @@ cmd_account(gchar **args, struct cmd_help_t help) cons_show(""); } } else if (strcmp(property, "eval_password") == 0) { - if(accounts_get_account(account_name)->password != NULL) { + if(accounts_get_account(account_name)->password) { cons_show("Cannot set eval_password when password is set."); } else { accounts_set_eval_password(account_name, value); @@ -410,42 +476,46 @@ cmd_account(gchar **args, struct cmd_help_t help) } cons_show(""); } else if (valid_resource_presence_string(property)) { - int intval; - - if (_strtoi(value, &intval, -128, 127) == 0) { - resource_presence_t presence_type = resource_presence_from_string(property); - 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; - } + int intval; + char *err_msg = NULL; + gboolean res = strtoi_range(value, &intval, -128, 127, &err_msg); + if (res) { + resource_presence_t presence_type = resource_presence_from_string(property); + 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 = jabber_get_connection_status(); - if (conn_status == JABBER_CONNECTED) { - char *connected_account = jabber_get_account_name(); - resource_presence_t last_presence = accounts_get_last_presence(connected_account); + jabber_conn_status_t conn_status = jabber_get_connection_status(); + if (conn_status == JABBER_CONNECTED) { + char *connected_account = jabber_get_account_name(); + resource_presence_t last_presence = accounts_get_last_presence(connected_account); - if (presence_type == last_presence) { - char *message = jabber_get_presence_message(); - presence_update(last_presence, message, 0); - } + if (presence_type == last_presence) { + char *message = jabber_get_presence_message(); + cl_ev_presence_send(last_presence, message, 0); } - cons_show("Updated %s priority for account %s: %s", property, account_name, value); - cons_show(""); } + cons_show("Updated %s priority for account %s: %s", property, account_name, value); + cons_show(""); + } else { + cons_show(err_msg); + free(err_msg); + } } else { cons_show("Invalid property: %s", property); cons_show(""); @@ -652,10 +722,14 @@ gboolean cmd_win(gchar **args, struct cmd_help_t help) { int num = atoi(args[0]); - gboolean switched = ui_switch_win(num); - if (switched == FALSE) { + + ProfWin *window = wins_get_by_num(num); + if (!window) { cons_show("Window %d does not exist.", num); + } else { + ui_ev_focus_win(window); } + return TRUE; } @@ -681,7 +755,7 @@ cmd_help(gchar **args, struct cmd_help_t help) } GList *curr = ordered_commands; - while (curr != NULL) { + while (curr) { Command *cmd = curr->data; cons_show("%-12s: %s", cmd->cmd, cmd->help.short_help); curr = g_list_next(curr); @@ -711,7 +785,7 @@ cmd_help(gchar **args, struct cmd_help_t help) "/rooms", "/tiny", "/who", "/nick", "/privileges", "/info", "/occupants" }; _cmd_show_filtered_help("Groupchat commands", filter, ARRAY_SIZE(filter)); - } else if (strcmp(args[0], "presence") == 0) { + } else if (strcmp(args[0], "presences") == 0) { gchar *filter[] = { "/autoaway", "/away", "/chat", "/dnd", "/online", "/priority", "/account", "/status", "/statuses", "/who", "/xa" }; @@ -727,7 +801,7 @@ cmd_help(gchar **args, struct cmd_help_t help) } else if (strcmp(args[0], "settings") == 0) { gchar *filter[] = { "/account", "/autoaway", "/autoping", "/autoconnect", "/beep", - "/chlog", "/flash", "/gone", "/grlog", "/history", "/intype", + "/carbons", "/chlog", "/flash", "/gone", "/grlog", "/history", "/intype", "/log", "/mouse", "/notify", "/outtype", "/prefs", "/priority", "/reconnect", "/roster", "/splash", "/states", "/statuses", "/theme", "/titlebar", "/vercheck", "/privileges", "/occupants", "/presence", "/wrap" }; @@ -743,12 +817,12 @@ cmd_help(gchar **args, struct cmd_help_t help) const gchar **help_text = NULL; Command *command = g_hash_table_lookup(commands, cmd_with_slash); - if (command != NULL) { + if (command) { help_text = command->help.long_help; } cons_show(""); - if (help_text != NULL) { + if (help_text) { ProfWin *console = wins_get_console(); ui_show_lines(console, help_text); } else { @@ -819,7 +893,7 @@ cmd_theme(gchar **args, struct cmd_help_t help) g_slist_free_full(themes, g_free); // load a theme - } else if (g_strcmp0(args[0], "set") == 0) { + } else if (g_strcmp0(args[0], "load") == 0) { if (args[1] == NULL) { cons_show("Usage: %s", help.usage); } else if (theme_load(args[1])) { @@ -854,13 +928,13 @@ cmd_theme(gchar **args, struct cmd_help_t help) static void _who_room(gchar **args, struct cmd_help_t help) { - if ((g_strv_length(args) == 2) && (args[1] != NULL)) { + if ((g_strv_length(args) == 2) && args[1]) { cons_show("Argument group is not applicable to chat rooms."); return; } // bad arg - if (args[0] != NULL && + if (args[0] && (g_strcmp0(args[0], "online") != 0) && (g_strcmp0(args[0], "available") != 0) && (g_strcmp0(args[0], "unavailable") != 0) && @@ -904,7 +978,7 @@ _who_room(gchar **args, struct cmd_help_t help) } else if (strcmp("available", presence) == 0) { GList *filtered = NULL; - while (occupants != NULL) { + while (occupants) { Occupant *occupant = occupants->data; if (muc_occupant_available(occupant)) { filtered = g_list_append(filtered, occupant); @@ -918,7 +992,7 @@ _who_room(gchar **args, struct cmd_help_t help) } else if (strcmp("unavailable", presence) == 0) { GList *filtered = NULL; - while (occupants != NULL) { + while (occupants) { Occupant *occupant = occupants->data; if (!muc_occupant_available(occupant)) { filtered = g_list_append(filtered, occupant); @@ -932,7 +1006,7 @@ _who_room(gchar **args, struct cmd_help_t help) } else { GList *filtered = NULL; - while (occupants != NULL) { + while (occupants) { Occupant *occupant = occupants->data; const char *presence_str = string_from_resource_presence(occupant->presence); if (strcmp(presence_str, presence) == 0) { @@ -986,7 +1060,7 @@ _who_roster(gchar **args, struct cmd_help_t help) char *presence = args[0]; // bad arg - if ((presence != NULL) + if (presence && (strcmp(presence, "online") != 0) && (strcmp(presence, "available") != 0) && (strcmp(presence, "unavailable") != 0) @@ -1001,13 +1075,13 @@ _who_roster(gchar **args, struct cmd_help_t help) } char *group = NULL; - if ((g_strv_length(args) == 2) && (args[1] != NULL)) { + if ((g_strv_length(args) == 2) && args[1]) { group = args[1]; } cons_show(""); GSList *list = NULL; - if (group != NULL) { + if (group) { list = roster_get_group(group); if (list == NULL) { cons_show("No such group: %s.", group); @@ -1023,7 +1097,7 @@ _who_roster(gchar **args, struct cmd_help_t help) // no arg, show all contacts if ((presence == NULL) || (g_strcmp0(presence, "any") == 0)) { - if (group != NULL) { + if (group) { if (list == NULL) { cons_show("No contacts in group %s.", group); } else { @@ -1043,15 +1117,16 @@ _who_roster(gchar **args, struct cmd_help_t help) } else if (strcmp("available", presence) == 0) { GSList *filtered = NULL; - while (list != NULL) { - PContact contact = list->data; + GSList *curr = list; + while (curr) { + PContact contact = curr->data; if (p_contact_is_available(contact)) { filtered = g_slist_append(filtered, contact); } - list = g_slist_next(list); + curr = g_slist_next(curr); } - if (group != NULL) { + if (group) { if (filtered == NULL) { cons_show("No contacts in group %s are %s.", group, presence); } else { @@ -1066,20 +1141,22 @@ _who_roster(gchar **args, struct cmd_help_t help) cons_show_contacts(filtered); } } + g_slist_free(filtered); // unavailable } else if (strcmp("unavailable", presence) == 0) { GSList *filtered = NULL; - while (list != NULL) { - PContact contact = list->data; + GSList *curr = list; + while (curr) { + PContact contact = curr->data; if (!p_contact_is_available(contact)) { filtered = g_slist_append(filtered, contact); } - list = g_slist_next(list); + curr = g_slist_next(curr); } - if (group != NULL) { + if (group) { if (filtered == NULL) { cons_show("No contacts in group %s are %s.", group, presence); } else { @@ -1094,20 +1171,22 @@ _who_roster(gchar **args, struct cmd_help_t help) cons_show_contacts(filtered); } } + g_slist_free(filtered); // online, available resources } else if (strcmp("online", presence) == 0) { GSList *filtered = NULL; - while (list != NULL) { - PContact contact = list->data; + GSList *curr = list; + while (curr) { + PContact contact = curr->data; if (p_contact_has_available_resource(contact)) { filtered = g_slist_append(filtered, contact); } - list = g_slist_next(list); + curr = g_slist_next(curr); } - if (group != NULL) { + if (group) { if (filtered == NULL) { cons_show("No contacts in group %s are %s.", group, presence); } else { @@ -1122,20 +1201,22 @@ _who_roster(gchar **args, struct cmd_help_t help) cons_show_contacts(filtered); } } + g_slist_free(filtered); // offline, no available resources } else if (strcmp("offline", presence) == 0) { GSList *filtered = NULL; - while (list != NULL) { - PContact contact = list->data; + GSList *curr = list; + while (curr) { + PContact contact = curr->data; if (!p_contact_has_available_resource(contact)) { filtered = g_slist_append(filtered, contact); } - list = g_slist_next(list); + curr = g_slist_next(curr); } - if (group != NULL) { + if (group) { if (filtered == NULL) { cons_show("No contacts in group %s are %s.", group, presence); } else { @@ -1150,20 +1231,22 @@ _who_roster(gchar **args, struct cmd_help_t help) cons_show_contacts(filtered); } } + g_slist_free(filtered); // show specific status } else { GSList *filtered = NULL; - while (list != NULL) { - PContact contact = list->data; + GSList *curr = list; + while (curr) { + PContact contact = curr->data; if (strcmp(p_contact_presence(contact), presence) == 0) { filtered = g_slist_append(filtered, contact); } - list = g_slist_next(list); + curr = g_slist_next(curr); } - if (group != NULL) { + if (group) { if (filtered == NULL) { cons_show("No contacts in group %s are %s.", group, presence); } else { @@ -1178,6 +1261,7 @@ _who_roster(gchar **args, struct cmd_help_t help) cons_show_contacts(filtered); } } + g_slist_free(filtered); } g_slist_free(list); @@ -1218,6 +1302,7 @@ cmd_msg(gchar **args, struct cmd_help_t help) return TRUE; } + // send private message when in MUC room if (win_type == WIN_MUC) { ProfMucWin *mucwin = wins_get_current_muc(); if (muc_roster_contains_nick(mucwin->roomjid, usr)) { @@ -1225,11 +1310,14 @@ cmd_msg(gchar **args, struct cmd_help_t help) g_string_append(full_jid, "/"); g_string_append(full_jid, usr); - if (msg != NULL) { - message_send_private(full_jid->str, msg); - ui_outgoing_private_msg("me", full_jid->str, msg); - } else { - ui_new_private_win(full_jid->str); + ProfPrivateWin *privwin = wins_get_private(full_jid->str); + if (!privwin) { + privwin = ui_ev_new_private_win(full_jid->str); + } + ui_ev_focus_win((ProfWin*)privwin); + + if (msg) { + cl_ev_send_priv_msg(privwin, msg); } g_string_free(full_jid, TRUE); @@ -1240,85 +1328,30 @@ cmd_msg(gchar **args, struct cmd_help_t help) return TRUE; + // send chat message } else { - // get barejid char *barejid = roster_barejid_from_name(usr); if (barejid == NULL) { barejid = usr; } - if (msg != NULL) { -#ifdef HAVE_LIBOTR - if (otr_is_secure(barejid)) { - char *encrypted = otr_encrypt_message(barejid, msg); - if (encrypted != NULL) { - message_send_chat(barejid, encrypted); - otr_free_message(encrypted); - ui_outgoing_chat_msg("me", barejid, msg); - - if (((win_type == WIN_CHAT) || (win_type == WIN_CONSOLE)) && prefs_get_boolean(PREF_CHLOG)) { - const char *jid = jabber_get_fulljid(); - Jid *jidp = jid_create(jid); - char *pref_otr_log = prefs_get_string(PREF_OTR_LOG); - if (strcmp(pref_otr_log, "on") == 0) { - chat_log_chat(jidp->barejid, barejid, msg, PROF_OUT_LOG, NULL); - } else if (strcmp(pref_otr_log, "redact") == 0) { - chat_log_chat(jidp->barejid, barejid, "[redacted]", PROF_OUT_LOG, NULL); - } - prefs_free_string(pref_otr_log); - jid_destroy(jidp); - } - } else { - cons_show_error("Failed to encrypt and send message,"); - } - } else { - prof_otrpolicy_t policy = otr_get_policy(barejid); - - if (policy == PROF_OTRPOLICY_ALWAYS) { - cons_show_error("Failed to send message. Please check OTR policy"); - return TRUE; - } else if (policy == PROF_OTRPOLICY_OPPORTUNISTIC) { - GString *otr_message = g_string_new(msg); - g_string_append(otr_message, OTRL_MESSAGE_TAG_BASE); - g_string_append(otr_message, OTRL_MESSAGE_TAG_V2); - message_send_chat(barejid, otr_message->str); - - g_string_free(otr_message, TRUE); - } else { - message_send_chat(barejid, msg); - } - ui_outgoing_chat_msg("me", barejid, msg); - - if (((win_type == WIN_CHAT) || (win_type == WIN_CONSOLE)) && prefs_get_boolean(PREF_CHLOG)) { - const char *jid = jabber_get_fulljid(); - Jid *jidp = jid_create(jid); - chat_log_chat(jidp->barejid, barejid, msg, PROF_OUT_LOG, NULL); - jid_destroy(jidp); - } - } - return TRUE; -#else - message_send_chat(barejid, msg); - ui_outgoing_chat_msg("me", barejid, msg); - - if (((win_type == WIN_CHAT) || (win_type == WIN_CONSOLE)) && prefs_get_boolean(PREF_CHLOG)) { - const char *jid = jabber_get_fulljid(); - Jid *jidp = jid_create(jid); - chat_log_chat(jidp->barejid, barejid, msg, PROF_OUT_LOG, NULL); - jid_destroy(jidp); - } - return TRUE; -#endif + ProfChatWin *chatwin = wins_get_chat(barejid); + if (!chatwin) { + chatwin = ui_ev_new_chat_win(barejid); + } + ui_ev_focus_win((ProfWin*)chatwin); - } else { // msg == NULL - ui_new_chat_win(barejid); + if (msg) { + cl_ev_send_msg(chatwin, msg); + } else { #ifdef HAVE_LIBOTR if (otr_is_secure(barejid)) { ui_gone_secure(barejid, otr_is_trusted(barejid)); } #endif - return TRUE; } + + return TRUE; } } @@ -1336,9 +1369,9 @@ cmd_group(gchar **args, struct cmd_help_t help) if (args[0] == NULL) { GSList *groups = roster_get_groups(); GSList *curr = groups; - if (curr != NULL) { + if (curr) { cons_show("Groups:"); - while (curr != NULL) { + while (curr) { cons_show(" %s", curr->data); curr = g_slist_next(curr); } @@ -1455,11 +1488,14 @@ cmd_roster(gchar **args, struct cmd_help_t help) // set roster size } else if (g_strcmp0(args[0], "size") == 0) { - int intval = 0; if (!args[1]) { cons_show("Usage: %s", help.usage); return TRUE; - } else if (_strtoi(args[1], &intval, 1, 99) == 0) { + } + 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 (prefs_get_boolean(PREF_ROSTER)) { @@ -1467,6 +1503,8 @@ cmd_roster(gchar **args, struct cmd_help_t help) } return TRUE; } else { + cons_show(err_msg); + free(err_msg); return TRUE; } @@ -1701,35 +1739,35 @@ cmd_status(gchar **args, struct cmd_help_t help) switch (win_type) { case WIN_MUC: - if (usr != NULL) { + if (usr) { ProfMucWin *mucwin = wins_get_current_muc(); ProfWin *window = (ProfWin*) mucwin; Occupant *occupant = muc_roster_item(mucwin->roomjid, usr); if (occupant) { win_show_occupant(window, occupant); } else { - win_save_vprint(window, '-', NULL, 0, 0, "", "No such participant \"%s\" in room.", usr); + win_vprint(window, '-', NULL, 0, 0, "", "No such participant \"%s\" in room.", usr); } } else { ui_current_print_line("You must specify a nickname."); } break; case WIN_CHAT: - if (usr != NULL) { + if (usr) { ui_current_print_line("No parameter required when in chat."); } else { ProfChatWin *chatwin = wins_get_current_chat(); ProfWin *window = (ProfWin*) chatwin; PContact pcontact = roster_get_contact(chatwin->barejid); - if (pcontact != NULL) { + if (pcontact) { win_show_contact(window, pcontact); } else { - win_save_println(window, "Error getting contact info."); + win_println(window, "Error getting contact info."); } } break; case WIN_PRIVATE: - if (usr != NULL) { + if (usr) { ui_current_print_line("No parameter required when in chat."); } else { ProfPrivateWin *privatewin = wins_get_current_private(); @@ -1739,13 +1777,13 @@ cmd_status(gchar **args, struct cmd_help_t help) if (occupant) { win_show_occupant(window, occupant); } else { - win_save_println(window, "Error getting contact info."); + win_println(window, "Error getting contact info."); } jid_destroy(jid); } break; case WIN_CONSOLE: - if (usr != NULL) { + if (usr) { char *usr_jid = roster_barejid_from_name(usr); if (usr_jid == NULL) { usr_jid = usr; @@ -1790,7 +1828,7 @@ cmd_info(gchar **args, struct cmd_help_t help) } } else { ProfMucWin *mucwin = wins_get_current_muc(); - iq_room_info_request(mucwin->roomjid); + iq_room_info_request(mucwin->roomjid, TRUE); ui_show_room_info(mucwin); return TRUE; } @@ -1802,10 +1840,10 @@ cmd_info(gchar **args, struct cmd_help_t help) ProfChatWin *chatwin = wins_get_current_chat(); ProfWin *window = (ProfWin*) chatwin; PContact pcontact = roster_get_contact(chatwin->barejid); - if (pcontact != NULL) { + if (pcontact) { win_show_info(window, pcontact); } else { - win_save_println(window, "Error getting contact info."); + win_println(window, "Error getting contact info."); } } break; @@ -1820,7 +1858,7 @@ cmd_info(gchar **args, struct cmd_help_t help) if (occupant) { win_show_occupant_info(window, jid->barejid, occupant); } else { - win_save_println(window, "Error getting contact info."); + win_println(window, "Error getting contact info."); } jid_destroy(jid); } @@ -1832,7 +1870,7 @@ cmd_info(gchar **args, struct cmd_help_t help) usr_jid = usr; } pcontact = roster_get_contact(usr_jid); - if (pcontact != NULL) { + if (pcontact) { cons_show_info(pcontact); } else { cons_show("No such contact \"%s\" in roster.", usr); @@ -1864,7 +1902,7 @@ cmd_caps(gchar **args, struct cmd_help_t help) switch (win_type) { case WIN_MUC: - if (args[0] != NULL) { + if (args[0]) { ProfMucWin *mucwin = wins_get_current_muc(); occupant = muc_roster_item(mucwin->roomjid, args[0]); if (occupant) { @@ -1880,7 +1918,7 @@ cmd_caps(gchar **args, struct cmd_help_t help) break; case WIN_CHAT: case WIN_CONSOLE: - if (args[0] != NULL) { + if (args[0]) { Jid *jid = jid_create(args[0]); if (jid->fulljid == NULL) { @@ -1904,7 +1942,7 @@ cmd_caps(gchar **args, struct cmd_help_t help) } break; case WIN_PRIVATE: - if (args[0] != NULL) { + if (args[0]) { cons_show("No parameter needed to /caps when in private chat."); } else { ProfPrivateWin *privatewin = wins_get_current_private(); @@ -1939,7 +1977,7 @@ cmd_software(gchar **args, struct cmd_help_t help) switch (win_type) { case WIN_MUC: - if (args[0] != NULL) { + if (args[0]) { ProfMucWin *mucwin = wins_get_current_muc(); occupant = muc_roster_item(mucwin->roomjid, args[0]); if (occupant) { @@ -1955,7 +1993,7 @@ cmd_software(gchar **args, struct cmd_help_t help) break; case WIN_CHAT: case WIN_CONSOLE: - if (args[0] != NULL) { + if (args[0]) { Jid *jid = jid_create(args[0]); if (jid == NULL || jid->fulljid == NULL) { @@ -1969,7 +2007,7 @@ cmd_software(gchar **args, struct cmd_help_t help) } break; case WIN_PRIVATE: - if (args[0] != NULL) { + if (args[0]) { cons_show("No parameter needed to /software when in private chat."); } else { ProfPrivateWin *privatewin = wins_get_current_private(); @@ -1993,8 +2031,24 @@ cmd_join(gchar **args, struct cmd_help_t help) } if (args[0] == NULL) { - cons_show("Usage: %s", help.usage); - cons_show(""); + uuid_t uuid; + uuid_generate(uuid); + char *uuid_str = malloc(sizeof(char) * 37); + uuid_unparse_lower(uuid, uuid_str); + + char *account_name = jabber_get_account_name(); + ProfAccount *account = accounts_get_account(account_name); + + GString *room_str = g_string_new(""); + g_string_append_printf(room_str, "private-chat-%s@%s", uuid_str, account->muc_service); + + 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); + free(uuid_str); + account_free(account); + return TRUE; } @@ -2013,7 +2067,7 @@ cmd_join(gchar **args, struct cmd_help_t help) ProfAccount *account = accounts_get_account(account_name); // full room jid supplied (room@server) - if (room_arg->localpart != NULL) { + if (room_arg->localpart) { room = args[0]; // server not supplied (room), use account preference @@ -2041,10 +2095,15 @@ cmd_join(gchar **args, struct cmd_help_t help) options_destroy(options); // In the case that a nick wasn't provided by the optional args... - if (nick == NULL) { + 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); @@ -2083,7 +2142,7 @@ cmd_invite(gchar **args, struct cmd_help_t help) ProfMucWin *mucwin = wins_get_current_muc(); message_send_invite(mucwin->roomjid, usr_jid, reason); - if (reason != NULL) { + if (reason) { cons_show("Room invite sent, contact: %s, room: %s, reason: \"%s\".", contact, mucwin->roomjid, reason); } else { @@ -2368,7 +2427,7 @@ cmd_form(gchar **args, struct cmd_help_t help) if (g_strcmp0(args[0], "help") == 0) { char *tag = args[1]; - if (tag != NULL) { + if (tag) { ui_show_form_field_help(confwin, tag); } else { ui_show_form_help(confwin); @@ -2376,7 +2435,7 @@ cmd_form(gchar **args, struct cmd_help_t help) const gchar **help_text = NULL; Command *command = g_hash_table_lookup(commands, "/form"); - if (command != NULL) { + if (command) { help_text = command->help.long_help; } @@ -2400,12 +2459,11 @@ cmd_form(gchar **args, struct cmd_help_t help) cmd_autocomplete_remove_form_fields(confwin->form); } wins_close_current(); - ProfWin *current = (ProfWin*)wins_get_muc(confwin->roomjid); - if (current == NULL) { - current = wins_get_console(); + ProfWin *new_current = (ProfWin*)wins_get_muc(confwin->roomjid); + if (!new_current) { + new_current = wins_get_console(); } - int num = wins_get_num(current); - ui_switch_win(num); + ui_ev_focus_win(new_current); } return TRUE; @@ -2435,7 +2493,7 @@ cmd_kick(gchar **args, struct cmd_help_t help) char *reason = args[1]; iq_room_kick_occupant(mucwin->roomjid, nick, reason); } else { - win_save_vprint((ProfWin*) mucwin, '!', NULL, 0, 0, "", "Occupant does not exist: %s", nick); + win_vprint((ProfWin*) mucwin, '!', NULL, 0, 0, "", "Occupant does not exist: %s", nick); } } else { cons_show("Usage: %s", help.usage); @@ -2494,10 +2552,10 @@ cmd_subject(gchar **args, struct cmd_help_t help) if (args[0] == NULL) { char *subject = muc_subject(mucwin->roomjid); if (subject) { - win_save_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "Room subject: "); - win_save_vprint(window, '!', NULL, NO_DATE, 0, "", "%s", subject); + win_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "Room subject: "); + win_vprint(window, '!', NULL, NO_DATE, 0, "", "%s", subject); } else { - win_save_print(window, '!', NULL, 0, THEME_ROOMINFO, "", "Room has no subject"); + win_print(window, '!', NULL, 0, THEME_ROOMINFO, "", "Room has no subject"); } return TRUE; } @@ -2543,7 +2601,7 @@ cmd_affiliation(gchar **args, struct cmd_help_t help) } char *affiliation = args[1]; - if ((affiliation != NULL) && + if (affiliation && (g_strcmp0(affiliation, "owner") != 0) && (g_strcmp0(affiliation, "admin") != 0) && (g_strcmp0(affiliation, "member") != 0) && @@ -2562,7 +2620,7 @@ cmd_affiliation(gchar **args, struct cmd_help_t help) iq_room_affiliation_list(mucwin->roomjid, "member"); iq_room_affiliation_list(mucwin->roomjid, "outcast"); } else if (g_strcmp0(affiliation, "none") == 0) { - win_save_print((ProfWin*) mucwin, '!', NULL, 0, 0, "", "Cannot list users with no affiliation."); + win_print((ProfWin*) mucwin, '!', NULL, 0, 0, "", "Cannot list users with no affiliation."); } else { iq_room_affiliation_list(mucwin->roomjid, affiliation); } @@ -2613,7 +2671,7 @@ cmd_role(gchar **args, struct cmd_help_t help) } char *role = args[1]; - if ((role != NULL ) && + if (role && (g_strcmp0(role, "visitor") != 0) && (g_strcmp0(role, "participant") != 0) && (g_strcmp0(role, "moderator") != 0) && @@ -2630,7 +2688,7 @@ cmd_role(gchar **args, struct cmd_help_t help) iq_room_role_list(mucwin->roomjid, "participant"); iq_room_role_list(mucwin->roomjid, "visitor"); } else if (g_strcmp0(role, "none") == 0) { - win_save_print((ProfWin*) mucwin, '!', NULL, 0, 0, "", "Cannot list users with no role."); + win_print((ProfWin*) mucwin, '!', NULL, 0, 0, "", "Cannot list users with no role."); } else { iq_room_role_list(mucwin->roomjid, role); } @@ -2693,12 +2751,12 @@ cmd_room(gchar **args, struct cmd_help_t help) if (g_strcmp0(args[0], "accept") == 0) { gboolean requires_config = muc_requires_config(mucwin->roomjid); if (!requires_config) { - win_save_print(window, '!', NULL, 0, THEME_ROOMINFO, "", "Current room does not require configuration."); + win_print(window, '!', NULL, 0, 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_save_print(window, '!', NULL, 0, THEME_ROOMINFO, "", "Room unlocked."); + win_print(window, '!', NULL, 0, THEME_ROOMINFO, "", "Room unlocked."); return TRUE; } } @@ -2711,9 +2769,8 @@ cmd_room(gchar **args, struct cmd_help_t help) if (g_strcmp0(args[0], "config") == 0) { ProfMucConfWin *confwin = wins_get_muc_conf(mucwin->roomjid); - if (confwin != NULL) { - num = wins_get_num(window); - ui_switch_win(num); + if (confwin) { + ui_ev_focus_win((ProfWin*)confwin); } else { iq_request_room_config_form(mucwin->roomjid); } @@ -2734,26 +2791,44 @@ cmd_occupants(gchar **args, struct cmd_help_t help) } if (g_strcmp0(args[0], "size") == 0) { - int intval = 0; if (!args[1]) { cons_show("Usage: %s", help.usage); return TRUE; - } else if (_strtoi(args[1], &intval, 1, 99) == 0) { - prefs_set_occupants_size(intval); - cons_show("Occupants screen size set to: %d%%", intval); - wins_resize_all(); - 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], "default") == 0) { if (g_strcmp0(args[1], "show") == 0) { - cons_show("Occupant list enabled."); - prefs_set_boolean(PREF_OCCUPANTS, TRUE); + if (g_strcmp0(args[2], "jid") == 0) { + cons_show("Occupant jids enabled."); + prefs_set_boolean(PREF_OCCUPANTS_JID, TRUE); + } else { + cons_show("Occupant list enabled."); + prefs_set_boolean(PREF_OCCUPANTS, TRUE); + } return TRUE; } else if (g_strcmp0(args[1], "hide") == 0) { - cons_show("Occupant list disabled."); - prefs_set_boolean(PREF_OCCUPANTS, FALSE); + if (g_strcmp0(args[2], "jid") == 0) { + cons_show("Occupant jids disabled."); + prefs_set_boolean(PREF_OCCUPANTS_JID, FALSE); + } else { + cons_show("Occupant list disabled."); + prefs_set_boolean(PREF_OCCUPANTS, FALSE); + } return TRUE; } else { cons_show("Usage: %s", help.usage); @@ -2763,16 +2838,26 @@ cmd_occupants(gchar **args, struct cmd_help_t help) win_type_t win_type = ui_current_win_type(); if (win_type != WIN_MUC) { - cons_show("Cannot show/hide occupant list when not in chat room."); + cons_show("Cannot apply setting when not in chat room."); return TRUE; } ProfMucWin *mucwin = wins_get_current_muc(); if (g_strcmp0(args[0], "show") == 0) { - ui_room_show_occupants(mucwin->roomjid); + if (g_strcmp0(args[1], "jid") == 0) { + mucwin->showjid = TRUE; + ui_room_update_occupants(mucwin->roomjid); + } else { + ui_room_show_occupants(mucwin->roomjid); + } } else if (g_strcmp0(args[0], "hide") == 0) { - ui_room_hide_occupants(mucwin->roomjid); + if (g_strcmp0(args[1], "jid") == 0) { + mucwin->showjid = FALSE; + ui_room_update_occupants(mucwin->roomjid); + } else { + ui_room_hide_occupants(mucwin->roomjid); + } } else { cons_show("Usage: %s", help.usage); } @@ -2876,7 +2961,7 @@ cmd_bookmark(gchar **args, struct cmd_help_t help) char *password = g_hash_table_lookup(options, "password"); char *autojoin = g_hash_table_lookup(options, "autojoin"); - if (autojoin != NULL) { + if (autojoin) { if ((strcmp(autojoin, "on") != 0) && (strcmp(autojoin, "off") != 0)) { cons_show("Usage: %s", help.usage); cons_show(""); @@ -2924,7 +3009,7 @@ cmd_disco(gchar **args, struct cmd_help_t help) } GString *jid = g_string_new(""); - if (args[1] != NULL) { + if (args[1]) { jid = g_string_append(jid, args[1]); } else { Jid *jidp = jid_create(jabber_get_fulljid()); @@ -3040,82 +3125,48 @@ gboolean cmd_tiny(gchar **args, struct cmd_help_t help) { char *url = args[0]; - win_type_t win_type = ui_current_win_type(); - - if (!tinyurl_valid(url)) { - GString *error = g_string_new("/tiny, badly formed URL: "); - g_string_append(error, url); - cons_show_error(error->str); - if (win_type != WIN_CONSOLE) { - ui_current_error_line(error->str); - } - g_string_free(error, TRUE); - } else if (win_type != WIN_CONSOLE) { - char *tiny = tinyurl_get(url); + ProfWin *current = wins_get_current(); - if (tiny != NULL) { - if (win_type == WIN_CHAT) { - ProfChatWin *chatwin = wins_get_current_chat(); -#ifdef HAVE_LIBOTR - if (otr_is_secure(chatwin->barejid)) { - char *encrypted = otr_encrypt_message(chatwin->barejid, tiny); - if (encrypted != NULL) { - message_send_chat(chatwin->barejid, encrypted); - otr_free_message(encrypted); - if (prefs_get_boolean(PREF_CHLOG)) { - const char *jid = jabber_get_fulljid(); - Jid *jidp = jid_create(jid); - char *pref_otr_log = prefs_get_string(PREF_OTR_LOG); - if (strcmp(pref_otr_log, "on") == 0) { - chat_log_chat(jidp->barejid, chatwin->barejid, tiny, PROF_OUT_LOG, NULL); - } else if (strcmp(pref_otr_log, "redact") == 0) { - chat_log_chat(jidp->barejid, chatwin->barejid, "[redacted]", PROF_OUT_LOG, NULL); - } - prefs_free_string(pref_otr_log); - jid_destroy(jidp); - } + if (current->type != WIN_CHAT && current->type != WIN_MUC && current->type != WIN_PRIVATE) { + cons_show("/tiny can only be used in chat windows"); + return TRUE; + } - ui_outgoing_chat_msg("me", chatwin->barejid, tiny); - } else { - cons_show_error("Failed to send message."); - } - } else { - message_send_chat(chatwin->barejid, tiny); - if (prefs_get_boolean(PREF_CHLOG)) { - const char *jid = jabber_get_fulljid(); - Jid *jidp = jid_create(jid); - chat_log_chat(jidp->barejid, chatwin->barejid, tiny, PROF_OUT_LOG, NULL); - jid_destroy(jidp); - } + if (!tinyurl_valid(url)) { + win_vprint(current, '-', NULL, 0, THEME_ERROR, "", "/tiny, badly formed URL: %s", url); + return TRUE; + } - ui_outgoing_chat_msg("me", chatwin->barejid, tiny); - } -#else - message_send_chat(chatwin->barejid, tiny); - if (prefs_get_boolean(PREF_CHLOG)) { - const char *jid = jabber_get_fulljid(); - Jid *jidp = jid_create(jid); - chat_log_chat(jidp->barejid, chatwin->barejid, tiny, PROF_OUT_LOG, NULL); - jid_destroy(jidp); - } + char *tiny = tinyurl_get(url); + if (!tiny) { + win_print(current, '-', NULL, 0, THEME_ERROR, "", "Couldn't create tinyurl."); + return TRUE; + } - ui_outgoing_chat_msg("me", chatwin->barejid, tiny); -#endif - } else if (win_type == WIN_PRIVATE) { - ProfPrivateWin *privatewin = wins_get_current_private(); - message_send_private(tiny, privatewin->fulljid); - ui_outgoing_private_msg("me", privatewin->fulljid, tiny); - } else if (win_type == WIN_MUC) { - ProfMucWin *mucwin = wins_get_current_muc(); - message_send_groupchat(tiny, mucwin->roomjid); - } - free(tiny); - } else { - cons_show_error("Couldn't get tinyurl."); - } - } else { - cons_show("/tiny can only be used in chat windows"); + switch (current->type){ + case WIN_CHAT: + { + ProfChatWin *chatwin = wins_get_current_chat(); + cl_ev_send_msg(chatwin, tiny); + break; + } + case WIN_PRIVATE: + { + ProfPrivateWin *privatewin = wins_get_current_private(); + cl_ev_send_priv_msg(privatewin, tiny); + break; + } + case WIN_MUC: + { + ProfMucWin *mucwin = wins_get_current_muc(); + cl_ev_send_muc_msg(mucwin, tiny); + break; } + default: + break; + } + + free(tiny); return TRUE; } @@ -3135,7 +3186,7 @@ cmd_close(gchar **args, struct cmd_help_t help) int count = 0; if (args[0] == NULL) { - index = ui_current_win_index(); + index = wins_get_current_num(); } else if (strcmp(args[0], "all") == 0) { count = ui_close_all_wins(); if (count == 0) { @@ -3170,19 +3221,15 @@ cmd_close(gchar **args, struct cmd_help_t help) return TRUE; } - if (!ui_win_exists(index)) { + ProfWin *window = wins_get_by_num(index); + if (!window) { cons_show("Window is not open."); return TRUE; } // check for unsaved form if (ui_win_has_unsaved_form(index)) { - ProfWin *window = wins_get_current(); - if (wins_is_current(window)) { - ui_current_print_line("You have unsaved changes, use /form submit or /form cancel"); - } else { - cons_show("Cannot close form window with unsaved changes, use /form submit or /form cancel"); - } + ui_current_print_line("You have unsaved changes, use /form submit or /form cancel"); return TRUE; } @@ -3203,7 +3250,7 @@ cmd_leave(gchar **args, struct cmd_help_t help) { jabber_conn_status_t conn_status = jabber_get_connection_status(); win_type_t win_type = ui_current_win_type(); - int index = ui_current_win_index(); + int index = wins_get_current_num(); if (win_type != WIN_MUC) { cons_show("You can only use the /leave command in a chat room."); @@ -3257,10 +3304,46 @@ cmd_wrap(gchar **args, struct cmd_help_t help) gboolean cmd_time(gchar **args, struct cmd_help_t help) { - prefs_set_string(PREF_TIME, args[0]); - cons_show("Time format set to '%s'", args[0]); - wins_resize_all(); - return TRUE; + if (g_strcmp0(args[0], "statusbar") == 0) { + if (args[1] == NULL) { + cons_show("Current status bar time format is '%s'.", prefs_get_string(PREF_TIME_STATUSBAR)); + 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, ""); + cons_show("Status bar time display disabled."); + ui_redraw(); + return TRUE; + } else { + cons_show("Usage: %s", help.usage); + return TRUE; + } + } else if (g_strcmp0(args[0], "main") == 0) { + if (args[1] == NULL) { + cons_show("Current time format is '%s'.", prefs_get_string(PREF_TIME)); + return TRUE; + } else if (g_strcmp0(args[1], "set") == 0 && args[2] != NULL) { + prefs_set_string(PREF_TIME, args[2]); + cons_show("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, ""); + cons_show("Time display disabled."); + wins_resize_all(); + return TRUE; + } else { + cons_show("Usage: %s", help.usage); + return TRUE; + } + } else { + cons_show("Usage: %s", help.usage); + return TRUE; + } } gboolean @@ -3481,7 +3564,6 @@ cmd_inpblock(gchar **args, struct cmd_help_t help) { char *subcmd = args[0]; char *value = args[1]; - int intval; if (g_strcmp0(subcmd, "timeout") == 0) { if (value == NULL) { @@ -3489,10 +3571,16 @@ cmd_inpblock(gchar **args, struct cmd_help_t help) return TRUE; } - if (_strtoi(value, &intval, 1, 1000) == 0) { + 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); ui_input_nonblocking(FALSE); + } else { + cons_show(err_msg); + free(err_msg); } return TRUE; @@ -3522,16 +3610,22 @@ cmd_log(gchar **args, struct cmd_help_t help) { char *subcmd = args[0]; char *value = args[1]; - int intval; if (strcmp(subcmd, "maxsize") == 0) { if (value == NULL) { cons_show("Usage: %s", help.usage); return TRUE; } - if (_strtoi(value, &intval, PREFS_MIN_LOG_SIZE, INT_MAX) == 0) { + + 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 maxinum size set to %d bytes", intval); + } else { + cons_show(err_msg); + free(err_msg); } return TRUE; } @@ -3571,9 +3665,11 @@ gboolean cmd_reconnect(gchar **args, struct cmd_help_t help) { char *value = args[0]; - int intval; - if (_strtoi(value, &intval, 0, INT_MAX) == 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); @@ -3581,7 +3677,9 @@ cmd_reconnect(gchar **args, struct cmd_help_t help) cons_show("Reconnect interval set to %d seconds.", intval); } } else { + cons_show(err_msg); cons_show("Usage: %s", help.usage); + free(err_msg); } return TRUE; @@ -3591,9 +3689,11 @@ gboolean cmd_autoping(gchar **args, struct cmd_help_t help) { char *value = args[0]; - int intval; - if (_strtoi(value, &intval, 0, INT_MAX) == 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) { @@ -3602,7 +3702,9 @@ cmd_autoping(gchar **args, struct cmd_help_t help) cons_show("Autoping interval set to %d seconds.", intval); } } else { + cons_show(err_msg); cons_show("Usage: %s", help.usage); + free(err_msg); } return TRUE; @@ -3633,7 +3735,6 @@ cmd_autoaway(gchar **args, struct cmd_help_t help) { char *setting = args[0]; char *value = args[1]; - int minutesval; if ((strcmp(setting, "mode") != 0) && (strcmp(setting, "time") != 0) && (strcmp(setting, "message") != 0) && (strcmp(setting, "check") != 0)) { @@ -3654,9 +3755,15 @@ cmd_autoaway(gchar **args, struct cmd_help_t help) } if (strcmp(setting, "time") == 0) { - if (_strtoi(value, &minutesval, 1, INT_MAX) == 0) { + int minutesval = 0; + char *err_msg = NULL; + gboolean res = strtoi_range(value, &minutesval, 1, INT_MAX, &err_msg); + if (res) { prefs_set_autoaway_time(minutesval); cons_show("Auto away time set to: %d minutes.", minutesval); + } else { + cons_show(err_msg); + free(err_msg); } return TRUE; @@ -3693,13 +3800,18 @@ cmd_priority(gchar **args, struct cmd_help_t help) } char *value = args[0]; - int intval; - if (_strtoi(value, &intval, -128, 127) == 0) { + int intval = 0; + char *err_msg = NULL; + gboolean res = strtoi_range(value, &intval, -128, 127, &err_msg); + if (res) { accounts_set_priority_all(jabber_get_account_name(), intval); resource_presence_t last_presence = accounts_get_last_presence(jabber_get_account_name()); - presence_update(last_presence, jabber_get_presence_message(), 0); + cl_ev_presence_send(last_presence, jabber_get_presence_message(), 0); cons_show("Priority set to %d.", intval); + } else { + cons_show(err_msg); + free(err_msg); } return TRUE; @@ -3865,6 +3977,42 @@ cmd_history(gchar **args, struct cmd_help_t help) } gboolean +cmd_carbons(gchar **args, struct cmd_help_t help) +{ + gboolean result = _cmd_set_boolean_preference(args[0], help, + "Message carbons preference", PREF_CARBONS); + + jabber_conn_status_t conn_status = jabber_get_connection_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 result; +} + +gboolean +cmd_receipts(gchar **args, struct cmd_help_t help) +{ + if (g_strcmp0(args[0], "send") == 0) { + return _cmd_set_boolean_preference(args[1], help, + "Send delivery receipts", PREF_RECEIPTS_SEND); + } else if (g_strcmp0(args[0], "request") == 0) { + return _cmd_set_boolean_preference(args[1], help, + "Request delivery receipets", PREF_RECEIPTS_REQUEST); + } else { + cons_show("Usage: %s", help.usage); + return TRUE; + } +} + +gboolean cmd_away(gchar **args, struct cmd_help_t help) { _update_presence(RESOURCE_AWAY, "away", args); @@ -4013,14 +4161,18 @@ cmd_otr(gchar **args, struct cmd_help_t help) return TRUE; } else if (strcmp(args[0], "start") == 0) { - if (args[1] != NULL) { + if (args[1]) { char *contact = args[1]; char *barejid = roster_barejid_from_name(contact); if (barejid == NULL) { barejid = contact; } - ui_new_chat_win(barejid); + ProfChatWin *chatwin = wins_get_chat(barejid); + if (!chatwin) { + chatwin = ui_ev_new_chat_win(barejid); + } + ui_ev_focus_win((ProfWin*)chatwin); if (ui_current_win_is_otr()) { ui_current_print_formatted_line('!', 0, "You are already in an OTR session."); @@ -4029,7 +4181,7 @@ cmd_otr(gchar **args, struct cmd_help_t help) ui_current_print_formatted_line('!', 0, "You have not generated or loaded a private key, use '/otr gen'"); } else if (!otr_is_secure(barejid)) { char *otr_query_message = otr_start_query(); - message_send_chat(barejid, otr_query_message); + message_send_chat_encrypted(barejid, otr_query_message); } else { ui_gone_secure(barejid, otr_is_trusted(barejid)); } @@ -4047,7 +4199,7 @@ cmd_otr(gchar **args, struct cmd_help_t help) } else { ProfChatWin *chatwin = ui_get_current_chat(); char *otr_query_message = otr_start_query(); - message_send_chat(chatwin->barejid, otr_query_message); + message_send_chat_encrypted(chatwin->barejid, otr_query_message); } } } @@ -4175,7 +4327,7 @@ _update_presence(const resource_presence_t resource_presence, if (conn_status != JABBER_CONNECTED) { cons_show("You are not currently connected."); } else { - presence_update(resource_presence, msg, 0); + cl_ev_presence_send(resource_presence, msg, 0); ui_update_presence(resource_presence, msg, show); } } @@ -4213,27 +4365,6 @@ _cmd_set_boolean_preference(gchar *arg, struct cmd_help_t help, return TRUE; } -static int -_strtoi(char *str, int *saveptr, int min, int max) -{ - char *ptr; - int val; - - errno = 0; - val = (int)strtol(str, &ptr, 0); - if (errno != 0 || *str == '\0' || *ptr != '\0') { - cons_show("Could not convert \"%s\" to a number.", str); - return -1; - } else if (val < min || val > max) { - cons_show("Value %s out of range. Must be in %d..%d.", str, min, max); - return -1; - } - - *saveptr = val; - - return 0; -} - static void _cmd_show_filtered_help(char *heading, gchar *cmd_filter[], int filter_size) { @@ -4249,7 +4380,7 @@ _cmd_show_filtered_help(char *heading, gchar *cmd_filter[], int filter_size) } GList *curr = ordered_commands; - while (curr != NULL) { + while (curr) { Command *cmd = curr->data; cons_show("%-12s: %s", cmd->cmd, cmd->help.short_help); curr = g_list_next(curr); diff --git a/src/command/commands.h b/src/command/commands.h index f4e040a9..7b7e7c93 100644 --- a/src/command/commands.h +++ b/src/command/commands.h @@ -1,7 +1,7 @@ /* * commands.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -62,6 +62,9 @@ typedef struct cmd_t { CommandHelp help; } Command; +gboolean cmd_execute_alias(const char * const inp, gboolean *ran); +gboolean cmd_execute_default(const char * inp); + gboolean cmd_about(gchar **args, struct cmd_help_t help); gboolean cmd_account(gchar **args, struct cmd_help_t help); gboolean cmd_autoaway(gchar **args, struct cmd_help_t help); @@ -85,6 +88,8 @@ gboolean cmd_grlog(gchar **args, struct cmd_help_t help); gboolean cmd_group(gchar **args, struct cmd_help_t help); gboolean cmd_help(gchar **args, struct cmd_help_t help); gboolean cmd_history(gchar **args, struct cmd_help_t help); +gboolean cmd_carbons(gchar **args, struct cmd_help_t help); +gboolean cmd_receipts(gchar **args, struct cmd_help_t help); gboolean cmd_info(gchar **args, struct cmd_help_t help); gboolean cmd_intype(gchar **args, struct cmd_help_t help); gboolean cmd_invite(gchar **args, struct cmd_help_t help); diff --git a/src/common.c b/src/common.c index 7638da31..772e24d3 100644 --- a/src/common.c +++ b/src/common.c @@ -1,7 +1,7 @@ /* * common.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -202,6 +202,33 @@ str_contains(const char str[], int size, char ch) return 0; } +gboolean +strtoi_range(char *str, int *saveptr, int min, int max, char **err_msg) +{ + char *ptr; + int val; + + errno = 0; + val = (int)strtol(str, &ptr, 0); + if (errno != 0 || *str == '\0' || *ptr != '\0') { + GString *err_str = g_string_new(""); + g_string_printf(err_str, "Could not convert \"%s\" to a number.", str); + *err_msg = err_str->str; + g_string_free(err_str, FALSE); + return FALSE; + } else if (val < min || val > max) { + GString *err_str = g_string_new(""); + g_string_printf(err_str, "Value %s out of range. Must be in %d..%d.", str, min, max); + *err_msg = err_str->str; + g_string_free(err_str, FALSE); + return FALSE; + } + + *saveptr = val; + + return TRUE; +} + int utf8_display_len(const char * const str) { @@ -224,6 +251,18 @@ utf8_display_len(const char * const str) return len; } +gboolean +utf8_is_printable(const wint_t ch) +{ + char bytes[MB_CUR_MAX+1]; + size_t utf_len = wcrtomb(bytes, ch, NULL); + bytes[utf_len] = '\0'; + + gunichar unichar = g_utf8_get_char(bytes); + + return g_unichar_isprint(unichar) && (ch != KEY_MOUSE); +} + char * prof_getline(FILE *stream) { @@ -248,7 +287,7 @@ prof_getline(FILE *stream) result = (char *)realloc(s, s_size + buf_size); if (result == NULL) { - if (s != NULL) { + if (s) { free(s); s = NULL; } @@ -286,7 +325,7 @@ release_get_latest() curl_easy_perform(handle); curl_easy_cleanup(handle); - if (output.buffer != NULL) { + if (output.buffer) { output.buffer[output.size++] = '\0'; return output.buffer; } else { @@ -393,10 +432,10 @@ gchar * xdg_get_config_home(void) { gchar *xdg_config_home = getenv("XDG_CONFIG_HOME"); - if (xdg_config_home != NULL) + if (xdg_config_home) g_strstrip(xdg_config_home); - if ((xdg_config_home != NULL) && (strcmp(xdg_config_home, "") != 0)) { + if (xdg_config_home && (strcmp(xdg_config_home, "") != 0)) { return strdup(xdg_config_home); } else { GString *default_path = g_string_new(getenv("HOME")); @@ -412,10 +451,10 @@ gchar * xdg_get_data_home(void) { gchar *xdg_data_home = getenv("XDG_DATA_HOME"); - if (xdg_data_home != NULL) + if (xdg_data_home) g_strstrip(xdg_data_home); - if ((xdg_data_home != NULL) && (strcmp(xdg_data_home, "") != 0)) { + if (xdg_data_home && (strcmp(xdg_data_home, "") != 0)) { return strdup(xdg_data_home); } else { GString *default_path = g_string_new(getenv("HOME")); @@ -435,7 +474,7 @@ create_unique_id(char *prefix) GString *result_str = g_string_new(""); unique_id++; - if (prefix != NULL) { + if (prefix) { g_string_printf(result_str, "prof_%s_%lu", prefix, unique_id); } else { g_string_printf(result_str, "prof_%lu", unique_id); @@ -488,25 +527,34 @@ cmp_win_num(gconstpointer a, gconstpointer b) int get_next_available_win_num(GList *used) { - used = g_list_sort(used, cmp_win_num); // only console used if (g_list_length(used) == 1) { return 2; } else { + GList *sorted = NULL; + GList *curr = used; + while (curr) { + sorted = g_list_insert_sorted(sorted, curr->data, cmp_win_num); + curr = g_list_next(curr); + } + int result = 0; int last_num = 1; - GList *curr = used; + curr = sorted; // skip console curr = g_list_next(curr); - while (curr != NULL) { + while (curr) { int curr_num = GPOINTER_TO_INT(curr->data); + if (((last_num != 9) && ((last_num + 1) != curr_num)) || ((last_num == 9) && (curr_num != 0))) { result = last_num + 1; if (result == 10) { result = 0; } + g_list_free(sorted); return (result); + } else { last_num = curr_num; if (last_num == 0) { @@ -520,6 +568,7 @@ get_next_available_win_num(GList *used) result = 0; } + g_list_free(sorted); return result; } } @@ -566,3 +615,25 @@ get_file_or_linked(char *loc, char *basedir) return true_loc; } + +char * +strip_arg_quotes(const char * const input) +{ + char *unquoted = strdup(input); + + // Remove starting quote if it exists + if(strchr(unquoted, '"')) { + if(strchr(unquoted, ' ') + 1 == strchr(unquoted, '"')) { + memmove(strchr(unquoted, '"'), strchr(unquoted, '"')+1, strchr(unquoted, '\0') - strchr(unquoted, '"')); + } + } + + // Remove ending quote if it exists + if(strchr(unquoted, '"')) { + if(strchr(unquoted, '\0') - 1 == strchr(unquoted, '"')) { + memmove(strchr(unquoted, '"'), strchr(unquoted, '"')+1, strchr(unquoted, '\0') - strchr(unquoted, '"')); + } + } + + return unquoted; +} diff --git a/src/common.h b/src/common.h index 26d4a99a..9521a701 100644 --- a/src/common.h +++ b/src/common.h @@ -1,7 +1,7 @@ /* * common.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -36,6 +36,13 @@ #define COMMON_H #include <stdio.h> +#include <wchar.h> + +#ifdef HAVE_NCURSESW_NCURSES_H +#include <ncursesw/ncurses.h> +#elif HAVE_NCURSES_H +#include <ncurses.h> +#endif #include <glib.h> @@ -104,7 +111,9 @@ gboolean mkdir_recursive(const char *dir); char * str_replace(const char *string, const char *substr, const char *replacement); int str_contains(const char str[], int size, char ch); +gboolean strtoi_range(char *str, int *saveptr, int min, int max, char **err_msg); int utf8_display_len(const char * const str); +gboolean utf8_is_printable(const wint_t ch); char * prof_getline(FILE *stream); char* release_get_latest(void); gboolean release_is_new(char *found_version); @@ -123,5 +132,6 @@ int cmp_win_num(gconstpointer a, gconstpointer b); int get_next_available_win_num(GList *used); char* get_file_or_linked(char *loc, char *basedir); +char * strip_arg_quotes(const char * const input); #endif diff --git a/src/config/account.c b/src/config/account.c index 6df00382..857d049b 100644 --- a/src/config/account.c +++ b/src/config/account.c @@ -1,7 +1,7 @@ /* * account.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -34,12 +34,14 @@ #include <stdlib.h> #include <string.h> +#include <assert.h> #include <glib.h> #include "jid.h" #include "config/account.h" #include "common.h" +#include "log.h" ProfAccount* account_new(const gchar * const name, const gchar * const jid, @@ -55,19 +57,19 @@ account_new(const gchar * const name, const gchar * const jid, new_account->name = strdup(name); - if (jid != NULL) { + if (jid) { new_account->jid = strdup(jid); } else { new_account->jid = strdup(name); } - if (password != NULL) { + if (password) { new_account->password = strdup(password); } else { new_account->password = NULL; } - if (eval_password != NULL) { + if (eval_password) { new_account->eval_password = strdup(eval_password); } else { new_account->eval_password = NULL; @@ -75,13 +77,13 @@ account_new(const gchar * const name, const gchar * const jid, new_account->enabled = enabled; - if (server != NULL) { + if (server) { new_account->server = strdup(server); } else { new_account->server = NULL; } - if (resource != NULL) { + if (resource) { new_account->resource = strdup(resource); } else { new_account->resource = NULL; @@ -132,7 +134,7 @@ account_new(const gchar * const name, const gchar * const jid, new_account->muc_nick = strdup(muc_nick); } - if (otr_policy != NULL) { + if (otr_policy) { new_account->otr_policy = strdup(otr_policy); } else { new_account->otr_policy = NULL; @@ -148,17 +150,55 @@ account_new(const gchar * const name, const gchar * const jid, char * account_create_full_jid(ProfAccount *account) { - if (account->resource != NULL) { + if (account->resource) { return create_fulljid(account->jid, account->resource); } else { return strdup(account->jid); } } +gboolean +account_eval_password(ProfAccount *account) +{ + assert(account != NULL); + assert(account->eval_password != NULL); + + // Evaluate as shell command to retrieve password + GString *cmd = g_string_new(""); + g_string_append_printf(cmd, "%s 2>/dev/null", account->eval_password); + + FILE *stream = popen(cmd->str, "r"); + g_string_free(cmd, TRUE); + if (stream) { + // Limit to READ_BUF_SIZE bytes to prevent overflows in the case of a poorly chosen command + account->password = g_malloc(READ_BUF_SIZE); + if (!account->password) { + log_error("Failed to allocate enough memory to read eval_password output"); + return FALSE; + } + account->password = fgets(account->password, READ_BUF_SIZE, stream); + pclose(stream); + if (!account->password) { + log_error("No result from eval_password."); + return FALSE; + } + + // strip trailing newline + if (g_str_has_suffix(account->password, "\n")) { + account->password[strlen(account->password)-1] = '\0'; + } + } else { + log_error("popen failed when running eval_password."); + return FALSE; + } + + return TRUE; +} + void account_free(ProfAccount *account) { - if (account != NULL) { + if (account) { free(account->name); free(account->jid); free(account->password); diff --git a/src/config/account.h b/src/config/account.h index ab43234d..218f8ce7 100644 --- a/src/config/account.h +++ b/src/config/account.h @@ -1,7 +1,7 @@ /* * account.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -69,9 +69,8 @@ ProfAccount* account_new(const gchar * const name, const gchar * const jid, const gchar * const muc_service, const gchar * const muc_nick, const gchar * const otr_policy, GList *otr_manual, GList *otr_opportunistic, GList *otr_always); - char* account_create_full_jid(ProfAccount *account); - +gboolean account_eval_password(ProfAccount *account); void account_free(ProfAccount *account); #endif diff --git a/src/config/accounts.c b/src/config/accounts.c index 4d4d47d0..d68f3a55 100644 --- a/src/config/accounts.c +++ b/src/config/accounts.c @@ -1,7 +1,7 @@ /* * accounts.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -147,9 +147,9 @@ accounts_add(const char *account_name, const char *altdomain, const int port) const char *barejid = account_name; const char *resource = "profanity"; Jid *jid = jid_create(account_name); - if (jid != NULL) { + if (jid) { barejid = jid->barejid; - if (jid->resourcepart != NULL) { + if (jid->resourcepart) { resource = jid->resourcepart; } } @@ -159,7 +159,7 @@ accounts_add(const char *account_name, const char *altdomain, const int port) g_key_file_set_boolean(accounts, account_name, "enabled", TRUE); g_key_file_set_string(accounts, account_name, "jid", barejid); g_key_file_set_string(accounts, account_name, "resource", resource); - if (altdomain != NULL) { + if (altdomain) { g_key_file_set_string(accounts, account_name, "server", altdomain); } if (port != 0) { @@ -252,7 +252,7 @@ accounts_get_account(const char * const name) gsize length; GList *otr_manual = NULL; gchar **manual = g_key_file_get_string_list(accounts, name, "otr.manual", &length, NULL); - if (manual != NULL) { + if (manual) { int i = 0; for (i = 0; i < length; i++) { otr_manual = g_list_append(otr_manual, strdup(manual[i])); @@ -262,7 +262,7 @@ accounts_get_account(const char * const name) GList *otr_opportunistic = NULL; gchar **opportunistic = g_key_file_get_string_list(accounts, name, "otr.opportunistic", &length, NULL); - if (opportunistic != NULL) { + if (opportunistic) { int i = 0; for (i = 0; i < length; i++) { otr_opportunistic = g_list_append(otr_opportunistic, strdup(opportunistic[i])); @@ -272,7 +272,7 @@ accounts_get_account(const char * const name) GList *otr_always = NULL; gchar **always = g_key_file_get_string_list(accounts, name, "otr.always", &length, NULL); - if (always != NULL) { + if (always) { int i = 0; for (i = 0; i < length; i++) { otr_always = g_list_append(otr_always, strdup(always[i])); @@ -356,7 +356,7 @@ accounts_rename(const char * const account_name, const char * const new_name) int i; for (i = 0; i < ARRAY_SIZE(string_keys); i++) { char *value = g_key_file_get_string(accounts, account_name, string_keys[i], NULL); - if (value != NULL) { + if (value) { g_key_file_set_string(accounts, new_name, string_keys[i], value); g_free(value); } @@ -386,10 +386,10 @@ void accounts_set_jid(const char * const account_name, const char * const value) { Jid *jid = jid_create(value); - if (jid != NULL) { + if (jid) { if (accounts_account_exists(account_name)) { g_key_file_set_string(accounts, account_name, "jid", jid->barejid); - if (jid->resourcepart != NULL) { + if (jid->resourcepart) { g_key_file_set_string(accounts, account_name, "resource", jid->resourcepart); } @@ -509,7 +509,7 @@ accounts_add_otr_policy(const char * const account_name, const char * const cont GList *glist = NULL; // list found - if (list != NULL) { + if (list) { int i = 0; for (i = 0; i < length; i++) { // item already in list, exit function @@ -529,7 +529,7 @@ accounts_add_otr_policy(const char * const account_name, const char * const cont const gchar* new_list[g_list_length(glist)+1]; GList *curr = glist; i = 0; - while (curr != NULL) { + while (curr) { new_list[i++] = strdup(curr->data); curr = g_list_next(curr); } @@ -572,7 +572,7 @@ _remove_from_list(GKeyFile *accounts, const char * const account_name, const cha gsize length; gchar **list = g_key_file_get_string_list(accounts, account_name, key, &length, NULL); - if (list != NULL) { + if (list) { int i = 0; GList *glist = NULL; gboolean deleted = FALSE; @@ -595,7 +595,7 @@ _remove_from_list(GKeyFile *accounts, const char * const account_name, const cha const gchar* new_list[g_list_length(glist)+1]; GList *curr = glist; i = 0; - while (curr != NULL) { + while (curr) { new_list[i++] = strdup(curr->data); curr = g_list_next(curr); } @@ -766,7 +766,7 @@ accounts_get_last_presence(const char * const account_name) result = RESOURCE_ONLINE; } - if (setting != NULL) { + if (setting) { g_free(setting); } return result; @@ -796,7 +796,7 @@ accounts_get_login_presence(const char * const account_name) result = RESOURCE_ONLINE; } - if (setting != NULL) { + if (setting) { g_free(setting); } return result; @@ -809,9 +809,9 @@ _fix_legacy_accounts(const char * const account_name) const char *barejid = account_name; const char *resource = "profanity"; Jid *jid = jid_create(account_name); - if (jid != NULL) { + if (jid) { barejid = jid->barejid; - if (jid->resourcepart != NULL) { + if (jid->resourcepart) { resource = jid->resourcepart; } } @@ -828,7 +828,7 @@ _fix_legacy_accounts(const char * const account_name) _save_accounts(); } - // acounts with no muc service or nick + // accounts with no muc service or nick if (!g_key_file_has_key(accounts, account_name, "muc.service", NULL)) { gchar *account_jid = g_key_file_get_string(accounts, account_name, "jid", NULL); Jid *jidp = jid_create(account_jid); diff --git a/src/config/accounts.h b/src/config/accounts.h index cbbe88e6..50307b5b 100644 --- a/src/config/accounts.h +++ b/src/config/accounts.h @@ -1,7 +1,7 @@ /* * accounts.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/config/preferences.c b/src/config/preferences.c index 652d4ed9..c0d6f6e5 100644 --- a/src/config/preferences.c +++ b/src/config/preferences.c @@ -1,7 +1,7 @@ /* * preferences.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -62,7 +62,7 @@ #define PREF_GROUP_ALIAS "alias" #define PREF_GROUP_OTR "otr" -#define INPBLOCK_DEFAULT 20 +#define INPBLOCK_DEFAULT 1000 static gchar *prefs_loc; static GKeyFile *prefs; @@ -95,35 +95,17 @@ prefs_load(void) err = NULL; log_maxsize = g_key_file_get_integer(prefs, PREF_GROUP_LOGGING, "maxsize", &err); - if (err != NULL) { + if (err) { log_maxsize = 0; g_error_free(err); } - // move pre 0.4.1 OTR preferences to [otr] group + // move pre 0.4.6 OTR warn preferences to [ui] group err = NULL; - gboolean ui_otr_warn = g_key_file_get_boolean(prefs, PREF_GROUP_UI, "otr.warn", &err); + gboolean otr_warn = g_key_file_get_boolean(prefs, PREF_GROUP_OTR, "warn", &err); if (err == NULL) { - g_key_file_set_boolean(prefs, PREF_GROUP_OTR, _get_key(PREF_OTR_WARN), ui_otr_warn); - g_key_file_remove_key(prefs, PREF_GROUP_UI, "otr.warn", NULL); - } else { - g_error_free(err); - } - - err = NULL; - gchar *ui_otr_log = g_key_file_get_string(prefs, PREF_GROUP_LOGGING, "otr", &err); - if (err == NULL) { - g_key_file_set_string(prefs, PREF_GROUP_OTR, _get_key(PREF_OTR_LOG), ui_otr_log); - g_key_file_remove_key(prefs, PREF_GROUP_LOGGING, "otr", NULL); - } else { - g_error_free(err); - } - - err = NULL; - gchar *ui_otr_policy = g_key_file_get_string(prefs, "policy", "otr.policy", &err); - if (err == NULL) { - g_key_file_set_string(prefs, PREF_GROUP_OTR, _get_key(PREF_OTR_POLICY), ui_otr_policy); - g_key_file_remove_group(prefs, "policy", NULL); + g_key_file_set_boolean(prefs, PREF_GROUP_UI, _get_key(PREF_OTR_WARN), otr_warn); + g_key_file_remove_key(prefs, PREF_GROUP_OTR, "warn", NULL); } else { g_error_free(err); } @@ -198,7 +180,7 @@ prefs_get_string(preference_t pref) char *result = g_key_file_get_string(prefs, group, key, NULL); if (result == NULL) { - if (def != NULL) { + if (def) { return strdup(def); } else { return NULL; @@ -211,7 +193,7 @@ prefs_get_string(preference_t pref) void prefs_free_string(char *pref) { - if (pref != NULL) { + if (pref) { free(pref); } pref = NULL; @@ -358,7 +340,7 @@ prefs_get_occupants_size(void) gint result = g_key_file_get_integer(prefs, PREF_GROUP_UI, "occupants.size", NULL); if (result > 99 || result < 1) { - return 20; + return 15; } else { return result; } @@ -377,7 +359,7 @@ prefs_get_roster_size(void) gint result = g_key_file_get_integer(prefs, PREF_GROUP_UI, "roster.size", NULL); if (result > 99 || result < 1) { - return 20; + return 25; } else { return result; } @@ -437,7 +419,7 @@ prefs_get_aliases(void) char *name = keys[i]; char *value = g_key_file_get_string(prefs, PREF_GROUP_ALIAS, name, NULL); - if (value != NULL) { + if (value) { ProfAlias *alias = malloc(sizeof(struct prof_alias_t)); alias->name = strdup(name); alias->value = strdup(value); @@ -517,6 +499,7 @@ _get_group(preference_t pref) case PREF_HISTORY: case PREF_MOUSE: case PREF_OCCUPANTS: + case PREF_OCCUPANTS_JID: case PREF_STATUSES: case PREF_STATUSES_CONSOLE: case PREF_STATUSES_CHAT: @@ -525,12 +508,14 @@ _get_group(preference_t pref) case PREF_PRESENCE: case PREF_WRAP: case PREF_TIME: + case PREF_TIME_STATUSBAR: case PREF_ROSTER: case PREF_ROSTER_OFFLINE: case PREF_ROSTER_RESOURCE: case PREF_ROSTER_BY: case PREF_RESOURCE_TITLE: case PREF_RESOURCE_MESSAGE: + case PREF_OTR_WARN: case PREF_INPBLOCK_DYNAMIC: return PREF_GROUP_UI; case PREF_STATES: @@ -558,8 +543,10 @@ _get_group(preference_t pref) return PREF_GROUP_PRESENCE; case PREF_CONNECT_ACCOUNT: case PREF_DEFAULT_ACCOUNT: + case PREF_CARBONS: + case PREF_RECEIPTS_SEND: + case PREF_RECEIPTS_REQUEST: return PREF_GROUP_CONNECTION; - case PREF_OTR_WARN: case PREF_OTR_LOG: case PREF_OTR_POLICY: return PREF_GROUP_OTR; @@ -593,10 +580,18 @@ _get_key(preference_t pref) return "intype"; case PREF_HISTORY: return "history"; + case PREF_CARBONS: + return "carbons"; + case PREF_RECEIPTS_SEND: + return "receipts.send"; + case PREF_RECEIPTS_REQUEST: + return "receipts.request"; case PREF_MOUSE: return "mouse"; case PREF_OCCUPANTS: return "occupants"; + case PREF_OCCUPANTS_JID: + return "occupants.jid"; case PREF_MUC_PRIVILEGES: return "privileges"; case PREF_STATUSES: @@ -648,7 +643,7 @@ _get_key(preference_t pref) case PREF_OTR_LOG: return "log"; case PREF_OTR_WARN: - return "warn"; + return "otr.warn"; case PREF_OTR_POLICY: return "policy"; case PREF_LOG_ROTATE: @@ -661,6 +656,8 @@ _get_key(preference_t pref) return "wrap"; case PREF_TIME: return "time"; + case PREF_TIME_STATUSBAR: + return "time.statusbar"; case PREF_ROSTER: return "roster"; case PREF_ROSTER_OFFLINE: @@ -691,15 +688,24 @@ _get_default_boolean(preference_t pref) case PREF_AUTOAWAY_CHECK: case PREF_LOG_ROTATE: case PREF_LOG_SHARED: + case PREF_NOTIFY_MESSAGE: case PREF_NOTIFY_MESSAGE_CURRENT: case PREF_NOTIFY_ROOM_CURRENT: + case PREF_NOTIFY_TYPING: case PREF_NOTIFY_TYPING_CURRENT: + case PREF_NOTIFY_SUB: + case PREF_NOTIFY_INVITE: case PREF_SPLASH: case PREF_OCCUPANTS: case PREF_MUC_PRIVILEGES: case PREF_PRESENCE: case PREF_WRAP: case PREF_INPBLOCK_DYNAMIC: + case PREF_RESOURCE_TITLE: + case PREF_RESOURCE_MESSAGE: + case PREF_ROSTER: + case PREF_ROSTER_OFFLINE: + case PREF_ROSTER_RESOURCE: return TRUE; default: return FALSE; @@ -715,7 +721,7 @@ _get_default_string(preference_t pref) { case PREF_AUTOAWAY_MODE: case PREF_NOTIFY_ROOM: - return "off"; + return "on"; case PREF_OTR_LOG: return "redact"; case PREF_OTR_POLICY: @@ -725,9 +731,11 @@ _get_default_string(preference_t pref) case PREF_STATUSES_MUC: return "all"; case PREF_ROSTER_BY: - return "none"; + return "presence"; case PREF_TIME: return "%H:%M:%S"; + case PREF_TIME_STATUSBAR: + return "%H:%M"; default: return NULL; } diff --git a/src/config/preferences.h b/src/config/preferences.h index 68286f09..4455eca1 100644 --- a/src/config/preferences.h +++ b/src/config/preferences.h @@ -1,7 +1,7 @@ /* * preferences.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -59,9 +59,13 @@ typedef enum { PREF_FLASH, PREF_INTYPE, PREF_HISTORY, + PREF_CARBONS, + PREF_RECEIPTS_SEND, + PREF_RECEIPTS_REQUEST, PREF_MOUSE, PREF_OCCUPANTS, PREF_OCCUPANTS_SIZE, + PREF_OCCUPANTS_JID, PREF_ROSTER, PREF_ROSTER_SIZE, PREF_ROSTER_OFFLINE, @@ -71,6 +75,7 @@ typedef enum { PREF_PRESENCE, PREF_WRAP, PREF_TIME, + PREF_TIME_STATUSBAR, PREF_STATUSES, PREF_STATUSES_CONSOLE, PREF_STATUSES_CHAT, diff --git a/src/config/theme.c b/src/config/theme.c index 6d3c5938..f73dee19 100644 --- a/src/config/theme.c +++ b/src/config/theme.c @@ -1,7 +1,7 @@ /* * theme.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -121,6 +121,7 @@ static struct colours_t { NCURSES_COLOR_T otruntrusted; NCURSES_COLOR_T rosterheader; NCURSES_COLOR_T occupantsheader; + NCURSES_COLOR_T receiptsent; } colour_prefs; static NCURSES_COLOR_T _lookup_colour(const char * const colour); @@ -159,7 +160,7 @@ _theme_load_file(const char * const theme_name) { // use default theme if (theme_name == NULL || strcmp(theme_name, "default") == 0) { - if (theme != NULL) { + if (theme) { g_key_file_free(theme); } theme = g_key_file_new(); @@ -172,12 +173,12 @@ _theme_load_file(const char * const theme_name) return FALSE; } - if (theme_loc != NULL) { + if (theme_loc) { g_string_free(theme_loc, TRUE); } theme_loc = new_theme_file; log_info("Loading theme \"%s\"", theme_name); - if (theme != NULL) { + if (theme) { g_key_file_free(theme); } theme = g_key_file_new(); @@ -192,7 +193,9 @@ GSList * theme_list(void) { GSList *result = NULL; - _theme_list_dir(_get_themes_dir(), &result); + char *themes_dir = _get_themes_dir(); + _theme_list_dir(themes_dir, &result); + free(themes_dir); #ifdef THEMES_PATH _theme_list_dir(THEMES_PATH, &result); #endif @@ -202,10 +205,10 @@ theme_list(void) void theme_close(void) { - if (theme != NULL) { + if (theme) { g_key_file_free(theme); } - if (theme_loc != NULL) { + if (theme_loc) { g_string_free(theme_loc, TRUE); } if (bold_items) { @@ -249,47 +252,48 @@ theme_init_colours(void) // chat init_pair(25, colour_prefs.me, colour_prefs.bkgnd); init_pair(26, colour_prefs.them, colour_prefs.bkgnd); + init_pair(27, colour_prefs.receiptsent, colour_prefs.bkgnd); // room chat - init_pair(27, colour_prefs.roominfo, colour_prefs.bkgnd); - init_pair(28, colour_prefs.roommention, colour_prefs.bkgnd); + init_pair(28, colour_prefs.roominfo, colour_prefs.bkgnd); + init_pair(29, colour_prefs.roommention, colour_prefs.bkgnd); // statuses - init_pair(29, colour_prefs.online, colour_prefs.bkgnd); - init_pair(30, colour_prefs.offline, colour_prefs.bkgnd); - init_pair(31, colour_prefs.away, colour_prefs.bkgnd); - init_pair(32, colour_prefs.chat, colour_prefs.bkgnd); - init_pair(33, colour_prefs.dnd, colour_prefs.bkgnd); - init_pair(34, colour_prefs.xa, colour_prefs.bkgnd); + init_pair(30, colour_prefs.online, colour_prefs.bkgnd); + init_pair(31, colour_prefs.offline, colour_prefs.bkgnd); + init_pair(32, colour_prefs.away, colour_prefs.bkgnd); + init_pair(33, colour_prefs.chat, colour_prefs.bkgnd); + init_pair(34, colour_prefs.dnd, colour_prefs.bkgnd); + init_pair(35, colour_prefs.xa, colour_prefs.bkgnd); // states - init_pair(35, colour_prefs.typing, colour_prefs.bkgnd); - init_pair(36, colour_prefs.gone, colour_prefs.bkgnd); + init_pair(36, colour_prefs.typing, colour_prefs.bkgnd); + init_pair(37, colour_prefs.gone, colour_prefs.bkgnd); // subscription status - init_pair(37, colour_prefs.subscribed, colour_prefs.bkgnd); - init_pair(38, colour_prefs.unsubscribed, colour_prefs.bkgnd); + init_pair(38, colour_prefs.subscribed, colour_prefs.bkgnd); + init_pair(39, colour_prefs.unsubscribed, colour_prefs.bkgnd); // otr messages - init_pair(39, colour_prefs.otrstartedtrusted, colour_prefs.bkgnd); - init_pair(40, colour_prefs.otrstarteduntrusted, colour_prefs.bkgnd); - init_pair(41, colour_prefs.otrended, colour_prefs.bkgnd); - init_pair(42, colour_prefs.otrtrusted, colour_prefs.bkgnd); - init_pair(43, colour_prefs.otruntrusted, colour_prefs.bkgnd); + init_pair(40, colour_prefs.otrstartedtrusted, colour_prefs.bkgnd); + init_pair(41, colour_prefs.otrstarteduntrusted, colour_prefs.bkgnd); + init_pair(42, colour_prefs.otrended, colour_prefs.bkgnd); + init_pair(43, colour_prefs.otrtrusted, colour_prefs.bkgnd); + init_pair(44, colour_prefs.otruntrusted, colour_prefs.bkgnd); // subwin headers - init_pair(44, colour_prefs.rosterheader, colour_prefs.bkgnd); - init_pair(45, colour_prefs.occupantsheader, colour_prefs.bkgnd); + init_pair(45, colour_prefs.rosterheader, colour_prefs.bkgnd); + init_pair(46, colour_prefs.occupantsheader, colour_prefs.bkgnd); // raw - init_pair(46, COLOR_WHITE, colour_prefs.bkgnd); - init_pair(47, COLOR_GREEN, colour_prefs.bkgnd); - init_pair(48, COLOR_RED, colour_prefs.bkgnd); - init_pair(49, COLOR_YELLOW, colour_prefs.bkgnd); - init_pair(50, COLOR_BLUE, colour_prefs.bkgnd); - init_pair(51, COLOR_CYAN, colour_prefs.bkgnd); - init_pair(52, COLOR_BLACK, colour_prefs.bkgnd); - init_pair(53, COLOR_MAGENTA, colour_prefs.bkgnd); + init_pair(47, COLOR_WHITE, colour_prefs.bkgnd); + init_pair(48, COLOR_GREEN, colour_prefs.bkgnd); + init_pair(49, COLOR_RED, colour_prefs.bkgnd); + init_pair(50, COLOR_YELLOW, colour_prefs.bkgnd); + init_pair(51, COLOR_BLUE, colour_prefs.bkgnd); + init_pair(52, COLOR_CYAN, colour_prefs.bkgnd); + init_pair(53, COLOR_BLACK, colour_prefs.bkgnd); + init_pair(54, COLOR_MAGENTA, colour_prefs.bkgnd); } static NCURSES_COLOR_T @@ -395,6 +399,7 @@ _load_colours(void) _set_colour("them", &colour_prefs.them, COLOR_GREEN, THEME_THEM); _set_colour("roster.header", &colour_prefs.rosterheader, COLOR_YELLOW, THEME_ROSTER_HEADER); _set_colour("occupants.header", &colour_prefs.occupantsheader, COLOR_YELLOW, THEME_OCCUPANTS_HEADER); + _set_colour("receipt.sent", &colour_prefs.receiptsent, COLOR_RED, THEME_RECEIPT_SENT); } static void @@ -419,20 +424,22 @@ _set_boolean_preference(char *prefstr, preference_t pref) static void _load_preferences(void) { - _set_boolean_preference("intype", PREF_INTYPE); _set_boolean_preference("beep", PREF_BEEP); _set_boolean_preference("flash", PREF_FLASH); - _set_boolean_preference("privileges", PREF_MUC_PRIVILEGES); - _set_boolean_preference("presence", PREF_PRESENCE); + _set_boolean_preference("splash", PREF_SPLASH); _set_boolean_preference("wrap", PREF_WRAP); - _set_string_preference("time", PREF_TIME); - _set_string_preference("statuses.muc", PREF_STATUSES_MUC); + _set_string_preference("time.statusbar", PREF_TIME_STATUSBAR); + + _set_boolean_preference("resource.title", PREF_RESOURCE_TITLE); + _set_boolean_preference("resource.message", PREF_RESOURCE_MESSAGE); + _set_string_preference("statuses.console", PREF_STATUSES_CONSOLE); _set_string_preference("statuses.chat", PREF_STATUSES_CHAT); + _set_string_preference("statuses.muc", PREF_STATUSES_MUC); _set_boolean_preference("occupants", PREF_OCCUPANTS); - + _set_boolean_preference("occupants.jid", PREF_OCCUPANTS_JID); if (g_key_file_has_key(theme, "ui", "occupants.size", NULL)) { gint occupants_size = g_key_file_get_integer(theme, "ui", "occupants.size", NULL); prefs_set_occupants_size(occupants_size); @@ -442,12 +449,16 @@ _load_preferences(void) _set_boolean_preference("roster.offline", PREF_ROSTER_OFFLINE); _set_boolean_preference("roster.resource", PREF_ROSTER_RESOURCE); _set_string_preference("roster.by", PREF_ROSTER_BY); - if (g_key_file_has_key(theme, "ui", "roster.size", NULL)) { gint roster_size = g_key_file_get_integer(theme, "ui", "roster.size", NULL); prefs_set_roster_size(roster_size); } + _set_boolean_preference("privileges", PREF_MUC_PRIVILEGES); + + _set_boolean_preference("presence", PREF_PRESENCE); + _set_boolean_preference("intype", PREF_INTYPE); + _set_boolean_preference("otr.warn", PREF_OTR_WARN); } @@ -465,9 +476,9 @@ void _theme_list_dir(const gchar * const dir, GSList **result) { GDir *themes = g_dir_open(dir, 0, NULL); - if (themes != NULL) { + if (themes) { const gchar *theme = g_dir_read_name(themes); - while (theme != NULL) { + while (theme) { *result = g_slist_append(*result, strdup(theme)); theme = g_dir_read_name(themes); } @@ -481,7 +492,7 @@ _theme_find(const char * const theme_name) GString *path = NULL; gchar *themes_dir = _get_themes_dir(); - if (themes_dir != NULL) { + if (themes_dir) { path = g_string_new(themes_dir); g_free(themes_dir); g_string_append(path, "/"); @@ -557,42 +568,43 @@ theme_attrs(theme_item_t attrs) case THEME_STATUS_NEW: result = COLOR_PAIR(24); break; case THEME_ME: result = COLOR_PAIR(25); break; case THEME_THEM: result = COLOR_PAIR(26); break; - case THEME_ROOMINFO: result = COLOR_PAIR(27); break; - case THEME_ROOMMENTION: result = COLOR_PAIR(28); break; - case THEME_ONLINE: result = COLOR_PAIR(29); break; - case THEME_OFFLINE: result = COLOR_PAIR(30); break; - case THEME_AWAY: result = COLOR_PAIR(31); break; - case THEME_CHAT: result = COLOR_PAIR(32); break; - case THEME_DND: result = COLOR_PAIR(33); break; - case THEME_XA: result = COLOR_PAIR(34); break; - case THEME_TYPING: result = COLOR_PAIR(35); break; - case THEME_GONE: result = COLOR_PAIR(36); break; - case THEME_SUBSCRIBED: result = COLOR_PAIR(37); break; - case THEME_UNSUBSCRIBED: result = COLOR_PAIR(38); break; - case THEME_OTR_STARTED_TRUSTED: result = COLOR_PAIR(39); break; - case THEME_OTR_STARTED_UNTRUSTED: result = COLOR_PAIR(40); break; - case THEME_OTR_ENDED: result = COLOR_PAIR(41); break; - case THEME_OTR_TRUSTED: result = COLOR_PAIR(42); break; - case THEME_OTR_UNTRUSTED: result = COLOR_PAIR(43); break; - case THEME_ROSTER_HEADER: result = COLOR_PAIR(44); break; - case THEME_OCCUPANTS_HEADER: result = COLOR_PAIR(45); break; - case THEME_WHITE: result = COLOR_PAIR(46); break; - case THEME_WHITE_BOLD: result = COLOR_PAIR(46); break; - case THEME_GREEN: result = COLOR_PAIR(47); break; - case THEME_GREEN_BOLD: result = COLOR_PAIR(47); break; - case THEME_RED: result = COLOR_PAIR(48); break; - case THEME_RED_BOLD: result = COLOR_PAIR(48); break; - case THEME_YELLOW: result = COLOR_PAIR(49); break; - case THEME_YELLOW_BOLD: result = COLOR_PAIR(49); break; - case THEME_BLUE: result = COLOR_PAIR(50); break; - case THEME_BLUE_BOLD: result = COLOR_PAIR(50); break; - case THEME_CYAN: result = COLOR_PAIR(51); break; - case THEME_CYAN_BOLD: result = COLOR_PAIR(51); break; - case THEME_BLACK: result = COLOR_PAIR(52); break; - case THEME_BLACK_BOLD: result = COLOR_PAIR(52); break; - case THEME_MAGENTA: result = COLOR_PAIR(53); break; - case THEME_MAGENTA_BOLD: result = COLOR_PAIR(53); break; - default: break; + case THEME_RECEIPT_SENT: result = COLOR_PAIR(27); break; + case THEME_ROOMINFO: result = COLOR_PAIR(28); break; + case THEME_ROOMMENTION: result = COLOR_PAIR(29); break; + case THEME_ONLINE: result = COLOR_PAIR(30); break; + case THEME_OFFLINE: result = COLOR_PAIR(31); break; + case THEME_AWAY: result = COLOR_PAIR(32); break; + case THEME_CHAT: result = COLOR_PAIR(33); break; + case THEME_DND: result = COLOR_PAIR(34); break; + case THEME_XA: result = COLOR_PAIR(35); break; + case THEME_TYPING: result = COLOR_PAIR(36); break; + case THEME_GONE: result = COLOR_PAIR(37); break; + case THEME_SUBSCRIBED: result = COLOR_PAIR(38); break; + case THEME_UNSUBSCRIBED: result = COLOR_PAIR(39); break; + case THEME_OTR_STARTED_TRUSTED: result = COLOR_PAIR(40); break; + case THEME_OTR_STARTED_UNTRUSTED: result = COLOR_PAIR(41); break; + case THEME_OTR_ENDED: result = COLOR_PAIR(42); break; + case THEME_OTR_TRUSTED: result = COLOR_PAIR(43); break; + case THEME_OTR_UNTRUSTED: result = COLOR_PAIR(44); break; + case THEME_ROSTER_HEADER: result = COLOR_PAIR(45); break; + case THEME_OCCUPANTS_HEADER: result = COLOR_PAIR(46); break; + case THEME_WHITE: result = COLOR_PAIR(47); break; + case THEME_WHITE_BOLD: result = COLOR_PAIR(47); break; + case THEME_GREEN: result = COLOR_PAIR(48); break; + case THEME_GREEN_BOLD: result = COLOR_PAIR(48); break; + case THEME_RED: result = COLOR_PAIR(49); break; + case THEME_RED_BOLD: result = COLOR_PAIR(49); break; + case THEME_YELLOW: result = COLOR_PAIR(50); break; + case THEME_YELLOW_BOLD: result = COLOR_PAIR(50); break; + case THEME_BLUE: result = COLOR_PAIR(51); break; + case THEME_BLUE_BOLD: result = COLOR_PAIR(51); break; + case THEME_CYAN: result = COLOR_PAIR(52); break; + case THEME_CYAN_BOLD: result = COLOR_PAIR(52); break; + case THEME_BLACK: result = COLOR_PAIR(53); break; + case THEME_BLACK_BOLD: result = COLOR_PAIR(53); break; + case THEME_MAGENTA: result = COLOR_PAIR(54); break; + case THEME_MAGENTA_BOLD: result = COLOR_PAIR(54); break; + default: break; } if (g_hash_table_lookup(bold_items, GINT_TO_POINTER(attrs))) { diff --git a/src/config/theme.h b/src/config/theme.h index a6a580f8..13099eb4 100644 --- a/src/config/theme.h +++ b/src/config/theme.h @@ -1,7 +1,7 @@ /* * theme.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -90,6 +90,7 @@ typedef enum { THEME_OTR_UNTRUSTED, THEME_OCCUPANTS_HEADER, THEME_ROSTER_HEADER, + THEME_RECEIPT_SENT, THEME_NONE, THEME_WHITE, THEME_WHITE_BOLD, diff --git a/src/contact.c b/src/contact.c index f16f1679..713af955 100644 --- a/src/contact.c +++ b/src/contact.c @@ -1,7 +1,7 @@ /* * contact.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -45,7 +45,9 @@ struct p_contact_t { char *barejid; + gchar *barejid_collate_key; char *name; + gchar *name_collate_key; GSList *groups; char *subscription; char *offline_message; @@ -62,21 +64,24 @@ p_contact_new(const char * const barejid, const char * const name, { PContact contact = malloc(sizeof(struct p_contact_t)); contact->barejid = strdup(barejid); + contact->barejid_collate_key = g_utf8_collate_key(contact->barejid, -1); - if (name != NULL) { + if (name) { contact->name = strdup(name); + contact->name_collate_key = g_utf8_collate_key(contact->name, -1); } else { contact->name = NULL; + contact->name_collate_key = NULL; } contact->groups = groups; - if (subscription != NULL) + if (subscription) contact->subscription = strdup(subscription); else contact->subscription = strdup("none"); - if (offline_message != NULL) + if (offline_message) contact->offline_message = strdup(offline_message); else contact->offline_message = NULL; @@ -96,15 +101,17 @@ void p_contact_set_name(const PContact contact, const char * const name) { FREE_SET_NULL(contact->name); - if (name != NULL) { + FREE_SET_NULL(contact->name_collate_key); + if (name) { contact->name = strdup(name); + contact->name_collate_key = g_utf8_collate_key(contact->name, -1); } } void p_contact_set_groups(const PContact contact, GSList *groups) { - if (contact->groups != NULL) { + if (contact->groups) { g_slist_free_full(contact->groups, g_free); contact->groups = NULL; } @@ -116,7 +123,7 @@ gboolean p_contact_in_group(const PContact contact, const char * const group) { GSList *groups = contact->groups; - while (groups != NULL) { + while (groups) { if (strcmp(groups->data, group) == 0) { return TRUE; } @@ -144,17 +151,19 @@ p_contact_remove_resource(PContact contact, const char * const resource) void p_contact_free(PContact contact) { - if (contact != NULL) { + if (contact) { free(contact->barejid); + free(contact->barejid_collate_key); free(contact->name); + free(contact->name_collate_key); free(contact->subscription); free(contact->offline_message); - if (contact->groups != NULL) { + if (contact->groups) { g_slist_free_full(contact->groups, g_free); } - if (contact->last_activity != NULL) { + if (contact->last_activity) { g_date_time_unref(contact->last_activity); } @@ -171,15 +180,27 @@ p_contact_barejid(const PContact contact) } const char * +p_contact_barejid_collate_key(const PContact contact) +{ + return contact->barejid_collate_key; +} + +const char * p_contact_name(const PContact contact) { return contact->name; } const char * +p_contact_name_collate_key(const PContact contact) +{ + return contact->name_collate_key; +} + +const char * p_contact_name_or_jid(const PContact contact) { - if (contact->name != NULL) { + if (contact->name) { return contact->name; } else { return contact->barejid; @@ -247,7 +268,7 @@ _get_most_available_resource(PContact contact) Resource *current = curr->data; Resource *highest = current; curr = g_list_next(curr); - while (curr != NULL) { + while (curr) { current = curr->data; // priority is same as current highest, choose presence @@ -381,14 +402,14 @@ void p_contact_set_presence(const PContact contact, Resource *resource) { g_hash_table_replace(contact->available_resources, strdup(resource->name), resource); - autocomplete_add(contact->resource_ac, strdup(resource->name)); + autocomplete_add(contact->resource_ac, resource->name); } void p_contact_set_subscription(const PContact contact, const char * const subscription) { FREE_SET_NULL(contact->subscription); - if (subscription != NULL) { + if (subscription) { contact->subscription = strdup(subscription); } } @@ -402,12 +423,12 @@ p_contact_set_pending_out(const PContact contact, gboolean pending_out) void p_contact_set_last_activity(const PContact contact, GDateTime *last_activity) { - if (contact->last_activity != NULL) { + if (contact->last_activity) { g_date_time_unref(contact->last_activity); contact->last_activity = NULL; } - if (last_activity != NULL) { + if (last_activity) { contact->last_activity = g_date_time_ref(last_activity); } } diff --git a/src/contact.h b/src/contact.h index 17a3b210..343b230f 100644 --- a/src/contact.h +++ b/src/contact.h @@ -1,7 +1,7 @@ /* * contact.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -47,7 +47,9 @@ void p_contact_add_resource(PContact contact, Resource *resource); gboolean p_contact_remove_resource(PContact contact, const char * const resource); void p_contact_free(PContact contact); const char* p_contact_barejid(PContact contact); +const char* p_contact_barejid_collate_key(PContact contact); const char* p_contact_name(PContact contact); +const char* p_contact_name_collate_key(PContact contact); const char* p_contact_name_or_jid(const PContact contact); const char* p_contact_presence(PContact contact); const char* p_contact_status(PContact contact); diff --git a/src/event/client_events.c b/src/event/client_events.c new file mode 100644 index 00000000..f0f763a6 --- /dev/null +++ b/src/event/client_events.c @@ -0,0 +1,95 @@ +/* + * client_events.c + * + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> + * + * 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 <http://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 <glib.h> + +#include "config.h" +#include "log.h" +#include "ui/ui.h" +#include "ui/windows.h" +#include "xmpp/xmpp.h" +#ifdef HAVE_LIBOTR +#include "otr/otr.h" +#endif + +jabber_conn_status_t +cl_ev_connect_jid(const char * const jid, const char * const passwd, const char * const altdomain, const int port) +{ + cons_show("Connecting as %s", jid); + return jabber_connect_with_details(jid, passwd, altdomain, port); +} + +jabber_conn_status_t +cl_ev_connect_account(ProfAccount *account) +{ + char *jid = account_create_full_jid(account); + cons_show("Connecting with account %s as %s", account->name, jid); + free(jid); + + return jabber_connect_with_account(account); +} + +void +cl_ev_presence_send(const resource_presence_t presence_type, const char * const msg, const int idle) +{ + presence_send(presence_type, msg, idle); +} + +void +cl_ev_send_msg(ProfChatWin *chatwin, const char * const msg) +{ + chat_state_active(chatwin->state); + +#ifdef HAVE_LIBOTR + otr_on_message_send(chatwin, msg); +#else + char *id = message_send_chat(chatwin->barejid, msg); + chat_log_msg_out(chatwin->barejid, msg); + ui_outgoing_chat_msg(chatwin, msg, id); + free(id); +#endif +} + +void +cl_ev_send_muc_msg(ProfMucWin *mucwin, const char * const msg) +{ + message_send_groupchat(mucwin->roomjid, msg); +} + +void +cl_ev_send_priv_msg(ProfPrivateWin *privwin, const char * const msg) +{ + message_send_private(privwin->fulljid, msg); + ui_outgoing_private_msg(privwin, msg); +} \ No newline at end of file diff --git a/src/event/client_events.h b/src/event/client_events.h new file mode 100644 index 00000000..207299c5 --- /dev/null +++ b/src/event/client_events.h @@ -0,0 +1,47 @@ +/* + * client_events.h + * + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> + * + * 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 <http://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. + * + */ + +#ifndef CLIENT_EVENTS_H +#define CLIENT_EVENTS_H + +jabber_conn_status_t cl_ev_connect_jid(const char * const jid, const char * const passwd, const char * const altdomain, const int port); +jabber_conn_status_t cl_ev_connect_account(ProfAccount *account); + +void cl_ev_presence_send(const resource_presence_t presence_type, const char * const msg, const int idle); + +void cl_ev_send_msg(ProfChatWin *chatwin, const char * const msg); +void cl_ev_send_muc_msg(ProfMucWin *mucwin, const char * const msg); +void cl_ev_send_priv_msg(ProfPrivateWin *privwin, const char * const msg); + +#endif \ No newline at end of file diff --git a/src/event/server_events.c b/src/event/server_events.c new file mode 100644 index 00000000..e2e910a3 --- /dev/null +++ b/src/event/server_events.c @@ -0,0 +1,522 @@ +/* + * server_events.c + * + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> + * + * 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 <http://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 <string.h> +#include <stdlib.h> + +#include "config.h" + +#include "chat_session.h" +#include "log.h" +#include "muc.h" +#include "config/preferences.h" +#include "config/account.h" +#include "roster_list.h" + +#ifdef HAVE_LIBOTR +#include "otr/otr.h" +#endif + +#include "ui/ui.h" + +void +sv_ev_login_account_success(char *account_name) +{ + ProfAccount *account = accounts_get_account(account_name); + +#ifdef HAVE_LIBOTR + otr_on_connect(account); +#endif + + ui_handle_login_account_success(account); + + // attempt to rejoin rooms with passwords + GList *curr = muc_rooms(); + while (curr) { + char *password = muc_password(curr->data); + if (password) { + char *nick = muc_nick(curr->data); + presence_join_room(curr->data, nick, password); + } + curr = g_list_next(curr); + } + g_list_free(curr); + + log_info("%s logged in successfully", account->jid); + account_free(account); +} + +void +sv_ev_roster_received(void) +{ + if (prefs_get_boolean(PREF_ROSTER)) { + ui_show_roster(); + } +} + +void +sv_ev_lost_connection(void) +{ + cons_show_error("Lost connection."); + roster_clear(); + muc_invites_clear(); + chat_sessions_clear(); + ui_disconnected(); +} + +void +sv_ev_failed_login(void) +{ + cons_show_error("Login failed."); + log_info("Login failed"); +} + +void +sv_ev_room_invite(jabber_invite_t invite_type, + const char * const invitor, const char * const room, + const char * const reason, const char * const password) +{ + if (!muc_active(room) && !muc_invites_contain(room)) { + cons_show_room_invite(invitor, room, reason); + muc_invites_add(room, password); + } +} + +void +sv_ev_room_broadcast(const char *const room_jid, + const char * const message) +{ + if (muc_roster_complete(room_jid)) { + ui_room_broadcast(room_jid, message); + } else { + muc_pending_broadcasts_add(room_jid, message); + } +} + +void +sv_ev_room_subject(const char * const room, const char * const nick, const char * const subject) +{ + muc_set_subject(room, subject); + if (muc_roster_complete(room)) { + ui_room_subject(room, nick, subject); + } +} + +void +sv_ev_room_history(const char * const room_jid, const char * const nick, + GTimeVal tv_stamp, const char * const message) +{ + ui_room_history(room_jid, nick, tv_stamp, message); +} + +void +sv_ev_room_message(const char * const room_jid, const char * const nick, + const char * const message) +{ + ui_room_message(room_jid, nick, message); + + if (prefs_get_boolean(PREF_GRLOG)) { + Jid *jid = jid_create(jabber_get_fulljid()); + groupchat_log_chat(jid->barejid, room_jid, nick, message); + jid_destroy(jid); + } +} + +void +sv_ev_incoming_private_message(const char * const fulljid, char *message) +{ + ui_incoming_private_msg(fulljid, message, NULL); +} + +void +sv_ev_carbon(char *barejid, char *message) +{ + ui_outgoing_chat_msg_carbon(barejid, message); +} + +void +sv_ev_incoming_message(char *barejid, char *resource, char *message) +{ +#ifdef HAVE_LIBOTR + otr_on_message_recv(barejid, resource, message); +#else + ui_incoming_msg(barejid, resource, message, NULL); + chat_log_msg_in(barejid, message); +#endif +} + +void +sv_ev_delayed_private_message(const char * const fulljid, char *message, GTimeVal tv_stamp) +{ + ui_incoming_private_msg(fulljid, message, &tv_stamp); +} + +void +sv_ev_delayed_message(char *barejid, char *message, GTimeVal tv_stamp) +{ + ui_incoming_msg(barejid, NULL, message, &tv_stamp); + chat_log_msg_in_delayed(barejid, message, &tv_stamp); +} + +void +sv_ev_message_receipt(char *barejid, char *id) +{ + ui_message_receipt(barejid, id); +} + +void +sv_ev_typing(char *barejid, char *resource) +{ + ui_contact_typing(barejid, resource); + if (ui_chat_win_exists(barejid)) { + chat_session_recipient_typing(barejid, resource); + } +} + +void +sv_ev_paused(char *barejid, char *resource) +{ + if (ui_chat_win_exists(barejid)) { + chat_session_recipient_paused(barejid, resource); + } +} + +void +sv_ev_inactive(char *barejid, char *resource) +{ + if (ui_chat_win_exists(barejid)) { + chat_session_recipient_inactive(barejid, resource); + } +} + +void +sv_ev_gone(const char * const barejid, const char * const resource) +{ + ui_recipient_gone(barejid, resource); + if (ui_chat_win_exists(barejid)) { + chat_session_recipient_gone(barejid, resource); + } +} + +void +sv_ev_activity(const char * const barejid, const char * const resource, gboolean send_states) +{ + if (ui_chat_win_exists(barejid)) { + chat_session_recipient_active(barejid, resource, send_states); + } +} + +void +sv_ev_subscription(const char *barejid, jabber_subscr_t type) +{ + switch (type) { + case PRESENCE_SUBSCRIBE: + /* TODO: auto-subscribe if needed */ + cons_show("Received authorization request from %s", barejid); + log_info("Received authorization request from %s", barejid); + ui_print_system_msg_from_recipient(barejid, "Authorization request, type '/sub allow' to accept or '/sub deny' to reject"); + if (prefs_get_boolean(PREF_NOTIFY_SUB)) { + notify_subscription(barejid); + } + break; + case PRESENCE_SUBSCRIBED: + cons_show("Subscription received from %s", barejid); + log_info("Subscription received from %s", barejid); + ui_print_system_msg_from_recipient(barejid, "Subscribed"); + break; + case PRESENCE_UNSUBSCRIBED: + cons_show("%s deleted subscription", barejid); + log_info("%s deleted subscription", barejid); + ui_print_system_msg_from_recipient(barejid, "Unsubscribed"); + break; + default: + /* unknown type */ + break; + } +} + +void +sv_ev_contact_offline(char *barejid, char *resource, char *status) +{ + gboolean updated = roster_contact_offline(barejid, resource, status); + + if (resource && updated) { + ui_contact_offline(barejid, resource, status); + } + + rosterwin_roster(); + chat_session_remove(barejid); +} + +void +sv_ev_contact_online(char *barejid, Resource *resource, GDateTime *last_activity) +{ + gboolean updated = roster_update_presence(barejid, resource, last_activity); + + if (updated) { + ui_contact_online(barejid, resource, last_activity); + } + + rosterwin_roster(); + chat_session_remove(barejid); +} + +void +sv_ev_leave_room(const char * const room) +{ + muc_leave(room); + ui_leave_room(room); +} + +void +sv_ev_room_destroy(const char * const room) +{ + muc_leave(room); + ui_room_destroy(room); +} + +void +sv_ev_room_destroyed(const char * const room, const char * const new_jid, const char * const password, + const char * const reason) +{ + muc_leave(room); + ui_room_destroyed(room, reason, new_jid, password); +} + +void +sv_ev_room_kicked(const char * const room, const char * const actor, const char * const reason) +{ + muc_leave(room); + ui_room_kicked(room, actor, reason); +} + +void +sv_ev_room_banned(const char * const room, const char * const actor, const char * const reason) +{ + muc_leave(room); + ui_room_banned(room, actor, reason); +} + +void +sv_ev_room_occupant_offline(const char * const room, const char * const nick, + const char * const show, const char * const status) +{ + muc_roster_remove(room, nick); + + char *muc_status_pref = prefs_get_string(PREF_STATUSES_MUC); + if (g_strcmp0(muc_status_pref, "none") != 0) { + ui_room_member_offline(room, nick); + } + prefs_free_string(muc_status_pref); + occupantswin_occupants(room); +} + +void +sv_ev_room_occupent_kicked(const char * const room, const char * const nick, const char * const actor, + const char * const reason) +{ + muc_roster_remove(room, nick); + ui_room_member_kicked(room, nick, actor, reason); + occupantswin_occupants(room); +} + +void +sv_ev_room_occupent_banned(const char * const room, const char * const nick, const char * const actor, + const char * const reason) +{ + muc_roster_remove(room, nick); + ui_room_member_banned(room, nick, actor, reason); + occupantswin_occupants(room); +} + +void +sv_ev_roster_update(const char * const barejid, const char * const name, + GSList *groups, const char * const subscription, gboolean pending_out) +{ + roster_update(barejid, name, groups, subscription, pending_out); + rosterwin_roster(); +} + +void +sv_ev_xmpp_stanza(const char * const msg) +{ + ui_handle_stanza(msg); +} + +void +sv_ev_muc_self_online(const char * const room, const char * const nick, gboolean config_required, + const char * const role, const char * const affiliation, const char * const actor, const char * const reason, + const char * const jid, const char * const show, const char * const status) +{ + muc_roster_add(room, nick, jid, role, affiliation, show, status); + char *old_role = muc_role_str(room); + char *old_affiliation = muc_affiliation_str(room); + muc_set_role(room, role); + muc_set_affiliation(room, affiliation); + + // handle self nick change + if (muc_nick_change_pending(room)) { + muc_nick_change_complete(room, nick); + ui_room_nick_change(room, nick); + + // handle roster complete + } else if (!muc_roster_complete(room)) { + if (muc_autojoin(room)) { + ui_room_join(room, FALSE); + } else { + ui_room_join(room, TRUE); + } + + iq_room_info_request(room, FALSE); + + muc_invites_remove(room); + muc_roster_set_complete(room); + + // show roster if occupants list disabled by default + if (!prefs_get_boolean(PREF_OCCUPANTS)) { + GList *occupants = muc_roster(room); + ui_room_roster(room, occupants, NULL); + g_list_free(occupants); + } + + char *subject = muc_subject(room); + if (subject) { + ui_room_subject(room, NULL, subject); + } + + GList *pending_broadcasts = muc_pending_broadcasts(room); + if (pending_broadcasts) { + GList *curr = pending_broadcasts; + while (curr) { + ui_room_broadcast(room, curr->data); + curr = g_list_next(curr); + } + } + + // room configuration required + if (config_required) { + muc_set_requires_config(room, TRUE); + ui_room_requires_config(room); + } + + // check for change in role/affiliation + } else { + if (prefs_get_boolean(PREF_MUC_PRIVILEGES)) { + // both changed + if ((g_strcmp0(role, old_role) != 0) && (g_strcmp0(affiliation, old_affiliation) != 0)) { + ui_room_role_and_affiliation_change(room, role, affiliation, actor, reason); + + // role changed + } else if (g_strcmp0(role, old_role) != 0) { + ui_room_role_change(room, role, actor, reason); + + // affiliation changed + } else if (g_strcmp0(affiliation, old_affiliation) != 0) { + ui_room_affiliation_change(room, affiliation, actor, reason); + } + } + } + + occupantswin_occupants(room); +} + +void +sv_ev_muc_occupant_online(const char * const room, const char * const nick, const char * const jid, + const char * const role, const char * const affiliation, const char * const actor, const char * const reason, + const char * const show, const char * const status) +{ + Occupant *occupant = muc_roster_item(room, nick); + + const char *old_role = NULL; + const char *old_affiliation = NULL; + if (occupant) { + old_role = muc_occupant_role_str(occupant); + old_affiliation = muc_occupant_affiliation_str(occupant); + } + + gboolean updated = muc_roster_add(room, nick, jid, role, affiliation, show, status); + + // not yet finished joining room + if (!muc_roster_complete(room)) { + return; + } + + // handle nickname change + char *old_nick = muc_roster_nick_change_complete(room, nick); + if (old_nick) { + ui_room_member_nick_change(room, old_nick, nick); + free(old_nick); + occupantswin_occupants(room); + return; + } + + // joined room + if (!occupant) { + char *muc_status_pref = prefs_get_string(PREF_STATUSES_MUC); + if (g_strcmp0(muc_status_pref, "none") != 0) { + ui_room_member_online(room, nick, role, affiliation, show, status); + } + prefs_free_string(muc_status_pref); + occupantswin_occupants(room); + return; + } + + // presence updated + if (updated) { + char *muc_status_pref = prefs_get_string(PREF_STATUSES_MUC); + if (g_strcmp0(muc_status_pref, "all") == 0) { + ui_room_member_presence(room, nick, show, status); + } + prefs_free_string(muc_status_pref); + occupantswin_occupants(room); + + // presence unchanged, check for role/affiliation change + } else { + if (prefs_get_boolean(PREF_MUC_PRIVILEGES)) { + // both changed + if ((g_strcmp0(role, old_role) != 0) && (g_strcmp0(affiliation, old_affiliation) != 0)) { + ui_room_occupant_role_and_affiliation_change(room, nick, role, affiliation, actor, reason); + + // role changed + } else if (g_strcmp0(role, old_role) != 0) { + ui_room_occupant_role_change(room, nick, role, actor, reason); + + // affiliation changed + } else if (g_strcmp0(affiliation, old_affiliation) != 0) { + ui_room_occupant_affiliation_change(room, nick, affiliation, actor, reason); + } + } + occupantswin_occupants(room); + } +} diff --git a/src/event/server_events.h b/src/event/server_events.h new file mode 100644 index 00000000..46d485da --- /dev/null +++ b/src/event/server_events.h @@ -0,0 +1,91 @@ +/* + * server_events.h + * + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> + * + * 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 <http://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. + * + */ + +#ifndef SERVER_EVENTS_H +#define SERVER_EVENTS_H + +#include "xmpp/xmpp.h" + +void sv_ev_login_account_success(char *account_name); +void sv_ev_lost_connection(void); +void sv_ev_failed_login(void); +void sv_ev_room_invite(jabber_invite_t invite_type, + const char * const invitor, const char * const room, + const char * const reason, const char * const password); +void sv_ev_room_broadcast(const char *const room_jid, + const char * const message); +void sv_ev_room_subject(const char * const room, const char * const nick, const char * const subject); +void sv_ev_room_history(const char * const room_jid, const char * const nick, + GTimeVal tv_stamp, const char * const message); +void sv_ev_room_message(const char * const room_jid, const char * const nick, + const char * const message); +void sv_ev_incoming_message(char *barejid, char *resource, char *message); +void sv_ev_incoming_private_message(const char * const fulljid, char *message); +void sv_ev_delayed_message(char *fulljid, char *message, GTimeVal tv_stamp); +void sv_ev_delayed_private_message(const char * const fulljid, char *message, GTimeVal tv_stamp); +void sv_ev_typing(char *barejid, char *resource); +void sv_ev_paused(char *barejid, char *resource); +void sv_ev_inactive(char *barejid, char *resource); +void sv_ev_activity(char *barejid, char *resource, gboolean send_states); +void sv_ev_gone(const char * const barejid, const char * const resource); +void sv_ev_subscription(const char *from, jabber_subscr_t type); +void sv_ev_message_receipt(char *barejid, char *id); +void sv_ev_contact_offline(char *contact, char *resource, char *status); +void sv_ev_contact_online(char *contact, Resource *resource, + GDateTime *last_activity); +void sv_ev_leave_room(const char * const room); +void sv_ev_room_destroy(const char * const room); +void sv_ev_room_occupant_offline(const char * const room, const char * const nick, + const char * const show, const char * const status); +void sv_ev_room_destroyed(const char * const room, const char * const new_jid, const char * const password, + const char * const reason); +void sv_ev_room_kicked(const char * const room, const char * const actor, const char * const reason); +void sv_ev_room_occupent_kicked(const char * const room, const char * const nick, const char * const actor, + const char * const reason); +void sv_ev_room_banned(const char * const room, const char * const actor, const char * const reason); +void sv_ev_room_occupent_banned(const char * const room, const char * const nick, const char * const actor, + const char * const reason); +void sv_ev_carbon(char *barejid, char *message); +void sv_ev_xmpp_stanza(const char * const msg); +void sv_ev_muc_self_online(const char * const room, const char * const nick, gboolean config_required, + const char * const role, const char * const affiliation, const char * const actor, const char * const reason, + const char * const jid, const char * const show, const char * const status); +void sv_ev_muc_occupant_online(const char * const room, const char * const nick, const char * const jid, + const char * const role, const char * const affiliation, const char * const actor, const char * const reason, + const char * const show_str, const char * const status_str); +void sv_ev_roster_update(const char * const barejid, const char * const name, + GSList *groups, const char * const subscription, gboolean pending_out); +void sv_ev_roster_received(void); + +#endif diff --git a/src/event/ui_events.c b/src/event/ui_events.c new file mode 100644 index 00000000..ff1d7273 --- /dev/null +++ b/src/event/ui_events.c @@ -0,0 +1,56 @@ +/* + * ui_events.c + * + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> + * + * 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 <http://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 "ui/ui.h" +#include "ui/windows.h" + +void +ui_ev_focus_win(ProfWin *win) +{ + if (!wins_is_current(win)) { + ui_switch_win(win); + } +} + +ProfChatWin* +ui_ev_new_chat_win(const char * const barejid) +{ + return ui_new_chat_win(barejid); +} + +ProfPrivateWin* +ui_ev_new_private_win(const char * const fulljid) +{ + return ui_new_private_win(fulljid); +} \ No newline at end of file diff --git a/src/tools/history.h b/src/event/ui_events.h index 7b334718..3f7fed02 100644 --- a/src/tools/history.h +++ b/src/event/ui_events.h @@ -1,7 +1,7 @@ /* - * history.h + * ui_events.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -32,14 +32,11 @@ * */ -#ifndef HISTORY_H -#define HISTORY_H +#ifndef UI_EVENTS_H +#define UI_EVENTS_H -typedef struct history_t *History; +void ui_ev_focus_win(ProfWin *win); +ProfChatWin* ui_ev_new_chat_win(const char * const barejid); +ProfPrivateWin* ui_ev_new_private_win(const char * const fulljid); -History history_new(unsigned int size); -char * history_previous(History history, char *item); -char * history_next(History history, char *item); -void history_append(History history, char *item); - -#endif +#endif \ No newline at end of file diff --git a/src/jid.c b/src/jid.c index 690f36ca..baeeb279 100644 --- a/src/jid.c +++ b/src/jid.c @@ -1,7 +1,7 @@ /* * jid.c * - * Copyright (C) 2012 -2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -80,19 +80,20 @@ jid_create(const gchar * const str) gchar *domain_start = trimmed; - if (atp != NULL) { + if (atp) { result->localpart = g_utf8_substring(trimmed, 0, g_utf8_pointer_to_offset(trimmed, atp)); domain_start = atp + 1; } - if (slashp != NULL) { + if (slashp) { result->resourcepart = g_strdup(slashp + 1); result->domainpart = g_utf8_substring(domain_start, 0, g_utf8_pointer_to_offset(domain_start, slashp)); - result->barejid = g_utf8_substring(trimmed, 0, g_utf8_pointer_to_offset(trimmed, slashp)); + char *barejidraw = g_utf8_substring(trimmed, 0, g_utf8_pointer_to_offset(trimmed, slashp)); + result->barejid = g_utf8_strdown(barejidraw, -1); result->fulljid = g_strdup(trimmed); } else { result->domainpart = g_strdup(domain_start); - result->barejid = g_strdup(trimmed); + result->barejid = g_utf8_strdown(trimmed, -1); } if (result->domainpart == NULL) { @@ -119,7 +120,7 @@ jid_create_from_bare_and_resource(const char * const room, const char * const ni void jid_destroy(Jid *jid) { - if (jid != NULL) { + if (jid) { g_free(jid->str); g_free(jid->localpart); g_free(jid->domainpart); @@ -144,7 +145,9 @@ jid_is_valid_room_form(Jid *jid) char * create_fulljid(const char * const barejid, const char * const resource) { - GString *full_jid = g_string_new(barejid); + gchar *barejidlower = g_utf8_strdown(barejid, -1); + GString *full_jid = g_string_new(barejidlower); + g_free(barejidlower); g_string_append(full_jid, "/"); g_string_append(full_jid, resource); @@ -166,8 +169,8 @@ get_nick_from_full_jid(const char * const full_room_jid) char **tokens = g_strsplit(full_room_jid, "/", 0); char *nick_part = NULL; - if (tokens != NULL) { - if (tokens[0] != NULL && tokens[1] != NULL) { + if (tokens) { + if (tokens[0] && tokens[1]) { nick_part = strdup(tokens[1]); } diff --git a/src/jid.h b/src/jid.h index 64c147f9..6d530c5a 100644 --- a/src/jid.h +++ b/src/jid.h @@ -1,7 +1,7 @@ /* * jid.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/log.c b/src/log.c index c525c3d9..a7727e8b 100644 --- a/src/log.c +++ b/src/log.c @@ -1,7 +1,7 @@ /* * log.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -46,6 +46,7 @@ #include "common.h" #include "config/preferences.h" +#include "xmpp/xmpp.h" #define PROF "prof" @@ -66,7 +67,7 @@ struct dated_chat_log { }; static gboolean _log_roll_needed(struct dated_chat_log *dated_log); -static struct dated_chat_log * _create_log(char *other, const char * const login); +static struct dated_chat_log * _create_log(const char * const other, const char * const login); static struct dated_chat_log * _create_groupchat_log(char *room, const char * const login); static void _free_chat_log(struct dated_chat_log *dated_log); static gboolean _key_equals(void *key1, void *key2); @@ -78,6 +79,8 @@ static gchar * _get_chatlog_dir(void); static gchar * _get_main_log_file(void); static void _rotate_log_file(void); static char* _log_string_from_level(log_level_t level); +static void _chat_log_chat(const char * const login, const char * const other, + const gchar * const msg, chat_log_direction_t direction, GTimeVal *tv_stamp); void log_debug(const char * const msg, ...) @@ -163,7 +166,7 @@ log_close(void) { g_string_free(mainlogfile, TRUE); g_time_zone_unref(tz); - if (logp != NULL) { + if (logp) { fclose(logp); } } @@ -171,7 +174,7 @@ log_close(void) void log_msg(log_level_t level, const char * const area, const char * const msg) { - if (level >= level_filter && logp != NULL) { + if (level >= level_filter && logp) { dt = g_date_time_new_now(tz); char *level_str = _log_string_from_level(level); @@ -236,7 +239,7 @@ chat_log_init(void) { session_started = g_date_time_new_now_local(); log_info("Initialising chat logs"); - logs = g_hash_table_new_full(g_str_hash, (GEqualFunc) _key_equals, g_free, + logs = g_hash_table_new_full(g_str_hash, (GEqualFunc) _key_equals, free, (GDestroyNotify)_free_chat_log); } @@ -244,13 +247,80 @@ void groupchat_log_init(void) { log_info("Initialising groupchat logs"); - groupchat_logs = g_hash_table_new_full(g_str_hash, (GEqualFunc) _key_equals, g_free, + groupchat_logs = g_hash_table_new_full(g_str_hash, (GEqualFunc) _key_equals, free, (GDestroyNotify)_free_chat_log); } void -chat_log_chat(const gchar * const login, gchar *other, - const gchar * const msg, chat_log_direction_t direction, GTimeVal *tv_stamp) +chat_log_msg_out(const char * const barejid, const char * const msg) +{ + if (prefs_get_boolean(PREF_CHLOG)) { + const char *jid = jabber_get_fulljid(); + Jid *jidp = jid_create(jid); + _chat_log_chat(jidp->barejid, barejid, msg, PROF_OUT_LOG, NULL); + jid_destroy(jidp); + } +} + +void +chat_log_otr_msg_out(const char * const barejid, const char * const msg) +{ + if (prefs_get_boolean(PREF_CHLOG)) { + const char *jid = jabber_get_fulljid(); + Jid *jidp = jid_create(jid); + char *pref_otr_log = prefs_get_string(PREF_OTR_LOG); + if (strcmp(pref_otr_log, "on") == 0) { + _chat_log_chat(jidp->barejid, barejid, msg, PROF_OUT_LOG, NULL); + } else if (strcmp(pref_otr_log, "redact") == 0) { + _chat_log_chat(jidp->barejid, barejid, "[redacted]", PROF_OUT_LOG, NULL); + } + prefs_free_string(pref_otr_log); + jid_destroy(jidp); + } +} + +void +chat_log_otr_msg_in(const char * const barejid, const char * const msg, gboolean was_decrypted) +{ + if (prefs_get_boolean(PREF_CHLOG)) { + const char *jid = jabber_get_fulljid(); + Jid *jidp = jid_create(jid); + char *pref_otr_log = prefs_get_string(PREF_OTR_LOG); + if (!was_decrypted || (strcmp(pref_otr_log, "on") == 0)) { + _chat_log_chat(jidp->barejid, barejid, msg, PROF_IN_LOG, NULL); + } else if (strcmp(pref_otr_log, "redact") == 0) { + _chat_log_chat(jidp->barejid, barejid, "[redacted]", PROF_IN_LOG, NULL); + } + prefs_free_string(pref_otr_log); + jid_destroy(jidp); + } +} + +void +chat_log_msg_in(const char * const barejid, const char * const msg) +{ + if (prefs_get_boolean(PREF_CHLOG)) { + const char *jid = jabber_get_fulljid(); + Jid *jidp = jid_create(jid); + _chat_log_chat(jidp->barejid, barejid, msg, PROF_IN_LOG, NULL); + jid_destroy(jidp); + } +} + +void +chat_log_msg_in_delayed(const char * const barejid, const char * msg, GTimeVal *tv_stamp) +{ + if (prefs_get_boolean(PREF_CHLOG)) { + const char *jid = jabber_get_fulljid(); + Jid *jidp = jid_create(jid); + _chat_log_chat(jidp->barejid, barejid, msg, PROF_IN_LOG, tv_stamp); + jid_destroy(jidp); + } +} + +static void +_chat_log_chat(const char * const login, const char * const other, + const char * const msg, chat_log_direction_t direction, GTimeVal *tv_stamp) { struct dated_chat_log *dated_log = g_hash_table_lookup(logs, other); @@ -277,7 +347,7 @@ chat_log_chat(const gchar * const login, gchar *other, FILE *logp = fopen(dated_log->filename, "a"); g_chmod(dated_log->filename, S_IRUSR | S_IWUSR); - if (logp != NULL) { + if (logp) { if (direction == PROF_IN_LOG) { if (strncmp(msg, "/me ", 4) == 0) { fprintf(logp, "%s - *%s %s\n", date_fmt, other, msg + 4); @@ -326,7 +396,7 @@ groupchat_log_chat(const gchar * const login, const gchar * const room, FILE *logp = fopen(dated_log->filename, "a"); g_chmod(dated_log->filename, S_IRUSR | S_IWUSR); - if (logp != NULL) { + if (logp) { if (strncmp(msg, "/me ", 4) == 0) { fprintf(logp, "%s - *%s %s\n", date_fmt, nick, msg + 4); } else { @@ -363,7 +433,7 @@ chat_log_get_previous(const gchar * const login, const gchar * const recipient) char *filename = _get_log_filename(recipient, login, log_date, FALSE); FILE *logp = fopen(filename, "r"); - if (logp != NULL) { + if (logp) { GString *header = g_string_new(""); g_string_append_printf(header, "%d/%d/%d:", g_date_time_get_day_of_month(log_date), @@ -396,13 +466,13 @@ chat_log_get_previous(const gchar * const login, const gchar * const recipient) void chat_log_close(void) { - g_hash_table_remove_all(logs); - g_hash_table_remove_all(groupchat_logs); + g_hash_table_destroy(logs); + g_hash_table_destroy(groupchat_logs); g_date_time_unref(session_started); } static struct dated_chat_log * -_create_log(char *other, const char * const login) +_create_log(const char * const other, const char * const login) { GDateTime *now = g_date_time_new_now_local(); char *filename = _get_log_filename(other, login, now, TRUE); @@ -448,12 +518,12 @@ _log_roll_needed(struct dated_chat_log *dated_log) static void _free_chat_log(struct dated_chat_log *dated_log) { - if (dated_log != NULL) { - if (dated_log->filename != NULL) { + if (dated_log) { + if (dated_log->filename) { g_free(dated_log->filename); dated_log->filename = NULL; } - if (dated_log->date != NULL) { + if (dated_log->date) { g_date_time_unref(dated_log->date); dated_log->date = NULL; } diff --git a/src/log.h b/src/log.h index 8ffc6f22..0689e2e6 100644 --- a/src/log.h +++ b/src/log.h @@ -1,7 +1,7 @@ /* * log.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -64,8 +64,14 @@ void log_msg(log_level_t level, const char * const area, log_level_t log_level_from_string(char *log_level); void chat_log_init(void); -void chat_log_chat(const gchar * const login, gchar *other, - const gchar * const msg, chat_log_direction_t direction, GTimeVal *tv_stamp); + +void chat_log_msg_out(const char * const barejid, const char * const msg); +void chat_log_otr_msg_out(const char * const barejid, const char * const msg); + +void chat_log_msg_in(const char * const barejid, const char * const msg); +void chat_log_msg_in_delayed(const char * const barejid, const char * msg, GTimeVal *tv_stamp); +void chat_log_otr_msg_in(const char * const barejid, const char * const msg, gboolean was_decrypted); + void chat_log_close(void); GSList * chat_log_get_previous(const gchar * const login, const gchar * const recipient); diff --git a/src/main.c b/src/main.c index f3b6a17f..3bb7eeb6 100644 --- a/src/main.c +++ b/src/main.c @@ -1,7 +1,7 @@ /* * main.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -40,13 +40,7 @@ #endif #include "profanity.h" - -#ifdef HAVE_LIBOTR -#include "otr/otr.h" -#endif -#include "xmpp/xmpp.h" - -#include "ui/ui.h" +#include "command/command.h" static gboolean disable_tls = FALSE; static gboolean version = FALSE; @@ -56,6 +50,11 @@ static char *account_name = NULL; int main(int argc, char **argv) { + if (argc == 2 && g_strcmp0(argv[1], "docgen") == 0 && g_strcmp0(PACKAGE_STATUS, "development") == 0) { + command_docgen(); + return 0; + } + static GOptionEntry entries[] = { { "version", 'v', 0, G_OPTION_ARG_NONE, &version, "Show version information", NULL }, @@ -90,7 +89,7 @@ main(int argc, char **argv) g_print("Profanity, version %s\n", PACKAGE_VERSION); } - g_print("Copyright (C) 2012 - 2014 James Booth <%s>.\n", PACKAGE_BUGREPORT); + g_print("Copyright (C) 2012 - 2015 James Booth <%s>.\n", PACKAGE_BUGREPORT); g_print("License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n"); g_print("\n"); g_print("This is free software; you are free to change and redistribute it.\n"); diff --git a/src/muc.c b/src/muc.c index f50f3879..d283b55e 100644 --- a/src/muc.c +++ b/src/muc.c @@ -1,7 +1,7 @@ /* * muc.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -62,9 +62,11 @@ typedef struct _muc_room_t { Autocomplete jid_ac; GHashTable *nick_changes; gboolean roster_received; + muc_member_type_t member_type; } ChatRoom; GHashTable *rooms = NULL; +GHashTable *invite_passwords = NULL; Autocomplete invite_ac; static void _free_room(ChatRoom *room); @@ -82,6 +84,7 @@ muc_init(void) { invite_ac = autocomplete_new(); rooms = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_free_room); + invite_passwords = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); } void @@ -89,19 +92,25 @@ muc_close(void) { autocomplete_free(invite_ac); g_hash_table_destroy(rooms); + g_hash_table_destroy(invite_passwords); rooms = NULL; + invite_passwords = NULL; } void -muc_invites_add(const char * const room) +muc_invites_add(const char * const room, const char * const password) { autocomplete_add(invite_ac, room); + if (password) { + g_hash_table_replace(invite_passwords, strdup(room), strdup(password)); + } } void muc_invites_remove(const char * const room) { autocomplete_remove(invite_ac, room); + g_hash_table_remove(invite_passwords, room); } gint @@ -116,6 +125,12 @@ muc_invites(void) return autocomplete_create_list(invite_ac); } +char * +muc_invite_password(const char * const room) +{ + return g_hash_table_lookup(invite_passwords, room); +} + gboolean muc_invites_contain(const char * const room) { @@ -150,6 +165,7 @@ void muc_invites_clear(void) { autocomplete_clear(invite_ac); + g_hash_table_remove_all(invite_passwords); } void @@ -177,6 +193,7 @@ muc_join(const char * const room, const char * const nick, new_room->roster_received = FALSE; new_room->pending_nick_change = FALSE; new_room->autojoin = autojoin; + new_room->member_type = MUC_MEMBER_TYPE_UNKNOWN; g_hash_table_insert(rooms, strdup(room), new_room); } @@ -208,6 +225,19 @@ muc_set_requires_config(const char * const room, gboolean val) } } +void +muc_set_features(const char * const room, GSList *features) +{ + ChatRoom *chat_room = g_hash_table_lookup(rooms, room); + if (chat_room && features) { + if (g_slist_find_custom(features, "muc_membersonly", (GCompareFunc)g_strcmp0)) { + chat_room->member_type = MUC_MEMBER_TYPE_MEMBERS_ONLY; + } else { + chat_room->member_type = MUC_MEMBER_TYPE_PUBLIC; + } + } +} + /* * Returns TRUE if the user is currently in the room */ @@ -315,7 +345,7 @@ muc_nick_change_pending(const char * const room) } /* - * Change the current nuck name for the room, call once + * Change the current nick name for the room, call once * the service has responded */ void @@ -763,6 +793,18 @@ muc_set_affiliation(const char * const room, const char * const affiliation) } } +muc_member_type_t +muc_member_type(const char * const room) +{ + ChatRoom *chat_room = g_hash_table_lookup(rooms, room); + if (chat_room) { + return chat_room->member_type; + } else { + return MUC_MEMBER_TYPE_UNKNOWN; + } +} + + static void _free_room(ChatRoom *room) { @@ -790,16 +832,10 @@ _free_room(ChatRoom *room) static gint _compare_occupants(Occupant *a, Occupant *b) { - const char * utf8_str_a = a->nick; - const char * utf8_str_b = b->nick; - - gchar *key_a = g_utf8_collate_key(utf8_str_a, -1); - gchar *key_b = g_utf8_collate_key(utf8_str_b, -1); - - gint result = g_strcmp0(key_a, key_b); + const char * utf8_str_a = a->nick_collate_key; + const char * utf8_str_b = b->nick_collate_key; - g_free(key_a); - g_free(key_b); + gint result = g_strcmp0(utf8_str_a, utf8_str_b); return result; } @@ -905,8 +941,10 @@ _muc_occupant_new(const char *const nick, const char * const jid, muc_role_t rol if (nick) { occupant->nick = strdup(nick); + occupant->nick_collate_key = g_utf8_collate_key(occupant->nick, -1); } else { occupant->nick = NULL; + occupant->nick_collate_key = NULL; } if (jid) { @@ -934,6 +972,7 @@ _occupant_free(Occupant *occupant) { if (occupant) { free(occupant->nick); + free(occupant->nick_collate_key); free(occupant->jid); free(occupant->status); free(occupant); diff --git a/src/muc.h b/src/muc.h index 01f8b44b..ad96f3d9 100644 --- a/src/muc.h +++ b/src/muc.h @@ -1,7 +1,7 @@ /* * muc.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -56,8 +56,15 @@ typedef enum { MUC_AFFILIATION_OWNER } muc_affiliation_t; +typedef enum { + MUC_MEMBER_TYPE_UNKNOWN, + MUC_MEMBER_TYPE_PUBLIC, + MUC_MEMBER_TYPE_MEMBERS_ONLY +} muc_member_type_t; + typedef struct _muc_occupant_t { char *nick; + gchar *nick_collate_key; char *jid; muc_role_t role; muc_affiliation_t affiliation; @@ -76,6 +83,8 @@ gboolean muc_autojoin(const char * const room); GList* muc_rooms(void); +void muc_set_features(const char * const room, GSList *features); + char* muc_nick(const char * const room); char* muc_password(const char * const room); @@ -108,7 +117,7 @@ GSList * muc_occupants_by_affiliation(const char * const room, muc_affiliation_t void muc_occupant_nick_change_start(const char * const room, const char * const new_nick, const char * const old_nick); char* muc_roster_nick_change_complete(const char * const room, const char * const nick); -void muc_invites_add(const char * const room); +void muc_invites_add(const char * const room, const char * const password); void muc_invites_remove(const char * const room); gint muc_invites_count(void); GSList* muc_invites(void); @@ -116,6 +125,7 @@ gboolean muc_invites_contain(const char * const room); void muc_invites_reset_ac(void); char* muc_invites_find(const char * const search_str); void muc_invites_clear(void); +char* muc_invite_password(const char * const room); void muc_set_subject(const char * const room, const char * const subject); char* muc_subject(const char * const room); @@ -134,4 +144,6 @@ void muc_set_affiliation(const char * const room, const char * const affiliation char *muc_role_str(const char * const room); char *muc_affiliation_str(const char * const room); +muc_member_type_t muc_member_type(const char * const room); + #endif diff --git a/src/otr/otr.c b/src/otr/otr.c index bd1c2ce3..e568af56 100644 --- a/src/otr/otr.c +++ b/src/otr/otr.c @@ -1,7 +1,7 @@ /* * otr.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -110,7 +110,7 @@ static void cb_inject_message(void *opdata, const char *accountname, const char *protocol, const char *recipient, const char *message) { - message_send_chat(recipient, message); + message_send_chat_encrypted(recipient, message); } static void @@ -179,7 +179,7 @@ otr_init(void) void otr_shutdown(void) { - if (jid != NULL) { + if (jid) { free(jid); } } @@ -193,7 +193,7 @@ otr_poll(void) void otr_on_connect(ProfAccount *account) { - if (jid != NULL) { + if (jid) { free(jid); } jid = strdup(account->jid); @@ -270,6 +270,89 @@ otr_on_connect(ProfAccount *account) } void +otr_on_message_recv(const char * const barejid, const char * const resource, const char * const message) +{ + gboolean was_decrypted = FALSE; + char *decrypted; + + prof_otrpolicy_t policy = otr_get_policy(barejid); + char *whitespace_base = strstr(message, OTRL_MESSAGE_TAG_BASE); + + //check for OTR whitespace (opportunistic or always) + if (policy == PROF_OTRPOLICY_OPPORTUNISTIC || policy == PROF_OTRPOLICY_ALWAYS) { + if (whitespace_base) { + if (strstr(message, OTRL_MESSAGE_TAG_V2) || strstr(message, OTRL_MESSAGE_TAG_V1)) { + // Remove whitespace pattern for proper display in UI + // Handle both BASE+TAGV1/2(16+8) and BASE+TAGV1+TAGV2(16+8+8) + int tag_length = 24; + if (strstr(message, OTRL_MESSAGE_TAG_V2) && strstr(message, OTRL_MESSAGE_TAG_V1)) { + tag_length = 32; + } + memmove(whitespace_base, whitespace_base+tag_length, tag_length); + char *otr_query_message = otr_start_query(); + cons_show("OTR Whitespace pattern detected. Attempting to start OTR session..."); + message_send_chat_encrypted(barejid, otr_query_message); + } + } + } + decrypted = otr_decrypt_message(barejid, message, &was_decrypted); + + // internal OTR message + if (decrypted == NULL) { + return; + } + + if (policy == PROF_OTRPOLICY_ALWAYS && !was_decrypted && !whitespace_base) { + char *otr_query_message = otr_start_query(); + cons_show("Attempting to start OTR session..."); + message_send_chat_encrypted(barejid, otr_query_message); + } + + ui_incoming_msg(barejid, resource, decrypted, NULL); + chat_log_otr_msg_in(barejid, decrypted, was_decrypted); + otr_free_message(decrypted); +} + +void +otr_on_message_send(ProfChatWin *chatwin, const char * const message) +{ + char *id = NULL; + + prof_otrpolicy_t policy = otr_get_policy(chatwin->barejid); + + if (otr_is_secure(chatwin->barejid)) { + char *encrypted = otr_encrypt_message(chatwin->barejid, message); + if (encrypted) { + id = message_send_chat_encrypted(chatwin->barejid, encrypted); + chat_log_otr_msg_out(chatwin->barejid, message); + ui_outgoing_chat_msg(chatwin, message, id); + otr_free_message(encrypted); + } else { + ui_win_error_line((ProfWin*)chatwin, "Failed to encrypt and send message."); + return; + } + + } else if (policy == PROF_OTRPOLICY_ALWAYS) { + ui_win_error_line((ProfWin*)chatwin, "Failed to send message. OTR policy set to: always"); + return; + + } else if (policy == PROF_OTRPOLICY_OPPORTUNISTIC) { + char *otr_tagged_msg = otr_tag_message(message); + id = message_send_chat_encrypted(chatwin->barejid, otr_tagged_msg); + ui_outgoing_chat_msg(chatwin, message, id); + chat_log_msg_out(chatwin->barejid, message); + free(otr_tagged_msg); + + } else { + id = message_send_chat(chatwin->barejid, message); + ui_outgoing_chat_msg(chatwin, message, id); + chat_log_msg_out(chatwin->barejid, message); + } + + free(id); +} + +void otr_keygen(ProfAccount *account) { if (data_loaded) { @@ -277,7 +360,7 @@ otr_keygen(ProfAccount *account) return; } - if (jid != NULL) { + if (jid) { free(jid); } jid = strdup(account->jid); @@ -365,6 +448,18 @@ otr_key_loaded(void) return data_loaded; } +char * +otr_tag_message(const char * const msg) +{ + GString *otr_message = g_string_new(msg); + g_string_append(otr_message, OTRL_MESSAGE_TAG_BASE); + g_string_append(otr_message, OTRL_MESSAGE_TAG_V2); + char *result = otr_message->str; + g_string_free(otr_message, FALSE); + + return result; +} + gboolean otr_is_secure(const char * const recipient) { @@ -421,7 +516,7 @@ otr_trust(const char * const recipient) } if (context->active_fingerprint) { - if (context->active_fingerprint->trust != NULL) { + if (context->active_fingerprint->trust) { free(context->active_fingerprint->trust); } context->active_fingerprint->trust = strdup("trusted"); @@ -445,7 +540,7 @@ otr_untrust(const char * const recipient) } if (context->active_fingerprint) { - if (context->active_fingerprint->trust != NULL) { + if (context->active_fingerprint->trust) { free(context->active_fingerprint->trust); } context->active_fingerprint->trust = NULL; @@ -534,7 +629,7 @@ otr_get_their_fingerprint(const char * const recipient) { ConnContext *context = otrlib_context_find(user_state, recipient, jid); - if (context != NULL) { + if (context) { Fingerprint *fingerprint = context->active_fingerprint; char readable[45]; otrl_privkey_hash_to_human(readable, fingerprint->fingerprint); @@ -563,7 +658,7 @@ otr_get_policy(const char * const recipient) } // check default account setting - if (account->otr_policy != NULL) { + if (account->otr_policy) { prof_otrpolicy_t result; if (g_strcmp0(account->otr_policy, "manual") == 0) { result = PROF_OTRPOLICY_MANUAL; @@ -625,7 +720,7 @@ otr_decrypt_message(const char * const from, const char * const message, gboolea OtrlTLV *tlv = otrl_tlv_find(tlvs, OTRL_TLV_DISCONNECTED); if (tlv) { - if (context != NULL) { + if (context) { otrl_context_force_plaintext(context); ui_gone_insecure(from); } @@ -637,7 +732,7 @@ otr_decrypt_message(const char * const from, const char * const message, gboolea return NULL; // message was decrypted, return to user - } else if (decrypted != NULL) { + } else if (decrypted) { *was_decrypted = TRUE; return decrypted; diff --git a/src/otr/otr.h b/src/otr/otr.h index 155e287b..e020c0c8 100644 --- a/src/otr/otr.h +++ b/src/otr/otr.h @@ -1,7 +1,7 @@ /* * otr.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -39,6 +39,7 @@ #include <libotr/message.h> #include "config/accounts.h" +#include "ui/window.h" typedef enum { PROF_OTRPOLICY_MANUAL, @@ -56,8 +57,14 @@ char* otr_libotr_version(void); char* otr_start_query(void); void otr_poll(void); void otr_on_connect(ProfAccount *account); + +void otr_on_message_recv(const char * const barejid, const char * const resource, const char * const message); +void otr_on_message_send(ProfChatWin *chatwin, const char * const message); + void otr_keygen(ProfAccount *account); +char* otr_tag_message(const char * const msg); + gboolean otr_key_loaded(void); gboolean otr_is_secure(const char * const recipient); diff --git a/src/otr/otrlib.h b/src/otr/otrlib.h index da1c8547..0310c9e6 100644 --- a/src/otr/otrlib.h +++ b/src/otr/otrlib.h @@ -1,7 +1,7 @@ /* * otrlib.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/otr/otrlibv3.c b/src/otr/otrlibv3.c index 77b00660..0b81796c 100644 --- a/src/otr/otrlibv3.c +++ b/src/otr/otrlibv3.c @@ -1,7 +1,7 @@ /* * otrlibv3.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -87,7 +87,7 @@ otrlib_end_session(OtrlUserState user_state, const char * const recipient, char ConnContext *context = otrl_context_find(user_state, recipient, jid, "xmpp", 0, NULL, NULL, NULL); - if (context != NULL) { + if (context) { otrl_message_disconnect(user_state, ops, NULL, jid, "xmpp", recipient); } } @@ -171,7 +171,7 @@ otrlib_handle_tlvs(OtrlUserState user_state, OtrlMessageAppOps *ops, ConnContext } else { context->smstate->nextExpected = OTRL_SMP_EXPECT1; if (context->smstate->received_question == 0) { - if ((context->active_fingerprint->trust != NULL) && (context->active_fingerprint->trust[0] != '\0')) { + if (context->active_fingerprint->trust && (context->active_fingerprint->trust[0] != '\0')) { ui_smp_successful(context->username); ui_trust(context->username); } else { @@ -193,7 +193,7 @@ otrlib_handle_tlvs(OtrlUserState user_state, OtrlMessageAppOps *ops, ConnContext otrl_message_abort_smp(user_state, ops, NULL, context); } else { context->smstate->nextExpected = OTRL_SMP_EXPECT1; - if ((context->active_fingerprint->trust != NULL) && (context->active_fingerprint->trust[0] != '\0')) { + if (context->active_fingerprint->trust && (context->active_fingerprint->trust[0] != '\0')) { ui_smp_successful(context->username); ui_trust(context->username); } else { diff --git a/src/otr/otrlibv4.c b/src/otr/otrlibv4.c index 62379d0f..fc1f5285 100644 --- a/src/otr/otrlibv4.c +++ b/src/otr/otrlibv4.c @@ -1,7 +1,7 @@ /* * otrlibv4.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -113,12 +113,57 @@ cb_handle_msg_event(void *opdata, OtrlMessageEvent msg_event, ConnContext *context, const char *message, gcry_error_t err) { - if (err != 0) { - if (message != NULL) { - cons_show_error("%s", message); - } else { - cons_show_error("OTR error event with no message."); - } + GString *err_msg; + switch (msg_event) + { + case OTRL_MSGEVENT_ENCRYPTION_REQUIRED: + ui_handle_otr_error(context->username, "OTR: Policy requires encryption, but attempting to send an unencrypted message."); + break; + case OTRL_MSGEVENT_ENCRYPTION_ERROR: + ui_handle_otr_error(context->username, "OTR: Error occured while encrypting a message, message not sent."); + break; + case OTRL_MSGEVENT_CONNECTION_ENDED: + ui_handle_otr_error(context->username, "OTR: Message not sent because contact has ended the private conversation."); + break; + case OTRL_MSGEVENT_SETUP_ERROR: + ui_handle_otr_error(context->username, "OTR: A private conversation could not be set up."); + break; + case OTRL_MSGEVENT_MSG_REFLECTED: + ui_handle_otr_error(context->username, "OTR: Received our own OTR message."); + break; + case OTRL_MSGEVENT_MSG_RESENT: + ui_handle_otr_error(context->username, "OTR: The previous message was resent."); + break; + case OTRL_MSGEVENT_RCVDMSG_NOT_IN_PRIVATE: + ui_handle_otr_error(context->username, "OTR: Received an encrypted message but no private connection established."); + break; + case OTRL_MSGEVENT_RCVDMSG_UNREADABLE: + ui_handle_otr_error(context->username, "OTR: Cannot read the received message."); + break; + case OTRL_MSGEVENT_RCVDMSG_MALFORMED: + ui_handle_otr_error(context->username, "OTR: The message received contains malformed data."); + break; + case OTRL_MSGEVENT_RCVDMSG_GENERAL_ERR: + err_msg = g_string_new("OTR: Received error: "); + g_string_append(err_msg, message); + g_string_append(err_msg, "."); + ui_handle_otr_error(context->username, err_msg->str); + g_string_free(err_msg, TRUE); + break; + case OTRL_MSGEVENT_RCVDMSG_UNENCRYPTED: + err_msg = g_string_new("OTR: Received an unencrypted message: "); + g_string_append(err_msg, message); + ui_handle_otr_error(context->username, err_msg->str); + g_string_free(err_msg, TRUE); + break; + case OTRL_MSGEVENT_RCVDMSG_UNRECOGNIZED: + ui_handle_otr_error(context->username, "OTR: Cannot recognize the type of message received."); + break; + case OTRL_MSGEVENT_RCVDMSG_FOR_OTHER_INSTANCE: + ui_handle_otr_error(context->username, "OTR: Received and discarded a message intended for another instance."); + break; + default: + break; } } @@ -208,7 +253,7 @@ otrlib_end_session(OtrlUserState user_state, const char * const recipient, char ConnContext *context = otrl_context_find(user_state, recipient, jid, "xmpp", OTRL_INSTAG_MASTER, 0, NULL, NULL, NULL); - if (context != NULL) { + if (context) { otrl_message_disconnect(user_state, ops, NULL, jid, "xmpp", recipient, 0); } } diff --git a/src/profanity.c b/src/profanity.c index 13297124..55a73430 100644 --- a/src/profanity.c +++ b/src/profanity.c @@ -1,7 +1,7 @@ /* * profanity.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -63,6 +63,7 @@ #include "xmpp/xmpp.h" #include "ui/ui.h" #include "ui/windows.h" +#include "event/client_events.h" static void _check_autoaway(void); static void _init(const int disable_tls, char *log_level); @@ -71,6 +72,7 @@ static void _create_directories(void); static void _connect_default(const char * const account); static gboolean idle = FALSE; +static gboolean cont = TRUE; void prof_run(const int disable_tls, char *log_level, char *account_name) @@ -79,25 +81,27 @@ prof_run(const int disable_tls, char *log_level, char *account_name) _connect_default(account_name); ui_update(); - char *line = NULL; - gboolean cmd_result = TRUE; - log_info("Starting main event loop"); - while(cmd_result) { - while(!line) { - _check_autoaway(); - line = ui_readline(); + char *line = NULL; + while(cont) { + _check_autoaway(); + + line = ui_readline(); + if (line) { + cont = cmd_process_input(line); + free(line); + line = NULL; + } else { + cont = TRUE; + } + #ifdef HAVE_LIBOTR - otr_poll(); + otr_poll(); #endif - notify_remind(); - jabber_process_events(); - ui_update(); - } - cmd_result = cmd_process_input(line); - ui_input_clear(); - FREE_SET_NULL(line); + notify_remind(); + jabber_process_events(); + ui_update(); } } @@ -109,14 +113,14 @@ prof_handle_idle(void) GSList *recipients = ui_get_chat_recipients(); GSList *curr = recipients; - while (curr != NULL) { + while (curr) { char *barejid = curr->data; ProfChatWin *chatwin = wins_get_chat(barejid); chat_state_handle_idle(chatwin->barejid, chatwin->state); curr = g_slist_next(curr); } - if (recipients != NULL) { + if (recipients) { g_slist_free(recipients); } } @@ -169,12 +173,12 @@ _check_autoaway() // handle away mode if (strcmp(pref_autoaway_mode, "away") == 0) { - presence_update(RESOURCE_AWAY, pref_autoaway_message, 0); + cl_ev_presence_send(RESOURCE_AWAY, pref_autoaway_message, 0); ui_auto_away(); // handle idle mode } else if (strcmp(pref_autoaway_mode, "idle") == 0) { - presence_update(RESOURCE_ONLINE, pref_autoaway_message, idle_ms / 1000); + cl_ev_presence_send(RESOURCE_ONLINE, pref_autoaway_message, idle_ms / 1000); } prefs_free_string(pref_autoaway_message); @@ -188,10 +192,10 @@ _check_autoaway() // handle check if (prefs_get_boolean(PREF_AUTOAWAY_CHECK)) { if (strcmp(pref_autoaway_mode, "away") == 0) { - presence_update(RESOURCE_ONLINE, NULL, 0); + cl_ev_presence_send(RESOURCE_ONLINE, NULL, 0); ui_end_auto_away(); } else if (strcmp(pref_autoaway_mode, "idle") == 0) { - presence_update(RESOURCE_ONLINE, NULL, 0); + cl_ev_presence_send(RESOURCE_ONLINE, NULL, 0); ui_titlebar_presence(CONTACT_ONLINE); } } @@ -209,6 +213,7 @@ _init(const int disable_tls, char *log_level) signal(SIGPIPE, SIG_IGN); signal(SIGINT, SIG_IGN); signal(SIGTSTP, SIG_IGN); + signal(SIGWINCH, ui_sigwinch_handler); _create_directories(); log_level_t prof_log_level = log_level_from_string(log_level); prefs_load(); diff --git a/src/profanity.h b/src/profanity.h index f01169f8..269c616a 100644 --- a/src/profanity.h +++ b/src/profanity.h @@ -1,7 +1,7 @@ /* * profanity.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/resource.c b/src/resource.c index 844cb1d3..1598c7b2 100644 --- a/src/resource.c +++ b/src/resource.c @@ -1,7 +1,7 @@ /* * resource.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -46,7 +46,7 @@ Resource * resource_new(const char * const name, resource_presence_t presence, Resource *new_resource = malloc(sizeof(struct resource_t)); new_resource->name = strdup(name); new_resource->presence = presence; - if (status != NULL) { + if (status) { new_resource->status = strdup(status); } else { new_resource->status = NULL; @@ -88,7 +88,7 @@ resource_compare_availability(Resource *first, Resource *second) void resource_destroy(Resource *resource) { - if (resource != NULL) { + if (resource) { free(resource->name); free(resource->status); free(resource); diff --git a/src/resource.h b/src/resource.h index 5c39d969..43bb6d18 100644 --- a/src/resource.h +++ b/src/resource.h @@ -1,7 +1,7 @@ /* * resource.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/roster_list.c b/src/roster_list.c index 44d05ff0..2d9df860 100644 --- a/src/roster_list.c +++ b/src/roster_list.c @@ -1,7 +1,7 @@ /* * roster_list.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -42,6 +42,7 @@ #include "contact.h" #include "jid.h" #include "tools/autocomplete.h" +#include "config/preferences.h" // nicknames static Autocomplete name_ac; @@ -91,7 +92,7 @@ roster_update_presence(const char * const barejid, Resource *resource, assert(barejid != NULL); assert(resource != NULL); - PContact contact = g_hash_table_lookup(contacts, barejid); + PContact contact = roster_get_contact(barejid); if (contact == NULL) { return FALSE; } @@ -109,14 +110,45 @@ roster_update_presence(const char * const barejid, Resource *resource, PContact roster_get_contact(const char * const barejid) { - return g_hash_table_lookup(contacts, barejid); + gchar *barejidlower = g_utf8_strdown(barejid, -1); + PContact contact = g_hash_table_lookup(contacts, barejidlower); + g_free(barejidlower); + + return contact; +} + +char * +roster_get_msg_display_name(const char * const barejid, const char * const resource) +{ + GString *result = g_string_new(""); + + PContact contact = roster_get_contact(barejid); + if (contact) { + if (p_contact_name(contact)) { + g_string_append(result, p_contact_name(contact)); + } else { + g_string_append(result, barejid); + } + } else { + g_string_append(result, barejid); + } + + if (resource && prefs_get_boolean(PREF_RESOURCE_MESSAGE)) { + g_string_append(result, "/"); + g_string_append(result, resource); + } + + char *result_str = result->str; + g_string_free(result, FALSE); + + return result_str; } gboolean roster_contact_offline(const char * const barejid, const char * const resource, const char * const status) { - PContact contact = g_hash_table_lookup(contacts, barejid); + PContact contact = roster_get_contact(barejid); if (contact == NULL) { return FALSE; @@ -174,7 +206,7 @@ roster_change_name(PContact contact, const char * const new_name) const char *current_name = NULL; const char *barejid = p_contact_barejid(contact); - if (p_contact_name(contact) != NULL) { + if (p_contact_name(contact)) { current_name = strdup(p_contact_name(contact)); } @@ -191,9 +223,9 @@ roster_remove(const char * const name, const char * const barejid) // remove each fulljid PContact contact = roster_get_contact(barejid); - if (contact != NULL) { + if (contact) { GList *resources = p_contact_get_available_resources(contact); - while (resources != NULL) { + while (resources) { GString *fulljid = g_string_new(strdup(barejid)); g_string_append(fulljid, "/"); g_string_append(fulljid, resources->data); @@ -212,7 +244,7 @@ void roster_update(const char * const barejid, const char * const name, GSList *groups, const char * const subscription, gboolean pending_out) { - PContact contact = g_hash_table_lookup(contacts, barejid); + PContact contact = roster_get_contact(barejid); assert(contact != NULL); p_contact_set_subscription(contact, subscription); @@ -220,7 +252,7 @@ roster_update(const char * const barejid, const char * const name, const char * const new_name = name; const char * current_name = NULL; - if (p_contact_name(contact) != NULL) { + if (p_contact_name(contact)) { current_name = strdup(p_contact_name(contact)); } @@ -229,7 +261,7 @@ roster_update(const char * const barejid, const char * const name, _replace_name(current_name, new_name, barejid); // add groups - while (groups != NULL) { + while (groups) { autocomplete_add(groups_ac, groups->data); groups = g_slist_next(groups); } @@ -239,8 +271,8 @@ gboolean roster_add(const char * const barejid, const char * const name, GSList *groups, const char * const subscription, gboolean pending_out) { - PContact contact = g_hash_table_lookup(contacts, barejid); - if (contact != NULL) { + PContact contact = roster_get_contact(barejid); + if (contact) { return FALSE; } @@ -248,7 +280,7 @@ roster_add(const char * const barejid, const char * const name, GSList *groups, pending_out); // add groups - while (groups != NULL) { + while (groups) { autocomplete_add(groups_ac, groups->data); groups = g_slist_next(groups); } @@ -286,7 +318,7 @@ roster_get_contacts_by_presence(const char * const presence) } } - // resturn all contact structs + // return all contact structs return result; } @@ -303,7 +335,7 @@ roster_get_contacts(void) result = g_slist_insert_sorted(result, value, (GCompareFunc)_compare_contacts); } - // resturn all contact structs + // return all contact structs return result; } @@ -321,7 +353,7 @@ roster_get_contacts_online(void) result = g_slist_insert_sorted(result, value, (GCompareFunc)_compare_contacts); } - // resturn all contact structs + // return all contact structs return result; } @@ -371,7 +403,7 @@ roster_get_nogroup(void) } } - // resturn all contact structs + // return all contact structs return result; } @@ -386,7 +418,7 @@ roster_get_group(const char * const group) g_hash_table_iter_init(&iter, contacts); while (g_hash_table_iter_next(&iter, &key, &value)) { GSList *groups = p_contact_groups(value); - while (groups != NULL) { + while (groups) { if (strcmp(groups->data, group) == 0) { result = g_slist_insert_sorted(result, value, (GCompareFunc)_compare_contacts); break; @@ -395,7 +427,7 @@ roster_get_group(const char * const group) } } - // resturn all contact structs + // return all contact structs return result; } @@ -445,12 +477,12 @@ _replace_name(const char * const current_name, const char * const new_name, const char * const barejid) { // current handle exists already - if (current_name != NULL) { + if (current_name) { autocomplete_remove(name_ac, current_name); g_hash_table_remove(name_to_barejid, current_name); _add_name_and_barejid(new_name, barejid); // no current handle - } else if (new_name != NULL) { + } else if (new_name) { autocomplete_remove(name_ac, barejid); g_hash_table_remove(name_to_barejid, barejid); _add_name_and_barejid(new_name, barejid); @@ -460,7 +492,7 @@ _replace_name(const char * const current_name, const char * const new_name, static void _add_name_and_barejid(const char * const name, const char * const barejid) { - if (name != NULL) { + if (name) { autocomplete_add(name_ac, name); g_hash_table_insert(name_to_barejid, strdup(name), strdup(barejid)); } else { @@ -475,24 +507,18 @@ gint _compare_contacts(PContact a, PContact b) const char * utf8_str_a = NULL; const char * utf8_str_b = NULL; - if (p_contact_name(a) != NULL) { - utf8_str_a = p_contact_name(a); + if (p_contact_name_collate_key(a)) { + utf8_str_a = p_contact_name_collate_key(a); } else { - utf8_str_a = p_contact_barejid(a); + utf8_str_a = p_contact_barejid_collate_key(a); } - if (p_contact_name(b) != NULL) { - utf8_str_b = p_contact_name(b); + if (p_contact_name_collate_key(b)) { + utf8_str_b = p_contact_name_collate_key(b); } else { - utf8_str_b = p_contact_barejid(b); + utf8_str_b = p_contact_barejid_collate_key(b); } - gchar *key_a = g_utf8_collate_key(utf8_str_a, -1); - gchar *key_b = g_utf8_collate_key(utf8_str_b, -1); - - gint result = g_strcmp0(key_a, key_b); - - g_free(key_a); - g_free(key_b); + gint result = g_strcmp0(utf8_str_a, utf8_str_b); return result; } diff --git a/src/roster_list.h b/src/roster_list.h index e193085b..4417c763 100644 --- a/src/roster_list.h +++ b/src/roster_list.h @@ -1,7 +1,7 @@ /* * roster_list.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -67,5 +67,6 @@ char * roster_group_autocomplete(const char * const search_str); char * roster_barejid_autocomplete(const char * const search_str); GSList * roster_get_contacts_by_presence(const char * const presence); GSList * roster_get_nogroup(void); +char * roster_get_msg_display_name(const char * const barejid, const char * const resource); #endif diff --git a/src/server_events.c b/src/server_events.c deleted file mode 100644 index fbf534ac..00000000 --- a/src/server_events.c +++ /dev/null @@ -1,822 +0,0 @@ -/* - * server_events.c - * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> - * - * 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 <http://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 <string.h> -#include <stdlib.h> - -#include "config.h" - -#include "chat_session.h" -#include "log.h" -#include "muc.h" -#include "config/preferences.h" -#include "config/account.h" -#include "roster_list.h" - -#ifdef HAVE_LIBOTR -#include "otr/otr.h" -#include <libotr/proto.h> -#endif - -#include "ui/ui.h" - -void -handle_room_join_error(const char * const room, const char * const err) -{ - if (muc_active(room)) { - muc_leave(room); - } - ui_handle_room_join_error(room, err); -} - -// handle presence stanza errors -void -handle_presence_error(const char *from, const char * const type, - const char *err_msg) -{ - // handle error from recipient - if (from != NULL) { - ui_handle_recipient_error(from, err_msg); - - // handle errors from no recipient - } else { - ui_handle_error(err_msg); - } -} - -// handle message stanza errors -void -handle_message_error(const char * const jid, const char * const type, - const char * const err_msg) -{ - // handle errors from no recipient - if (jid == NULL) { - ui_handle_error(err_msg); - - // handle recipient not found ('from' contains a value and type is 'cancel') - } else if (type != NULL && (strcmp(type, "cancel") == 0)) { - log_info("Recipient %s not found: %s", jid, err_msg); - Jid *jidp = jid_create(jid); - chat_session_remove(jidp->barejid); - - // handle any other error from recipient - } else { - ui_handle_recipient_error(jid, err_msg); - } -} - -void -handle_login_account_success(char *account_name) -{ - ProfAccount *account = accounts_get_account(account_name); - -#ifdef HAVE_LIBOTR - otr_on_connect(account); -#endif - - ui_handle_login_account_success(account); - - // attempt to rejoin rooms with passwords - GList *curr = muc_rooms(); - while (curr != NULL) { - char *password = muc_password(curr->data); - if (password != NULL) { - char *nick = muc_nick(curr->data); - presence_join_room(curr->data, nick, password); - } - curr = g_list_next(curr); - } - g_list_free(curr); - - log_info("%s logged in successfully", account->jid); - account_free(account); -} - -void -handle_roster_received(void) -{ - if (prefs_get_boolean(PREF_ROSTER)) { - ui_show_roster(); - } -} - -void -handle_lost_connection(void) -{ - cons_show_error("Lost connection."); - roster_clear(); - muc_invites_clear(); - chat_sessions_clear(); - ui_disconnected(); -} - -void -handle_failed_login(void) -{ - cons_show_error("Login failed."); - log_info("Login failed"); -} - -void -handle_software_version_result(const char * const jid, const char * const presence, - const char * const name, const char * const version, const char * const os) -{ - cons_show_software_version(jid, presence, name, version, os); -} - -void -handle_disco_info(const char *from, GSList *identities, GSList *features) -{ - cons_show_disco_info(from, identities, features); -} - -void -handle_room_disco_info(const char * const room, GSList *identities, GSList *features) -{ - ui_show_room_disco_info(room, identities, features); -} - -void -handle_disco_info_error(const char * const from, const char * const error) -{ - if (from) { - cons_show_error("Service discovery failed for %s: %s", from, error); - } else { - cons_show_error("Service discovery failed: %s", error); - } -} - -void -handle_room_info_error(const char * const room, const char * const error) -{ - ui_handle_room_info_error(room, error); -} - -void -handle_room_list(GSList *rooms, const char *conference_node) -{ - cons_show_room_list(rooms, conference_node); -} - -void -handle_room_affiliation_list_result_error(const char * const room, const char * const affiliation, - const char * const error) -{ - log_debug("Error retrieving %s list for room %s: %s", affiliation, room, error); - ui_handle_room_affiliation_list_error(room, affiliation, error); -} - -void -handle_room_affiliation_list(const char * const room, const char * const affiliation, GSList *jids) -{ - muc_jid_autocomplete_add_all(room, jids); - ui_handle_room_affiliation_list(room, affiliation, jids); -} - -void -handle_room_role_set_error(const char * const room, const char * const nick, const char * const role, - const char * const error) -{ - log_debug("Error setting role %s list for room %s, user %s: %s", role, room, nick, error); - ui_handle_room_role_set_error(room, nick, role, error); -} - -void -handle_room_role_list_result_error(const char * const room, const char * const role, const char * const error) -{ - log_debug("Error retrieving %s list for room %s: %s", role, room, error); - ui_handle_room_role_list_error(room, role, error); -} - -void -handle_room_role_list(const char * const room, const char * const role, GSList *nicks) -{ - ui_handle_room_role_list(room, role, nicks); -} - -void -handle_room_affiliation_set_error(const char * const room, const char * const jid, const char * const affiliation, - const char * const error) -{ - log_debug("Error setting affiliation %s list for room %s, user %s: %s", affiliation, room, jid, error); - ui_handle_room_affiliation_set_error(room, jid, affiliation, error); -} - -void -handle_disco_items(GSList *items, const char *jid) -{ - cons_show_disco_items(items, jid); -} - -void -handle_room_invite(jabber_invite_t invite_type, - const char * const invitor, const char * const room, - const char * const reason) -{ - if (!muc_active(room) && !muc_invites_contain(room)) { - cons_show_room_invite(invitor, room, reason); - muc_invites_add(room); - } -} - -void -handle_room_broadcast(const char *const room_jid, - const char * const message) -{ - if (muc_roster_complete(room_jid)) { - ui_room_broadcast(room_jid, message); - } else { - muc_pending_broadcasts_add(room_jid, message); - } -} - -void -handle_room_subject(const char * const room, const char * const nick, const char * const subject) -{ - muc_set_subject(room, subject); - if (muc_roster_complete(room)) { - ui_room_subject(room, nick, subject); - } -} - -void -handle_room_history(const char * const room_jid, const char * const nick, - GTimeVal tv_stamp, const char * const message) -{ - ui_room_history(room_jid, nick, tv_stamp, message); -} - -void -handle_room_message(const char * const room_jid, const char * const nick, - const char * const message) -{ - ui_room_message(room_jid, nick, message); - - if (prefs_get_boolean(PREF_GRLOG)) { - Jid *jid = jid_create(jabber_get_fulljid()); - groupchat_log_chat(jid->barejid, room_jid, nick, message); - jid_destroy(jid); - } -} - -void -handle_incoming_private_message(char *fulljid, char *message) -{ - ui_incoming_private_msg(fulljid, message, NULL); -} - -void -handle_incoming_message(char *barejid, char *resource, char *message) -{ -#ifdef HAVE_LIBOTR - gboolean was_decrypted = FALSE; - char *newmessage; - - prof_otrpolicy_t policy = otr_get_policy(barejid); - char *whitespace_base = strstr(message,OTRL_MESSAGE_TAG_BASE); - - //check for OTR whitespace (opportunistic or always) - if (policy == PROF_OTRPOLICY_OPPORTUNISTIC || policy == PROF_OTRPOLICY_ALWAYS) { - if (whitespace_base) { - if (strstr(message, OTRL_MESSAGE_TAG_V2) || strstr(message, OTRL_MESSAGE_TAG_V1)) { - // Remove whitespace pattern for proper display in UI - // Handle both BASE+TAGV1/2(16+8) and BASE+TAGV1+TAGV2(16+8+8) - int tag_length = 24; - if (strstr(message, OTRL_MESSAGE_TAG_V2) && strstr(message, OTRL_MESSAGE_TAG_V1)) { - tag_length = 32; - } - memmove(whitespace_base, whitespace_base+tag_length, tag_length); - char *otr_query_message = otr_start_query(); - cons_show("OTR Whitespace pattern detected. Attempting to start OTR session..."); - message_send_chat(barejid, otr_query_message); - } - } - } - newmessage = otr_decrypt_message(barejid, message, &was_decrypted); - - // internal OTR message - if (newmessage == NULL) { - return; - } - - if (policy == PROF_OTRPOLICY_ALWAYS && !was_decrypted && !whitespace_base) { - char *otr_query_message = otr_start_query(); - cons_show("Attempting to start OTR session..."); - message_send_chat(barejid, otr_query_message); - } - - ui_incoming_msg(barejid, resource, newmessage, NULL); - - if (prefs_get_boolean(PREF_CHLOG)) { - const char *jid = jabber_get_fulljid(); - Jid *jidp = jid_create(jid); - - char *pref_otr_log = prefs_get_string(PREF_OTR_LOG); - if (!was_decrypted || (strcmp(pref_otr_log, "on") == 0)) { - chat_log_chat(jidp->barejid, barejid, newmessage, PROF_IN_LOG, NULL); - } else if (strcmp(pref_otr_log, "redact") == 0) { - chat_log_chat(jidp->barejid, barejid, "[redacted]", PROF_IN_LOG, NULL); - } - prefs_free_string(pref_otr_log); - - jid_destroy(jidp); - } - - otr_free_message(newmessage); -#else - ui_incoming_msg(barejid, resource, message, NULL); - - if (prefs_get_boolean(PREF_CHLOG)) { - const char *jid = jabber_get_fulljid(); - Jid *jidp = jid_create(jid); - chat_log_chat(jidp->barejid, barejid, message, PROF_IN_LOG, NULL); - jid_destroy(jidp); - } -#endif -} - -void -handle_delayed_private_message(char *fulljid, char *message, GTimeVal tv_stamp) -{ - ui_incoming_private_msg(fulljid, message, &tv_stamp); -} - -void -handle_delayed_message(char *barejid, char *message, GTimeVal tv_stamp) -{ - ui_incoming_msg(barejid, NULL, message, &tv_stamp); - - if (prefs_get_boolean(PREF_CHLOG)) { - const char *jid = jabber_get_fulljid(); - Jid *jidp = jid_create(jid); - chat_log_chat(jidp->barejid, barejid, message, PROF_IN_LOG, &tv_stamp); - jid_destroy(jidp); - } -} - -void -handle_typing(char *barejid, char *resource) -{ - ui_contact_typing(barejid, resource); - if (ui_chat_win_exists(barejid)) { - chat_session_recipient_typing(barejid, resource); - } -} - -void -handle_paused(char *barejid, char *resource) -{ - if (ui_chat_win_exists(barejid)) { - chat_session_recipient_paused(barejid, resource); - } -} - -void -handle_inactive(char *barejid, char *resource) -{ - if (ui_chat_win_exists(barejid)) { - chat_session_recipient_inactive(barejid, resource); - } -} - -void -handle_gone(const char * const barejid, const char * const resource) -{ - ui_recipient_gone(barejid, resource); - if (ui_chat_win_exists(barejid)) { - chat_session_recipient_gone(barejid, resource); - } -} - -void -handle_activity(const char * const barejid, const char * const resource, gboolean send_states) -{ - if (ui_chat_win_exists(barejid)) { - chat_session_recipient_active(barejid, resource, send_states); - } -} - -void -handle_subscription(const char *barejid, jabber_subscr_t type) -{ - switch (type) { - case PRESENCE_SUBSCRIBE: - /* TODO: auto-subscribe if needed */ - cons_show("Received authorization request from %s", barejid); - log_info("Received authorization request from %s", barejid); - ui_print_system_msg_from_recipient(barejid, "Authorization request, type '/sub allow' to accept or '/sub deny' to reject"); - if (prefs_get_boolean(PREF_NOTIFY_SUB)) { - notify_subscription(barejid); - } - break; - case PRESENCE_SUBSCRIBED: - cons_show("Subscription received from %s", barejid); - log_info("Subscription received from %s", barejid); - ui_print_system_msg_from_recipient(barejid, "Subscribed"); - break; - case PRESENCE_UNSUBSCRIBED: - cons_show("%s deleted subscription", barejid); - log_info("%s deleted subscription", barejid); - ui_print_system_msg_from_recipient(barejid, "Unsubscribed"); - break; - default: - /* unknown type */ - break; - } -} - -void -handle_contact_offline(char *barejid, char *resource, char *status) -{ - gboolean updated = roster_contact_offline(barejid, resource, status); - - if (resource != NULL && updated) { - ui_contact_offline(barejid, resource, status); - } - - rosterwin_roster(); - chat_session_remove(barejid); -} - -void -handle_contact_online(char *barejid, Resource *resource, - GDateTime *last_activity) -{ - gboolean updated = roster_update_presence(barejid, resource, last_activity); - - if (updated) { - char *show_console = prefs_get_string(PREF_STATUSES_CONSOLE); - char *show_chat_win = prefs_get_string(PREF_STATUSES_CHAT); - PContact contact = roster_get_contact(barejid); - if (p_contact_subscription(contact) != NULL) { - if (strcmp(p_contact_subscription(contact), "none") != 0) { - - // show in console if "all" - if (g_strcmp0(show_console, "all") == 0) { - cons_show_contact_online(contact, resource, last_activity); - - // show in console of "online" and presence online - } else if (g_strcmp0(show_console, "online") == 0 && - resource->presence == RESOURCE_ONLINE) { - cons_show_contact_online(contact, resource, last_activity); - - } - - // show in chat win if "all" - if (g_strcmp0(show_chat_win, "all") == 0) { - ui_chat_win_contact_online(contact, resource, last_activity); - - // show in char win if "online" and presence online - } else if (g_strcmp0(show_chat_win, "online") == 0 && - resource->presence == RESOURCE_ONLINE) { - ui_chat_win_contact_online(contact, resource, last_activity); - } - } - } - prefs_free_string(show_console); - prefs_free_string(show_chat_win); - } - - rosterwin_roster(); - chat_session_remove(barejid); -} - -void -handle_leave_room(const char * const room) -{ - muc_leave(room); - ui_leave_room(room); -} - -void -handle_room_destroy(const char * const room) -{ - muc_leave(room); - ui_room_destroy(room); -} - -void -handle_room_destroyed(const char * const room, const char * const new_jid, const char * const password, - const char * const reason) -{ - muc_leave(room); - ui_room_destroyed(room, reason, new_jid, password); -} - -void -handle_room_kicked(const char * const room, const char * const actor, const char * const reason) -{ - muc_leave(room); - ui_room_kicked(room, actor, reason); -} - -void -handle_room_banned(const char * const room, const char * const actor, const char * const reason) -{ - muc_leave(room); - ui_room_banned(room, actor, reason); -} - -void -handle_room_configure(const char * const room, DataForm *form) -{ - ui_handle_room_configuration(room, form); -} - -void -handle_room_configuration_form_error(const char * const room, const char * const message) -{ - ui_handle_room_configuration_form_error(room, message); -} - -void -handle_room_config_submit_result(const char * const room) -{ - ui_handle_room_config_submit_result(room); -} - -void -handle_room_config_submit_result_error(const char * const room, const char * const message) -{ - ui_handle_room_config_submit_result_error(room, message); -} - -void -handle_room_kick_result_error(const char * const room, const char * const nick, const char * const error) -{ - ui_handle_room_kick_error(room, nick, error); -} - -void -handle_room_occupant_offline(const char * const room, const char * const nick, - const char * const show, const char * const status) -{ - muc_roster_remove(room, nick); - - char *muc_status_pref = prefs_get_string(PREF_STATUSES_MUC); - if (g_strcmp0(muc_status_pref, "none") != 0) { - ui_room_member_offline(room, nick); - } - prefs_free_string(muc_status_pref); - occupantswin_occupants(room); -} - -void -handle_room_occupent_kicked(const char * const room, const char * const nick, const char * const actor, - const char * const reason) -{ - muc_roster_remove(room, nick); - ui_room_member_kicked(room, nick, actor, reason); - occupantswin_occupants(room); -} - -void -handle_room_occupent_banned(const char * const room, const char * const nick, const char * const actor, - const char * const reason) -{ - muc_roster_remove(room, nick); - ui_room_member_banned(room, nick, actor, reason); - occupantswin_occupants(room); -} - -void -handle_group_add(const char * const contact, - const char * const group) -{ - ui_group_added(contact, group); -} - -void -handle_group_remove(const char * const contact, - const char * const group) -{ - ui_group_removed(contact, group); -} - -void -handle_roster_remove(const char * const barejid) -{ - ui_roster_remove(barejid); -} - -void -handle_roster_add(const char * const barejid, const char * const name) -{ - ui_roster_add(barejid, name); -} - -void -handle_roster_update(const char * const barejid, const char * const name, - GSList *groups, const char * const subscription, gboolean pending_out) -{ - roster_update(barejid, name, groups, subscription, pending_out); - rosterwin_roster(); -} - -void -handle_autoping_cancel(void) -{ - prefs_set_autoping(0); - cons_show_error("Server ping not supported, autoping disabled."); -} - -void -handle_xmpp_stanza(const char * const msg) -{ - ui_handle_stanza(msg); -} - -void -handle_ping_result(const char * const from, int millis) -{ - if (from == NULL) { - cons_show("Ping response from server: %dms.", millis); - } else { - cons_show("Ping response from %s: %dms.", from, millis); - } -} - -void -handle_ping_error_result(const char * const from, const char * const error) -{ - if (error == NULL) { - cons_show_error("Error returned from pinging %s.", from); - } else { - cons_show_error("Error returned from pinging %s: %s.", from, error); - } -} - -void -handle_muc_self_online(const char * const room, const char * const nick, gboolean config_required, - const char * const role, const char * const affiliation, const char * const actor, const char * const reason, - const char * const jid, const char * const show, const char * const status) -{ - muc_roster_add(room, nick, jid, role, affiliation, show, status); - char *old_role = muc_role_str(room); - char *old_affiliation = muc_affiliation_str(room); - muc_set_role(room, role); - muc_set_affiliation(room, affiliation); - - // handle self nick change - if (muc_nick_change_pending(room)) { - muc_nick_change_complete(room, nick); - ui_room_nick_change(room, nick); - - // handle roster complete - } else if (!muc_roster_complete(room)) { - if (muc_autojoin(room)) { - ui_room_join(room, FALSE); - } else { - ui_room_join(room, TRUE); - } - muc_invites_remove(room); - muc_roster_set_complete(room); - - // show roster if occupants list disabled by default - if (!prefs_get_boolean(PREF_OCCUPANTS)) { - GList *occupants = muc_roster(room); - ui_room_roster(room, occupants, NULL); - g_list_free(occupants); - } - - char *subject = muc_subject(room); - if (subject != NULL) { - ui_room_subject(room, NULL, subject); - } - - GList *pending_broadcasts = muc_pending_broadcasts(room); - if (pending_broadcasts != NULL) { - GList *curr = pending_broadcasts; - while (curr != NULL) { - ui_room_broadcast(room, curr->data); - curr = g_list_next(curr); - } - } - - // room configuration required - if (config_required) { - muc_set_requires_config(room, TRUE); - ui_room_requires_config(room); - } - - // check for change in role/affiliation - } else { - if (prefs_get_boolean(PREF_MUC_PRIVILEGES)) { - // both changed - if ((g_strcmp0(role, old_role) != 0) && (g_strcmp0(affiliation, old_affiliation) != 0)) { - ui_room_role_and_affiliation_change(room, role, affiliation, actor, reason); - - // role changed - } else if (g_strcmp0(role, old_role) != 0) { - ui_room_role_change(room, role, actor, reason); - - // affiliation changed - } else if (g_strcmp0(affiliation, old_affiliation) != 0) { - ui_room_affiliation_change(room, affiliation, actor, reason); - } - } - } - - occupantswin_occupants(room); -} - -void -handle_muc_occupant_online(const char * const room, const char * const nick, const char * const jid, - const char * const role, const char * const affiliation, const char * const actor, const char * const reason, - const char * const show, const char * const status) -{ - Occupant *occupant = muc_roster_item(room, nick); - - const char *old_role = NULL; - const char *old_affiliation = NULL; - if (occupant) { - old_role = muc_occupant_role_str(occupant); - old_affiliation = muc_occupant_affiliation_str(occupant); - } - - gboolean updated = muc_roster_add(room, nick, jid, role, affiliation, show, status); - - // not yet finished joining room - if (!muc_roster_complete(room)) { - return; - } - - // handle nickname change - char *old_nick = muc_roster_nick_change_complete(room, nick); - if (old_nick) { - ui_room_member_nick_change(room, old_nick, nick); - free(old_nick); - occupantswin_occupants(room); - return; - } - - // joined room - if (!occupant) { - char *muc_status_pref = prefs_get_string(PREF_STATUSES_MUC); - if (g_strcmp0(muc_status_pref, "none") != 0) { - ui_room_member_online(room, nick, role, affiliation, show, status); - } - prefs_free_string(muc_status_pref); - occupantswin_occupants(room); - return; - } - - // presence updated - if (updated) { - char *muc_status_pref = prefs_get_string(PREF_STATUSES_MUC); - if (g_strcmp0(muc_status_pref, "all") == 0) { - ui_room_member_presence(room, nick, show, status); - } - prefs_free_string(muc_status_pref); - occupantswin_occupants(room); - - // presence unchanged, check for role/affiliation change - } else { - if (prefs_get_boolean(PREF_MUC_PRIVILEGES)) { - // both changed - if ((g_strcmp0(role, old_role) != 0) && (g_strcmp0(affiliation, old_affiliation) != 0)) { - ui_room_occupant_role_and_affiliation_change(room, nick, role, affiliation, actor, reason); - - // role changed - } else if (g_strcmp0(role, old_role) != 0) { - ui_room_occupant_role_change(room, nick, role, actor, reason); - - // affiliation changed - } else if (g_strcmp0(affiliation, old_affiliation) != 0) { - ui_room_occupant_affiliation_change(room, nick, affiliation, actor, reason); - } - } - occupantswin_occupants(room); - } -} \ No newline at end of file diff --git a/src/server_events.h b/src/server_events.h deleted file mode 100644 index 6a12dc6e..00000000 --- a/src/server_events.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * server_events.h - * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> - * - * 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 <http://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. - * - */ - -#ifndef SERVER_EVENTS_H -#define SERVER_EVENTS_H - -#include "xmpp/xmpp.h" - -void handle_login_account_success(char *account_name); -void handle_lost_connection(void); -void handle_failed_login(void); -void handle_software_version_result(const char * const jid, const char * const presence, - const char * const name, const char * const version, const char * const os); -void handle_disco_info(const char *from, GSList *identities, GSList *features); -void handle_disco_info_error(const char * const from, const char * const error); -void handle_room_list(GSList *rooms, const char *conference_node); -void handle_disco_items(GSList *items, const char *jid); -void handle_room_invite(jabber_invite_t invite_type, - const char * const invitor, const char * const room, - const char * const reason); -void handle_room_broadcast(const char *const room_jid, - const char * const message); -void handle_room_subject(const char * const room, const char * const nick, const char * const subject); -void handle_room_history(const char * const room_jid, const char * const nick, - GTimeVal tv_stamp, const char * const message); -void handle_room_message(const char * const room_jid, const char * const nick, - const char * const message); -void handle_room_join_error(const char * const room, const char * const err); -void handle_room_info_error(const char * const room, const char * const error); -void handle_room_disco_info(const char * const room, GSList *identities, GSList *features); -void handle_room_affiliation_list_result_error(const char * const room, const char * const affiliation, - const char * const error); -void handle_room_affiliation_list(const char * const room, const char * const affiliation, GSList *jids); -void handle_room_affiliation_set_error(const char * const room, const char * const jid, const char * const affiliation, - const char * const error); -void handle_room_role_list_result_error(const char * const from, const char * const role, const char * const error); -void handle_room_role_list(const char * const from, const char * const role, GSList *nicks); -void handle_room_role_set_error(const char * const room, const char * const nick, const char * const role, - const char * const error); -void handle_room_kick_result_error(const char * const room, const char * const nick, const char * const error); -void handle_incoming_message(char *barejid, char *resource, char *message); -void handle_incoming_private_message(char *fulljid, char *message); -void handle_delayed_message(char *fulljid, char *message, GTimeVal tv_stamp); -void handle_delayed_private_message(char *fulljid, char *message, GTimeVal tv_stamp); -void handle_typing(char *barejid, char *resource); -void handle_paused(char *barejid, char *resource); -void handle_inactive(char *barejid, char *resource); -void handle_activity(char *barejid, char *resource, gboolean send_states); -void handle_gone(const char * const barejid, const char * const resource); -void handle_subscription(const char *from, jabber_subscr_t type); -void handle_contact_offline(char *contact, char *resource, char *status); -void handle_contact_online(char *contact, Resource *resource, - GDateTime *last_activity); -void handle_leave_room(const char * const room); -void handle_room_destroy(const char * const room); -void handle_room_occupant_offline(const char * const room, const char * const nick, - const char * const show, const char * const status); -void handle_room_destroyed(const char * const room, const char * const new_jid, const char * const password, - const char * const reason); -void handle_room_kicked(const char * const room, const char * const actor, const char * const reason); -void handle_room_occupent_kicked(const char * const room, const char * const nick, const char * const actor, - const char * const reason); -void handle_room_banned(const char * const room, const char * const actor, const char * const reason); -void handle_room_occupent_banned(const char * const room, const char * const nick, const char * const actor, - const char * const reason); -void handle_group_add(const char * const contact, - const char * const group); -void handle_group_remove(const char * const contact, - const char * const group); -void handle_roster_remove(const char * const barejid); -void handle_roster_add(const char * const barejid, const char * const name); -void handle_autoping_cancel(void); -void handle_message_error(const char * const from, const char * const type, - const char * const err_msg); -void handle_presence_error(const char *from, const char * const type, - const char *err_msg); -void handle_xmpp_stanza(const char * const msg); -void handle_ping_result(const char * const from, int millis); -void handle_ping_error_result(const char * const from, const char * const error); -void handle_room_configure(const char * const room, DataForm *form); -void handle_room_configuration_form_error(const char * const from, const char * const message); -void handle_room_config_submit_result(const char * const room); -void handle_room_config_submit_result_error(const char * const room, const char * const message); -void handle_muc_self_online(const char * const room, const char * const nick, gboolean config_required, - const char * const role, const char * const affiliation, const char * const actor, const char * const reason, - const char * const jid, const char * const show, const char * const status); -void handle_muc_occupant_online(const char * const room, const char * const nick, const char * const jid, - const char * const role, const char * const affiliation, const char * const actor, const char * const reason, - const char * const show_str, const char * const status_str); -void handle_roster_update(const char * const barejid, const char * const name, - GSList *groups, const char * const subscription, gboolean pending_out); -void handle_roster_received(void); - -#endif diff --git a/src/tools/autocomplete.c b/src/tools/autocomplete.c index 2623c828..7624f1df 100644 --- a/src/tools/autocomplete.c +++ b/src/tools/autocomplete.c @@ -1,7 +1,7 @@ /* * autocomplete.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/tools/autocomplete.h b/src/tools/autocomplete.h index 70cd8f30..c4b94b09 100644 --- a/src/tools/autocomplete.h +++ b/src/tools/autocomplete.h @@ -1,7 +1,7 @@ /* * autocomplete.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/tools/history.c b/src/tools/history.c deleted file mode 100644 index def10feb..00000000 --- a/src/tools/history.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * history.c - * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> - * - * 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 <http://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 <stdlib.h> -#include <string.h> - -#include <glib.h> - -#include "history.h" - -struct history_session_t { - GList *items; - GList *sess_curr; - GList *sess_new; - GList *orig_curr; -}; - -struct history_t { - GList *items; - guint max_size; - struct history_session_t session; -}; - -static void _replace_history_with_session(History history); -static gboolean _adding_new(History history); -static void _reset_session(History history); -static gboolean _has_session(History history); -static void _remove_first(History history); -static void _update_current_session_item(History history, char *item); -static void _add_to_history(History history, char *item); -static void _remove_last_session_item(History history); -static void _replace_current_with_original(History history); -static void _create_session(History history); -static void _session_previous(History history); -static void _session_next(History history); - -History -history_new(unsigned int size) -{ - History new_history = malloc(sizeof(struct history_t)); - new_history->items = NULL; - new_history->max_size = size; - - _reset_session(new_history); - - return new_history; -} - -void -history_append(History history, char *item) -{ - char *copied = ""; - if (item != NULL) { - copied = strdup(item); - } - - if (history->items == NULL) { - _add_to_history(history, copied); - return; - } - - if (!_has_session(history)) { - if (g_list_length(history->items) == history->max_size) { - _remove_first(history); - } - - _add_to_history(history, copied); - - } else { - _update_current_session_item(history, copied); - - if (_adding_new(history)) { - if (strcmp(history->session.sess_curr->data, "") == 0) { - _remove_last_session_item(history); - } - - _replace_history_with_session(history); - - } else { - _remove_last_session_item(history); - - char *new = strdup(history->session.sess_curr->data); - history->session.items = g_list_append(history->session.items, new); - - _replace_current_with_original(history); - _replace_history_with_session(history); - } - } -} - -char * -history_previous(History history, char *item) -{ - // no history - if (history->items == NULL) { - return NULL; - } - - char *copied = ""; - if (item != NULL) { - copied = strdup(item); - } - - if (!_has_session(history)) { - _create_session(history); - - // add the new item - history->session.items = g_list_append(history->session.items, copied); - history->session.sess_new = g_list_last(history->session.items); - - char *result = strdup(history->session.sess_curr->data); - return result; - } else { - _update_current_session_item(history, copied); - _session_previous(history); - } - - char *result = strdup(history->session.sess_curr->data); - return result; -} - -char * -history_next(History history, char *item) -{ - // no history, or no session, return NULL - if ((history->items == NULL) || (history->session.items == NULL)) { - return NULL; - } - - if (g_list_next(history->session.sess_curr) == NULL) { - return NULL; - } - - char *copied = ""; - if (item != NULL) { - copied = strdup(item); - } - - _update_current_session_item(history, copied); - _session_next(history); - - char *result = strdup(history->session.sess_curr->data); - return result; -} - -static void -_replace_history_with_session(History history) -{ - g_list_free(history->items); - history->items = g_list_copy(history->session.items); - - if (g_list_length(history->items) > history->max_size) { - _remove_first(history); - } - - _reset_session(history); -} - -static gboolean -_adding_new(History history) -{ - return (history->session.sess_curr == - g_list_last(history->session.items)); -} - -static void -_reset_session(History history) -{ - history->session.items = NULL; - history->session.sess_curr = NULL; - history->session.sess_new = NULL; - history->session.orig_curr = NULL; -} - -static gboolean -_has_session(History history) -{ - return (history->session.items != NULL); -} - -static void -_remove_first(History history) -{ - GList *first = g_list_first(history->items); - char *first_item = first->data; - history->items = g_list_remove(history->items, first_item); -} - -static void -_update_current_session_item(History history, char *item) -{ - history->session.sess_curr->data = item; -} - -static void -_add_to_history(History history, char *item) -{ - history->items = g_list_append(history->items, item); -} - -static void -_remove_last_session_item(History history) -{ - history->session.items = g_list_reverse(history->session.items); - GList *first = g_list_first(history->session.items); - history->session.items = - g_list_remove(history->session.items, first->data); - history->session.items = g_list_reverse(history->session.items); -} - -static void -_replace_current_with_original(History history) -{ - history->session.sess_curr->data = strdup(history->session.orig_curr->data); -} - -static void -_create_session(History history) -{ - history->session.items = g_list_copy(history->items); - history->session.sess_curr = g_list_last(history->session.items); - history->session.orig_curr = g_list_last(history->items); -} - -static void -_session_previous(History history) -{ - history->session.sess_curr = - g_list_previous(history->session.sess_curr); - if (history->session.orig_curr == NULL) - history->session.orig_curr = g_list_last(history->items); - else - history->session.orig_curr = - g_list_previous(history->session.orig_curr); - - if (history->session.sess_curr == NULL) { - history->session.sess_curr = g_list_first(history->session.items); - history->session.orig_curr = g_list_first(history->items); - } -} - -static void -_session_next(History history) -{ - history->session.sess_curr = g_list_next(history->session.sess_curr); - history->session.orig_curr = g_list_next(history->session.orig_curr); - - if (history->session.sess_curr == NULL) { - history->session.sess_curr = g_list_last(history->session.items); - history->session.orig_curr = NULL; - } -} diff --git a/src/tools/parser.c b/src/tools/parser.c index e91b227d..d3a23264 100644 --- a/src/tools/parser.c +++ b/src/tools/parser.c @@ -1,7 +1,7 @@ /* * parser.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -47,9 +47,9 @@ * * inp - The line of input * min - The minimum allowed number of arguments - * max - The maxmimum allowed number of arguments + * max - The maximum allowed number of arguments * - * Returns - An NULL terminated array of strings representing the aguments + * Returns - An NULL terminated array of strings representing the arguments * of the command, or NULL if the validation fails. * * E.g. the following input line: @@ -69,7 +69,7 @@ parse_args(const char * const inp, int min, int max, gboolean *result) return NULL; } - // copy and strip input of leading/trailing whitepsace + // copy and strip input of leading/trailing whitespace char *copy = strdup(inp); g_strstrip(copy); @@ -156,7 +156,7 @@ parse_args(const char * const inp, int min, int max, gboolean *result) token = g_slist_next(token); int arg_count = 0; - while (token != NULL) { + while (token) { args[arg_count++] = strdup(token->data); token = g_slist_next(token); } @@ -181,9 +181,9 @@ parse_args(const char * const inp, int min, int max, gboolean *result) * * inp - The line of input * min - The minimum allowed number of arguments - * max - The maxmimum allowed number of arguments + * max - The maximum allowed number of arguments * - * Returns - An NULL terminated array of strings representing the aguments + * Returns - An NULL terminated array of strings representing the arguments * of the command, or NULL if the validation fails. * * E.g. the following input line: @@ -303,7 +303,7 @@ parse_args_with_freetext(const char * const inp, int min, int max, gboolean *res token = g_slist_next(token); int arg_count = 0; - while (token != NULL) { + while (token) { args[arg_count++] = strdup(token->data); token = g_slist_next(token); } @@ -419,7 +419,7 @@ parse_options(gchar **args, gchar **opt_keys, gboolean *res) } // check if duplicate - if (g_list_find_custom(found_keys, args[curr], (GCompareFunc)g_strcmp0) != NULL) { + if (g_list_find_custom(found_keys, args[curr], (GCompareFunc)g_strcmp0)) { *res = FALSE; g_list_free(keys); return options; @@ -450,7 +450,7 @@ parse_options(gchar **args, gchar **opt_keys, gboolean *res) void options_destroy(GHashTable *options) { - if (options != NULL) { + if (options) { g_hash_table_destroy(options); } } diff --git a/src/tools/parser.h b/src/tools/parser.h index eeb97df3..34fa55a0 100644 --- a/src/tools/parser.h +++ b/src/tools/parser.h @@ -1,7 +1,7 @@ /* * parser.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/tools/tinyurl.c b/src/tools/tinyurl.c index 3addc646..92ff97b8 100644 --- a/src/tools/tinyurl.c +++ b/src/tools/tinyurl.c @@ -1,7 +1,7 @@ /* * tinyurl.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -74,7 +74,7 @@ tinyurl_get(char *url) g_string_free(full_url, TRUE); - if (output.buffer != NULL) { + if (output.buffer) { output.buffer[output.size++] = '\0'; return output.buffer; } else { diff --git a/src/tools/tinyurl.h b/src/tools/tinyurl.h index 9557228f..f69570c3 100644 --- a/src/tools/tinyurl.h +++ b/src/tools/tinyurl.h @@ -1,7 +1,7 @@ /* * tinyurl.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/ui/buffer.c b/src/ui/buffer.c index 52397b4b..0848b60f 100644 --- a/src/ui/buffer.c +++ b/src/ui/buffer.c @@ -1,7 +1,7 @@ /* * buffer.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -81,7 +81,7 @@ buffer_free(ProfBuff buffer) void buffer_push(ProfBuff buffer, const char show_char, GDateTime *time, - int flags, theme_item_t theme_item, const char * const from, const char * const message) + int flags, theme_item_t theme_item, const char * const from, const char * const message, DeliveryReceipt *receipt) { ProfBuffEntry *e = malloc(sizeof(struct prof_buff_entry_t)); e->show_char = show_char; @@ -90,6 +90,7 @@ buffer_push(ProfBuff buffer, const char show_char, GDateTime *time, e->time = time; e->from = strdup(from); e->message = strdup(message); + e->receipt = receipt; if (g_slist_length(buffer->entries) == BUFF_SIZE) { _free_entry(buffer->entries->data); @@ -99,6 +100,24 @@ buffer_push(ProfBuff buffer, const char show_char, GDateTime *time, buffer->entries = g_slist_append(buffer->entries, e); } +gboolean +buffer_mark_received(ProfBuff buffer, const char * const id) +{ + GSList *entries = buffer->entries; + while (entries) { + ProfBuffEntry *entry = entries->data; + if (entry->receipt && g_strcmp0(entry->receipt->id, id) == 0) { + if (!entry->receipt->received) { + entry->receipt->received = TRUE; + return TRUE; + } + } + entries = g_slist_next(entries); + } + + return FALSE; +} + ProfBuffEntry* buffer_yield_entry(ProfBuff buffer, int entry) { @@ -112,5 +131,9 @@ _free_entry(ProfBuffEntry *entry) free(entry->message); free(entry->from); g_date_time_unref(entry->time); + if (entry->receipt) { + free(entry->receipt->id); + free(entry->receipt); + } free(entry); } \ No newline at end of file diff --git a/src/ui/buffer.h b/src/ui/buffer.h index 34d6b04f..cad7eee0 100644 --- a/src/ui/buffer.h +++ b/src/ui/buffer.h @@ -1,7 +1,7 @@ /* * buffer.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -40,6 +40,11 @@ #include <glib.h> +typedef struct delivery_receipt_t { + char *id; + gboolean received; +} DeliveryReceipt; + typedef struct prof_buff_entry_t { char show_char; GDateTime *time; @@ -47,13 +52,18 @@ typedef struct prof_buff_entry_t { theme_item_t theme_item; char *from; char *message; + DeliveryReceipt *receipt; } ProfBuffEntry; typedef struct prof_buff_t *ProfBuff; ProfBuff buffer_create(); void buffer_free(ProfBuff buffer); -void buffer_push(ProfBuff buffer, const char show_char, GDateTime *time, int flags, theme_item_t theme_item, const char * const from, const char * const message); +void buffer_push(ProfBuff buffer, const char show_char, GDateTime *time, int flags, theme_item_t theme_item, + const char * const from, const char * const message, DeliveryReceipt *receipt); int buffer_size(ProfBuff buffer); ProfBuffEntry* buffer_yield_entry(ProfBuff buffer, int entry); +gboolean buffer_mark_received(ProfBuff buffer, const char * const id); + + #endif diff --git a/src/ui/console.c b/src/ui/console.c index 689f218c..895efda4 100644 --- a/src/ui/console.c +++ b/src/ui/console.c @@ -1,7 +1,7 @@ /* * console.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -67,14 +67,14 @@ void cons_show_time(void) { ProfWin *console = wins_get_console(); - win_save_print(console, '-', NULL, NO_EOL, 0, "", ""); + win_print(console, '-', NULL, NO_EOL, 0, "", ""); } void cons_show_word(const char * const word) { ProfWin *console = wins_get_console(); - win_save_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", word); + win_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", word); } void @@ -86,7 +86,7 @@ cons_debug(const char * const msg, ...) va_start(arg, msg); GString *fmt_msg = g_string_new(NULL); g_string_vprintf(fmt_msg, msg, arg); - win_save_println(console, fmt_msg->str); + win_println(console, fmt_msg->str); g_string_free(fmt_msg, TRUE); va_end(arg); } @@ -100,7 +100,7 @@ cons_show(const char * const msg, ...) va_start(arg, msg); GString *fmt_msg = g_string_new(NULL); g_string_vprintf(fmt_msg, msg, arg); - win_save_println(console, fmt_msg->str); + win_println(console, fmt_msg->str); g_string_free(fmt_msg, TRUE); va_end(arg); } @@ -113,7 +113,7 @@ cons_show_error(const char * const msg, ...) va_start(arg, msg); GString *fmt_msg = g_string_new(NULL); g_string_vprintf(fmt_msg, msg, arg); - win_save_print(console, '-', NULL, 0, THEME_ERROR, "", fmt_msg->str); + win_print(console, '-', NULL, 0, THEME_ERROR, "", fmt_msg->str); g_string_free(fmt_msg, TRUE); va_end(arg); @@ -126,8 +126,8 @@ cons_show_typing(const char * const barejid) ProfWin *console = wins_get_console(); const char * display_usr = NULL; PContact contact = roster_get_contact(barejid); - if (contact != NULL) { - if (p_contact_name(contact) != NULL) { + if (contact) { + if (p_contact_name(contact)) { display_usr = p_contact_name(contact); } else { display_usr = barejid; @@ -136,7 +136,7 @@ cons_show_typing(const char * const barejid) display_usr = barejid; } - win_save_vprint(console, '-', NULL, 0, THEME_TYPING, "", "!! %s is typing a message...", display_usr); + win_vprint(console, '-', NULL, 0, THEME_TYPING, "", "!! %s is typing a message...", display_usr); cons_alert(); } @@ -149,7 +149,7 @@ cons_show_incoming_message(const char * const short_from, const int win_index) if (ui_index == 10) { ui_index = 0; } - win_save_vprint(console, '-', NULL, 0, THEME_INCOMING, "", "<< incoming from %s (%d)", short_from, ui_index); + win_vprint(console, '-', NULL, 0, THEME_INCOMING, "", "<< incoming from %s (%d)", short_from, ui_index); cons_alert(); } @@ -167,23 +167,23 @@ cons_about(void) if (strcmp(PACKAGE_STATUS, "development") == 0) { #ifdef HAVE_GIT_VERSION - win_save_vprint(console, '-', NULL, 0, 0, "", "Welcome to Profanity, version %sdev.%s.%s", PACKAGE_VERSION, PROF_GIT_BRANCH, PROF_GIT_REVISION); + win_vprint(console, '-', NULL, 0, 0, "", "Welcome to Profanity, version %sdev.%s.%s", PACKAGE_VERSION, PROF_GIT_BRANCH, PROF_GIT_REVISION); #else - win_save_vprint(console, '-', NULL, 0, 0, "", "Welcome to Profanity, version %sdev", PACKAGE_VERSION); + win_vprint(console, '-', NULL, 0, 0, "", "Welcome to Profanity, version %sdev", PACKAGE_VERSION); #endif } else { - win_save_vprint(console, '-', NULL, 0, 0, "", "Welcome to Profanity, version %s", PACKAGE_VERSION); + win_vprint(console, '-', NULL, 0, 0, "", "Welcome to Profanity, version %s", PACKAGE_VERSION); } } - win_save_vprint(console, '-', NULL, 0, 0, "", "Copyright (C) 2012 - 2014 James Booth <%s>.", PACKAGE_BUGREPORT); - win_save_println(console, "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>"); - win_save_println(console, ""); - win_save_println(console, "This is free software; you are free to change and redistribute it."); - win_save_println(console, "There is NO WARRANTY, to the extent permitted by law."); - win_save_println(console, ""); - win_save_println(console, "Type '/help' to show complete help."); - win_save_println(console, ""); + win_vprint(console, '-', NULL, 0, 0, "", "Copyright (C) 2012 - 2015 James Booth <%s>.", PACKAGE_BUGREPORT); + win_println(console, "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>"); + win_println(console, ""); + win_println(console, "This is free software; you are free to change and redistribute it."); + win_println(console, "There is NO WARRANTY, to the extent permitted by law."); + win_println(console, ""); + win_println(console, "Type '/help' to show complete help."); + win_println(console, ""); if (prefs_get_boolean(PREF_VERCHECK)) { cons_check_version(FALSE); @@ -200,18 +200,18 @@ cons_check_version(gboolean not_available_msg) ProfWin *console = wins_get_console(); char *latest_release = release_get_latest(); - if (latest_release != NULL) { + if (latest_release) { gboolean relase_valid = g_regex_match_simple("^\\d+\\.\\d+\\.\\d+$", latest_release, 0, 0); if (relase_valid) { if (release_is_new(latest_release)) { - win_save_vprint(console, '-', NULL, 0, 0, "", "A new version of Profanity is available: %s", latest_release); - win_save_println(console, "Check <http://www.profanity.im> for details."); - win_save_println(console, ""); + win_vprint(console, '-', NULL, 0, 0, "", "A new version of Profanity is available: %s", latest_release); + win_println(console, "Check <http://www.profanity.im> for details."); + win_println(console, ""); } else { if (not_available_msg) { - win_save_println(console, "No new version available."); - win_save_println(console, ""); + win_println(console, "No new version available."); + win_println(console, ""); } } @@ -225,16 +225,16 @@ void cons_show_login_success(ProfAccount *account) { ProfWin *console = wins_get_console(); - win_save_vprint(console, '-', NULL, NO_EOL, 0, "", "%s logged in successfully, ", account->jid); + win_vprint(console, '-', NULL, NO_EOL, 0, "", "%s logged in successfully, ", account->jid); resource_presence_t presence = accounts_get_login_presence(account->name); const char *presence_str = string_from_resource_presence(presence); theme_item_t presence_colour = theme_main_presence_attrs(presence_str); - win_save_vprint(console, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", "%s", presence_str); - win_save_vprint(console, '-', NULL, NO_DATE | NO_EOL, 0, "", " (priority %d)", + win_vprint(console, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", "%s", presence_str); + win_vprint(console, '-', NULL, NO_DATE | NO_EOL, 0, "", " (priority %d)", accounts_get_priority_for_presence_type(account->name, presence)); - win_save_print(console, '-', NULL, NO_DATE, 0, "", "."); + win_print(console, '-', NULL, NO_DATE, 0, "", "."); cons_alert(); } @@ -247,10 +247,11 @@ cons_show_wins(void) GSList *window_strings = wins_create_summary(); GSList *curr = window_strings; - while (curr != NULL) { - win_save_println(console, curr->data); + while (curr) { + win_println(console, curr->data); curr = g_slist_next(curr); } + g_slist_free_full(window_strings, free); cons_show(""); cons_alert(); @@ -264,7 +265,7 @@ cons_show_room_invites(GSList *invites) cons_show("No outstanding chat room invites."); } else { cons_show("Chat room invites, use /join or /decline commands:"); - while (invites != NULL) { + while (invites) { cons_show(" %s", invites->data); invites = g_slist_next(invites); } @@ -293,53 +294,53 @@ cons_show_caps(const char * const fulljid, resource_presence_t presence) const char *resource_presence = string_from_resource_presence(presence); theme_item_t presence_colour = theme_main_presence_attrs(resource_presence); - win_save_vprint(console, '-', NULL, NO_EOL, presence_colour, "", "%s", fulljid); - win_save_print(console, '-', NULL, NO_DATE, 0, "", ":"); + win_vprint(console, '-', NULL, NO_EOL, presence_colour, "", "%s", fulljid); + win_print(console, '-', NULL, NO_DATE, 0, "", ":"); // show identity - if ((caps->category != NULL) || (caps->type != NULL) || (caps->name != NULL)) { - win_save_print(console, '-', NULL, NO_EOL, 0, "", "Identity: "); - if (caps->name != NULL) { - win_save_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", caps->name); - if ((caps->category != NULL) || (caps->type != NULL)) { - win_save_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", " "); + if (caps->category || caps->type || caps->name) { + win_print(console, '-', NULL, NO_EOL, 0, "", "Identity: "); + if (caps->name) { + win_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", caps->name); + if (caps->category || caps->type) { + win_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", " "); } } - if (caps->type != NULL) { - win_save_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", caps->type); - if (caps->category != NULL) { - win_save_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", " "); + if (caps->type) { + win_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", caps->type); + if (caps->category) { + win_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", " "); } } - if (caps->category != NULL) { - win_save_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", caps->category); + if (caps->category) { + win_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", caps->category); } - win_save_newline(console); + win_newline(console); } - if (caps->software != NULL) { - win_save_vprint(console, '-', NULL, NO_EOL, 0, "", "Software: %s", caps->software); + if (caps->software) { + win_vprint(console, '-', NULL, NO_EOL, 0, "", "Software: %s", caps->software); } - if (caps->software_version != NULL) { - win_save_vprint(console, '-', NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->software_version); + if (caps->software_version) { + win_vprint(console, '-', NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->software_version); } - if ((caps->software != NULL) || (caps->software_version != NULL)) { - win_save_newline(console); + if (caps->software || caps->software_version) { + win_newline(console); } - if (caps->os != NULL) { - win_save_vprint(console, '-', NULL, NO_EOL, 0, "", "OS: %s", caps->os); + if (caps->os) { + win_vprint(console, '-', NULL, NO_EOL, 0, "", "OS: %s", caps->os); } - if (caps->os_version != NULL) { - win_save_vprint(console, '-', NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->os_version); + if (caps->os_version) { + win_vprint(console, '-', NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->os_version); } - if ((caps->os != NULL) || (caps->os_version != NULL)) { - win_save_newline(console); + if (caps->os || caps->os_version) { + win_newline(console); } - if (caps->features != NULL) { - win_save_println(console, "Features:"); + if (caps->features) { + win_println(console, "Features:"); GSList *feature = caps->features; - while (feature != NULL) { - win_save_vprint(console, '-', NULL, 0, 0, "", " %s", feature->data); + while (feature) { + win_vprint(console, '-', NULL, 0, 0, "", " %s", feature->data); feature = g_slist_next(feature); } } @@ -357,19 +358,19 @@ cons_show_software_version(const char * const jid, const char * const presence, const char * const name, const char * const version, const char * const os) { ProfWin *console = wins_get_console(); - if ((name != NULL) || (version != NULL) || (os != NULL)) { + if (name || version || os) { cons_show(""); theme_item_t presence_colour = theme_main_presence_attrs(presence); - win_save_vprint(console, '-', NULL, NO_EOL, presence_colour, "", "%s", jid); - win_save_print(console, '-', NULL, NO_DATE, 0, "", ":"); + win_vprint(console, '-', NULL, NO_EOL, presence_colour, "", "%s", jid); + win_print(console, '-', NULL, NO_DATE, 0, "", ":"); } - if (name != NULL) { + if (name) { cons_show("Name : %s", name); } - if (version != NULL) { + if (version) { cons_show("Version : %s", version); } - if (os != NULL) { + if (os) { cons_show("OS : %s", os); } @@ -385,7 +386,7 @@ cons_show_received_subs(void) } else { cons_show("Outstanding subscription requests from:", g_slist_length(received)); - while (received != NULL) { + while (received) { cons_show(" %s", received->data); received = g_slist_next(received); } @@ -402,17 +403,18 @@ cons_show_sent_subs(void) GSList *contacts = roster_get_contacts(); PContact contact = NULL; cons_show("Awaiting subscription responses from:"); - while (contacts != NULL) { - contact = (PContact) contacts->data; + GSList *curr = contacts; + while (curr) { + contact = (PContact) curr->data; if (p_contact_pending_out(contact)) { cons_show(" %s", p_contact_barejid(contact)); } - contacts = g_slist_next(contacts); + curr = g_slist_next(curr); } + g_slist_free(contacts); } else { cons_show("No pending requests sent."); } - cons_alert(); } @@ -420,15 +422,15 @@ void cons_show_room_list(GSList *rooms, const char * const conference_node) { ProfWin *console = wins_get_console(); - if ((rooms != NULL) && (g_slist_length(rooms) > 0)) { + if (rooms && (g_slist_length(rooms) > 0)) { cons_show("Chat rooms at %s:", conference_node); - while (rooms != NULL) { + while (rooms) { DiscoItem *room = rooms->data; - win_save_vprint(console, '-', NULL, NO_EOL, 0, "", " %s", room->jid); - if (room->name != NULL) { - win_save_vprint(console, '-', NULL, NO_DATE | NO_EOL, 0, "", ", (%s)", room->name); + win_vprint(console, '-', NULL, NO_EOL, 0, "", " %s", room->jid); + if (room->name) { + win_vprint(console, '-', NULL, NO_DATE | NO_EOL, 0, "", ", (%s)", room->name); } - win_save_newline(console); + win_newline(console); rooms = g_slist_next(rooms); } } else { @@ -450,7 +452,7 @@ cons_show_bookmarks(const GList *list) cons_show(""); cons_show("Bookmarks:"); - while (list != NULL) { + while (list) { Bookmark *item = list->data; theme_item_t presence_colour = THEME_TEXT; @@ -458,24 +460,24 @@ cons_show_bookmarks(const GList *list) if (muc_active(item->jid)) { presence_colour = THEME_ONLINE; } - win_save_vprint(console, '-', NULL, NO_EOL, presence_colour, "", " %s", item->jid); - if (item->nick != NULL) { - win_save_vprint(console, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", "/%s", item->nick); + win_vprint(console, '-', NULL, NO_EOL, presence_colour, "", " %s", item->jid); + if (item->nick) { + win_vprint(console, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", "/%s", item->nick); } if (item->autojoin) { - win_save_print(console, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", " (autojoin)"); + win_print(console, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", " (autojoin)"); } - if (item->password != NULL) { - win_save_print(console, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", " (private)"); + if (item->password) { + win_print(console, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", " (private)"); } if (muc_active(item->jid)) { ProfWin *roomwin = (ProfWin*)wins_get_muc(item->jid); - if (roomwin != NULL) { + if (roomwin) { int num = wins_get_num(roomwin); - win_save_vprint(console, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", " (%d)", num); + win_vprint(console, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", " (%d)", num); } } - win_save_newline(console); + win_newline(console); list = g_list_next(list); } } @@ -485,26 +487,26 @@ cons_show_bookmarks(const GList *list) void cons_show_disco_info(const char *jid, GSList *identities, GSList *features) { - if (((identities != NULL) && (g_slist_length(identities) > 0)) || - ((features != NULL) && (g_slist_length(features) > 0))) { + if ((identities && (g_slist_length(identities) > 0)) || + (features && (g_slist_length(features) > 0))) { cons_show(""); cons_show("Service disovery info for %s", jid); - if (identities != NULL) { + if (identities) { cons_show(" Identities"); } - while (identities != NULL) { + while (identities) { DiscoIdentity *identity = identities->data; // anme trpe, cat GString *identity_str = g_string_new(" "); - if (identity->name != NULL) { + if (identity->name) { identity_str = g_string_append(identity_str, identity->name); identity_str = g_string_append(identity_str, " "); } - if (identity->type != NULL) { + if (identity->type) { identity_str = g_string_append(identity_str, identity->type); identity_str = g_string_append(identity_str, " "); } - if (identity->category != NULL) { + if (identity->category) { identity_str = g_string_append(identity_str, identity->category); } cons_show(identity_str->str); @@ -512,10 +514,10 @@ cons_show_disco_info(const char *jid, GSList *identities, GSList *features) identities = g_slist_next(identities); } - if (features != NULL) { + if (features) { cons_show(" Features:"); } - while (features != NULL) { + while (features) { cons_show(" %s", features->data); features = g_slist_next(features); } @@ -528,16 +530,16 @@ void cons_show_disco_items(GSList *items, const char * const jid) { ProfWin *console = wins_get_console(); - if ((items != NULL) && (g_slist_length(items) > 0)) { + if (items && (g_slist_length(items) > 0)) { cons_show(""); cons_show("Service discovery items for %s:", jid); - while (items != NULL) { + while (items) { DiscoItem *item = items->data; - win_save_vprint(console, '-', NULL, NO_EOL, 0, "", " %s", item->jid); - if (item->name != NULL) { - win_save_vprint(console, '-', NULL, NO_DATE | NO_EOL, 0, "", ", (%s)", item->name); + win_vprint(console, '-', NULL, NO_EOL, 0, "", " %s", item->jid); + if (item->name) { + win_vprint(console, '-', NULL, NO_DATE | NO_EOL, 0, "", ", (%s)", item->name); } - win_save_vprint(console, '-', NULL, NO_DATE, 0, "", ""); + win_vprint(console, '-', NULL, NO_DATE, 0, "", ""); items = g_slist_next(items); } } else { @@ -554,7 +556,7 @@ cons_show_status(const char * const barejid) ProfWin *console = wins_get_console(); PContact pcontact = roster_get_contact(barejid); - if (pcontact != NULL) { + if (pcontact) { win_show_contact(console, pcontact); } else { cons_show("No such contact \"%s\" in roster.", barejid); @@ -569,8 +571,8 @@ cons_show_room_invite(const char * const invitor, const char * const room, { char *display_from = NULL; PContact contact = roster_get_contact(invitor); - if (contact != NULL) { - if (p_contact_name(contact) != NULL) { + if (contact) { + if (p_contact_name(contact)) { display_from = strdup(p_contact_name(contact)); } else { display_from = strdup(invitor); @@ -584,7 +586,7 @@ cons_show_room_invite(const char * const invitor, const char * const room, cons_show(" From : %s", display_from); cons_show(" Room : %s", room); - if (reason != NULL) { + if (reason) { cons_show(" Message: %s", reason); } @@ -612,7 +614,7 @@ cons_show_account_list(gchar **accounts) (g_strcmp0(jabber_get_account_name(), accounts[i]) == 0)) { resource_presence_t presence = accounts_get_last_presence(accounts[i]); theme_item_t presence_colour = theme_main_presence_attrs(string_from_resource_presence(presence)); - win_save_vprint(console, '-', NULL, 0, presence_colour, "", "%s", accounts[i]); + win_vprint(console, '-', NULL, 0, presence_colour, "", "%s", accounts[i]); } else { cons_show(accounts[i]); } @@ -671,9 +673,9 @@ cons_show_account(ProfAccount *account) if (g_list_length(account->otr_manual) > 0) { GString *manual = g_string_new("OTR manual : "); GList *curr = account->otr_manual; - while (curr != NULL) { + while (curr) { g_string_append(manual, curr->data); - if (curr->next != NULL) { + if (curr->next) { g_string_append(manual, ", "); } curr = curr->next; @@ -684,9 +686,9 @@ cons_show_account(ProfAccount *account) if (g_list_length(account->otr_opportunistic) > 0) { GString *opportunistic = g_string_new("OTR opportunistic : "); GList *curr = account->otr_opportunistic; - while (curr != NULL) { + while (curr) { g_string_append(opportunistic, curr->data); - if (curr->next != NULL) { + if (curr->next) { g_string_append(opportunistic, ", "); } curr = curr->next; @@ -697,9 +699,9 @@ cons_show_account(ProfAccount *account) if (g_list_length(account->otr_always) > 0) { GString *always = g_string_new("OTR always : "); GList *curr = account->otr_always; - while (curr != NULL) { + while (curr) { g_string_append(always, curr->data); - if (curr->next != NULL) { + if (curr->next) { g_string_append(always, ", "); } curr = curr->next; @@ -717,76 +719,81 @@ cons_show_account(ProfAccount *account) GList *resources = jabber_get_available_resources(); GList *ordered_resources = NULL; - if (resources != NULL) { - win_save_println(console, "Resources:"); + GList *curr = resources; + if (curr) { + win_println(console, "Resources:"); - // sort in order of availabiltiy - while (resources != NULL) { - Resource *resource = resources->data; + // sort in order of availability + while (curr) { + Resource *resource = curr->data; ordered_resources = g_list_insert_sorted(ordered_resources, resource, (GCompareFunc)resource_compare_availability); - resources = g_list_next(resources); + curr = g_list_next(curr); } } - while (ordered_resources != NULL) { - Resource *resource = ordered_resources->data; + g_list_free(resources); + + curr = ordered_resources; + while (curr) { + Resource *resource = curr->data; const char *resource_presence = string_from_resource_presence(resource->presence); theme_item_t presence_colour = theme_main_presence_attrs(resource_presence); - win_save_vprint(console, '-', NULL, NO_EOL, presence_colour, "", " %s (%d), %s", resource->name, resource->priority, resource_presence); + win_vprint(console, '-', NULL, NO_EOL, presence_colour, "", " %s (%d), %s", resource->name, resource->priority, resource_presence); - if (resource->status != NULL) { - win_save_vprint(console, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", ", \"%s\"", resource->status); + if (resource->status) { + win_vprint(console, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", ", \"%s\"", resource->status); } - win_save_vprint(console, '-', NULL, NO_DATE, 0, "", ""); + win_vprint(console, '-', NULL, NO_DATE, 0, "", ""); Jid *jidp = jid_create_from_bare_and_resource(account->jid, resource->name); Capabilities *caps = caps_lookup(jidp->fulljid); jid_destroy(jidp); - if (caps != NULL) { + if (caps) { // show identity - if ((caps->category != NULL) || (caps->type != NULL) || (caps->name != NULL)) { - win_save_print(console, '-', NULL, NO_EOL, 0, "", " Identity: "); - if (caps->name != NULL) { - win_save_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", caps->name); - if ((caps->category != NULL) || (caps->type != NULL)) { - win_save_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", " "); + if (caps->category || caps->type || caps->name) { + win_print(console, '-', NULL, NO_EOL, 0, "", " Identity: "); + if (caps->name) { + win_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", caps->name); + if (caps->category || caps->type) { + win_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", " "); } } - if (caps->type != NULL) { - win_save_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", caps->type); - if (caps->category != NULL) { - win_save_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", " "); + if (caps->type) { + win_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", caps->type); + if (caps->category) { + win_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", " "); } } - if (caps->category != NULL) { - win_save_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", caps->category); + if (caps->category) { + win_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", caps->category); } - win_save_newline(console); + win_newline(console); } - if (caps->software != NULL) { - win_save_vprint(console, '-', NULL, NO_EOL, 0, "", " Software: %s", caps->software); + if (caps->software) { + win_vprint(console, '-', NULL, NO_EOL, 0, "", " Software: %s", caps->software); } - if (caps->software_version != NULL) { - win_save_vprint(console, '-', NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->software_version); + if (caps->software_version) { + win_vprint(console, '-', NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->software_version); } - if ((caps->software != NULL) || (caps->software_version != NULL)) { - win_save_newline(console); + if (caps->software || caps->software_version) { + win_newline(console); } - if (caps->os != NULL) { - win_save_vprint(console, '-', NULL, NO_EOL, 0, "", " OS: %s", caps->os); + if (caps->os) { + win_vprint(console, '-', NULL, NO_EOL, 0, "", " OS: %s", caps->os); } - if (caps->os_version != NULL) { - win_save_vprint(console, '-', NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->os_version); + if (caps->os_version) { + win_vprint(console, '-', NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->os_version); } - if ((caps->os != NULL) || (caps->os_version != NULL)) { - win_save_newline(console); + if (caps->os || caps->os_version) { + win_newline(console); } caps_destroy(caps); } - ordered_resources = g_list_next(ordered_resources); + curr = g_list_next(curr); } + g_list_free(ordered_resources); } cons_alert(); @@ -801,10 +808,10 @@ cons_show_aliases(GList *aliases) } GList *curr = aliases; - if (curr != NULL) { + if (curr) { cons_show("Command aliases:"); } - while (curr != NULL) { + while (curr) { ProfAlias *alias = curr->data; cons_show(" /%s -> %s", alias->name, alias->value); curr = g_list_next(curr); @@ -850,9 +857,9 @@ cons_resource_setting(void) else cons_show("Resource title (/resource) : OFF"); if (prefs_get_boolean(PREF_RESOURCE_MESSAGE)) - cons_show("Message title (/resource) : ON"); + cons_show("Resource message (/resource) : ON"); else - cons_show("Message title (/resource) : OFF"); + cons_show("Resource message (/resource) : OFF"); } void @@ -899,6 +906,11 @@ cons_occupants_setting(void) else cons_show("Occupants (/occupants) : hide"); + if (prefs_get_boolean(PREF_OCCUPANTS_JID)) + cons_show("Occupant jids (/occupants) : show"); + else + cons_show("Occupant jids (/occupants) : hide"); + int size = prefs_get_occupants_size(); cons_show("Occupants size (/occupants) : %d", size); } @@ -907,7 +919,7 @@ void cons_autoconnect_setting(void) { char *pref_connect_account = prefs_get_string(PREF_CONNECT_ACCOUNT); - if (pref_connect_account != NULL) + if (pref_connect_account) cons_show("Autoconnect (/autoconnect) : %s", pref_connect_account); else cons_show("Autoconnect (/autoconnect) : OFF"); @@ -925,6 +937,16 @@ cons_time_setting(void) cons_show("Time (/time) : %s", pref_time); prefs_free_string(pref_time); + + char *pref_time_statusbar = prefs_get_string(PREF_TIME_STATUSBAR); + if (g_strcmp0(pref_time_statusbar, "minutes") == 0) + cons_show("Time statusbar (/time) : minutes"); + else if (g_strcmp0(pref_time_statusbar, "off") == 0) + cons_show("Time statusbar (/time) : OFF"); + else + cons_show("Time statusbar (/time) : seconds"); + + prefs_free_string(pref_time_statusbar); } void @@ -994,6 +1016,9 @@ cons_roster_setting(void) else cons_show("Roster resource (/roster) : hide"); + char *by = prefs_get_string(PREF_ROSTER_BY); + cons_show("Roster by (/roster) : %s", by); + int size = prefs_get_roster_size(); cons_show("Roster size (/roster) : %d", size); } @@ -1120,27 +1145,27 @@ void cons_states_setting(void) { if (prefs_get_boolean(PREF_STATES)) - cons_show("Send chat states (/states) : ON"); + cons_show("Send chat states (/states) : ON"); else - cons_show("Send chat states (/states) : OFF"); + cons_show("Send chat states (/states) : OFF"); } void cons_outtype_setting(void) { if (prefs_get_boolean(PREF_OUTTYPE)) - cons_show("Send composing (/outtype) : ON"); + cons_show("Send composing (/outtype) : ON"); else - cons_show("Send composing (/outtype) : OFF"); + cons_show("Send composing (/outtype) : OFF"); } void cons_intype_setting(void) { if (prefs_get_boolean(PREF_INTYPE)) - cons_show("Show typing (/intype) : ON"); + cons_show("Show typing (/intype) : ON"); else - cons_show("Show typing (/intype) : OFF"); + cons_show("Show typing (/intype) : OFF"); } void @@ -1148,11 +1173,11 @@ cons_gone_setting(void) { gint gone_time = prefs_get_gone(); if (gone_time == 0) { - cons_show("Leave conversation (/gone) : OFF"); + cons_show("Leave conversation (/gone) : OFF"); } else if (gone_time == 1) { - cons_show("Leave conversation (/gone) : 1 minute"); + cons_show("Leave conversation (/gone) : 1 minute"); } else { - cons_show("Leave conversation (/gone) : %d minutes", gone_time); + cons_show("Leave conversation (/gone) : %d minutes", gone_time); } } @@ -1160,9 +1185,33 @@ void cons_history_setting(void) { if (prefs_get_boolean(PREF_HISTORY)) - cons_show("Chat history (/history) : ON"); + cons_show("Chat history (/history) : ON"); else - cons_show("Chat history (/history) : OFF"); + cons_show("Chat history (/history) : OFF"); +} + +void +cons_carbons_setting(void) +{ + if (prefs_get_boolean(PREF_CARBONS)) + cons_show("Message carbons (/carbons) : ON"); + else + cons_show("Message carbons (/carbons) : OFF"); +} + +void +cons_receipts_setting(void) +{ + if (prefs_get_boolean(PREF_RECEIPTS_REQUEST)) + cons_show("Request receipts (/receipts) : ON"); + else + cons_show("Request receipts (/receipts) : OFF"); + + if (prefs_get_boolean(PREF_RECEIPTS_SEND)) + cons_show("Send receipts (/receipts) : ON"); + else + cons_show("Send receipts (/receipts) : OFF"); + } void @@ -1175,6 +1224,8 @@ cons_show_chat_prefs(void) cons_intype_setting(); cons_gone_setting(); cons_history_setting(); + cons_carbons_setting(); + cons_receipts_setting(); cons_alert(); } @@ -1359,7 +1410,7 @@ cons_show_themes(GSList *themes) cons_show("No available themes."); } else { cons_show("Available themes:"); - while (themes != NULL) { + while (themes) { cons_show(themes->data); themes = g_slist_next(themes); } @@ -1400,7 +1451,7 @@ cons_help(void) cons_show("/help basic - List basic commands for getting started."); cons_show("/help chatting - List chat commands."); cons_show("/help groupchat - List groupchat commands."); - cons_show("/help presence - List commands to change presence."); + cons_show("/help presences - List commands to change presence."); cons_show("/help contacts - List commands for manipulating your roster."); cons_show("/help service - List service discovery commands."); cons_show("/help settings - List commands for changing settings."); @@ -1417,27 +1468,10 @@ cons_navigation_help(void) cons_show(""); cons_show("Navigation:"); cons_show(""); - cons_show("Alt-1 : This console window."); - cons_show("F1 : This console window."); - cons_show("Alt-2..Alt-0 : Chat windows."); - cons_show("F2..F10 : Chat windows."); + cons_show("Alt-1..Alt-0, F1..F10 : Choose window."); cons_show("Alt-LEFT, Alt-RIGHT : Previous/next chat window"); - cons_show("UP, DOWN : Navigate input history."); - cons_show("Ctrl-n, Ctrl-p : Navigate input history."); - cons_show("LEFT, RIGHT, HOME, END : Move cursor."); - cons_show("Ctrl-b, Ctrl-f, Ctrl-a, Ctrl-e : Move cursor."); - cons_show("Ctrl-LEFT, Ctrl-RIGHT : Jump word."); - cons_show("Ctrl-w : Delete previous word."); - cons_show("Alt-Backspace : Delete previous word."); - cons_show("Backspace : Delete previous character."); - cons_show("DEL : Delete next character."); - cons_show("Ctrl-d : Delete next character."); - cons_show("ESC : Clear current input."); - cons_show("Ctrl-u : Delete all previous characters."); - cons_show("TAB : Autocomplete."); - cons_show("PAGE UP, PAGE DOWN : Page the main window."); - cons_show("Shift-UP, Shift-DOWN : Page occupants/roster panel."); - cons_show("Ctrl-UP, Ctrl-DOWN : Page occupants/roster panel."); + cons_show("PAGEUP, PAGEDOWN : Page the main window."); + cons_show("Alt-PAGEUP, Alt-PAGEDOWN : Page occupants/roster panel."); cons_show(""); cons_alert(); @@ -1448,7 +1482,7 @@ cons_show_roster_group(const char * const group, GSList *list) { cons_show(""); - if (list != NULL) { + if (list) { cons_show("%s:", group); } else { cons_show("No group named %s exists.", group); @@ -1537,22 +1571,22 @@ cons_theme_colours(void) ProfWin *console = wins_get_console(); cons_show("Theme colours:"); - win_save_print(console, '-', NULL, NO_EOL, THEME_WHITE, "", " white "); - win_save_print(console, '-', NULL, NO_DATE, THEME_WHITE_BOLD, "", " bold_white"); - win_save_print(console, '-', NULL, NO_EOL, THEME_GREEN, "", " green "); - win_save_print(console, '-', NULL, NO_DATE, THEME_GREEN_BOLD, "", " bold_green"); - win_save_print(console, '-', NULL, NO_EOL, THEME_RED, "", " red "); - win_save_print(console, '-', NULL, NO_DATE, THEME_RED_BOLD, "", " bold_red"); - win_save_print(console, '-', NULL, NO_EOL, THEME_YELLOW, "", " yellow "); - win_save_print(console, '-', NULL, NO_DATE, THEME_YELLOW_BOLD, "", " bold_yellow"); - win_save_print(console, '-', NULL, NO_EOL, THEME_BLUE, "", " blue "); - win_save_print(console, '-', NULL, NO_DATE, THEME_BLUE_BOLD, "", " bold_blue"); - win_save_print(console, '-', NULL, NO_EOL, THEME_CYAN, "", " cyan "); - win_save_print(console, '-', NULL, NO_DATE, THEME_CYAN_BOLD, "", " bold_cyan"); - win_save_print(console, '-', NULL, NO_EOL, THEME_MAGENTA, "", " magenta "); - win_save_print(console, '-', NULL, NO_DATE, THEME_MAGENTA_BOLD, "", " bold_magenta"); - win_save_print(console, '-', NULL, NO_EOL, THEME_BLACK, "", " black "); - win_save_print(console, '-', NULL, NO_DATE, THEME_BLACK_BOLD, "", " bold_black"); + win_print(console, '-', NULL, NO_EOL, THEME_WHITE, "", " white "); + win_print(console, '-', NULL, NO_DATE, THEME_WHITE_BOLD, "", " bold_white"); + win_print(console, '-', NULL, NO_EOL, THEME_GREEN, "", " green "); + win_print(console, '-', NULL, NO_DATE, THEME_GREEN_BOLD, "", " bold_green"); + win_print(console, '-', NULL, NO_EOL, THEME_RED, "", " red "); + win_print(console, '-', NULL, NO_DATE, THEME_RED_BOLD, "", " bold_red"); + win_print(console, '-', NULL, NO_EOL, THEME_YELLOW, "", " yellow "); + win_print(console, '-', NULL, NO_DATE, THEME_YELLOW_BOLD, "", " bold_yellow"); + win_print(console, '-', NULL, NO_EOL, THEME_BLUE, "", " blue "); + win_print(console, '-', NULL, NO_DATE, THEME_BLUE_BOLD, "", " bold_blue"); + win_print(console, '-', NULL, NO_EOL, THEME_CYAN, "", " cyan "); + win_print(console, '-', NULL, NO_DATE, THEME_CYAN_BOLD, "", " bold_cyan"); + win_print(console, '-', NULL, NO_EOL, THEME_MAGENTA, "", " magenta "); + win_print(console, '-', NULL, NO_DATE, THEME_MAGENTA_BOLD, "", " bold_magenta"); + win_print(console, '-', NULL, NO_EOL, THEME_BLACK, "", " black "); + win_print(console, '-', NULL, NO_DATE, THEME_BLACK_BOLD, "", " bold_black"); cons_show(""); } @@ -1560,25 +1594,25 @@ static void _cons_splash_logo(void) { ProfWin *console = wins_get_console(); - win_save_println(console, "Welcome to"); + win_println(console, "Welcome to"); - win_save_print(console, '-', NULL, 0, THEME_SPLASH, "", " ___ _ "); - win_save_print(console, '-', NULL, 0, THEME_SPLASH, "", " / __) (_)_ "); - win_save_print(console, '-', NULL, 0, THEME_SPLASH, "", " ____ ____ ___ | |__ ____ ____ _| |_ _ _ "); - win_save_print(console, '-', NULL, 0, THEME_SPLASH, "", "| _ \\ / ___) _ \\| __) _ | _ \\| | _) | | |"); - win_save_print(console, '-', NULL, 0, THEME_SPLASH, "", "| | | | | | |_| | | ( ( | | | | | | |_| |_| |"); - win_save_print(console, '-', NULL, 0, THEME_SPLASH, "", "| ||_/|_| \\___/|_| \\_||_|_| |_|_|\\___)__ |"); - win_save_print(console, '-', NULL, 0, THEME_SPLASH, "", "|_| (____/ "); - win_save_print(console, '-', NULL, 0, THEME_SPLASH, "", ""); + win_print(console, '-', NULL, 0, THEME_SPLASH, "", " ___ _ "); + win_print(console, '-', NULL, 0, THEME_SPLASH, "", " / __) (_)_ "); + win_print(console, '-', NULL, 0, THEME_SPLASH, "", " ____ ____ ___ | |__ ____ ____ _| |_ _ _ "); + win_print(console, '-', NULL, 0, THEME_SPLASH, "", "| _ \\ / ___) _ \\| __) _ | _ \\| | _) | | |"); + win_print(console, '-', NULL, 0, THEME_SPLASH, "", "| | | | | | |_| | | ( ( | | | | | | |_| |_| |"); + win_print(console, '-', NULL, 0, THEME_SPLASH, "", "| ||_/|_| \\___/|_| \\_||_|_| |_|_|\\___)__ |"); + win_print(console, '-', NULL, 0, THEME_SPLASH, "", "|_| (____/ "); + win_print(console, '-', NULL, 0, THEME_SPLASH, "", ""); if (strcmp(PACKAGE_STATUS, "development") == 0) { #ifdef HAVE_GIT_VERSION - win_save_vprint(console, '-', NULL, 0, 0, "", "Version %sdev.%s.%s", PACKAGE_VERSION, PROF_GIT_BRANCH, PROF_GIT_REVISION); + win_vprint(console, '-', NULL, 0, 0, "", "Version %sdev.%s.%s", PACKAGE_VERSION, PROF_GIT_BRANCH, PROF_GIT_REVISION); #else - win_save_vprint(console, '-', NULL, 0, 0, "", "Version %sdev", PACKAGE_VERSION); + win_vprint(console, '-', NULL, 0, 0, "", "Version %sdev", PACKAGE_VERSION); #endif } else { - win_save_vprint(console, '-', NULL, 0, 0, "", "Version %s", PACKAGE_VERSION); + win_vprint(console, '-', NULL, 0, 0, "", "Version %s", PACKAGE_VERSION); } } @@ -1592,7 +1626,7 @@ _show_roster_contacts(GSList *list, gboolean show_groups) PContact contact = curr->data; GString *title = g_string_new(" "); title = g_string_append(title, p_contact_barejid(contact)); - if (p_contact_name(contact) != NULL) { + if (p_contact_name(contact)) { title = g_string_append(title, " ("); title = g_string_append(title, p_contact_name(contact)); title = g_string_append(title, ")"); @@ -1605,11 +1639,11 @@ _show_roster_contacts(GSList *list, gboolean show_groups) } else { presence_colour = theme_main_presence_attrs("offline"); } - win_save_vprint(console, '-', NULL, NO_EOL, presence_colour, "", title->str); + win_vprint(console, '-', NULL, NO_EOL, presence_colour, "", title->str); g_string_free(title, TRUE); - win_save_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", " - "); + win_print(console, '-', NULL, NO_DATE | NO_EOL, 0, "", " - "); GString *sub = g_string_new(""); sub = g_string_append(sub, p_contact_subscription(contact)); if (p_contact_pending_out(contact)) { @@ -1625,28 +1659,28 @@ _show_roster_contacts(GSList *list, gboolean show_groups) } if (show_groups) { - win_save_vprint(console, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", "%s", sub->str); + win_vprint(console, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", "%s", sub->str); } else { - win_save_vprint(console, '-', NULL, NO_DATE, presence_colour, "", "%s", sub->str); + win_vprint(console, '-', NULL, NO_DATE, presence_colour, "", "%s", sub->str); } g_string_free(sub, TRUE); if (show_groups) { GSList *groups = p_contact_groups(contact); - if (groups != NULL) { + if (groups) { GString *groups_str = g_string_new(" - "); - while (groups != NULL) { + while (groups) { g_string_append(groups_str, groups->data); - if (g_slist_next(groups) != NULL) { + if (g_slist_next(groups)) { g_string_append(groups_str, ", "); } groups = g_slist_next(groups); } - win_save_vprint(console, '-', NULL, NO_DATE, 0, "", "%s", groups_str->str); + win_vprint(console, '-', NULL, NO_DATE, 0, "", "%s", groups_str->str); g_string_free(groups_str, TRUE); } else { - win_save_print(console, '-', NULL, NO_DATE, 0, "", " "); + win_print(console, '-', NULL, NO_DATE, 0, "", " "); } } diff --git a/src/ui/core.c b/src/ui/core.c index 85d5748a..e7059ef0 100644 --- a/src/ui/core.c +++ b/src/ui/core.c @@ -1,7 +1,7 @@ /* * core.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -41,6 +41,9 @@ #include <stdlib.h> #include <string.h> #include <assert.h> +#include <sys/ioctl.h> +#include <unistd.h> + #ifdef HAVE_LIBXSS #include <X11/extensions/scrnsaver.h> #endif @@ -71,19 +74,22 @@ #include "ui/window.h" #include "ui/windows.h" #include "xmpp/xmpp.h" +#include "event/ui_events.h" static char *win_title; static int inp_size; +static gboolean perform_resize = FALSE; + #ifdef HAVE_LIBXSS static Display *display; #endif static GTimer *ui_idle_time; -static void _win_handle_switch(const wint_t ch); -static void _win_show_history(int win_index, const char * const contact); +//static void _win_handle_switch(const wint_t ch); +static void _win_show_history(ProfChatWin *chatwin, const char * const contact); static void _ui_draw_term_title(void); void @@ -91,7 +97,9 @@ ui_init(void) { log_info("Initialising UI"); initscr(); - raw(); + nonl(); + cbreak(); + noecho(); keypad(stdscr, TRUE); if (prefs_get_boolean(PREF_MOUSE)) { mousemask(ALL_MOUSE_EVENTS, NULL); @@ -116,6 +124,12 @@ ui_init(void) } void +ui_sigwinch_handler(int sig) +{ + perform_resize = TRUE; +} + +void ui_update(void) { ProfWin *current = wins_get_current(); @@ -132,6 +146,13 @@ ui_update(void) status_bar_update_virtual(); inp_put_back(); doupdate(); + + if (perform_resize) { + signal(SIGWINCH, SIG_IGN); + ui_resize(); + perform_resize = FALSE; + signal(SIGWINCH, ui_sigwinch_handler); + } } void @@ -147,13 +168,13 @@ ui_get_idle_time(void) // if compiled with libxss, get the x sessions idle time #ifdef HAVE_LIBXSS XScreenSaverInfo *info = XScreenSaverAllocInfo(); - if (info != NULL && display != NULL) { + if (info && display) { XScreenSaverQueryInfo(display, DefaultRootWindow(display), info); unsigned long result = info->idle; XFree(info); return result; } - if (info != NULL) { + if (info) { XFree(info); } // if no libxss or xss idle time failed, use profanity idle time @@ -174,84 +195,66 @@ ui_close(void) { notifier_uninit(); wins_destroy(); + inp_close(); endwin(); } -char* +char * ui_readline(void) { - int key_type; - wint_t ch; - - char *line = inp_read(&key_type, &ch); - _win_handle_switch(ch); + return inp_readline(); +} +void +ui_page_up(void) +{ ProfWin *current = wins_get_current(); - win_handle_page(current, ch, key_type); - - if (ch == KEY_RESIZE) { - ui_resize(); - } + win_page_up(current); +} - if (ch != ERR && key_type != ERR) { - ui_reset_idle_time(); - ui_input_nonblocking(TRUE); - } else { - ui_input_nonblocking(FALSE); - } +void +ui_page_down(void) +{ + ProfWin *current = wins_get_current(); + win_page_down(current); +} - return line; +void +ui_subwin_page_up(void) +{ + ProfWin *current = wins_get_current(); + win_sub_page_up(current); } void -ui_inp_history_append(char *inp) +ui_subwin_page_down(void) { - inp_history_append(inp); + ProfWin *current = wins_get_current(); + win_sub_page_down(current); } void ui_input_clear(void) { - inp_win_reset(); + inp_win_clear(); } void ui_input_nonblocking(gboolean reset) { - static gint timeout = 0; - static gint no_input_count = 0; - - if (! prefs_get_boolean(PREF_INPBLOCK_DYNAMIC)) { - inp_non_block(prefs_get_inpblock()); - return; - } - - if (reset) { - timeout = 0; - no_input_count = 0; - } - - if (timeout < prefs_get_inpblock()) { - no_input_count++; - - if (no_input_count % 10 == 0) { - timeout += no_input_count; - - if (timeout > prefs_get_inpblock()) { - timeout = prefs_get_inpblock(); - } - } - } - - inp_non_block(timeout); + inp_nonblocking(reset); } void ui_resize(void) { - log_info("Resizing UI"); + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); erase(); + resizeterm(w.ws_row, w.ws_col); refresh(); + + log_info("Resizing UI"); title_bar_resize(); wins_resize_all(); status_bar_resize(); @@ -280,13 +283,6 @@ ui_load_colours(void) } gboolean -ui_win_exists(int index) -{ - ProfWin *window = wins_get_by_num(index); - return (window != NULL); -} - -gboolean ui_xmlconsole_exists(void) { ProfXMLWin *xmlwin = wins_get_xmlconsole(); @@ -305,13 +301,13 @@ ui_handle_stanza(const char * const msg) ProfWin *window = (ProfWin*) xmlconsole; if (g_str_has_prefix(msg, "SENT:")) { - win_save_print(window, '-', NULL, 0, 0, "", "SENT:"); - win_save_print(window, '-', NULL, 0, THEME_ONLINE, "", &msg[6]); - win_save_print(window, '-', NULL, 0, THEME_ONLINE, "", ""); + win_print(window, '-', NULL, 0, 0, "", "SENT:"); + win_print(window, '-', NULL, 0, THEME_ONLINE, "", &msg[6]); + win_print(window, '-', NULL, 0, THEME_ONLINE, "", ""); } else if (g_str_has_prefix(msg, "RECV:")) { - win_save_print(window, '-', NULL, 0, 0, "", "RECV:"); - win_save_print(window, '-', NULL, 0, THEME_AWAY, "", &msg[6]); - win_save_print(window, '-', NULL, 0, THEME_AWAY, "", ""); + win_print(window, '-', NULL, 0, 0, "", "RECV:"); + win_print(window, '-', NULL, 0, THEME_AWAY, "", &msg[6]); + win_print(window, '-', NULL, 0, THEME_AWAY, "", ""); } } } @@ -324,6 +320,42 @@ ui_chat_win_exists(const char * const barejid) } void +ui_contact_online(char *barejid, Resource *resource, GDateTime *last_activity) +{ + char *show_console = prefs_get_string(PREF_STATUSES_CONSOLE); + char *show_chat_win = prefs_get_string(PREF_STATUSES_CHAT); + PContact contact = roster_get_contact(barejid); + + // show nothing + if (g_strcmp0(p_contact_subscription(contact), "none") == 0) { + free(show_console); + free(show_chat_win); + return; + } + + // show in console if "all" + if (g_strcmp0(show_console, "all") == 0) { + cons_show_contact_online(contact, resource, last_activity); + + // show in console of "online" and presence online + } else if (g_strcmp0(show_console, "online") == 0 && resource->presence == RESOURCE_ONLINE) { + cons_show_contact_online(contact, resource, last_activity); + } + + // show in chat win if "all" + if (g_strcmp0(show_chat_win, "all") == 0) { + ui_chat_win_contact_online(contact, resource, last_activity); + + // show in char win if "online" and presence online + } else if (g_strcmp0(show_chat_win, "online") == 0 && resource->presence == RESOURCE_ONLINE) { + ui_chat_win_contact_online(contact, resource, last_activity); + } + + free(show_console); + free(show_chat_win); +} + +void ui_contact_typing(const char * const barejid, const char * const resource) { ProfChatWin *chatwin = wins_get_chat(barejid); @@ -356,7 +388,7 @@ ui_contact_typing(const char * const barejid, const char * const resource) if ( !is_current || (is_current && prefs_get_boolean(PREF_NOTIFY_TYPING_CURRENT)) ) { PContact contact = roster_get_contact(barejid); char const *display_usr = NULL; - if (p_contact_name(contact) != NULL) { + if (p_contact_name(contact)) { display_usr = p_contact_name(contact); } else { display_usr = barejid; @@ -380,53 +412,42 @@ ui_get_current_chat(void) } void -ui_incoming_msg(const char * const barejid, const char * const resource, const char * const message, GTimeVal *tv_stamp) +ui_message_receipt(const char * const barejid, const char * const id) { - gboolean win_created = FALSE; - GString *user = g_string_new(""); - - PContact contact = roster_get_contact(barejid); - if (contact != NULL) { - if (p_contact_name(contact) != NULL) { - g_string_append(user, p_contact_name(contact)); - } else { - g_string_append(user, barejid); - } - } else { - g_string_append(user, barejid); + ProfChatWin *chatwin = wins_get_chat(barejid); + if (chatwin) { + ProfWin *win = (ProfWin*) chatwin; + win_mark_received(win, id); } +} - if (resource && prefs_get_boolean(PREF_RESOURCE_MESSAGE)) { - g_string_append(user, "/"); - g_string_append(user, resource); - } +void +ui_incoming_msg(const char * const barejid, const char * const resource, const char * const message, GTimeVal *tv_stamp) +{ + gboolean win_created = FALSE; ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin == NULL) { ProfWin *window = wins_new_chat(barejid); chatwin = (ProfChatWin*)window; -#ifdef HAVE_LIBOTR - if (otr_is_secure(barejid)) { - chatwin->is_otr = TRUE; - } -#endif win_created = TRUE; } ProfWin *window = (ProfWin*) chatwin; - int num = wins_get_num(window); + char *display_name = roster_get_msg_display_name(barejid, resource); + // currently viewing chat window with sender if (wins_is_current(window)) { - win_print_incoming_message(window, tv_stamp, user->str, message); + win_print_incoming_message(window, tv_stamp, display_name, message); title_bar_set_typing(FALSE); status_bar_active(num); // not currently viewing chat window with sender } else { status_bar_new(num); - cons_show_incoming_message(user->str, num); + cons_show_incoming_message(display_name, num); if (prefs_get_boolean(PREF_FLASH)) { flash(); @@ -434,23 +455,18 @@ ui_incoming_msg(const char * const barejid, const char * const resource, const c chatwin->unread++; if (prefs_get_boolean(PREF_CHLOG) && prefs_get_boolean(PREF_HISTORY)) { - _win_show_history(num, barejid); + _win_show_history(chatwin, barejid); } // show users status first, when receiving message via delayed delivery - if ((tv_stamp != NULL) && (win_created)) { + if (tv_stamp && (win_created)) { PContact pcontact = roster_get_contact(barejid); - if (pcontact != NULL) { + if (pcontact) { win_show_contact(window, pcontact); } } - win_print_incoming_message(window, tv_stamp, user->str, message); - } - - int ui_index = num; - if (ui_index == 10) { - ui_index = 0; + win_print_incoming_message(window, tv_stamp, display_name, message); } if (prefs_get_boolean(PREF_BEEP)) { @@ -458,17 +474,10 @@ ui_incoming_msg(const char * const barejid, const char * const resource, const c } if (prefs_get_boolean(PREF_NOTIFY_MESSAGE)) { - gboolean is_current = wins_is_current(window); - if ( !is_current || (is_current && prefs_get_boolean(PREF_NOTIFY_MESSAGE_CURRENT)) ) { - if (prefs_get_boolean(PREF_NOTIFY_MESSAGE_TEXT)) { - notify_message(user->str, ui_index, message); - } else { - notify_message(user->str, ui_index, NULL); - } - } + notify_message(window, display_name, message); } - g_string_free(user, TRUE); + free(display_name); } void @@ -494,24 +503,14 @@ ui_incoming_private_msg(const char * const fulljid, const char * const message, // not currently viewing chat window with sender } else { + privatewin->unread++; status_bar_new(num); cons_show_incoming_message(display_from, num); + win_print_incoming_message(window, tv_stamp, display_from, message); if (prefs_get_boolean(PREF_FLASH)) { flash(); } - - privatewin->unread++; - if (prefs_get_boolean(PREF_CHLOG) && prefs_get_boolean(PREF_HISTORY)) { - _win_show_history(num, fulljid); - } - - win_print_incoming_message(window, tv_stamp, display_from, message); - } - - int ui_index = num; - if (ui_index == 10) { - ui_index = 0; } if (prefs_get_boolean(PREF_BEEP)) { @@ -519,14 +518,7 @@ ui_incoming_private_msg(const char * const fulljid, const char * const message, } if (prefs_get_boolean(PREF_NOTIFY_MESSAGE)) { - gboolean is_current = wins_is_current(window); - if ( !is_current || (is_current && prefs_get_boolean(PREF_NOTIFY_MESSAGE_CURRENT)) ) { - if (prefs_get_boolean(PREF_NOTIFY_MESSAGE_TEXT)) { - notify_message(display_from, ui_index, message); - } else { - notify_message(display_from, ui_index, NULL); - } - } + notify_message(window, display_from, message); } free(display_from); @@ -535,7 +527,7 @@ ui_incoming_private_msg(const char * const fulljid, const char * const message, void ui_roster_add(const char * const barejid, const char * const name) { - if (name != NULL) { + if (name) { cons_show("Roster item added: %s (%s)", barejid, name); } else { cons_show("Roster item added: %s", barejid); @@ -582,7 +574,7 @@ void ui_auto_away(void) { char *pref_autoaway_message = prefs_get_string(PREF_AUTOAWAY_MESSAGE); - if (pref_autoaway_message != NULL) { + if (pref_autoaway_message) { int pri = accounts_get_priority_for_presence_type(jabber_get_account_name(), RESOURCE_AWAY); @@ -622,7 +614,12 @@ ui_handle_login_account_success(ProfAccount *account) contact_presence_t contact_presence = contact_presence_from_resource_presence(resource_presence); cons_show_login_success(account); title_bar_set_presence(contact_presence); - status_bar_print_message(account->jid); + + GString *fulljid = g_string_new(account->jid); + g_string_append(fulljid, "/"); + g_string_append(fulljid, account->resource); + status_bar_print_message(fulljid->str); + g_string_free(fulljid, TRUE); status_bar_update_virtual(); } @@ -633,7 +630,7 @@ ui_update_presence(const resource_presence_t resource_presence, contact_presence_t contact_presence = contact_presence_from_resource_presence(resource_presence); title_bar_set_presence(contact_presence); gint priority = accounts_get_priority_for_presence_type(jabber_get_account_name(), resource_presence); - if (message != NULL) { + if (message) { cons_show("Status set to %s (priority %d), \"%s\".", show, priority, message); } else { cons_show("Status set to %s (priority %d).", show, priority); @@ -647,7 +644,7 @@ ui_handle_recipient_not_found(const char * const recipient, const char * const e ProfMucWin *mucwin = wins_get_muc(recipient); if (mucwin) { cons_show_error("Room %s not found: %s", recipient, err_msg); - win_save_vprint((ProfWin*) mucwin, '!', NULL, 0, THEME_ERROR, "", "Room %s not found: %s", recipient, err_msg); + win_vprint((ProfWin*) mucwin, '!', NULL, 0, THEME_ERROR, "", "Room %s not found: %s", recipient, err_msg); return; } } @@ -660,19 +657,19 @@ ui_handle_recipient_error(const char * const recipient, const char * const err_m ProfChatWin *chatwin = wins_get_chat(recipient); if (chatwin) { - win_save_vprint((ProfWin*)chatwin, '!', NULL, 0, THEME_ERROR, "", "Error from %s: %s", recipient, err_msg); + win_vprint((ProfWin*)chatwin, '!', NULL, 0, THEME_ERROR, "", "Error from %s: %s", recipient, err_msg); return; } ProfMucWin *mucwin = wins_get_muc(recipient); if (mucwin) { - win_save_vprint((ProfWin*)mucwin, '!', NULL, 0, THEME_ERROR, "", "Error from %s: %s", recipient, err_msg); + win_vprint((ProfWin*)mucwin, '!', NULL, 0, THEME_ERROR, "", "Error from %s: %s", recipient, err_msg); return; } ProfPrivateWin *privatewin = wins_get_private(recipient); if (privatewin) { - win_save_vprint((ProfWin*)privatewin, '!', NULL, 0, THEME_ERROR, "", "Error from %s: %s", recipient, err_msg); + win_vprint((ProfWin*)privatewin, '!', NULL, 0, THEME_ERROR, "", "Error from %s: %s", recipient, err_msg); return; } } @@ -691,7 +688,7 @@ ui_handle_error(const char * const err_msg) void ui_invalid_command_usage(const char * const usage, void (*setting_func)(void)) { - if (setting_func != NULL) { + if (setting_func) { cons_show(""); (*setting_func)(); cons_show("Usage: %s", usage); @@ -729,7 +726,7 @@ ui_close_connected_win(int index) ProfChatWin *chatwin = (ProfChatWin*) window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); #ifdef HAVE_LIBOTR - if (chatwin->is_otr) { + if (chatwin->enc_mode == PROF_ENC_OTR) { otr_end_session(chatwin->barejid); } #endif @@ -748,7 +745,7 @@ ui_close_all_wins(void) GList *win_nums = wins_get_nums(); GList *curr = win_nums; - while (curr != NULL) { + while (curr) { int num = GPOINTER_TO_INT(curr->data); if ((num != 1) && (!ui_win_has_unsaved_form(num))) { if (conn_status == JABBER_CONNECTED) { @@ -775,7 +772,7 @@ ui_close_read_wins(void) GList *win_nums = wins_get_nums(); GList *curr = win_nums; - while (curr != NULL) { + while (curr) { int num = GPOINTER_TO_INT(curr->data); if ((num != 1) && (ui_win_unread(num) == 0) && (!ui_win_has_unsaved_form(num))) { if (conn_status == JABBER_CONNECTED) { @@ -799,7 +796,7 @@ ui_redraw_all_room_rosters(void) GList *win_nums = wins_get_nums(); GList *curr = win_nums; - while (curr != NULL) { + while (curr) { int num = GPOINTER_TO_INT(curr->data); ProfWin *window = wins_get_by_num(num); if (window->type == WIN_MUC && win_has_active_subwin(window)) { @@ -820,7 +817,7 @@ ui_hide_all_room_rosters(void) GList *win_nums = wins_get_nums(); GList *curr = win_nums; - while (curr != NULL) { + while (curr) { int num = GPOINTER_TO_INT(curr->data); ProfWin *window = wins_get_by_num(num); if (window->type == WIN_MUC && win_has_active_subwin(window)) { @@ -841,7 +838,7 @@ ui_show_all_room_rosters(void) GList *win_nums = wins_get_nums(); GList *curr = win_nums; - while (curr != NULL) { + while (curr) { int num = GPOINTER_TO_INT(curr->data); ProfWin *window = wins_get_by_num(num); if (window->type == WIN_MUC && !win_has_active_subwin(window)) { @@ -870,95 +867,32 @@ ui_win_has_unsaved_form(int num) } } -gboolean -ui_switch_win(const int i) -{ - if (ui_win_exists(i)) { - ProfWin *old_current = wins_get_current(); - if (old_current->type == WIN_MUC_CONFIG) { - ProfMucConfWin *confwin = (ProfMucConfWin*)old_current; - cmd_autocomplete_remove_form_fields(confwin->form); - } - - ProfWin *new_current = wins_get_by_num(i); - if (new_current->type == WIN_MUC_CONFIG) { - ProfMucConfWin *confwin = (ProfMucConfWin*)new_current; - cmd_autocomplete_add_form_fields(confwin->form); - } - - wins_set_current_by_num(i); - - if (i == 1) { - title_bar_console(); - status_bar_current(1); - status_bar_active(1); - } else { - title_bar_switch(); - status_bar_current(i); - status_bar_active(i); - } - return TRUE; - } else { - return FALSE; - } -} - void -ui_previous_win(void) +ui_switch_win(ProfWin *window) { - ProfWin *old_current = wins_get_current(); - if (old_current->type == WIN_MUC_CONFIG) { - ProfMucConfWin *confwin = (ProfMucConfWin*)old_current; - cmd_autocomplete_remove_form_fields(confwin->form); - } - - ProfWin *new_current = wins_get_previous(); - if (new_current->type == WIN_MUC_CONFIG) { - ProfMucConfWin *confwin = (ProfMucConfWin*)new_current; - cmd_autocomplete_add_form_fields(confwin->form); - } + assert(window != NULL); - int i = wins_get_num(new_current); - wins_set_current_by_num(i); - - if (i == 1) { - title_bar_console(); - status_bar_current(1); - status_bar_active(1); - } else { - title_bar_switch(); - status_bar_current(i); - status_bar_active(i); - } -} - -void -ui_next_win(void) -{ ProfWin *old_current = wins_get_current(); if (old_current->type == WIN_MUC_CONFIG) { ProfMucConfWin *confwin = (ProfMucConfWin*)old_current; cmd_autocomplete_remove_form_fields(confwin->form); } - ProfWin *new_current = wins_get_next(); - if (new_current->type == WIN_MUC_CONFIG) { - ProfMucConfWin *confwin = (ProfMucConfWin*)new_current; + if (window->type == WIN_MUC_CONFIG) { + ProfMucConfWin *confwin = (ProfMucConfWin*)window; cmd_autocomplete_add_form_fields(confwin->form); } - int i = wins_get_num(new_current); + int i = wins_get_num(window); wins_set_current_by_num(i); if (i == 1) { title_bar_console(); - status_bar_current(1); - status_bar_active(1); } else { title_bar_switch(); - status_bar_current(i); - status_bar_active(i); } + status_bar_current(i); + status_bar_active(i); } void @@ -974,12 +908,12 @@ ui_gone_secure(const char * const barejid, gboolean trusted) chatwin = (ProfChatWin*)window; } - chatwin->is_otr = TRUE; + chatwin->enc_mode = PROF_ENC_OTR; chatwin->is_trusted = trusted; if (trusted) { - win_save_print(window, '!', NULL, 0, THEME_OTR_STARTED_TRUSTED, "", "OTR session started (trusted)."); + win_print(window, '!', NULL, 0, THEME_OTR_STARTED_TRUSTED, "", "OTR session started (trusted)."); } else { - win_save_print(window, '!', NULL, 0, THEME_OTR_STARTED_UNTRUSTED, "", "OTR session started (untrusted)."); + win_print(window, '!', NULL, 0, THEME_OTR_STARTED_UNTRUSTED, "", "OTR session started (untrusted)."); } if (wins_is_current(window)) { @@ -1002,11 +936,11 @@ ui_gone_insecure(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { - chatwin->is_otr = FALSE; + chatwin->enc_mode = PROF_ENC_NONE; chatwin->is_trusted = FALSE; ProfWin *window = (ProfWin*)chatwin; - win_save_print(window, '!', NULL, 0, THEME_OTR_ENDED, "", "OTR session ended."); + win_print(window, '!', NULL, 0, THEME_OTR_ENDED, "", "OTR session ended."); if (wins_is_current(window)) { title_bar_switch(); } @@ -1018,7 +952,7 @@ ui_smp_recipient_initiated(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { - win_save_vprint((ProfWin*)chatwin, '!', NULL, 0, 0, "", "%s wants to authenticate your identity, use '/otr secret <secret>'.", barejid); + win_vprint((ProfWin*)chatwin, '!', NULL, 0, 0, "", "%s wants to authenticate your identity, use '/otr secret <secret>'.", barejid); } } @@ -1027,9 +961,9 @@ ui_smp_recipient_initiated_q(const char * const barejid, const char *question) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { - win_save_vprint((ProfWin*)chatwin, '!', NULL, 0, 0, "", "%s wants to authenticate your identity with the following question:", barejid); - win_save_vprint((ProfWin*)chatwin, '!', NULL, 0, 0, "", " %s", question); - win_save_print((ProfWin*)chatwin, '!', NULL, 0, 0, "", "use '/otr answer <answer>'."); + win_vprint((ProfWin*)chatwin, '!', NULL, 0, 0, "", "%s wants to authenticate your identity with the following question:", barejid); + win_vprint((ProfWin*)chatwin, '!', NULL, 0, 0, "", " %s", question); + win_print((ProfWin*)chatwin, '!', NULL, 0, 0, "", "use '/otr answer <answer>'."); } } @@ -1038,7 +972,7 @@ ui_smp_unsuccessful_sender(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { - win_save_vprint((ProfWin*)chatwin, '!', NULL, 0, 0, "", "Authentication failed, the secret you entered does not match the secret entered by %s.", barejid); + win_vprint((ProfWin*)chatwin, '!', NULL, 0, 0, "", "Authentication failed, the secret you entered does not match the secret entered by %s.", barejid); } } @@ -1047,7 +981,7 @@ ui_smp_unsuccessful_receiver(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { - win_save_vprint((ProfWin*)chatwin, '!', NULL, 0, 0, "", "Authentication failed, the secret entered by %s does not match yours.", barejid); + win_vprint((ProfWin*)chatwin, '!', NULL, 0, 0, "", "Authentication failed, the secret entered by %s does not match yours.", barejid); } } @@ -1056,7 +990,7 @@ ui_smp_aborted(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { - win_save_print((ProfWin*)chatwin, '!', NULL, 0, 0, "", "SMP session aborted."); + win_print((ProfWin*)chatwin, '!', NULL, 0, 0, "", "SMP session aborted."); } } @@ -1065,7 +999,7 @@ ui_smp_successful(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { - win_save_print((ProfWin*)chatwin, '!', NULL, 0, 0, "", "Authentication successful."); + win_print((ProfWin*)chatwin, '!', NULL, 0, 0, "", "Authentication successful."); } } @@ -1074,7 +1008,7 @@ ui_smp_answer_success(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { - win_save_vprint((ProfWin*)chatwin, '!', NULL, 0, 0, "", "%s successfully authenticated you.", barejid); + win_vprint((ProfWin*)chatwin, '!', NULL, 0, 0, "", "%s successfully authenticated you.", barejid); } } @@ -1083,7 +1017,7 @@ ui_smp_answer_failure(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { - win_save_vprint((ProfWin*)chatwin, '!', NULL, 0, 0, "", "%s failed to authenticate you.", barejid); + win_vprint((ProfWin*)chatwin, '!', NULL, 0, 0, "", "%s failed to authenticate you.", barejid); } } @@ -1092,7 +1026,7 @@ ui_otr_authenticating(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { - win_save_vprint((ProfWin*)chatwin, '!', NULL, 0, 0, "", "Authenticating %s...", barejid); + win_vprint((ProfWin*)chatwin, '!', NULL, 0, 0, "", "Authenticating %s...", barejid); } } @@ -1101,7 +1035,18 @@ ui_otr_authetication_waiting(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { - win_save_vprint((ProfWin*)chatwin, '!', NULL, 0, 0, "", "Awaiting authentication from %s...", barejid); + win_vprint((ProfWin*)chatwin, '!', NULL, 0, 0, "", "Awaiting authentication from %s...", barejid); + } +} + +void +ui_handle_otr_error(const char * const barejid, const char * const message) +{ + ProfChatWin *chatwin = wins_get_chat(barejid); + if (chatwin) { + win_print((ProfWin*)chatwin, '!', NULL, 0, THEME_ERROR, "", message); + } else { + cons_show_error("%s - %s", barejid, message); } } @@ -1110,11 +1055,11 @@ ui_trust(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { - chatwin->is_otr = TRUE; + chatwin->enc_mode = PROF_ENC_OTR; chatwin->is_trusted = TRUE; ProfWin *window = (ProfWin*)chatwin; - win_save_print(window, '!', NULL, 0, THEME_OTR_TRUSTED, "", "OTR session trusted."); + win_print(window, '!', NULL, 0, THEME_OTR_TRUSTED, "", "OTR session trusted."); if (wins_is_current(window)) { title_bar_switch(); } @@ -1126,11 +1071,11 @@ ui_untrust(const char * const barejid) { ProfChatWin *chatwin = wins_get_chat(barejid); if (chatwin) { - chatwin->is_otr = TRUE; + chatwin->enc_mode = PROF_ENC_OTR; chatwin->is_trusted = FALSE; ProfWin *window = (ProfWin*)chatwin; - win_save_print(window, '!', NULL, 0, THEME_OTR_UNTRUSTED, "", "OTR session untrusted."); + win_print(window, '!', NULL, 0, THEME_OTR_UNTRUSTED, "", "OTR session untrusted."); if (wins_is_current(window)) { title_bar_switch(); } @@ -1179,12 +1124,12 @@ ui_prune_wins(void) gboolean pruned = FALSE; GSList *wins = wins_get_prune_wins(); - if (wins != NULL) { + if (wins) { pruned = TRUE; } GSList *curr = wins; - while (curr != NULL) { + while (curr) { ProfWin *window = curr->data; if (window->type == WIN_CHAT) { if (conn_status == JABBER_CONNECTED) { @@ -1199,7 +1144,7 @@ ui_prune_wins(void) curr = g_slist_next(curr); } - if (wins != NULL) { + if (wins) { g_slist_free(wins); } @@ -1231,18 +1176,12 @@ ui_current_win_is_otr(void) if (current->type == WIN_CHAT) { ProfChatWin *chatwin = (ProfChatWin*)current; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); - return chatwin->is_otr; + return chatwin->enc_mode == PROF_ENC_OTR; } else { return FALSE; } } -int -ui_current_win_index(void) -{ - return wins_get_current_num(); -} - win_type_t ui_win_type(int index) { @@ -1258,7 +1197,7 @@ ui_current_print_line(const char * const msg, ...) va_start(arg, msg); GString *fmt_msg = g_string_new(NULL); g_string_vprintf(fmt_msg, msg, arg); - win_save_println(window, fmt_msg->str); + win_println(window, fmt_msg->str); va_end(arg); g_string_free(fmt_msg, TRUE); } @@ -1271,16 +1210,22 @@ ui_current_print_formatted_line(const char show_char, int attrs, const char * co va_start(arg, msg); GString *fmt_msg = g_string_new(NULL); g_string_vprintf(fmt_msg, msg, arg); - win_save_print(current, show_char, NULL, 0, attrs, "", fmt_msg->str); + win_print(current, show_char, NULL, 0, attrs, "", fmt_msg->str); va_end(arg); g_string_free(fmt_msg, TRUE); } void +ui_win_error_line(ProfWin *window, const char * const msg) +{ + win_print(window, '-', NULL, 0, THEME_ERROR, "", msg); +} + +void ui_current_error_line(const char * const msg) { ProfWin *current = wins_get_current(); - win_save_print(current, '-', NULL, 0, THEME_ERROR, "", msg); + win_print(current, '-', NULL, 0, THEME_ERROR, "", msg); } void @@ -1293,7 +1238,7 @@ ui_print_system_msg_from_recipient(const char * const barejid, const char *messa if (window == NULL) { int num = 0; window = wins_new_chat(barejid); - if (window != NULL) { + if (window) { num = wins_get_num(window); status_bar_active(num); } else { @@ -1303,7 +1248,7 @@ ui_print_system_msg_from_recipient(const char * const barejid, const char *messa } } - win_save_vprint(window, '-', NULL, 0, 0, "", "*%s %s", barejid, message); + win_vprint(window, '-', NULL, 0, 0, "", "*%s %s", barejid, message); } void @@ -1325,8 +1270,8 @@ ui_recipient_gone(const char * const barejid, const char * const resource) if (show_message) { const char * display_usr = NULL; PContact contact = roster_get_contact(barejid); - if (contact != NULL) { - if (p_contact_name(contact) != NULL) { + if (contact) { + if (p_contact_name(contact)) { display_usr = p_contact_name(contact); } else { display_usr = barejid; @@ -1335,175 +1280,128 @@ ui_recipient_gone(const char * const barejid, const char * const resource) display_usr = barejid; } - win_save_vprint((ProfWin*)chatwin, '!', NULL, 0, THEME_GONE, "", "<- %s has left the conversation.", display_usr); + win_vprint((ProfWin*)chatwin, '!', NULL, 0, THEME_GONE, "", "<- %s has left the conversation.", display_usr); } } } -void +ProfPrivateWin* ui_new_private_win(const char * const fulljid) { - ProfWin *window = (ProfWin*)wins_get_private(fulljid); - int num = 0; - - // create new window - if (window == NULL) { - window = wins_new_private(fulljid); - num = wins_get_num(window); - } else { - num = wins_get_num(window); - } - - ui_switch_win(num); -} - -void -ui_new_chat_win(const char * const barejid) -{ - ProfWin *window = (ProfWin*)wins_get_chat(barejid); - int num = 0; - - // create new window - if (window == NULL) { - window = wins_new_chat(barejid); - - num = wins_get_num(window); - - if (prefs_get_boolean(PREF_CHLOG) && prefs_get_boolean(PREF_HISTORY)) { - _win_show_history(num, barejid); - } - - // if the contact is offline, show a message - PContact contact = roster_get_contact(barejid); - if (contact != NULL) { - if (strcmp(p_contact_presence(contact), "offline") == 0) { - const char * const show = p_contact_presence(contact); - const char * const status = p_contact_status(contact); - win_show_status_string(window, barejid, show, status, NULL, "--", "offline"); - } - } - } else { - num = wins_get_num(window); - } - - ui_switch_win(num); + ProfWin *window = wins_new_private(fulljid); + return (ProfPrivateWin*)window; } void ui_create_xmlconsole_win(void) { ProfWin *window = wins_new_xmlconsole(); - int num = wins_get_num(window); - ui_switch_win(num); + ui_ev_focus_win(window); } void ui_open_xmlconsole_win(void) { ProfXMLWin *xmlwin = wins_get_xmlconsole(); - if (xmlwin != NULL) { - int num = wins_get_num((ProfWin*)xmlwin); - ui_switch_win(num); + if (xmlwin) { + ui_ev_focus_win((ProfWin*)xmlwin); } } -void -ui_outgoing_chat_msg(const char * const from, const char * const barejid, - const char * const message) +ProfChatWin* +ui_new_chat_win(const char * const barejid) { - PContact contact = roster_get_contact(barejid); - ProfWin *window = (ProfWin*)wins_get_chat(barejid); - int num = 0; + ProfWin *window = wins_new_chat(barejid); + ProfChatWin *chatwin = (ProfChatWin *)window; - // create new window - if (window == NULL) { - window = wins_new_chat(barejid); #ifdef HAVE_LIBOTR - ProfChatWin *chatwin = (ProfChatWin*)window; - if (otr_is_secure(barejid)) { - chatwin->is_otr = TRUE; - } + if (otr_is_secure(barejid)) { + chatwin->enc_mode = PROF_ENC_OTR; + } #endif - num = wins_get_num(window); - if (prefs_get_boolean(PREF_CHLOG) && prefs_get_boolean(PREF_HISTORY)) { - _win_show_history(num, barejid); - } + if (prefs_get_boolean(PREF_CHLOG) && prefs_get_boolean(PREF_HISTORY)) { + _win_show_history(chatwin, barejid); + } - if (contact != NULL) { - if (strcmp(p_contact_presence(contact), "offline") == 0) { - const char *show = p_contact_presence(contact); - const char *status = p_contact_status(contact); - win_show_status_string(window, barejid, show, status, NULL, "--", "offline"); - } + // if the contact is offline, show a message + PContact contact = roster_get_contact(barejid); + if (contact) { + if (strcmp(p_contact_presence(contact), "offline") == 0) { + const char * const show = p_contact_presence(contact); + const char * const status = p_contact_status(contact); + win_show_status_string(window, barejid, show, status, NULL, "--", "offline"); } + } + + return chatwin; +} - // use existing window +void +ui_outgoing_chat_msg(ProfChatWin *chatwin, const char * const message, char *id) +{ + if (prefs_get_boolean(PREF_RECEIPTS_REQUEST) && id) { + win_print_with_receipt((ProfWin*)chatwin, '-', NULL, 0, THEME_TEXT_ME, "me", message, id); } else { - num = wins_get_num(window); + win_print((ProfWin*)chatwin, '-', NULL, 0, THEME_TEXT_ME, "me", message); } - ProfChatWin *chatwin = (ProfChatWin*)window; - chat_state_active(chatwin->state); - - win_save_print(window, '-', NULL, 0, THEME_TEXT_ME, from, message); - ui_switch_win(num); } void -ui_outgoing_private_msg(const char * const from, const char * const fulljid, - const char * const message) +ui_outgoing_chat_msg_carbon(const char * const barejid, const char * const message) { - ProfWin *window = (ProfWin*)wins_get_private(fulljid); - int num = 0; + ProfChatWin *chatwin = wins_get_chat(barejid); // create new window - if (window == NULL) { - window = wins_new_private(fulljid); - num = wins_get_num(window); - - // use existing window - } else { - num = wins_get_num(window); + if (!chatwin) { + chatwin = ui_new_chat_win(barejid); } - win_save_print(window, '-', NULL, 0, THEME_TEXT_ME, from, message); - ui_switch_win(num); + chat_state_active(chatwin->state); + + win_print((ProfWin*)chatwin, '-', NULL, 0, THEME_TEXT_ME, "me", message); + + int num = wins_get_num((ProfWin*)chatwin); + status_bar_active(num); +} + +void +ui_outgoing_private_msg(ProfPrivateWin *privwin, const char * const message) +{ + win_print((ProfWin*)privwin, '-', NULL, 0, THEME_TEXT_ME, "me", message); } void ui_room_join(const char * const roomjid, gboolean focus) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); - int num = 0; - - // create new window - if (window == NULL) { + if (!window) { window = wins_new_muc(roomjid); } char *nick = muc_nick(roomjid); - win_save_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "-> You have joined the room as %s", nick); + win_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "-> You have joined the room as %s", nick); if (prefs_get_boolean(PREF_MUC_PRIVILEGES)) { char *role = muc_role_str(roomjid); char *affiliation = muc_affiliation_str(roomjid); if (role) { - win_save_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", role: %s", role); + win_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", role: %s", role); } if (affiliation) { - win_save_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", affiliation: %s", affiliation); + win_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", affiliation: %s", affiliation); } } - win_save_print(window, '!', NULL, NO_DATE, THEME_ROOMINFO, "", ""); + win_print(window, '!', NULL, NO_DATE, THEME_ROOMINFO, "", ""); - num = wins_get_num(window); if (focus) { - ui_switch_win(num); + ui_ev_focus_win(window); } else { + int num = wins_get_num(window); status_bar_active(num); ProfWin *console = wins_get_console(); char *nick = muc_nick(roomjid); - win_save_vprint(console, '!', NULL, 0, THEME_TYPING, "", "-> Autojoined %s as %s (%d).", roomjid, nick, num); + win_vprint(console, '!', NULL, 0, THEME_TYPING, "", "-> Autojoined %s as %s (%d).", roomjid, nick, num); } } @@ -1511,9 +1409,7 @@ void ui_switch_to_room(const char * const roomjid) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); - int num = wins_get_num(window); - num = wins_get_num(window); - ui_switch_win(num); + ui_ev_focus_win(window); } void @@ -1521,14 +1417,14 @@ ui_room_role_change(const char * const roomjid, const char * const role, const c const char * const reason) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); - win_save_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "Your role has been changed to: %s", role); + win_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "Your role has been changed to: %s", role); if (actor) { - win_save_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", by: %s", actor); + win_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", by: %s", actor); } if (reason) { - win_save_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", reason: %s", reason); + win_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", reason: %s", reason); } - win_save_print(window, '!', NULL, NO_DATE, THEME_ROOMINFO, "", ""); + win_print(window, '!', NULL, NO_DATE, THEME_ROOMINFO, "", ""); } void @@ -1536,14 +1432,14 @@ ui_room_affiliation_change(const char * const roomjid, const char * const affili const char * const reason) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); - win_save_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "Your affiliation has been changed to: %s", affiliation); + win_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "Your affiliation has been changed to: %s", affiliation); if (actor) { - win_save_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", by: %s", actor); + win_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", by: %s", actor); } if (reason) { - win_save_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", reason: %s", reason); + win_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", reason: %s", reason); } - win_save_print(window, '!', NULL, NO_DATE, THEME_ROOMINFO, "", ""); + win_print(window, '!', NULL, NO_DATE, THEME_ROOMINFO, "", ""); } void @@ -1551,14 +1447,14 @@ ui_room_role_and_affiliation_change(const char * const roomjid, const char * con const char * const actor, const char * const reason) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); - win_save_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "Your role and affiliation have been changed, role: %s, affiliation: %s", role, affiliation); + win_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "Your role and affiliation have been changed, role: %s, affiliation: %s", role, affiliation); if (actor) { - win_save_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", by: %s", actor); + win_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", by: %s", actor); } if (reason) { - win_save_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", reason: %s", reason); + win_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", reason: %s", reason); } - win_save_print(window, '!', NULL, NO_DATE, THEME_ROOMINFO, "", ""); + win_print(window, '!', NULL, NO_DATE, THEME_ROOMINFO, "", ""); } @@ -1567,14 +1463,14 @@ ui_room_occupant_role_change(const char * const roomjid, const char * const nick const char * const actor, const char * const reason) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); - win_save_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "%s's role has been changed to: %s", nick, role); + win_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "%s's role has been changed to: %s", nick, role); if (actor) { - win_save_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", by: %s", actor); + win_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", by: %s", actor); } if (reason) { - win_save_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", reason: %s", reason); + win_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", reason: %s", reason); } - win_save_print(window, '!', NULL, NO_DATE, THEME_ROOMINFO, "", ""); + win_print(window, '!', NULL, NO_DATE, THEME_ROOMINFO, "", ""); } void @@ -1582,14 +1478,14 @@ ui_room_occupant_affiliation_change(const char * const roomjid, const char * con const char * const actor, const char * const reason) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); - win_save_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "%s's affiliation has been changed to: %s", nick, affiliation); + win_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "%s's affiliation has been changed to: %s", nick, affiliation); if (actor) { - win_save_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", by: %s", actor); + win_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", by: %s", actor); } if (reason) { - win_save_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", reason: %s", reason); + win_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", reason: %s", reason); } - win_save_print(window, '!', NULL, NO_DATE, THEME_ROOMINFO, "", ""); + win_print(window, '!', NULL, NO_DATE, THEME_ROOMINFO, "", ""); } void @@ -1597,14 +1493,14 @@ ui_room_occupant_role_and_affiliation_change(const char * const roomjid, const c const char * const affiliation, const char * const actor, const char * const reason) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); - win_save_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "%s's role and affiliation have been changed, role: %s, affiliation: %s", nick, role, affiliation); + win_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "%s's role and affiliation have been changed, role: %s, affiliation: %s", nick, role, affiliation); if (actor) { - win_save_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", by: %s", actor); + win_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", by: %s", actor); } if (reason) { - win_save_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", reason: %s", reason); + win_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ROOMINFO, "", ", reason: %s", reason); } - win_save_print(window, '!', NULL, NO_DATE, THEME_ROOMINFO, "", ""); + win_print(window, '!', NULL, NO_DATE, THEME_ROOMINFO, "", ""); } void @@ -1612,8 +1508,8 @@ ui_handle_room_info_error(const char * const roomjid, const char * const error) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window) { - win_save_vprint(window, '!', NULL, 0, 0, "", "Room info request failed: %s", error); - win_save_print(window, '-', NULL, 0, 0, "", ""); + win_vprint(window, '!', NULL, 0, 0, "", "Room info request failed: %s", error); + win_print(window, '-', NULL, 0, 0, "", ""); } } @@ -1622,38 +1518,38 @@ ui_show_room_disco_info(const char * const roomjid, GSList *identities, GSList * { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window) { - if (((identities != NULL) && (g_slist_length(identities) > 0)) || - ((features != NULL) && (g_slist_length(features) > 0))) { - if (identities != NULL) { - win_save_print(window, '!', NULL, 0, 0, "", "Identities:"); + if ((identities && (g_slist_length(identities) > 0)) || + (features && (g_slist_length(features) > 0))) { + if (identities) { + win_print(window, '!', NULL, 0, 0, "", "Identities:"); } - while (identities != NULL) { + while (identities) { DiscoIdentity *identity = identities->data; // anme trpe, cat GString *identity_str = g_string_new(" "); - if (identity->name != NULL) { + if (identity->name) { identity_str = g_string_append(identity_str, identity->name); identity_str = g_string_append(identity_str, " "); } - if (identity->type != NULL) { + if (identity->type) { identity_str = g_string_append(identity_str, identity->type); identity_str = g_string_append(identity_str, " "); } - if (identity->category != NULL) { + if (identity->category) { identity_str = g_string_append(identity_str, identity->category); } - win_save_print(window, '!', NULL, 0, 0, "", identity_str->str); + win_print(window, '!', NULL, 0, 0, "", identity_str->str); g_string_free(identity_str, TRUE); identities = g_slist_next(identities); } - if (features != NULL) { - win_save_print(window, '!', NULL, 0, 0, "", "Features:"); + if (features) { + win_print(window, '!', NULL, 0, 0, "", "Features:"); } - while (features != NULL) { - win_save_vprint(window, '!', NULL, 0, 0, "", " %s", features->data); + while (features) { + win_vprint(window, '!', NULL, 0, 0, "", " %s", features->data); features = g_slist_next(features); } - win_save_print(window, '-', NULL, 0, 0, "", ""); + win_print(window, '-', NULL, 0, 0, "", ""); } } } @@ -1667,32 +1563,32 @@ ui_room_roster(const char * const roomjid, GList *roster, const char * const pre } else { if ((roster == NULL) || (g_list_length(roster) == 0)) { if (presence == NULL) { - win_save_print(window, '!', NULL, 0, THEME_ROOMINFO, "", "Room is empty."); + win_print(window, '!', NULL, 0, THEME_ROOMINFO, "", "Room is empty."); } else { - win_save_vprint(window, '!', NULL, 0, THEME_ROOMINFO, "", "No occupants %s.", presence); + win_vprint(window, '!', NULL, 0, THEME_ROOMINFO, "", "No occupants %s.", presence); } } else { int length = g_list_length(roster); if (presence == NULL) { - win_save_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "%d occupants: ", length); + win_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "%d occupants: ", length); } else { - win_save_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "%d %s: ", length, presence); + win_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "%d %s: ", length, presence); } - while (roster != NULL) { + while (roster) { Occupant *occupant = roster->data; const char *presence_str = string_from_resource_presence(occupant->presence); theme_item_t presence_colour = theme_main_presence_attrs(presence_str); - win_save_vprint(window, '!', NULL, NO_DATE | NO_EOL, presence_colour, "", "%s", occupant->nick); + win_vprint(window, '!', NULL, NO_DATE | NO_EOL, presence_colour, "", "%s", occupant->nick); - if (roster->next != NULL) { - win_save_print(window, '!', NULL, NO_DATE | NO_EOL, 0, "", ", "); + if (roster->next) { + win_print(window, '!', NULL, NO_DATE | NO_EOL, 0, "", ", "); } roster = g_list_next(roster); } - win_save_print(window, '!', NULL, NO_DATE, THEME_ONLINE, "", ""); + win_print(window, '!', NULL, NO_DATE, THEME_ONLINE, "", ""); } } @@ -1711,7 +1607,7 @@ ui_room_member_offline(const char * const roomjid, const char * const nick) if (window == NULL) { log_error("Received offline presence for room participant %s, but no window open for %s.", nick, roomjid); } else { - win_save_vprint(window, '!', NULL, 0, THEME_OFFLINE, "", "<- %s has left the room.", nick); + win_vprint(window, '!', NULL, 0, THEME_OFFLINE, "", "<- %s has left the room.", nick); } } @@ -1734,7 +1630,7 @@ ui_room_member_kicked(const char * const roomjid, const char * const nick, const g_string_append(message, reason); } - win_save_vprint(window, '!', NULL, 0, THEME_OFFLINE, "", "<- %s", message->str); + win_vprint(window, '!', NULL, 0, THEME_OFFLINE, "", "<- %s", message->str); g_string_free(message, TRUE); } } @@ -1758,7 +1654,7 @@ ui_room_member_banned(const char * const roomjid, const char * const nick, const g_string_append(message, reason); } - win_save_vprint(window, '!', NULL, 0, THEME_OFFLINE, "", "<- %s", message->str); + win_vprint(window, '!', NULL, 0, THEME_OFFLINE, "", "<- %s", message->str); g_string_free(message, TRUE); } } @@ -1771,16 +1667,16 @@ ui_room_member_online(const char * const roomjid, const char * const nick, const if (window == NULL) { log_error("Received online presence for room participant %s, but no window open for %s.", nick, roomjid); } else { - win_save_vprint(window, '!', NULL, NO_EOL, THEME_ONLINE, "", "-> %s has joined the room", nick); + win_vprint(window, '!', NULL, NO_EOL, THEME_ONLINE, "", "-> %s has joined the room", nick); if (prefs_get_boolean(PREF_MUC_PRIVILEGES)) { if (role) { - win_save_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ONLINE, "", ", role: %s", role); + win_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ONLINE, "", ", role: %s", role); } if (affiliation) { - win_save_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ONLINE, "", ", affiliation: %s", affiliation); + win_vprint(window, '!', NULL, NO_DATE | NO_EOL, THEME_ONLINE, "", ", affiliation: %s", affiliation); } } - win_save_print(window, '!', NULL, NO_DATE, THEME_ROOMINFO, "", ""); + win_print(window, '!', NULL, NO_DATE, THEME_ROOMINFO, "", ""); } } @@ -1804,7 +1700,7 @@ ui_room_member_nick_change(const char * const roomjid, if (window == NULL) { log_error("Received nick change for room participant %s, but no window open for %s.", old_nick, roomjid); } else { - win_save_vprint(window, '!', NULL, 0, THEME_THEM, "", "** %s is now known as %s", old_nick, nick); + win_vprint(window, '!', NULL, 0, THEME_THEM, "", "** %s is now known as %s", old_nick, nick); } } @@ -1815,7 +1711,7 @@ ui_room_nick_change(const char * const roomjid, const char * const nick) if (window == NULL) { log_error("Received self nick change %s, but no window open for %s.", nick, roomjid); } else { - win_save_vprint(window, '!', NULL, 0, THEME_ME, "", "** You are now known as %s", nick); + win_vprint(window, '!', NULL, 0, THEME_ME, "", "** You are now known as %s", nick); } } @@ -1840,7 +1736,7 @@ ui_room_history(const char * const roomjid, const char * const nick, g_string_append(line, message); } - win_save_print(window, '-', &tv_stamp, NO_COLOUR_DATE, 0, "", line->str); + win_print(window, '-', &tv_stamp, NO_COLOUR_DATE, 0, "", line->str); g_string_free(line, TRUE); } } @@ -1852,77 +1748,79 @@ ui_room_message(const char * const roomjid, const char * const nick, ProfMucWin *mucwin = wins_get_muc(roomjid); if (mucwin == NULL) { log_error("Room message received from %s, but no window open for %s", nick, roomjid); - } else { - ProfWin *window = (ProfWin*) mucwin; - int num = wins_get_num(window); - char *my_nick = muc_nick(roomjid); + return; + } - if (g_strcmp0(nick, my_nick) != 0) { - if (g_strrstr(message, my_nick) != NULL) { - win_save_print(window, '-', NULL, NO_ME, THEME_ROOMMENTION, nick, message); - } else { - win_save_print(window, '-', NULL, NO_ME, THEME_TEXT_THEM, nick, message); - } + ProfWin *window = (ProfWin*) mucwin; + int num = wins_get_num(window); + char *my_nick = muc_nick(roomjid); + + if (g_strcmp0(nick, my_nick) != 0) { + if (g_strrstr(message, my_nick)) { + win_print(window, '-', NULL, NO_ME, THEME_ROOMMENTION, nick, message); } else { - win_save_print(window, '-', NULL, 0, THEME_TEXT_ME, nick, message); + win_print(window, '-', NULL, NO_ME, THEME_TEXT_THEM, nick, message); } + } else { + win_print(window, '-', NULL, 0, THEME_TEXT_ME, nick, message); + } - // currently in groupchat window - if (wins_is_current(window)) { - status_bar_active(num); - - // not currenlty on groupchat window - } else { - status_bar_new(num); - cons_show_incoming_message(nick, num); + // currently in groupchat window + if (wins_is_current(window)) { + status_bar_active(num); - if (strcmp(nick, my_nick) != 0) { - if (prefs_get_boolean(PREF_FLASH)) { - flash(); - } - } + // not currently on groupchat window + } else { + status_bar_new(num); + cons_show_incoming_message(nick, num); - mucwin->unread++; + if (prefs_get_boolean(PREF_FLASH) && (strcmp(nick, my_nick) != 0)) { + flash(); } - int ui_index = num; - if (ui_index == 10) { - ui_index = 0; - } + mucwin->unread++; + } - if (strcmp(nick, muc_nick(roomjid)) != 0) { - if (prefs_get_boolean(PREF_BEEP)) { - beep(); - } + int ui_index = num; + if (ui_index == 10) { + ui_index = 0; + } - gboolean notify = FALSE; - char *room_setting = prefs_get_string(PREF_NOTIFY_ROOM); - if (g_strcmp0(room_setting, "on") == 0) { - notify = TRUE; - } - if (g_strcmp0(room_setting, "mention") == 0) { - char *message_lower = g_utf8_strdown(message, -1); - char *nick_lower = g_utf8_strdown(nick, -1); - if (g_strrstr(message_lower, nick_lower) != NULL) { - notify = TRUE; - } - g_free(message_lower); - g_free(nick_lower); - } - prefs_free_string(room_setting); - - if (notify) { - gboolean is_current = wins_is_current(window); - if ( !is_current || (is_current && prefs_get_boolean(PREF_NOTIFY_ROOM_CURRENT)) ) { - Jid *jidp = jid_create(roomjid); - if (prefs_get_boolean(PREF_NOTIFY_ROOM_TEXT)) { - notify_room_message(nick, jidp->localpart, ui_index, message); - } else { - notify_room_message(nick, jidp->localpart, ui_index, NULL); - } - jid_destroy(jidp); - } + // don't notify self messages + if (strcmp(nick, my_nick) == 0) { + return; + } + + if (prefs_get_boolean(PREF_BEEP)) { + beep(); + } + + gboolean notify = FALSE; + char *room_setting = prefs_get_string(PREF_NOTIFY_ROOM); + if (g_strcmp0(room_setting, "on") == 0) { + notify = TRUE; + } + if (g_strcmp0(room_setting, "mention") == 0) { + char *message_lower = g_utf8_strdown(message, -1); + char *nick_lower = g_utf8_strdown(nick, -1); + if (g_strrstr(message_lower, nick_lower)) { + notify = TRUE; + } + g_free(message_lower); + g_free(nick_lower); + } + prefs_free_string(room_setting); + + if (notify) { + gboolean is_current = wins_is_current(window); + if ( !is_current || (is_current && prefs_get_boolean(PREF_NOTIFY_ROOM_CURRENT)) ) { + Jid *jidp = jid_create(roomjid); + if (prefs_get_boolean(PREF_NOTIFY_ROOM_TEXT)) { + notify_room_message(nick, jidp->localpart, ui_index, message); + } else { + notify_room_message(nick, jidp->localpart, ui_index, NULL); } + jid_destroy(jidp); } } } @@ -1940,22 +1838,22 @@ ui_room_requires_config(const char * const roomjid) ui_index = 0; } - win_save_print(window, '-', NULL, 0, 0, "", ""); - win_save_vprint(window, '!', NULL, 0, THEME_ROOMINFO, "", + win_print(window, '-', NULL, 0, 0, "", ""); + win_vprint(window, '!', NULL, 0, THEME_ROOMINFO, "", "Room locked, requires configuration."); - win_save_vprint(window, '!', NULL, 0, THEME_ROOMINFO, "", + win_vprint(window, '!', NULL, 0, THEME_ROOMINFO, "", "Use '/room accept' to accept the defaults"); - win_save_vprint(window, '!', NULL, 0, THEME_ROOMINFO, "", + win_vprint(window, '!', NULL, 0, THEME_ROOMINFO, "", "Use '/room destroy' to cancel and destroy the room"); - win_save_vprint(window, '!', NULL, 0, THEME_ROOMINFO, "", + win_vprint(window, '!', NULL, 0, THEME_ROOMINFO, "", "Use '/room config' to edit the room configuration"); - win_save_print(window, '-', NULL, 0, 0, "", ""); + win_print(window, '-', NULL, 0, 0, "", ""); // currently in groupchat window if (wins_is_current(window)) { status_bar_active(num); - // not currenlty on groupchat window + // not currently on groupchat window } else { status_bar_new(num); } @@ -1998,16 +1896,16 @@ ui_room_destroyed(const char * const roomjid, const char * const reason, const c ProfWin *console = wins_get_console(); if (reason) { - win_save_vprint(console, '!', NULL, 0, THEME_TYPING, "", "<- Room destroyed: %s, reason: %s", roomjid, reason); + win_vprint(console, '!', NULL, 0, THEME_TYPING, "", "<- Room destroyed: %s, reason: %s", roomjid, reason); } else { - win_save_vprint(console, '!', NULL, 0, THEME_TYPING, "", "<- Room destroyed: %s", roomjid); + win_vprint(console, '!', NULL, 0, THEME_TYPING, "", "<- Room destroyed: %s", roomjid); } if (new_jid) { if (password) { - win_save_vprint(console, '!', NULL, 0, THEME_TYPING, "", "Replacement room: %s, password: %s", new_jid, password); + win_vprint(console, '!', NULL, 0, THEME_TYPING, "", "Replacement room: %s, password: %s", new_jid, password); } else { - win_save_vprint(console, '!', NULL, 0, THEME_TYPING, "", "Replacement room: %s", new_jid); + win_vprint(console, '!', NULL, 0, THEME_TYPING, "", "Replacement room: %s", new_jid); } } } @@ -2035,7 +1933,7 @@ ui_room_kicked(const char * const roomjid, const char * const actor, const char } ProfWin *console = wins_get_console(); - win_save_vprint(console, '!', NULL, 0, THEME_TYPING, "", "<- %s", message->str); + win_vprint(console, '!', NULL, 0, THEME_TYPING, "", "<- %s", message->str); g_string_free(message, TRUE); } } @@ -2062,7 +1960,7 @@ ui_room_banned(const char * const roomjid, const char * const actor, const char } ProfWin *console = wins_get_console(); - win_save_vprint(console, '!', NULL, 0, THEME_TYPING, "", "<- %s", message->str); + win_vprint(console, '!', NULL, 0, THEME_TYPING, "", "<- %s", message->str); g_string_free(message, TRUE); } } @@ -2078,17 +1976,17 @@ ui_room_subject(const char * const roomjid, const char * const nick, const char if (subject) { if (nick) { - win_save_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "*%s has set the room subject: ", nick); - win_save_vprint(window, '!', NULL, NO_DATE, 0, "", "%s", subject); + win_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "*%s has set the room subject: ", nick); + win_vprint(window, '!', NULL, NO_DATE, 0, "", "%s", subject); } else { - win_save_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "Room subject: "); - win_save_vprint(window, '!', NULL, NO_DATE, 0, "", "%s", subject); + win_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "Room subject: "); + win_vprint(window, '!', NULL, NO_DATE, 0, "", "%s", subject); } } else { if (nick) { - win_save_vprint(window, '!', NULL, 0, THEME_ROOMINFO, "", "*%s has cleared the room subject: ", nick); + win_vprint(window, '!', NULL, 0, THEME_ROOMINFO, "", "*%s has cleared the room subject: ", nick); } else { - win_save_vprint(window, '!', NULL, 0, THEME_ROOMINFO, "", "Room subject cleared"); + win_vprint(window, '!', NULL, 0, THEME_ROOMINFO, "", "Room subject cleared"); } } @@ -2096,7 +1994,7 @@ ui_room_subject(const char * const roomjid, const char * const nick, const char if (wins_is_current(window)) { status_bar_active(num); - // not currenlty on groupchat window + // not currently on groupchat window } else { status_bar_active(num); } @@ -2110,7 +2008,7 @@ ui_handle_room_kick_error(const char * const roomjid, const char * const nick, c if (window == NULL) { log_error("Kick error received for %s, but no window open for %s.", nick, roomjid); } else { - win_save_vprint(window, '!', NULL, 0, THEME_ERROR, "", "Error kicking %s: %s", nick, error); + win_vprint(window, '!', NULL, 0, THEME_ERROR, "", "Error kicking %s: %s", nick, error); } } @@ -2123,14 +2021,14 @@ ui_room_broadcast(const char * const roomjid, const char * const message) } else { int num = wins_get_num(window); - win_save_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "Room message: "); - win_save_vprint(window, '!', NULL, NO_DATE, 0, "", "%s", message); + win_vprint(window, '!', NULL, NO_EOL, THEME_ROOMINFO, "", "Room message: "); + win_vprint(window, '!', NULL, NO_DATE, 0, "", "%s", message); // currently in groupchat window if (wins_is_current(window)) { status_bar_active(num); - // not currenlty on groupchat window + // not currently on groupchat window } else { status_bar_new(num); } @@ -2143,7 +2041,7 @@ ui_handle_room_affiliation_list_error(const char * const roomjid, const char * c { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window) { - win_save_vprint(window, '!', NULL, 0, THEME_ERROR, "", "Error retrieving %s list: %s", affiliation, error); + win_vprint(window, '!', NULL, 0, THEME_ERROR, "", "Error retrieving %s list: %s", affiliation, error); } } @@ -2153,17 +2051,17 @@ ui_handle_room_affiliation_list(const char * const roomjid, const char * const a ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window) { if (jids) { - win_save_vprint(window, '!', NULL, 0, 0, "", "Affiliation: %s", affiliation); + win_vprint(window, '!', NULL, 0, 0, "", "Affiliation: %s", affiliation); GSList *curr_jid = jids; while (curr_jid) { char *jid = curr_jid->data; - win_save_vprint(window, '!', NULL, 0, 0, "", " %s", jid); + win_vprint(window, '!', NULL, 0, 0, "", " %s", jid); curr_jid = g_slist_next(curr_jid); } - win_save_print(window, '!', NULL, 0, 0, "", ""); + win_print(window, '!', NULL, 0, 0, "", ""); } else { - win_save_vprint(window, '!', NULL, 0, 0, "", "No users found with affiliation: %s", affiliation); - win_save_print(window, '!', NULL, 0, 0, "", ""); + win_vprint(window, '!', NULL, 0, 0, "", "No users found with affiliation: %s", affiliation); + win_print(window, '!', NULL, 0, 0, "", ""); } } } @@ -2173,7 +2071,7 @@ ui_handle_room_role_list_error(const char * const roomjid, const char * const ro { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window) { - win_save_vprint(window, '!', NULL, 0, THEME_ERROR, "", "Error retrieving %s list: %s", role, error); + win_vprint(window, '!', NULL, 0, THEME_ERROR, "", "Error retrieving %s list: %s", role, error); } } @@ -2183,26 +2081,26 @@ ui_handle_room_role_list(const char * const roomjid, const char * const role, GS ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window) { if (nicks) { - win_save_vprint(window, '!', NULL, 0, 0, "", "Role: %s", role); + win_vprint(window, '!', NULL, 0, 0, "", "Role: %s", role); GSList *curr_nick = nicks; while (curr_nick) { char *nick = curr_nick->data; Occupant *occupant = muc_roster_item(roomjid, nick); if (occupant) { if (occupant->jid) { - win_save_vprint(window, '!', NULL, 0, 0, "", " %s (%s)", nick, occupant->jid); + win_vprint(window, '!', NULL, 0, 0, "", " %s (%s)", nick, occupant->jid); } else { - win_save_vprint(window, '!', NULL, 0, 0, "", " %s", nick); + win_vprint(window, '!', NULL, 0, 0, "", " %s", nick); } } else { - win_save_vprint(window, '!', NULL, 0, 0, "", " %s", nick); + win_vprint(window, '!', NULL, 0, 0, "", " %s", nick); } curr_nick = g_slist_next(curr_nick); } - win_save_print(window, '!', NULL, 0, 0, "", ""); + win_print(window, '!', NULL, 0, 0, "", ""); } else { - win_save_vprint(window, '!', NULL, 0, 0, "", "No occupants found with role: %s", role); - win_save_print(window, '!', NULL, 0, 0, "", ""); + win_vprint(window, '!', NULL, 0, 0, "", "No occupants found with role: %s", role); + win_print(window, '!', NULL, 0, 0, "", ""); } } } @@ -2213,7 +2111,7 @@ ui_handle_room_affiliation_set_error(const char * const roomjid, const char * co { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window) { - win_save_vprint(window, '!', NULL, 0, THEME_ERROR, "", "Error setting %s affiliation for %s: %s", affiliation, jid, error); + win_vprint(window, '!', NULL, 0, THEME_ERROR, "", "Error setting %s affiliation for %s: %s", affiliation, jid, error); } } @@ -2223,7 +2121,7 @@ ui_handle_room_role_set_error(const char * const roomjid, const char * const nic { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); if (window) { - win_save_vprint(window, '!', NULL, 0, THEME_ERROR, "", "Error setting %s role for %s: %s", role, nick, error); + win_vprint(window, '!', NULL, 0, THEME_ERROR, "", "Error setting %s role for %s: %s", role, nick, error); } } @@ -2237,7 +2135,7 @@ int ui_win_unread(int index) { ProfWin *window = wins_get_by_num(index); - if (window != NULL) { + if (window) { return win_unread(window); } else { return 0; @@ -2247,14 +2145,9 @@ ui_win_unread(int index) char * ui_ask_password(void) { - char *passwd = malloc(sizeof(char) * (MAX_PASSWORD_SIZE + 1)); status_bar_get_password(); status_bar_update_virtual(); - inp_block(); - inp_get_password(passwd); - inp_non_block(prefs_get_inpblock()); - - return passwd; + return inp_get_password(); } void @@ -2265,7 +2158,7 @@ ui_chat_win_contact_online(PContact contact, Resource *resource, GDateTime *last const char *barejid = p_contact_barejid(contact); ProfWin *window = (ProfWin*)wins_get_chat(barejid); - if (window != NULL) { + if (window) { win_show_status_string(window, display_str, show, resource->status, last_activity, "++", "online"); @@ -2281,7 +2174,7 @@ ui_chat_win_contact_offline(PContact contact, char *resource, char *status) const char *barejid = p_contact_barejid(contact); ProfWin *window = (ProfWin*)wins_get_chat(barejid); - if (window != NULL) { + if (window) { win_show_status_string(window, display_str, "offline", status, NULL, "--", "offline"); } @@ -2296,7 +2189,7 @@ ui_contact_offline(char *barejid, char *resource, char *status) char *show_chat_win = prefs_get_string(PREF_STATUSES_CHAT); Jid *jid = jid_create_from_bare_and_resource(barejid, resource); PContact contact = roster_get_contact(barejid); - if (p_contact_subscription(contact) != NULL) { + if (p_contact_subscription(contact)) { if (strcmp(p_contact_subscription(contact), "none") != 0) { // show in console if "all" @@ -2377,7 +2270,7 @@ _ui_draw_term_title(void) if (res == -1) { log_error("Error writing terminal window title."); } - if (win_title != NULL) { + if (win_title) { free(win_title); } win_title = strdup(new_win_title); @@ -2391,10 +2284,10 @@ ui_show_room_info(ProfMucWin *mucwin) char *affiliation = muc_affiliation_str(mucwin->roomjid); ProfWin *window = (ProfWin*) mucwin; - win_save_vprint(window, '!', NULL, 0, 0, "", "Room: %s", mucwin->roomjid); - win_save_vprint(window, '!', NULL, 0, 0, "", "Affiliation: %s", affiliation); - win_save_vprint(window, '!', NULL, 0, 0, "", "Role: %s", role); - win_save_print(window, '-', NULL, 0, 0, "", ""); + win_vprint(window, '!', NULL, 0, 0, "", "Room: %s", mucwin->roomjid); + win_vprint(window, '!', NULL, 0, 0, "", "Affiliation: %s", affiliation); + win_vprint(window, '!', NULL, 0, 0, "", "Role: %s", role); + win_print(window, '-', NULL, 0, 0, "", ""); } void @@ -2406,28 +2299,28 @@ ui_show_room_role_list(ProfMucWin *mucwin, muc_role_t role) if (!occupants) { switch (role) { case MUC_ROLE_MODERATOR: - win_save_print(window, '!', NULL, 0, 0, "", "No moderators found."); + win_print(window, '!', NULL, 0, 0, "", "No moderators found."); break; case MUC_ROLE_PARTICIPANT: - win_save_print(window, '!', NULL, 0, 0, "", "No participants found."); + win_print(window, '!', NULL, 0, 0, "", "No participants found."); break; case MUC_ROLE_VISITOR: - win_save_print(window, '!', NULL, 0, 0, "", "No visitors found."); + win_print(window, '!', NULL, 0, 0, "", "No visitors found."); break; default: break; } - win_save_print(window, '-', NULL, 0, 0, "", ""); + win_print(window, '-', NULL, 0, 0, "", ""); } else { switch (role) { case MUC_ROLE_MODERATOR: - win_save_print(window, '!', NULL, 0, 0, "", "Moderators:"); + win_print(window, '!', NULL, 0, 0, "", "Moderators:"); break; case MUC_ROLE_PARTICIPANT: - win_save_print(window, '!', NULL, 0, 0, "", "Participants:"); + win_print(window, '!', NULL, 0, 0, "", "Participants:"); break; case MUC_ROLE_VISITOR: - win_save_print(window, '!', NULL, 0, 0, "", "Visitors:"); + win_print(window, '!', NULL, 0, 0, "", "Visitors:"); break; default: break; @@ -2438,16 +2331,16 @@ ui_show_room_role_list(ProfMucWin *mucwin, muc_role_t role) Occupant *occupant = curr_occupant->data; if (occupant->role == role) { if (occupant->jid) { - win_save_vprint(window, '!', NULL, 0, 0, "", " %s (%s)", occupant->nick, occupant->jid); + win_vprint(window, '!', NULL, 0, 0, "", " %s (%s)", occupant->nick, occupant->jid); } else { - win_save_vprint(window, '!', NULL, 0, 0, "", " %s", occupant->nick); + win_vprint(window, '!', NULL, 0, 0, "", " %s", occupant->nick); } } curr_occupant = g_slist_next(curr_occupant); } - win_save_print(window, '-', NULL, 0, 0, "", ""); + win_print(window, '-', NULL, 0, 0, "", ""); } } @@ -2460,34 +2353,34 @@ ui_show_room_affiliation_list(ProfMucWin *mucwin, muc_affiliation_t affiliation) if (!occupants) { switch (affiliation) { case MUC_AFFILIATION_OWNER: - win_save_print(window, '!', NULL, 0, 0, "", "No owners found."); + win_print(window, '!', NULL, 0, 0, "", "No owners found."); break; case MUC_AFFILIATION_ADMIN: - win_save_print(window, '!', NULL, 0, 0, "", "No admins found."); + win_print(window, '!', NULL, 0, 0, "", "No admins found."); break; case MUC_AFFILIATION_MEMBER: - win_save_print(window, '!', NULL, 0, 0, "", "No members found."); + win_print(window, '!', NULL, 0, 0, "", "No members found."); break; case MUC_AFFILIATION_OUTCAST: - win_save_print(window, '!', NULL, 0, 0, "", "No outcasts found."); + win_print(window, '!', NULL, 0, 0, "", "No outcasts found."); break; default: break; } - win_save_print(window, '-', NULL, 0, 0, "", ""); + win_print(window, '-', NULL, 0, 0, "", ""); } else { switch (affiliation) { case MUC_AFFILIATION_OWNER: - win_save_print(window, '!', NULL, 0, 0, "", "Owners:"); + win_print(window, '!', NULL, 0, 0, "", "Owners:"); break; case MUC_AFFILIATION_ADMIN: - win_save_print(window, '!', NULL, 0, 0, "", "Admins:"); + win_print(window, '!', NULL, 0, 0, "", "Admins:"); break; case MUC_AFFILIATION_MEMBER: - win_save_print(window, '!', NULL, 0, 0, "", "Members:"); + win_print(window, '!', NULL, 0, 0, "", "Members:"); break; case MUC_AFFILIATION_OUTCAST: - win_save_print(window, '!', NULL, 0, 0, "", "Outcasts:"); + win_print(window, '!', NULL, 0, 0, "", "Outcasts:"); break; default: break; @@ -2498,28 +2391,28 @@ ui_show_room_affiliation_list(ProfMucWin *mucwin, muc_affiliation_t affiliation) Occupant *occupant = curr_occupant->data; if (occupant->affiliation == affiliation) { if (occupant->jid) { - win_save_vprint(window, '!', NULL, 0, 0, "", " %s (%s)", occupant->nick, occupant->jid); + win_vprint(window, '!', NULL, 0, 0, "", " %s (%s)", occupant->nick, occupant->jid); } else { - win_save_vprint(window, '!', NULL, 0, 0, "", " %s", occupant->nick); + win_vprint(window, '!', NULL, 0, 0, "", " %s", occupant->nick); } } curr_occupant = g_slist_next(curr_occupant); } - win_save_print(window, '-', NULL, 0, 0, "", ""); + win_print(window, '-', NULL, 0, 0, "", ""); } } static void _ui_handle_form_field(ProfWin *window, char *tag, FormField *field) { - win_save_vprint(window, '-', NULL, NO_EOL, THEME_AWAY, "", "[%s] ", tag); - win_save_vprint(window, '-', NULL, NO_EOL | NO_DATE, 0, "", "%s", field->label); + win_vprint(window, '-', NULL, NO_EOL, THEME_AWAY, "", "[%s] ", tag); + win_vprint(window, '-', NULL, NO_EOL | NO_DATE, 0, "", "%s", field->label); if (field->required) { - win_save_print(window, '-', NULL, NO_DATE | NO_EOL, 0, "", " (required): "); + win_print(window, '-', NULL, NO_DATE | NO_EOL, 0, "", " (required): "); } else { - win_save_print(window, '-', NULL, NO_DATE | NO_EOL, 0, "", ": "); + win_print(window, '-', NULL, NO_DATE | NO_EOL, 0, "", ": "); } GSList *values = field->values; @@ -2529,113 +2422,113 @@ _ui_handle_form_field(ProfWin *window, char *tag, FormField *field) case FIELD_HIDDEN: break; case FIELD_TEXT_SINGLE: - if (curr_value != NULL) { + if (curr_value) { char *value = curr_value->data; - if (value != NULL) { + if (value) { if (g_strcmp0(field->var, "muc#roomconfig_roomsecret") == 0) { - win_save_print(window, '-', NULL, NO_DATE | NO_EOL, THEME_ONLINE, "", "[hidden]"); + win_print(window, '-', NULL, NO_DATE | NO_EOL, THEME_ONLINE, "", "[hidden]"); } else { - win_save_print(window, '-', NULL, NO_DATE | NO_EOL, THEME_ONLINE, "", value); + win_print(window, '-', NULL, NO_DATE | NO_EOL, THEME_ONLINE, "", value); } } } - win_save_newline(window); + win_newline(window); break; case FIELD_TEXT_PRIVATE: - if (curr_value != NULL) { + if (curr_value) { char *value = curr_value->data; - if (value != NULL) { - win_save_print(window, '-', NULL, NO_DATE | NO_EOL, THEME_ONLINE, "", "[hidden]"); + if (value) { + win_print(window, '-', NULL, NO_DATE | NO_EOL, THEME_ONLINE, "", "[hidden]"); } } - win_save_newline(window); + win_newline(window); break; case FIELD_TEXT_MULTI: - win_save_newline(window); + win_newline(window); int index = 1; - while (curr_value != NULL) { + while (curr_value) { char *value = curr_value->data; GString *val_tag = g_string_new(""); g_string_printf(val_tag, "val%d", index++); - win_save_vprint(window, '-', NULL, 0, THEME_ONLINE, "", " [%s] %s", val_tag->str, value); + win_vprint(window, '-', NULL, 0, THEME_ONLINE, "", " [%s] %s", val_tag->str, value); g_string_free(val_tag, TRUE); curr_value = g_slist_next(curr_value); } break; case FIELD_BOOLEAN: if (curr_value == NULL) { - win_save_print(window, '-', NULL, NO_DATE, THEME_OFFLINE, "", "FALSE"); + win_print(window, '-', NULL, NO_DATE, THEME_OFFLINE, "", "FALSE"); } else { char *value = curr_value->data; if (value == NULL) { - win_save_print(window, '-', NULL, NO_DATE, THEME_OFFLINE, "", "FALSE"); + win_print(window, '-', NULL, NO_DATE, THEME_OFFLINE, "", "FALSE"); } else { if (g_strcmp0(value, "0") == 0) { - win_save_print(window, '-', NULL, NO_DATE, THEME_OFFLINE, "", "FALSE"); + win_print(window, '-', NULL, NO_DATE, THEME_OFFLINE, "", "FALSE"); } else { - win_save_print(window, '-', NULL, NO_DATE, THEME_ONLINE, "", "TRUE"); + win_print(window, '-', NULL, NO_DATE, THEME_ONLINE, "", "TRUE"); } } } break; case FIELD_LIST_SINGLE: - if (curr_value != NULL) { - win_save_newline(window); + if (curr_value) { + win_newline(window); char *value = curr_value->data; GSList *options = field->options; GSList *curr_option = options; - while (curr_option != NULL) { + while (curr_option) { FormOption *option = curr_option->data; if (g_strcmp0(option->value, value) == 0) { - win_save_vprint(window, '-', NULL, 0, THEME_ONLINE, "", " [%s] %s", option->value, option->label); + win_vprint(window, '-', NULL, 0, THEME_ONLINE, "", " [%s] %s", option->value, option->label); } else { - win_save_vprint(window, '-', NULL, 0, THEME_OFFLINE, "", " [%s] %s", option->value, option->label); + win_vprint(window, '-', NULL, 0, THEME_OFFLINE, "", " [%s] %s", option->value, option->label); } curr_option = g_slist_next(curr_option); } } break; case FIELD_LIST_MULTI: - if (curr_value != NULL) { - win_save_newline(window); + if (curr_value) { + win_newline(window); GSList *options = field->options; GSList *curr_option = options; - while (curr_option != NULL) { + while (curr_option) { FormOption *option = curr_option->data; - if (g_slist_find_custom(curr_value, option->value, (GCompareFunc)g_strcmp0) != NULL) { - win_save_vprint(window, '-', NULL, 0, THEME_ONLINE, "", " [%s] %s", option->value, option->label); + if (g_slist_find_custom(curr_value, option->value, (GCompareFunc)g_strcmp0)) { + win_vprint(window, '-', NULL, 0, THEME_ONLINE, "", " [%s] %s", option->value, option->label); } else { - win_save_vprint(window, '-', NULL, 0, THEME_OFFLINE, "", " [%s] %s", option->value, option->label); + win_vprint(window, '-', NULL, 0, THEME_OFFLINE, "", " [%s] %s", option->value, option->label); } curr_option = g_slist_next(curr_option); } } break; case FIELD_JID_SINGLE: - if (curr_value != NULL) { + if (curr_value) { char *value = curr_value->data; - if (value != NULL) { - win_save_print(window, '-', NULL, NO_DATE | NO_EOL, THEME_ONLINE, "", value); + if (value) { + win_print(window, '-', NULL, NO_DATE | NO_EOL, THEME_ONLINE, "", value); } } - win_save_newline(window); + win_newline(window); break; case FIELD_JID_MULTI: - win_save_newline(window); - while (curr_value != NULL) { + win_newline(window); + while (curr_value) { char *value = curr_value->data; - win_save_vprint(window, '-', NULL, 0, THEME_ONLINE, "", " %s", value); + win_vprint(window, '-', NULL, 0, THEME_ONLINE, "", " %s", value); curr_value = g_slist_next(curr_value); } break; case FIELD_FIXED: - if (curr_value != NULL) { + if (curr_value) { char *value = curr_value->data; - if (value != NULL) { - win_save_print(window, '-', NULL, NO_DATE | NO_EOL, 0, "", value); + if (value) { + win_print(window, '-', NULL, NO_DATE | NO_EOL, 0, "", value); } } - win_save_newline(window); + win_newline(window); break; default: break; @@ -2646,25 +2539,25 @@ void ui_show_form(ProfMucConfWin *confwin) { ProfWin *window = (ProfWin*) confwin; - if (confwin->form->title != NULL) { - win_save_print(window, '-', NULL, NO_EOL, 0, "", "Form title: "); - win_save_print(window, '-', NULL, NO_DATE, 0, "", confwin->form->title); + if (confwin->form->title) { + win_print(window, '-', NULL, NO_EOL, 0, "", "Form title: "); + win_print(window, '-', NULL, NO_DATE, 0, "", confwin->form->title); } else { - win_save_vprint(window, '-', NULL, 0, 0, "", "Configuration for room %s.", confwin->roomjid); + win_vprint(window, '-', NULL, 0, 0, "", "Configuration for room %s.", confwin->roomjid); } - win_save_print(window, '-', NULL, 0, 0, "", ""); + win_print(window, '-', NULL, 0, 0, "", ""); ui_show_form_help(confwin); GSList *fields = confwin->form->fields; GSList *curr_field = fields; - while (curr_field != NULL) { + while (curr_field) { FormField *field = curr_field->data; if ((g_strcmp0(field->type, "fixed") == 0) && field->values) { if (field->values) { char *value = field->values->data; - win_save_print(window, '-', NULL, 0, 0, "", value); + win_print(window, '-', NULL, 0, 0, "", value); } } else if (g_strcmp0(field->type, "hidden") != 0 && field->var) { char *tag = g_hash_table_lookup(confwin->form->var_to_tag, field->var); @@ -2680,7 +2573,7 @@ ui_show_form_field(ProfWin *window, DataForm *form, char *tag) { FormField *field = form_get_field_by_tag(form, tag); _ui_handle_form_field(window, tag, field); - win_save_println(window, ""); + win_println(window, ""); } void @@ -2690,16 +2583,14 @@ ui_handle_room_configuration(const char * const roomjid, DataForm *form) ProfMucConfWin *confwin = (ProfMucConfWin*)window; assert(confwin->memcheck == PROFCONFWIN_MEMCHECK); - int num = wins_get_num(window); - ui_switch_win(num); - + ui_ev_focus_win(window); ui_show_form(confwin); - win_save_print(window, '-', NULL, 0, 0, "", ""); - win_save_print(window, '-', NULL, 0, 0, "", "Use '/form submit' to save changes."); - win_save_print(window, '-', NULL, 0, 0, "", "Use '/form cancel' to cancel changes."); - win_save_print(window, '-', NULL, 0, 0, "", "See '/form help' for more information."); - win_save_print(window, '-', NULL, 0, 0, "", ""); + win_print(window, '-', NULL, 0, 0, "", ""); + win_print(window, '-', NULL, 0, 0, "", "Use '/form submit' to save changes."); + win_print(window, '-', NULL, 0, 0, "", "Use '/form cancel' to cancel changes."); + win_print(window, '-', NULL, 0, 0, "", "See '/form help' for more information."); + win_print(window, '-', NULL, 0, 0, "", ""); } void @@ -2721,7 +2612,7 @@ ui_handle_room_configuration_form_error(const char * const roomjid, const char * g_string_append(message_str, message); } - win_save_print(window, '-', NULL, 0, THEME_ERROR, "", message_str->str); + win_print(window, '-', NULL, 0, THEME_ERROR, "", message_str->str); g_string_free(message_str, TRUE); } @@ -2747,11 +2638,11 @@ ui_handle_room_config_submit_result(const char * const roomjid) } if (muc_window) { - int num = wins_get_num(muc_window); - ui_switch_win(num); - win_save_print(muc_window, '!', NULL, 0, THEME_ROOMINFO, "", "Room configuration successful"); + ui_ev_focus_win((ProfWin*)muc_window); + win_print(muc_window, '!', NULL, 0, THEME_ROOMINFO, "", "Room configuration successful"); } else { - ui_switch_win(1); + ProfWin *console = wins_get_console(); + ui_ev_focus_win(console); cons_show("Room configuration successful: %s", roomjid); } } else { @@ -2776,25 +2667,25 @@ ui_handle_room_config_submit_result_error(const char * const roomjid, const char if (form_window) { if (message) { - win_save_vprint(form_window, '!', NULL, 0, THEME_ERROR, "", "Configuration error: %s", message); + win_vprint(form_window, '!', NULL, 0, THEME_ERROR, "", "Configuration error: %s", message); } else { - win_save_print(form_window, '!', NULL, 0, THEME_ERROR, "", "Configuration error"); + win_print(form_window, '!', NULL, 0, THEME_ERROR, "", "Configuration error"); } } else if (muc_window) { if (message) { - win_save_vprint(muc_window, '!', NULL, 0, THEME_ERROR, "", "Configuration error: %s", message); + win_vprint(muc_window, '!', NULL, 0, THEME_ERROR, "", "Configuration error: %s", message); } else { - win_save_print(muc_window, '!', NULL, 0, THEME_ERROR, "", "Configuration error"); + win_print(muc_window, '!', NULL, 0, THEME_ERROR, "", "Configuration error"); } } else { if (message) { - win_save_vprint(console, '!', NULL, 0, THEME_ERROR, "", "Configuration error for %s: %s", roomjid, message); + win_vprint(console, '!', NULL, 0, THEME_ERROR, "", "Configuration error for %s: %s", roomjid, message); } else { - win_save_vprint(console, '!', NULL, 0, THEME_ERROR, "", "Configuration error for %s", roomjid); + win_vprint(console, '!', NULL, 0, THEME_ERROR, "", "Configuration error for %s", roomjid); } } } else { - win_save_print(console, '!', NULL, 0, THEME_ERROR, "", "Configuration error"); + win_print(console, '!', NULL, 0, THEME_ERROR, "", "Configuration error"); } } @@ -2803,17 +2694,17 @@ ui_show_form_field_help(ProfMucConfWin *confwin, char *tag) { ProfWin *window = (ProfWin*) confwin; FormField *field = form_get_field_by_tag(confwin->form, tag); - if (field != NULL) { - win_save_print(window, '-', NULL, NO_EOL, 0, "", field->label); + if (field) { + win_print(window, '-', NULL, NO_EOL, 0, "", field->label); if (field->required) { - win_save_print(window, '-', NULL, NO_DATE, 0, "", " (Required):"); + win_print(window, '-', NULL, NO_DATE, 0, "", " (Required):"); } else { - win_save_print(window, '-', NULL, NO_DATE, 0, "", ":"); + win_print(window, '-', NULL, NO_DATE, 0, "", ":"); } - if (field->description != NULL) { - win_save_vprint(window, '-', NULL, 0, 0, "", " Description : %s", field->description); + if (field->description) { + win_vprint(window, '-', NULL, 0, 0, "", " Description : %s", field->description); } - win_save_vprint(window, '-', NULL, 0, 0, "", " Type : %s", field->type); + win_vprint(window, '-', NULL, 0, 0, "", " Type : %s", field->type); int num_values = 0; GSList *curr_option = NULL; @@ -2822,51 +2713,51 @@ ui_show_form_field_help(ProfMucConfWin *confwin, char *tag) switch (field->type_t) { case FIELD_TEXT_SINGLE: case FIELD_TEXT_PRIVATE: - win_save_vprint(window, '-', NULL, 0, 0, "", " Set : /%s <value>", tag); - win_save_print(window, '-', NULL, 0, 0, "", " Where : <value> is any text"); + win_vprint(window, '-', NULL, 0, 0, "", " Set : /%s <value>", tag); + win_print(window, '-', NULL, 0, 0, "", " Where : <value> is any text"); break; case FIELD_TEXT_MULTI: num_values = form_get_value_count(confwin->form, tag); - win_save_vprint(window, '-', NULL, 0, 0, "", " Add : /%s add <value>", tag); - win_save_print(window, '-', NULL, 0, 0, "", " Where : <value> is any text"); + win_vprint(window, '-', NULL, 0, 0, "", " Add : /%s add <value>", tag); + win_print(window, '-', NULL, 0, 0, "", " Where : <value> is any text"); if (num_values > 0) { - win_save_vprint(window, '-', NULL, 0, 0, "", " Remove : /%s remove <value>", tag); - win_save_vprint(window, '-', NULL, 0, 0, "", " Where : <value> between 'val1' and 'val%d'", num_values); + win_vprint(window, '-', NULL, 0, 0, "", " Remove : /%s remove <value>", tag); + win_vprint(window, '-', NULL, 0, 0, "", " Where : <value> between 'val1' and 'val%d'", num_values); } break; case FIELD_BOOLEAN: - win_save_vprint(window, '-', NULL, 0, 0, "", " Set : /%s <value>", tag); - win_save_print(window, '-', NULL, 0, 0, "", " Where : <value> is either 'on' or 'off'"); + win_vprint(window, '-', NULL, 0, 0, "", " Set : /%s <value>", tag); + win_print(window, '-', NULL, 0, 0, "", " Where : <value> is either 'on' or 'off'"); break; case FIELD_LIST_SINGLE: - win_save_vprint(window, '-', NULL, 0, 0, "", " Set : /%s <value>", tag); - win_save_print(window, '-', NULL, 0, 0, "", " Where : <value> is one of"); + win_vprint(window, '-', NULL, 0, 0, "", " Set : /%s <value>", tag); + win_print(window, '-', NULL, 0, 0, "", " Where : <value> is one of"); curr_option = field->options; - while (curr_option != NULL) { + while (curr_option) { option = curr_option->data; - win_save_vprint(window, '-', NULL, 0, 0, "", " %s", option->value); + win_vprint(window, '-', NULL, 0, 0, "", " %s", option->value); curr_option = g_slist_next(curr_option); } break; case FIELD_LIST_MULTI: - win_save_vprint(window, '-', NULL, 0, 0, "", " Add : /%s add <value>", tag); - win_save_vprint(window, '-', NULL, 0, 0, "", " Remove : /%s remove <value>", tag); - win_save_print(window, '-', NULL, 0, 0, "", " Where : <value> is one of"); + win_vprint(window, '-', NULL, 0, 0, "", " Add : /%s add <value>", tag); + win_vprint(window, '-', NULL, 0, 0, "", " Remove : /%s remove <value>", tag); + win_print(window, '-', NULL, 0, 0, "", " Where : <value> is one of"); curr_option = field->options; - while (curr_option != NULL) { + while (curr_option) { option = curr_option->data; - win_save_vprint(window, '-', NULL, 0, 0, "", " %s", option->value); + win_vprint(window, '-', NULL, 0, 0, "", " %s", option->value); curr_option = g_slist_next(curr_option); } break; case FIELD_JID_SINGLE: - win_save_vprint(window, '-', NULL, 0, 0, "", " Set : /%s <value>", tag); - win_save_print(window, '-', NULL, 0, 0, "", " Where : <value> is a valid Jabber ID"); + win_vprint(window, '-', NULL, 0, 0, "", " Set : /%s <value>", tag); + win_print(window, '-', NULL, 0, 0, "", " Where : <value> is a valid Jabber ID"); break; case FIELD_JID_MULTI: - win_save_vprint(window, '-', NULL, 0, 0, "", " Add : /%s add <value>", tag); - win_save_vprint(window, '-', NULL, 0, 0, "", " Remove : /%s remove <value>", tag); - win_save_print(window, '-', NULL, 0, 0, "", " Where : <value> is a valid Jabber ID"); + win_vprint(window, '-', NULL, 0, 0, "", " Add : /%s add <value>", tag); + win_vprint(window, '-', NULL, 0, 0, "", " Remove : /%s remove <value>", tag); + win_print(window, '-', NULL, 0, 0, "", " Where : <value> is a valid Jabber ID"); break; case FIELD_FIXED: case FIELD_UNKNOWN: @@ -2875,33 +2766,42 @@ ui_show_form_field_help(ProfMucConfWin *confwin, char *tag) break; } } else { - win_save_vprint(window, '-', NULL, 0, 0, "", "No such field %s", tag); + win_vprint(window, '-', NULL, 0, 0, "", "No such field %s", tag); } } void ui_show_form_help(ProfMucConfWin *confwin) { - if (confwin->form->instructions != NULL) { + if (confwin->form->instructions) { ProfWin *window = (ProfWin*) confwin; - win_save_print(window, '-', NULL, 0, 0, "", "Supplied instructions:"); - win_save_print(window, '-', NULL, 0, 0, "", confwin->form->instructions); - win_save_print(window, '-', NULL, 0, 0, "", ""); + win_print(window, '-', NULL, 0, 0, "", "Supplied instructions:"); + win_print(window, '-', NULL, 0, 0, "", confwin->form->instructions); + win_print(window, '-', NULL, 0, 0, "", ""); } } void ui_show_lines(ProfWin *window, const gchar** lines) { - if (lines != NULL) { + if (lines) { int i; for (i = 0; lines[i] != NULL; i++) { - win_save_print(window, '-', NULL, 0, 0, "", lines[i]); + win_print(window, '-', NULL, 0, 0, "", lines[i]); } } } void +ui_room_update_occupants(const char * const roomjid) +{ + ProfWin *window = (ProfWin*)wins_get_muc(roomjid); + if (window && win_has_active_subwin(window)) { + occupantswin_occupants(roomjid); + } +} + +void ui_room_show_occupants(const char * const roomjid) { ProfWin *window = (ProfWin*)wins_get_muc(roomjid); @@ -2940,65 +2840,34 @@ ui_hide_roster(void) } static void -_win_handle_switch(const wint_t ch) -{ - if (ch == KEY_F(1)) { - ui_switch_win(1); - } else if (ch == KEY_F(2)) { - ui_switch_win(2); - } else if (ch == KEY_F(3)) { - ui_switch_win(3); - } else if (ch == KEY_F(4)) { - ui_switch_win(4); - } else if (ch == KEY_F(5)) { - ui_switch_win(5); - } else if (ch == KEY_F(6)) { - ui_switch_win(6); - } else if (ch == KEY_F(7)) { - ui_switch_win(7); - } else if (ch == KEY_F(8)) { - ui_switch_win(8); - } else if (ch == KEY_F(9)) { - ui_switch_win(9); - } else if (ch == KEY_F(10)) { - ui_switch_win(0); - } -} - -static void -_win_show_history(int win_index, const char * const contact) -{ - ProfWin *window = wins_get_by_num(win_index); - if (window->type == WIN_CHAT) { - ProfChatWin *chatwin = (ProfChatWin*) window; - assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); - if (!chatwin->history_shown) { - Jid *jid = jid_create(jabber_get_fulljid()); - GSList *history = chat_log_get_previous(jid->barejid, contact); - jid_destroy(jid); - GSList *curr = history; - while (curr != NULL) { - char *line = curr->data; - // entry - if (line[2] == ':') { - char hh[3]; memcpy(hh, &line[0], 2); hh[2] = '\0'; int ihh = atoi(hh); - char mm[3]; memcpy(mm, &line[3], 2); mm[2] = '\0'; int imm = atoi(mm); - char ss[3]; memcpy(ss, &line[6], 2); ss[2] = '\0'; int iss = atoi(ss); - GDateTime *time = g_date_time_new_local(2000, 1, 1, ihh, imm, iss); - GTimeVal tv; - g_date_time_to_timeval(time, &tv); - win_save_print(window, '-', &tv, NO_COLOUR_DATE, 0, "", curr->data+11); - g_date_time_unref(time); - // header - } else { - win_save_print(window, '-', NULL, 0, 0, "", curr->data); - } - curr = g_slist_next(curr); +_win_show_history(ProfChatWin *chatwin, const char * const contact) +{ + if (!chatwin->history_shown) { + Jid *jid = jid_create(jabber_get_fulljid()); + GSList *history = chat_log_get_previous(jid->barejid, contact); + jid_destroy(jid); + GSList *curr = history; + while (curr) { + char *line = curr->data; + // entry + if (line[2] == ':') { + char hh[3]; memcpy(hh, &line[0], 2); hh[2] = '\0'; int ihh = atoi(hh); + char mm[3]; memcpy(mm, &line[3], 2); mm[2] = '\0'; int imm = atoi(mm); + char ss[3]; memcpy(ss, &line[6], 2); ss[2] = '\0'; int iss = atoi(ss); + GDateTime *time = g_date_time_new_local(2000, 1, 1, ihh, imm, iss); + GTimeVal tv; + g_date_time_to_timeval(time, &tv); + win_print((ProfWin*)chatwin, '-', &tv, NO_COLOUR_DATE, 0, "", curr->data+11); + g_date_time_unref(time); + // header + } else { + win_print((ProfWin*)chatwin, '-', NULL, 0, 0, "", curr->data); } - chatwin->history_shown = TRUE; - - g_slist_free_full(history, free); + curr = g_slist_next(curr); } + chatwin->history_shown = TRUE; + + g_slist_free_full(history, free); } } diff --git a/src/ui/inputwin.c b/src/ui/inputwin.c index 85ddc79a..caea8ea9 100644 --- a/src/ui/inputwin.c +++ b/src/ui/inputwin.c @@ -1,7 +1,7 @@ /* * inputwin.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -38,6 +38,11 @@ #include <stdlib.h> #include <string.h> #include <wchar.h> +#include <sys/time.h> +#include <errno.h> + +#include <readline/readline.h> +#include <readline/history.h> #ifdef HAVE_NCURSESW_NCURSES_H #include <ncursesw/ncurses.h> @@ -50,7 +55,6 @@ #include "config/accounts.h" #include "config/preferences.h" #include "config/theme.h" -#include "tools/history.h" #include "log.h" #include "muc.h" #include "profanity.h" @@ -59,39 +63,48 @@ #include "ui/statusbar.h" #include "ui/inputwin.h" #include "ui/windows.h" +#include "event/ui_events.h" #include "xmpp/xmpp.h" -#define _inp_win_update_virtual() pnoutrefresh(inp_win, 0, pad_start, rows-1, 0, rows-1, cols-1) - -#define KEY_CTRL_A 0001 -#define KEY_CTRL_B 0002 -#define KEY_CTRL_D 0004 -#define KEY_CTRL_E 0005 -#define KEY_CTRL_F 0006 -#define KEY_CTRL_N 0016 -#define KEY_CTRL_P 0020 -#define KEY_CTRL_U 0025 -#define KEY_CTRL_W 0027 - -#define MAX_HISTORY 100 -#define INP_WIN_MAX 1000 - static WINDOW *inp_win; -static History history; - -static char input[INP_WIN_MAX]; -static int input_len_bytes; - static int pad_start = 0; -static int rows, cols; -static int _handle_edit(int key_type, const wint_t ch); -static int _handle_alt_key(int key); -static void _handle_backspace(void); -static int _printable(const wint_t ch); -static void _clear_input(void); -static void _go_to_end(void); -static void _delete_previous_word(void); +static struct timeval p_rl_timeout; +static gint inp_timeout = 0; +static gint no_input_count = 0; + +static fd_set fds; +static int r; +static char *inp_line = NULL; +static gboolean get_password = FALSE; + +static void _inp_win_update_virtual(void); +static int _inp_printable(const wint_t ch); +static void _inp_win_handle_scroll(void); +static int _inp_offset_to_col(char *str, int offset); +static void _inp_write(char *line, int offset); + +static int _inp_rl_getc(FILE *stream); +static void _inp_rl_linehandler(char *line); +static int _inp_rl_tab_handler(int count, int key); +static int _inp_rl_clear_handler(int count, int key); +static int _inp_rl_win1_handler(int count, int key); +static int _inp_rl_win2_handler(int count, int key); +static int _inp_rl_win3_handler(int count, int key); +static int _inp_rl_win4_handler(int count, int key); +static int _inp_rl_win5_handler(int count, int key); +static int _inp_rl_win6_handler(int count, int key); +static int _inp_rl_win7_handler(int count, int key); +static int _inp_rl_win8_handler(int count, int key); +static int _inp_rl_win9_handler(int count, int key); +static int _inp_rl_win0_handler(int count, int key); +static int _inp_rl_altleft_handler(int count, int key); +static int _inp_rl_altright_handler(int count, int key); +static int _inp_rl_pageup_handler(int count, int key); +static int _inp_rl_pagedown_handler(int count, int key); +static int _inp_rl_altpageup_handler(int count, int key); +static int _inp_rl_altpagedown_handler(int count, int key); +static int _inp_rl_startup_hook(void); void create_input_window(void) @@ -101,25 +114,84 @@ create_input_window(void) #else ESCDELAY = 25; #endif - getmaxyx(stdscr, rows, cols); + if (inp_timeout == 1000) { + p_rl_timeout.tv_sec = 1; + p_rl_timeout.tv_usec = 0; + } else { + p_rl_timeout.tv_sec = 0; + p_rl_timeout.tv_usec = inp_timeout * 1000; + } + + rl_readline_name = "profanity"; + rl_getc_function = _inp_rl_getc; + rl_startup_hook = _inp_rl_startup_hook; + rl_callback_handler_install(NULL, _inp_rl_linehandler); + inp_win = newpad(1, INP_WIN_MAX); wbkgd(inp_win, theme_attrs(THEME_INPUT_TEXT));; keypad(inp_win, TRUE); wmove(inp_win, 0, 0); + _inp_win_update_virtual(); - history = history_new(MAX_HISTORY); +} + +char * +inp_readline(void) +{ + free(inp_line); + inp_line = NULL; + FD_ZERO(&fds); + FD_SET(fileno(rl_instream), &fds); + errno = 0; + r = select(FD_SETSIZE, &fds, NULL, NULL, &p_rl_timeout); + if (r < 0) { + char *err_msg = strerror(errno); + log_error("Readline failed: %s", err_msg); + return NULL; + } + + if (FD_ISSET(fileno(rl_instream), &fds)) { + rl_callback_read_char(); + + if (rl_line_buffer && + rl_line_buffer[0] != '/' && + rl_line_buffer[0] != '\0' && + rl_line_buffer[0] != '\n') { + prof_handle_activity(); + } + + ui_reset_idle_time(); + _inp_write(rl_line_buffer, rl_point); + inp_nonblocking(TRUE); + } else { + inp_nonblocking(FALSE); + prof_handle_idle(); + } + + if (inp_timeout == 1000) { + p_rl_timeout.tv_sec = 1; + p_rl_timeout.tv_usec = 0; + } else { + p_rl_timeout.tv_sec = 0; + p_rl_timeout.tv_usec = inp_timeout * 1000; + } + + if (inp_line) { + return strdup(inp_line); + } else { + return NULL; + } } void inp_win_resize(void) { - int inp_x; - getmaxyx(stdscr, rows, cols); - inp_x = getcurx(inp_win); + int col = getcurx(inp_win); + int wcols = getmaxx(stdscr); // if lost cursor off screen, move contents to show it - if (inp_x >= pad_start + cols) { - pad_start = inp_x - (cols / 2); + if (col >= pad_start + wcols) { + pad_start = col - (wcols / 2); if (pad_start < 0) { pad_start = 0; } @@ -130,127 +202,60 @@ inp_win_resize(void) } void -inp_non_block(gint timeout) -{ - wtimeout(inp_win, timeout); -} - -void -inp_block(void) +inp_nonblocking(gboolean reset) { - wtimeout(inp_win, -1); -} - -char * -inp_read(int *key_type, wint_t *ch) -{ - int display_size = utf8_display_len(input); - - // echo off, and get some more input - noecho(); - *key_type = wget_wch(inp_win, ch); - - gboolean in_command = FALSE; - if ((display_size > 0 && input[0] == '/') || - (display_size == 0 && *ch == '/')) { - in_command = TRUE; + if (! prefs_get_boolean(PREF_INPBLOCK_DYNAMIC)) { + inp_timeout = prefs_get_inpblock(); + return; } - if (*key_type == ERR) { - prof_handle_idle(); - } - if ((*key_type != ERR) && (*key_type != KEY_CODE_YES) && !in_command && _printable(*ch)) { - prof_handle_activity(); + if (reset) { + inp_timeout = 0; + no_input_count = 0; } - // if it wasn't an arrow key etc - if (!_handle_edit(*key_type, *ch)) { - if (_printable(*ch) && *key_type != KEY_CODE_YES) { - if (input_len_bytes >= INP_WIN_MAX) { - *ch = ERR; - return NULL; - } + if (inp_timeout < prefs_get_inpblock()) { + no_input_count++; - int inp_x = getcurx(inp_win); - - // handle insert if not at end of input - if (inp_x < display_size) { - char bytes[MB_CUR_MAX]; - size_t utf_len = wcrtomb(bytes, *ch, NULL); - - char *next_ch = g_utf8_offset_to_pointer(input, inp_x); - char *offset; - for (offset = &input[input_len_bytes - 1]; offset >= next_ch; offset--) { - *(offset + utf_len) = *offset; - } - int i; - for (i = 0; i < utf_len; i++) { - *(next_ch + i) = bytes[i]; - } - - input_len_bytes += utf_len; - input[input_len_bytes] = '\0'; - waddstr(inp_win, next_ch); - wmove(inp_win, 0, inp_x + 1); - - if (inp_x - pad_start > cols-3) { - pad_start++; - _inp_win_update_virtual(); - } - - // otherwise just append - } else { - char bytes[MB_CUR_MAX+1]; - size_t utf_len = wcrtomb(bytes, *ch, NULL); - - // wcrtomb can return (size_t) -1 - if (utf_len < MB_CUR_MAX) { - int i; - for (i = 0 ; i < utf_len; i++) { - input[input_len_bytes++] = bytes[i]; - } - input[input_len_bytes] = '\0'; - - bytes[utf_len] = '\0'; - waddstr(inp_win, bytes); - display_size++; - - // if gone over screen size follow input - int rows, cols; - getmaxyx(stdscr, rows, cols); - if (display_size - pad_start > cols-2) { - pad_start++; - _inp_win_update_virtual(); - } - } - } + if (no_input_count % 10 == 0) { + inp_timeout += no_input_count; - cmd_reset_autocomplete(); + if (inp_timeout > prefs_get_inpblock()) { + inp_timeout = prefs_get_inpblock(); + } } } - - echo(); - - if (*ch == '\n') { - input[input_len_bytes] = '\0'; - input_len_bytes = 0; - return strdup(input); - } else { - return NULL; - } } void -inp_get_password(char *passwd) +inp_close(void) +{ + rl_callback_handler_remove(); +} + +char* +inp_get_password(void) { - _clear_input(); + werase(inp_win); + wmove(inp_win, 0, 0); + pad_start = 0; _inp_win_update_virtual(); doupdate(); - noecho(); - mvwgetnstr(inp_win, 0, 1, passwd, MAX_PASSWORD_SIZE); - wmove(inp_win, 0, 0); - echo(); + char *password = NULL; + get_password = TRUE; + while (!password) { + password = inp_readline(); + ui_update(); + werase(inp_win); + wmove(inp_win, 0, 0); + pad_start = 0; + _inp_win_update_virtual(); + doupdate(); + } + get_password = FALSE; + status_bar_clear(); + return password; } void @@ -260,525 +265,314 @@ inp_put_back(void) } void -inp_replace_input(const char * const new_input) -{ - strncpy(input, new_input, INP_WIN_MAX); - input_len_bytes = strlen(input); - inp_win_reset(); - input[input_len_bytes] = '\0'; - waddstr(inp_win, input); - _go_to_end(); -} - -void -inp_win_reset(void) +inp_win_clear(void) { - _clear_input(); + werase(inp_win); + wmove(inp_win, 0, 0); pad_start = 0; _inp_win_update_virtual(); } -void -inp_history_append(char *inp) +static void +_inp_win_update_virtual(void) { - history_append(history, inp); + int wrows, wcols; + getmaxyx(stdscr, wrows, wcols); + pnoutrefresh(inp_win, 0, pad_start, wrows-1, 0, wrows-1, wcols-2); } static void -_clear_input(void) +_inp_write(char *line, int offset) { + int col = _inp_offset_to_col(line, offset); werase(inp_win); - wmove(inp_win, 0, 0); + waddstr(inp_win, line); + wmove(inp_win, 0, col); + _inp_win_handle_scroll(); + + _inp_win_update_virtual(); } -/* - * Deal with command editing, return 1 if ch was an edit - * key press: up, down, left, right or backspace - * return 0 if it wasn't - */ static int -_handle_edit(int key_type, const wint_t ch) -{ - char *prev = NULL; - char *next = NULL; - int inp_x = getcurx(inp_win); - int next_ch; - int display_size = utf8_display_len(input); - - // CTRL-LEFT - if ((key_type == KEY_CODE_YES) && (ch == 547 || ch == 545 || ch == 544 || ch == 540 || ch == 539) && (inp_x > 0)) { - input[input_len_bytes] = '\0'; - gchar *curr_ch = g_utf8_offset_to_pointer(input, inp_x); - curr_ch = g_utf8_find_prev_char(input, curr_ch); - gchar *prev_ch; - gunichar curr_uni; - gunichar prev_uni; - - while (curr_ch != NULL) { - curr_uni = g_utf8_get_char(curr_ch); - - if (g_unichar_isspace(curr_uni)) { - curr_ch = g_utf8_find_prev_char(input, curr_ch); - } else { - prev_ch = g_utf8_find_prev_char(input, curr_ch); - if (prev_ch == NULL) { - curr_ch = NULL; - break; - } else { - prev_uni = g_utf8_get_char(prev_ch); - if (g_unichar_isspace(prev_uni)) { - break; - } else { - curr_ch = prev_ch; - } - } - } - } +_inp_printable(const wint_t ch) +{ + char bytes[MB_CUR_MAX+1]; + size_t utf_len = wcrtomb(bytes, ch, NULL); + bytes[utf_len] = '\0'; + gunichar unichar = g_utf8_get_char(bytes); - if (curr_ch == NULL) { - inp_x = 0; - wmove(inp_win, 0, inp_x); - } else { - glong offset = g_utf8_pointer_to_offset(input, curr_ch); - inp_x = offset; - wmove(inp_win, 0, inp_x); + return g_unichar_isprint(unichar) && (ch != KEY_MOUSE); +} + +static int +_inp_offset_to_col(char *str, int offset) +{ + int i = 0; + int col = 0; + + while (i < offset && str[i] != '\0') { + gunichar uni = g_utf8_get_char(&str[i]); + size_t ch_len = mbrlen(&str[i], 4, NULL); + i += ch_len; + col++; + if (g_unichar_iswide(uni)) { + col++; } + } - // if gone off screen to left, jump left (half a screen worth) - if (inp_x <= pad_start) { - pad_start = pad_start - (cols / 2); - if (pad_start < 0) { - pad_start = 0; - } + return col; +} - _inp_win_update_virtual(); - } - return 1; - - // CTRL-RIGHT - } else if ((key_type == KEY_CODE_YES) && (ch == 562 || ch == 560 || ch == 555 || ch == 559 || ch == 554) && (inp_x < display_size)) { - input[input_len_bytes] = '\0'; - gchar *curr_ch = g_utf8_offset_to_pointer(input, inp_x); - gchar *next_ch = g_utf8_find_next_char(curr_ch, NULL); - gunichar curr_uni; - gunichar next_uni; - gboolean moved = FALSE; - - while (g_utf8_pointer_to_offset(input, next_ch) < display_size) { - curr_uni = g_utf8_get_char(curr_ch); - next_uni = g_utf8_get_char(next_ch); - curr_ch = next_ch; - next_ch = g_utf8_find_next_char(next_ch, NULL); - - if (!g_unichar_isspace(curr_uni) && g_unichar_isspace(next_uni) && moved) { - break; - } else { - moved = TRUE; - } - } +static void +_inp_win_handle_scroll(void) +{ + int col = getcurx(inp_win); + int wcols = getmaxx(stdscr); - if (next_ch == NULL) { - inp_x = display_size; - wmove(inp_win, 0, inp_x); - } else { - glong offset = g_utf8_pointer_to_offset(input, curr_ch); - if (offset == display_size - 1) { - inp_x = offset + 1; - } else { - inp_x = offset; - } - wmove(inp_win, 0, inp_x); + if (col == 0) { + pad_start = 0; + } else if (col >= pad_start + (wcols -2)) { + pad_start = col - (wcols / 2); + if (pad_start < 0) { + pad_start = 0; } - - // if gone off screen to right, jump right (half a screen worth) - if (inp_x > pad_start + cols) { - pad_start = pad_start + (cols / 2); - _inp_win_update_virtual(); + } else if (col <= pad_start) { + pad_start = pad_start - (wcols / 2); + if (pad_start < 0) { + pad_start = 0; } + } +} - return 1; - - // ALT-LEFT - } else if ((key_type == KEY_CODE_YES) && (ch == 537 || ch == 542)) { - ui_previous_win(); - return 1; - - // ALT-RIGHT - } else if ((key_type == KEY_CODE_YES) && (ch == 552 || ch == 557)) { - ui_next_win(); - return 1; - - // other editing keys - } else { - switch(ch) { - - case 27: // ESC - // check for ALT-key - next_ch = wgetch(inp_win); - if (next_ch != ERR) { - return _handle_alt_key(next_ch); - } else { - input_len_bytes = 0; - inp_win_reset(); - return 1; - } - - case 127: - _handle_backspace(); - return 1; - case KEY_BACKSPACE: - if (key_type != KEY_CODE_YES) { - return 0; - } - _handle_backspace(); - return 1; - - case KEY_DC: // DEL - if (key_type != KEY_CODE_YES) { - return 0; - } - case KEY_CTRL_D: - if (inp_x == display_size-1) { - gchar *start = g_utf8_substring(input, 0, inp_x); - for (input_len_bytes = 0; input_len_bytes < strlen(start); input_len_bytes++) { - input[input_len_bytes] = start[input_len_bytes]; - } - input[input_len_bytes] = '\0'; - - g_free(start); - - _clear_input(); - waddstr(inp_win, input); - } else if (inp_x < display_size-1) { - gchar *start = g_utf8_substring(input, 0, inp_x); - gchar *end = g_utf8_substring(input, inp_x+1, input_len_bytes); - GString *new = g_string_new(start); - g_string_append(new, end); - - for (input_len_bytes = 0; input_len_bytes < strlen(new->str); input_len_bytes++) { - input[input_len_bytes] = new->str[input_len_bytes]; - } - input[input_len_bytes] = '\0'; - - g_free(start); - g_free(end); - g_string_free(new, FALSE); - - _clear_input(); - waddstr(inp_win, input); - wmove(inp_win, 0, inp_x); - } - return 1; - - case KEY_LEFT: - if (key_type != KEY_CODE_YES) { - return 0; - } - case KEY_CTRL_B: - if (inp_x > 0) { - wmove(inp_win, 0, inp_x-1); - - // current position off screen to left - if (inp_x - 1 < pad_start) { - pad_start--; - _inp_win_update_virtual(); - } - } - return 1; - - case KEY_RIGHT: - if (key_type != KEY_CODE_YES) { - return 0; - } - case KEY_CTRL_F: - if (inp_x < display_size) { - wmove(inp_win, 0, inp_x+1); - - // current position off screen to right - if ((inp_x + 1 - pad_start) >= cols) { - pad_start++; - _inp_win_update_virtual(); - } - } - return 1; - - case KEY_UP: - if (key_type != KEY_CODE_YES) { - return 0; - } - case KEY_CTRL_P: - input[input_len_bytes] = '\0'; - prev = history_previous(history, input); - if (prev) { - inp_replace_input(prev); - } - return 1; +// Readline callbacks - case KEY_DOWN: - if (key_type != KEY_CODE_YES) { - return 0; - } - case KEY_CTRL_N: - input[input_len_bytes] = '\0'; - next = history_next(history, input); - if (next) { - inp_replace_input(next); - } else if (input_len_bytes != 0) { - input[input_len_bytes] = '\0'; - history_append(history, input); - inp_replace_input(""); - } - return 1; +static int +_inp_rl_startup_hook(void) +{ + rl_bind_keyseq("\\e1", _inp_rl_win1_handler); + rl_bind_keyseq("\\e2", _inp_rl_win2_handler); + rl_bind_keyseq("\\e3", _inp_rl_win3_handler); + rl_bind_keyseq("\\e4", _inp_rl_win4_handler); + rl_bind_keyseq("\\e5", _inp_rl_win5_handler); + rl_bind_keyseq("\\e6", _inp_rl_win6_handler); + rl_bind_keyseq("\\e7", _inp_rl_win7_handler); + rl_bind_keyseq("\\e8", _inp_rl_win8_handler); + rl_bind_keyseq("\\e9", _inp_rl_win9_handler); + rl_bind_keyseq("\\e0", _inp_rl_win0_handler); + + rl_bind_keyseq("\\eOP", _inp_rl_win1_handler); + rl_bind_keyseq("\\eOQ", _inp_rl_win2_handler); + rl_bind_keyseq("\\eOR", _inp_rl_win3_handler); + rl_bind_keyseq("\\eOS", _inp_rl_win4_handler); + rl_bind_keyseq("\\e[15~", _inp_rl_win5_handler); + rl_bind_keyseq("\\e[17~", _inp_rl_win6_handler); + rl_bind_keyseq("\\e[18~", _inp_rl_win7_handler); + rl_bind_keyseq("\\e[19~", _inp_rl_win8_handler); + rl_bind_keyseq("\\e[20~", _inp_rl_win9_handler); + rl_bind_keyseq("\\e[21~", _inp_rl_win0_handler); + + rl_bind_keyseq("\\e[1;9D", _inp_rl_altleft_handler); + rl_bind_keyseq("\\e[1;3D", _inp_rl_altleft_handler); + rl_bind_keyseq("\\e\\e[D", _inp_rl_altleft_handler); + + rl_bind_keyseq("\\e[1;9C", _inp_rl_altright_handler); + rl_bind_keyseq("\\e[1;3C", _inp_rl_altright_handler); + rl_bind_keyseq("\\e\\e[C", _inp_rl_altright_handler); + + rl_bind_keyseq("\\e\\e[5~", _inp_rl_altpageup_handler); + rl_bind_keyseq("\\e[5;3~", _inp_rl_altpageup_handler); + rl_bind_keyseq("\\e\\eOy", _inp_rl_altpageup_handler); + + rl_bind_keyseq("\\e\\e[6~", _inp_rl_altpagedown_handler); + rl_bind_keyseq("\\e[6;3~", _inp_rl_altpagedown_handler); + rl_bind_keyseq("\\e\\eOs", _inp_rl_altpagedown_handler); + + rl_bind_keyseq("\\e[5~", _inp_rl_pageup_handler); + rl_bind_keyseq("\\eOy", _inp_rl_pageup_handler); + rl_bind_keyseq("\\e[6~", _inp_rl_pagedown_handler); + rl_bind_keyseq("\\eOs", _inp_rl_pagedown_handler); + + rl_bind_key('\t', _inp_rl_tab_handler); + rl_bind_key(CTRL('L'), _inp_rl_clear_handler); + + return 0; +} - case KEY_HOME: - if (key_type != KEY_CODE_YES) { - return 0; - } - case KEY_CTRL_A: - wmove(inp_win, 0, 0); - pad_start = 0; - _inp_win_update_virtual(); - return 1; +static void +_inp_rl_linehandler(char *line) +{ + if (line && *line) { + if (!get_password) { + add_history(line); + } + } + inp_line = line; +} - case KEY_END: - if (key_type != KEY_CODE_YES) { - return 0; - } - case KEY_CTRL_E: - _go_to_end(); - return 1; - - case 9: // tab - if (input_len_bytes != 0) { - input[input_len_bytes] = '\0'; - if ((strncmp(input, "/", 1) != 0) && (ui_current_win_type() == WIN_MUC)) { - char *result = muc_autocomplete(input); - if (result) { - inp_replace_input(result); - free(result); - } - } else if (strncmp(input, "/", 1) == 0) { - char *result = cmd_autocomplete(input); - if (result) { - inp_replace_input(result); - free(result); - } - } - } - return 1; +static int +_inp_rl_getc(FILE *stream) +{ + int ch = rl_getc(stream); + if (_inp_printable(ch)) { + cmd_reset_autocomplete(); + } + return ch; +} - case KEY_CTRL_W: - _delete_previous_word(); - return 1; - break; +static int +_inp_rl_clear_handler(int count, int key) +{ + ui_clear_current(); + return 0; +} - case KEY_CTRL_U: - while (getcurx(inp_win) > 0) { - _delete_previous_word(); - } - return 1; - break; +static int +_inp_rl_tab_handler(int count, int key) +{ + if (rl_point != rl_end || !rl_line_buffer) { + return 0; + } - default: - return 0; + if ((strncmp(rl_line_buffer, "/", 1) != 0) && (ui_current_win_type() == WIN_MUC)) { + char *result = muc_autocomplete(rl_line_buffer); + if (result) { + rl_replace_line(result, 0); + rl_point = rl_end; + } + } else if (strncmp(rl_line_buffer, "/", 1) == 0) { + char *result = cmd_autocomplete(rl_line_buffer); + if (result) { + rl_replace_line(result, 0); + rl_point = rl_end; } } + + return 0; } static void -_handle_backspace(void) -{ - int inp_x = getcurx(inp_win); - int display_size = utf8_display_len(input); - roster_reset_search_attempts(); - if (display_size > 0) { - - // if at end, delete last char - if (inp_x >= display_size) { - gchar *start = g_utf8_substring(input, 0, inp_x-1); - for (input_len_bytes = 0; input_len_bytes < strlen(start); input_len_bytes++) { - input[input_len_bytes] = start[input_len_bytes]; - } - input[input_len_bytes] = '\0'; - - g_free(start); +_go_to_win(int i) +{ + ProfWin *window = wins_get_by_num(i); + if (window) { + ui_ev_focus_win(window); + } +} - _clear_input(); - waddstr(inp_win, input); - wmove(inp_win, 0, inp_x -1); +static int +_inp_rl_win1_handler(int count, int key) +{ + _go_to_win(1); + return 0; +} - // if in middle, delete and shift chars left - } else if (inp_x > 0 && inp_x < display_size) { - gchar *start = g_utf8_substring(input, 0, inp_x - 1); - gchar *end = g_utf8_substring(input, inp_x, input_len_bytes); - GString *new = g_string_new(start); - g_string_append(new, end); +static int +_inp_rl_win2_handler(int count, int key) +{ + _go_to_win(2); + return 0; +} - for (input_len_bytes = 0; input_len_bytes < strlen(new->str); input_len_bytes++) { - input[input_len_bytes] = new->str[input_len_bytes]; - } - input[input_len_bytes] = '\0'; +static int +_inp_rl_win3_handler(int count, int key) +{ + _go_to_win(3); + return 0; +} - g_free(start); - g_free(end); - g_string_free(new, FALSE); +static int +_inp_rl_win4_handler(int count, int key) +{ + _go_to_win(4); + return 0; +} - _clear_input(); - waddstr(inp_win, input); - wmove(inp_win, 0, inp_x -1); - } +static int +_inp_rl_win5_handler(int count, int key) +{ + _go_to_win(5); + return 0; +} - // if gone off screen to left, jump left (half a screen worth) - if (inp_x <= pad_start) { - pad_start = pad_start - (cols / 2); - if (pad_start < 0) { - pad_start = 0; - } +static int +_inp_rl_win6_handler(int count, int key) +{ + _go_to_win(6); + return 0; +} - _inp_win_update_virtual(); - } - } +static int +_inp_rl_win7_handler(int count, int key) +{ + _go_to_win(7); + return 0; +} +static int +_inp_rl_win8_handler(int count, int key) +{ + _go_to_win(8); + return 0; } static int -_handle_alt_key(int key) -{ - switch (key) - { - case '1': - ui_switch_win(1); - break; - case '2': - ui_switch_win(2); - break; - case '3': - ui_switch_win(3); - break; - case '4': - ui_switch_win(4); - break; - case '5': - ui_switch_win(5); - break; - case '6': - ui_switch_win(6); - break; - case '7': - ui_switch_win(7); - break; - case '8': - ui_switch_win(8); - break; - case '9': - ui_switch_win(9); - break; - case '0': - ui_switch_win(0); - break; - case KEY_LEFT: - ui_previous_win(); - break; - case KEY_RIGHT: - ui_next_win(); - break; - case 263: - case 127: - _delete_previous_word(); - break; - default: - break; - } - return 1; +_inp_rl_win9_handler(int count, int key) +{ + _go_to_win(9); + return 0; } -static void -_delete_previous_word(void) -{ - int end_del = getcurx(inp_win); - int start_del = end_del; - - input[input_len_bytes] = '\0'; - gchar *curr_ch = g_utf8_offset_to_pointer(input, end_del); - curr_ch = g_utf8_find_prev_char(input, curr_ch); - gchar *prev_ch; - gunichar curr_uni; - gunichar prev_uni; - - while (curr_ch != NULL) { - curr_uni = g_utf8_get_char(curr_ch); - - if (g_unichar_isspace(curr_uni)) { - curr_ch = g_utf8_find_prev_char(input, curr_ch); - } else { - prev_ch = g_utf8_find_prev_char(input, curr_ch); - if (prev_ch == NULL) { - curr_ch = NULL; - break; - } else { - prev_uni = g_utf8_get_char(prev_ch); - if (g_unichar_isspace(prev_uni)) { - break; - } else { - curr_ch = prev_ch; - } - } - } - } +static int +_inp_rl_win0_handler(int count, int key) +{ + _go_to_win(0); + return 0; +} - if (curr_ch == NULL) { - start_del = 0; - } else { - start_del = g_utf8_pointer_to_offset(input, curr_ch); +static int +_inp_rl_altleft_handler(int count, int key) +{ + ProfWin *window = wins_get_previous(); + if (window) { + ui_ev_focus_win(window); } + return 0; +} - gint len = g_utf8_strlen(input, -1); - gchar *start_string = g_utf8_substring(input, 0, start_del); - gchar *end_string = g_utf8_substring(input, end_del, len); - - int i; - for (i = 0; i < strlen(start_string); i++) { - input[i] = start_string[i]; - } - for (i = 0; i < strlen(end_string); i++) { - input[strlen(start_string)+i] = end_string[i]; +static int +_inp_rl_altright_handler(int count, int key) +{ + ProfWin *window = wins_get_next(); + if (window) { + ui_ev_focus_win(window); } + return 0; +} - input_len_bytes = strlen(start_string)+i; - input[input_len_bytes] = '\0'; - - _clear_input(); - waddstr(inp_win, input); - wmove(inp_win, 0, start_del); - - // if gone off screen to left, jump left (half a screen worth) - if (start_del <= pad_start) { - pad_start = pad_start - (cols / 2); - if (pad_start < 0) { - pad_start = 0; - } +static int +_inp_rl_pageup_handler(int count, int key) +{ + ui_page_up(); + return 0; +} - _inp_win_update_virtual(); - } +static int +_inp_rl_pagedown_handler(int count, int key) +{ + ui_page_down(); + return 0; } -static void -_go_to_end(void) +static int +_inp_rl_altpageup_handler(int count, int key) { - int display_size = utf8_display_len(input); - wmove(inp_win, 0, display_size); - if (display_size > cols-2) { - pad_start = display_size - cols + 1; - _inp_win_update_virtual(); - } + ui_subwin_page_up(); + return 0; } static int -_printable(const wint_t ch) +_inp_rl_altpagedown_handler(int count, int key) { - char bytes[MB_CUR_MAX+1]; - size_t utf_len = wcrtomb(bytes, ch, NULL); - bytes[utf_len] = '\0'; - gunichar unichar = g_utf8_get_char(bytes); - return g_unichar_isprint(unichar) && (ch != KEY_MOUSE); + ui_subwin_page_down(); + return 0; } diff --git a/src/ui/inputwin.h b/src/ui/inputwin.h index 39fde720..f49a6a76 100644 --- a/src/ui/inputwin.h +++ b/src/ui/inputwin.h @@ -1,7 +1,7 @@ /* * inputwin.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -35,15 +35,17 @@ #ifndef UI_INPUTWIN_H #define UI_INPUTWIN_H +#include <glib.h> + +#define INP_WIN_MAX 1000 + void create_input_window(void); -char* inp_read(int *key_type, wint_t *ch); -void inp_win_reset(void); +char* inp_readline(void); +void inp_nonblocking(gboolean reset); +void inp_close(void); +void inp_win_clear(void); void inp_win_resize(void); void inp_put_back(void); -void inp_non_block(gint); -void inp_block(void); -void inp_get_password(char *passwd); -void inp_replace_input(const char * const new_input); -void inp_history_append(char *inp); +char* inp_get_password(void); #endif diff --git a/src/ui/notifier.c b/src/ui/notifier.c index 7ca8f705..76290daf 100644 --- a/src/ui/notifier.c +++ b/src/ui/notifier.c @@ -1,7 +1,7 @@ /* * notifier.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -48,10 +48,10 @@ #include "log.h" #include "muc.h" #include "ui/ui.h" +#include "ui/windows.h" #include "config/preferences.h" -static void _notify(const char * const message, int timeout, - const char * const category); +static void _notify(const char * const message, int timeout, const char * const category); static GTimer *remind_timer; @@ -89,7 +89,7 @@ notify_invite(const char * const from, const char * const room, g_string_append(message, from); g_string_append(message, "\nto: "); g_string_append(message, room); - if (reason != NULL) { + if (reason) { g_string_append_printf(message, "\n\"%s\"", reason); } @@ -99,17 +99,25 @@ notify_invite(const char * const from, const char * const room, } void -notify_message(const char * const handle, int win, const char * const text) +notify_message(ProfWin *window, const char * const name, const char * const text) { - GString *message = g_string_new(""); - g_string_append_printf(message, "%s (win %d)", handle, win); - if (text != NULL) { - g_string_append_printf(message, "\n%s", text); + int num = wins_get_num(window); + if (num == 10) { + num = 0; } - _notify(message->str, 10000, "incoming message"); + gboolean is_current = wins_is_current(window); + if (!is_current || (is_current && prefs_get_boolean(PREF_NOTIFY_MESSAGE_CURRENT)) ) { + GString *message = g_string_new(""); + g_string_append_printf(message, "%s (win %d)", name, num); - g_string_free(message, TRUE); + if (prefs_get_boolean(PREF_NOTIFY_MESSAGE_TEXT) && text) { + g_string_append_printf(message, "\n%s", text); + } + + _notify(message->str, 10000, "incoming message"); + g_string_free(message, TRUE); + } } void @@ -117,7 +125,7 @@ notify_room_message(const char * const handle, const char * const room, int win, { GString *message = g_string_new(""); g_string_append_printf(message, "%s in %s (win %d)", handle, room, win); - if (text != NULL) { + if (text) { g_string_append_printf(message, "\n%s", text); } @@ -243,10 +251,9 @@ _notify(const char * const message, int timeout, Shell_NotifyIcon(NIM_MODIFY, &nid); #endif #ifdef HAVE_OSXNOTIFY - GString *notify_command = g_string_new("terminal-notifier -title \"Profanity\" -message \""); + GString *notify_command = g_string_new("terminal-notifier -title \"Profanity\" -message '"); - char *escaped_double = str_replace(message, "\"", "\\\""); - char *escaped_single = str_replace(escaped_double, "`", "\\`"); + char *escaped_single = str_replace(message, "'", "'\\''"); if (escaped_single[0] == '<') { g_string_append(notify_command, "\\<"); @@ -264,8 +271,7 @@ _notify(const char * const message, int timeout, g_string_append(notify_command, escaped_single); } - g_string_append(notify_command, "\""); - free(escaped_double); + g_string_append(notify_command, "'"); free(escaped_single); char *term_name = getenv("TERM_PROGRAM"); @@ -276,7 +282,7 @@ _notify(const char * const message, int timeout, app_id = "com.googlecode.iterm2"; } - if (app_id != NULL) { + if (app_id) { g_string_append(notify_command, " -sender "); g_string_append(notify_command, app_id); } @@ -288,4 +294,4 @@ _notify(const char * const message, int timeout, g_string_free(notify_command, TRUE); #endif -} \ No newline at end of file +} diff --git a/src/ui/occupantswin.c b/src/ui/occupantswin.c index 429c2fdf..bba9d0b9 100644 --- a/src/ui/occupantswin.c +++ b/src/ui/occupantswin.c @@ -1,7 +1,7 @@ /* * occupantswin.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -40,7 +40,7 @@ #include "config/preferences.h" static void -_occuptantswin_occupant(ProfLayoutSplit *layout, Occupant *occupant) +_occuptantswin_occupant(ProfLayoutSplit *layout, Occupant *occupant, gboolean showjid) { const char *presence_str = string_from_resource_presence(occupant->presence); theme_item_t presence_colour = theme_main_presence_attrs(presence_str); @@ -51,6 +51,13 @@ _occuptantswin_occupant(ProfLayoutSplit *layout, Occupant *occupant) win_printline_nowrap(layout->subwin, msg->str); g_string_free(msg, TRUE); + if (showjid && occupant->jid) { + GString *msg = g_string_new(" "); + g_string_append(msg, occupant->jid); + win_printline_nowrap(layout->subwin, msg->str); + g_string_free(msg, TRUE); + } + wattroff(layout->subwin, theme_attrs(presence_colour)); } @@ -74,7 +81,7 @@ occupantswin_occupants(const char * const roomjid) while (roster_curr) { Occupant *occupant = roster_curr->data; if (occupant->role == MUC_ROLE_MODERATOR) { - _occuptantswin_occupant(layout, occupant); + _occuptantswin_occupant(layout, occupant, mucwin->showjid); } roster_curr = g_list_next(roster_curr); } @@ -86,7 +93,7 @@ occupantswin_occupants(const char * const roomjid) while (roster_curr) { Occupant *occupant = roster_curr->data; if (occupant->role == MUC_ROLE_PARTICIPANT) { - _occuptantswin_occupant(layout, occupant); + _occuptantswin_occupant(layout, occupant, mucwin->showjid); } roster_curr = g_list_next(roster_curr); } @@ -98,7 +105,7 @@ occupantswin_occupants(const char * const roomjid) while (roster_curr) { Occupant *occupant = roster_curr->data; if (occupant->role == MUC_ROLE_VISITOR) { - _occuptantswin_occupant(layout, occupant); + _occuptantswin_occupant(layout, occupant, mucwin->showjid); } roster_curr = g_list_next(roster_curr); } @@ -109,7 +116,7 @@ occupantswin_occupants(const char * const roomjid) GList *roster_curr = occupants; while (roster_curr) { Occupant *occupant = roster_curr->data; - _occuptantswin_occupant(layout, occupant); + _occuptantswin_occupant(layout, occupant, mucwin->showjid); roster_curr = g_list_next(roster_curr); } } diff --git a/src/ui/rosterwin.c b/src/ui/rosterwin.c index 828ed429..763490c3 100644 --- a/src/ui/rosterwin.c +++ b/src/ui/rosterwin.c @@ -1,7 +1,7 @@ /* * rosterwin.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/ui/statusbar.c b/src/ui/statusbar.c index 2ef20913..581e63df 100644 --- a/src/ui/statusbar.c +++ b/src/ui/statusbar.c @@ -1,7 +1,7 @@ /* * statusbar.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -48,6 +48,7 @@ #include "ui/ui.h" #include "ui/statusbar.h" #include "ui/inputwin.h" +#include "config/preferences.h" #define TIME_CHECK 60000000 @@ -94,7 +95,7 @@ create_status_bar(void) mvwprintw(status_bar, 0, cols - 34 + ((current - 1) * 3), bracket); wattroff(status_bar, bracket_attrs); - if (last_time != NULL) { + if (last_time) { g_date_time_unref(last_time); } last_time = g_date_time_new_now_local(); @@ -126,10 +127,17 @@ status_bar_resize(void) mvwprintw(status_bar, 0, cols - 34 + ((current - 1) * 3), bracket); wattroff(status_bar, bracket_attrs); - if (message != NULL) { - mvwprintw(status_bar, 0, 10, message); + if (message) { + char *time_pref = prefs_get_string(PREF_TIME_STATUSBAR); + if (g_strcmp0(time_pref, "minutes") == 0) { + mvwprintw(status_bar, 0, 10, message); + } else if (g_strcmp0(time_pref, "seconds") == 0) { + mvwprintw(status_bar, 0, 13, message); + } else { + mvwprintw(status_bar, 0, 1, message); + } } - if (last_time != NULL) { + if (last_time) { g_date_time_unref(last_time); } last_time = g_date_time_new_now_local(); @@ -192,7 +200,7 @@ status_bar_inactive(const int win) is_new[11] = TRUE; _mark_new(11); - // still have active winsows + // still have active windows } else if (g_hash_table_size(remaining_active) != 0) { is_active[11] = TRUE; is_new[11] = FALSE; @@ -241,7 +249,7 @@ status_bar_active(const int win) _mark_active(11); } - // visible winsow indicators + // visible window indicators } else { is_active[true_win] = TRUE; is_new[true_win] = FALSE; @@ -289,11 +297,19 @@ status_bar_print_message(const char * const msg) { werase(status_bar); - if (message != NULL) { + if (message) { free(message); } message = strdup(msg); - mvwprintw(status_bar, 0, 10, message); + + char *time_pref = prefs_get_string(PREF_TIME_STATUSBAR); + if (g_strcmp0(time_pref, "minutes") == 0) { + mvwprintw(status_bar, 0, 10, message); + } else if (g_strcmp0(time_pref, "seconds") == 0) { + mvwprintw(status_bar, 0, 13, message); + } else { + mvwprintw(status_bar, 0, 1, message); + } int cols = getmaxx(stdscr); int bracket_attrs = theme_attrs(THEME_STATUS_BRACKET); @@ -309,7 +325,7 @@ status_bar_print_message(const char * const msg) void status_bar_clear(void) { - if (message != NULL) { + if (message) { free(message); message = NULL; } @@ -330,7 +346,7 @@ status_bar_clear(void) void status_bar_clear_message(void) { - if (message != NULL) { + if (message) { free(message); message = NULL; } @@ -412,23 +428,37 @@ _mark_inactive(int num) static void _status_bar_draw(void) { - if (last_time != NULL) { + if (last_time) { g_date_time_unref(last_time); } last_time = g_date_time_new_now_local(); - gchar *date_fmt = g_date_time_format(last_time, "%H:%M"); - assert(date_fmt != NULL); int bracket_attrs = theme_attrs(THEME_STATUS_BRACKET); - wattron(status_bar, bracket_attrs); - mvwaddch(status_bar, 0, 1, '['); - wattroff(status_bar, bracket_attrs); - mvwprintw(status_bar, 0, 2, date_fmt); - wattron(status_bar, bracket_attrs); - mvwaddch(status_bar, 0, 7, ']'); - wattroff(status_bar, bracket_attrs); - g_free(date_fmt); + char *time_pref = prefs_get_string(PREF_TIME_STATUSBAR); + if (g_strcmp0(time_pref, "minutes") == 0) { + gchar *date_fmt = g_date_time_format(last_time, "%H:%M"); + assert(date_fmt != NULL); + wattron(status_bar, bracket_attrs); + mvwaddch(status_bar, 0, 1, '['); + wattroff(status_bar, bracket_attrs); + mvwprintw(status_bar, 0, 2, date_fmt); + wattron(status_bar, bracket_attrs); + mvwaddch(status_bar, 0, 7, ']'); + wattroff(status_bar, bracket_attrs); + g_free(date_fmt); + } else if (g_strcmp0(time_pref, "seconds") == 0) { + gchar *date_fmt = g_date_time_format(last_time, "%H:%M:%S"); + assert(date_fmt != NULL); + wattron(status_bar, bracket_attrs); + mvwaddch(status_bar, 0, 1, '['); + wattroff(status_bar, bracket_attrs); + mvwprintw(status_bar, 0, 2, date_fmt); + wattron(status_bar, bracket_attrs); + mvwaddch(status_bar, 0, 10, ']'); + wattroff(status_bar, bracket_attrs); + g_free(date_fmt); + } _update_win_statuses(); wnoutrefresh(status_bar); diff --git a/src/ui/statusbar.h b/src/ui/statusbar.h index 5c37867b..7d2c5ea0 100644 --- a/src/ui/statusbar.h +++ b/src/ui/statusbar.h @@ -1,7 +1,7 @@ /* * statusbar.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/ui/titlebar.c b/src/ui/titlebar.c index 326dbf8b..9bb84f9d 100644 --- a/src/ui/titlebar.c +++ b/src/ui/titlebar.c @@ -1,7 +1,7 @@ /* * titlebar.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -80,7 +80,7 @@ title_bar_update_virtual(void) { ProfWin *window = wins_get_current(); if (window->type != WIN_CONSOLE) { - if (typing_elapsed != NULL) { + if (typing_elapsed) { gdouble seconds = g_timer_elapsed(typing_elapsed, NULL); if (seconds >= 10) { @@ -109,8 +109,11 @@ void title_bar_console(void) { werase(win); - typing = FALSE; + if (typing_elapsed) { + g_timer_destroy(typing_elapsed); + } typing_elapsed = NULL; + typing = FALSE; _title_bar_draw(); } @@ -125,7 +128,7 @@ title_bar_set_presence(contact_presence_t presence) void title_bar_switch(void) { - if (typing_elapsed != NULL) { + if (typing_elapsed) { g_timer_destroy(typing_elapsed); typing_elapsed = NULL; typing = FALSE; @@ -138,7 +141,7 @@ void title_bar_set_typing(gboolean is_typing) { if (is_typing) { - if (typing_elapsed != NULL) { + if (typing_elapsed) { g_timer_start(typing_elapsed); } else { typing_elapsed = g_timer_new(); @@ -249,7 +252,7 @@ _show_privacy(ProfChatWin *chatwin) { int bracket_attrs = theme_attrs(THEME_TITLE_BRACKET); - if (!chatwin->is_otr) { + if (chatwin->enc_mode == PROF_ENC_NONE) { if (prefs_get_boolean(PREF_OTR_WARN)) { int unencrypted_attrs = theme_attrs(THEME_TITLE_UNENCRYPTED); wprintw(win, " "); diff --git a/src/ui/titlebar.h b/src/ui/titlebar.h index 08a56514..66237f86 100644 --- a/src/ui/titlebar.h +++ b/src/ui/titlebar.h @@ -1,7 +1,7 @@ /* * titlebar.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/ui/ui.h b/src/ui/ui.h index 99e73b4a..0ee21be4 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -1,7 +1,7 @@ /* * ui.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -59,9 +59,8 @@ void ui_close(void); void ui_redraw(void); void ui_resize(void); GSList* ui_get_chat_recipients(void); -gboolean ui_switch_win(const int i); -void ui_next_win(void); -void ui_previous_win(void); +void ui_switch_win(ProfWin *window); +void ui_sigwinch_handler(int sig); void ui_gone_secure(const char * const barejid, gboolean trusted); void ui_gone_insecure(const char * const barejid); @@ -81,10 +80,12 @@ void ui_smp_answer_failure(const char * const barejid); void ui_otr_authenticating(const char * const barejid); void ui_otr_authetication_waiting(const char * const recipient); +void ui_handle_otr_error(const char * const barejid, const char * const message); + unsigned long ui_get_idle_time(void); void ui_reset_idle_time(void); -void ui_new_chat_win(const char * const barejid); -void ui_new_private_win(const char * const fulljid); +ProfPrivateWin* ui_new_private_win(const char * const fulljid); +ProfChatWin* ui_new_chat_win(const char * const barejid); void ui_print_system_msg_from_recipient(const char * const barejid, const char *message); gint ui_unread(void); void ui_close_connected_win(int index); @@ -94,7 +95,6 @@ int ui_close_read_wins(void); // current window actions void ui_clear_current(void); win_type_t ui_current_win_type(void); -int ui_current_win_index(void); gboolean ui_current_win_is_otr(void); ProfChatWin *ui_get_current_chat(void); @@ -102,27 +102,28 @@ ProfChatWin *ui_get_current_chat(void); void ui_current_print_line(const char * const msg, ...); void ui_current_print_formatted_line(const char show_char, int attrs, const char * const msg, ...); void ui_current_error_line(const char * const msg); +void ui_win_error_line(ProfWin *window, const char * const msg); win_type_t ui_win_type(int index); void ui_close_win(int index); -gboolean ui_win_exists(int index); int ui_win_unread(int index); char * ui_ask_password(void); void ui_handle_stanza(const char * const msg); // ui events +void ui_contact_online(char *barejid, Resource *resource, GDateTime *last_activity); void ui_contact_typing(const char * const barejid, const char * const resource); void ui_incoming_msg(const char * const from, const char * const resource, const char * const message, GTimeVal *tv_stamp); void ui_incoming_private_msg(const char * const fulljid, const char * const message, GTimeVal *tv_stamp); +void ui_message_receipt(const char * const barejid, const char * const id); void ui_disconnected(void); void ui_recipient_gone(const char * const barejid, const char * const resource); -void ui_outgoing_chat_msg(const char * const from, const char * const barejid, - const char * const message); -void ui_outgoing_private_msg(const char * const from, const char * const fulljid, - const char * const message); +void ui_outgoing_chat_msg(ProfChatWin *chatwin, const char * const message, char *id); +void ui_outgoing_chat_msg_carbon(const char * const barejid, const char * const message); +void ui_outgoing_private_msg(ProfPrivateWin *privwin, const char * const message); void ui_room_join(const char * const roomjid, gboolean focus); void ui_switch_to_room(const char * const roomjid); @@ -171,6 +172,7 @@ void ui_room_member_nick_change(const char * const roomjid, void ui_room_nick_change(const char * const roomjid, const char * const nick); void ui_room_member_presence(const char * const roomjid, const char * const nick, const char * const show, const char * const status); +void ui_room_update_occupants(const char * const roomjid); void ui_room_show_occupants(const char * const roomjid); void ui_room_hide_occupants(const char * const roomjid); void ui_show_roster(void); @@ -218,6 +220,11 @@ void ui_tidy_wins(void); void ui_prune_wins(void); gboolean ui_swap_wins(int source_win, int target_win); +void ui_page_up(void); +void ui_page_down(void); +void ui_subwin_page_up(void); +void ui_subwin_page_down(void); + void ui_auto_away(void); void ui_end_auto_away(void); void ui_titlebar_presence(contact_presence_t presence); @@ -227,9 +234,10 @@ void ui_update_presence(const resource_presence_t resource_presence, void ui_about(void); void ui_statusbar_new(const int win); -char * ui_readline(void); +char* ui_readline(void); void ui_input_clear(void); void ui_input_nonblocking(gboolean); +void ui_write(char *line, int offset); void ui_invalid_command_usage(const char * const usage, void (*setting_func)(void)); @@ -308,6 +316,8 @@ void cons_outtype_setting(void); void cons_intype_setting(void); void cons_gone_setting(void); void cons_history_setting(void); +void cons_carbons_setting(void); +void cons_receipts_setting(void); void cons_log_setting(void); void cons_chlog_setting(void); void cons_grlog_setting(void); @@ -332,7 +342,7 @@ void notifier_initialise(void); void notifier_uninit(void); void notify_typing(const char * const handle); -void notify_message(const char * const handle, int win, const char * const text); +void notify_message(ProfWin *window, const char * const name, const char * const text); void notify_room_message(const char * const handle, const char * const room, int win, const char * const text); void notify_remind(void); diff --git a/src/ui/window.c b/src/ui/window.c index 7757fe39..d2462a61 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -1,7 +1,7 @@ /* * window.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -38,6 +38,7 @@ #include <string.h> #include <time.h> #include <assert.h> +#include <wchar.h> #include <glib.h> #ifdef HAVE_NCURSESW_NCURSES_H @@ -59,7 +60,7 @@ #define CEILING(X) (X-(int)(X) > 0 ? (int)(X+1) : (int)(X)) static void _win_print(ProfWin *window, const char show_char, GDateTime *time, - int flags, theme_item_t theme_item, const char * const from, const char * const message); + int flags, theme_item_t theme_item, const char * const from, const char * const message, DeliveryReceipt *receipt); static void _win_print_wrapped(WINDOW *win, const char * const message); int @@ -134,7 +135,7 @@ win_create_chat(const char * const barejid) new_win->barejid = strdup(barejid); new_win->resource_override = NULL; - new_win->is_otr = FALSE; + new_win->enc_mode = PROF_ENC_NONE; new_win->is_trusted = FALSE; new_win->history_shown = FALSE; new_win->unread = 0; @@ -177,6 +178,11 @@ win_create_muc(const char * const roomjid) new_win->roomjid = strdup(roomjid); new_win->unread = 0; + if (prefs_get_boolean(PREF_OCCUPANTS_JID)) { + new_win->showjid = TRUE; + } else { + new_win->showjid = FALSE; + } new_win->memcheck = PROFMUCWIN_MEMCHECK; @@ -331,12 +337,13 @@ win_free(ProfWin* window) buffer_free(window->layout->buffer); delwin(window->layout->win); } + free(window->layout); if (window->type == WIN_CHAT) { ProfChatWin *chatwin = (ProfChatWin*)window; free(chatwin->barejid); free(chatwin->resource_override); - free(chatwin->state); + chat_state_free(chatwin->state); } if (window->type == WIN_MUC) { @@ -359,7 +366,101 @@ win_free(ProfWin* window) } void -win_handle_page(ProfWin *window, const wint_t ch, const int result) +win_page_up(ProfWin *window) +{ + int rows = getmaxy(stdscr); + int y = getcury(window->layout->win); + int page_space = rows - 4; + int *page_start = &(window->layout->y_pos); + + *page_start -= page_space; + + // went past beginning, show first page + if (*page_start < 0) + *page_start = 0; + + window->layout->paged = 1; + win_update_virtual(window); + + // switch off page if last line and space line visible + if ((y) - *page_start == page_space) { + window->layout->paged = 0; + } +} + +void +win_page_down(ProfWin *window) +{ + int rows = getmaxy(stdscr); + int y = getcury(window->layout->win); + int page_space = rows - 4; + int *page_start = &(window->layout->y_pos); + + *page_start += page_space; + + // only got half a screen, show full screen + if ((y - (*page_start)) < page_space) + *page_start = y - page_space; + + // went past end, show full screen + else if (*page_start >= y) + *page_start = y - page_space - 1; + + window->layout->paged = 1; + win_update_virtual(window); + + // switch off page if last line and space line visible + if ((y) - *page_start == page_space) { + window->layout->paged = 0; + } +} + +void +win_sub_page_down(ProfWin *window) +{ + + if (window->layout->type == LAYOUT_SPLIT) { + int rows = getmaxy(stdscr); + int page_space = rows - 4; + ProfLayoutSplit *split_layout = (ProfLayoutSplit*)window->layout; + int sub_y = getcury(split_layout->subwin); + int *sub_y_pos = &(split_layout->sub_y_pos); + + *sub_y_pos += page_space; + + // only got half a screen, show full screen + if ((sub_y- (*sub_y_pos)) < page_space) + *sub_y_pos = sub_y - page_space; + + // went past end, show full screen + else if (*sub_y_pos >= sub_y) + *sub_y_pos = sub_y - page_space - 1; + + win_update_virtual(window); + } +} + +void +win_sub_page_up(ProfWin *window) +{ + if (window->layout->type == LAYOUT_SPLIT) { + int rows = getmaxy(stdscr); + int page_space = rows - 4; + ProfLayoutSplit *split_layout = (ProfLayoutSplit*)window->layout; + int *sub_y_pos = &(split_layout->sub_y_pos); + + *sub_y_pos -= page_space; + + // went past beginning, show first page + if (*sub_y_pos < 0) + *sub_y_pos = 0; + + win_update_virtual(window); + } +} + +void +win_mouse(ProfWin *window, const wint_t ch, const int result) { int rows = getmaxy(stdscr); int y = getcury(window->layout->win); @@ -403,69 +504,6 @@ win_handle_page(ProfWin *window, const wint_t ch, const int result) } } } - - // page up - if (ch == KEY_PPAGE) { - *page_start -= page_space; - - // went past beginning, show first page - if (*page_start < 0) - *page_start = 0; - - window->layout->paged = 1; - win_update_virtual(window); - - // page down - } else if (ch == KEY_NPAGE) { - *page_start += page_space; - - // only got half a screen, show full screen - if ((y - (*page_start)) < page_space) - *page_start = y - page_space; - - // went past end, show full screen - else if (*page_start >= y) - *page_start = y - page_space - 1; - - window->layout->paged = 1; - win_update_virtual(window); - } - - // switch off page if last line and space line visible - if ((y) - *page_start == page_space) { - window->layout->paged = 0; - } - - if (window->layout->type == LAYOUT_SPLIT) { - ProfLayoutSplit *split_layout = (ProfLayoutSplit*)window->layout; - int sub_y = getcury(split_layout->subwin); - int *sub_y_pos = &(split_layout->sub_y_pos); - - // alt up arrow - if ((result == KEY_CODE_YES) && ((ch == 565) || (ch == 337))) { - *sub_y_pos -= page_space; - - // went past beginning, show first page - if (*sub_y_pos < 0) - *sub_y_pos = 0; - - win_update_virtual(window); - - // alt down arrow - } else if ((result == KEY_CODE_YES) && ((ch == 524) || (ch == 336))) { - *sub_y_pos += page_space; - - // only got half a screen, show full screen - if ((sub_y- (*sub_y_pos)) < page_space) - *sub_y_pos = sub_y - page_space; - - // went past end, show full screen - else if (*sub_y_pos >= sub_y) - *sub_y_pos = sub_y - page_space - 1; - - win_update_virtual(window); - } - } } void @@ -515,14 +553,14 @@ win_show_occupant(ProfWin *window, Occupant *occupant) theme_item_t presence_colour = theme_main_presence_attrs(presence_str); - win_save_print(window, '-', NULL, NO_EOL, presence_colour, "", occupant->nick); - win_save_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", " is %s", presence_str); + win_print(window, '-', NULL, NO_EOL, presence_colour, "", occupant->nick); + win_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", " is %s", presence_str); if (occupant->status) { - win_save_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", ", \"%s\"", occupant->status); + win_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", ", \"%s\"", occupant->status); } - win_save_print(window, '-', NULL, NO_DATE, presence_colour, "", ""); + win_print(window, '-', NULL, NO_DATE, presence_colour, "", ""); } void @@ -536,15 +574,15 @@ win_show_contact(ProfWin *window, PContact contact) theme_item_t presence_colour = theme_main_presence_attrs(presence); - if (name != NULL) { - win_save_print(window, '-', NULL, NO_EOL, presence_colour, "", name); + if (name) { + win_print(window, '-', NULL, NO_EOL, presence_colour, "", name); } else { - win_save_print(window, '-', NULL, NO_EOL, presence_colour, "", barejid); + win_print(window, '-', NULL, NO_EOL, presence_colour, "", barejid); } - win_save_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", " is %s", presence); + win_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", " is %s", presence); - if (last_activity != NULL) { + if (last_activity) { GDateTime *now = g_date_time_new_now_local(); GTimeSpan span = g_date_time_difference(now, last_activity); @@ -555,18 +593,18 @@ win_show_contact(ProfWin *window, PContact contact) int seconds = span / G_TIME_SPAN_SECOND; if (hours > 0) { - win_save_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", ", idle %dh%dm%ds", hours, minutes, seconds); + win_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", ", idle %dh%dm%ds", hours, minutes, seconds); } else { - win_save_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", ", idle %dm%ds", minutes, seconds); + win_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", ", idle %dm%ds", minutes, seconds); } } - if (status != NULL) { - win_save_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", ", \"%s\"", p_contact_status(contact)); + if (status) { + win_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", ", \"%s\"", p_contact_status(contact)); } - win_save_print(window, '-', NULL, NO_DATE, presence_colour, "", ""); + win_print(window, '-', NULL, NO_DATE, presence_colour, "", ""); } void @@ -578,21 +616,21 @@ win_show_occupant_info(ProfWin *window, const char * const room, Occupant *occup theme_item_t presence_colour = theme_main_presence_attrs(presence_str); - win_save_print(window, '!', NULL, NO_EOL, presence_colour, "", occupant->nick); - win_save_vprint(window, '!', NULL, NO_DATE | NO_EOL, presence_colour, "", " is %s", presence_str); + win_print(window, '!', NULL, NO_EOL, presence_colour, "", occupant->nick); + win_vprint(window, '!', NULL, NO_DATE | NO_EOL, presence_colour, "", " is %s", presence_str); if (occupant->status) { - win_save_vprint(window, '!', NULL, NO_DATE | NO_EOL, presence_colour, "", ", \"%s\"", occupant->status); + win_vprint(window, '!', NULL, NO_DATE | NO_EOL, presence_colour, "", ", \"%s\"", occupant->status); } - win_save_newline(window); + win_newline(window); if (occupant->jid) { - win_save_vprint(window, '!', NULL, 0, 0, "", " Jid: %s", occupant->jid); + win_vprint(window, '!', NULL, 0, 0, "", " Jid: %s", occupant->jid); } - win_save_vprint(window, '!', NULL, 0, 0, "", " Affiliation: %s", occupant_affiliation); - win_save_vprint(window, '!', NULL, 0, 0, "", " Role: %s", occupant_role); + win_vprint(window, '!', NULL, 0, 0, "", " Affiliation: %s", occupant_affiliation); + win_vprint(window, '!', NULL, 0, 0, "", " Role: %s", occupant_role); Jid *jidp = jid_create_from_bare_and_resource(room, occupant->nick); Capabilities *caps = caps_lookup(jidp->fulljid); @@ -600,47 +638,47 @@ win_show_occupant_info(ProfWin *window, const char * const room, Occupant *occup if (caps) { // show identity - if ((caps->category != NULL) || (caps->type != NULL) || (caps->name != NULL)) { - win_save_print(window, '!', NULL, NO_EOL, 0, "", " Identity: "); - if (caps->name != NULL) { - win_save_print(window, '!', NULL, NO_DATE | NO_EOL, 0, "", caps->name); - if ((caps->category != NULL) || (caps->type != NULL)) { - win_save_print(window, '-', NULL, NO_DATE | NO_EOL, 0, "", " "); + if (caps->category || caps->type || caps->name) { + win_print(window, '!', NULL, NO_EOL, 0, "", " Identity: "); + if (caps->name) { + win_print(window, '!', NULL, NO_DATE | NO_EOL, 0, "", caps->name); + if (caps->category || caps->type) { + win_print(window, '-', NULL, NO_DATE | NO_EOL, 0, "", " "); } } - if (caps->type != NULL) { - win_save_print(window, '!', NULL, NO_DATE | NO_EOL, 0, "", caps->type); - if (caps->category != NULL) { - win_save_print(window, '!', NULL, NO_DATE | NO_EOL, 0, "", " "); + if (caps->type) { + win_print(window, '!', NULL, NO_DATE | NO_EOL, 0, "", caps->type); + if (caps->category) { + win_print(window, '!', NULL, NO_DATE | NO_EOL, 0, "", " "); } } - if (caps->category != NULL) { - win_save_print(window, '!', NULL, NO_DATE | NO_EOL, 0, "", caps->category); + if (caps->category) { + win_print(window, '!', NULL, NO_DATE | NO_EOL, 0, "", caps->category); } - win_save_newline(window); + win_newline(window); } - if (caps->software != NULL) { - win_save_vprint(window, '!', NULL, NO_EOL, 0, "", " Software: %s", caps->software); + if (caps->software) { + win_vprint(window, '!', NULL, NO_EOL, 0, "", " Software: %s", caps->software); } - if (caps->software_version != NULL) { - win_save_vprint(window, '!', NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->software_version); + if (caps->software_version) { + win_vprint(window, '!', NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->software_version); } - if ((caps->software != NULL) || (caps->software_version != NULL)) { - win_save_newline(window); + if (caps->software || caps->software_version) { + win_newline(window); } - if (caps->os != NULL) { - win_save_vprint(window, '!', NULL, NO_EOL, 0, "", " OS: %s", caps->os); + if (caps->os) { + win_vprint(window, '!', NULL, NO_EOL, 0, "", " OS: %s", caps->os); } - if (caps->os_version != NULL) { - win_save_vprint(window, '!', NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->os_version); + if (caps->os_version) { + win_vprint(window, '!', NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->os_version); } - if ((caps->os != NULL) || (caps->os_version != NULL)) { - win_save_newline(window); + if (caps->os || caps->os_version) { + win_newline(window); } caps_destroy(caps); } - win_save_print(window, '-', NULL, 0, 0, "", ""); + win_print(window, '-', NULL, 0, 0, "", ""); } void @@ -650,24 +688,22 @@ win_show_info(ProfWin *window, PContact contact) const char *name = p_contact_name(contact); const char *presence = p_contact_presence(contact); const char *sub = p_contact_subscription(contact); - GList *resources = p_contact_get_available_resources(contact); - GList *ordered_resources = NULL; GDateTime *last_activity = p_contact_last_activity(contact); theme_item_t presence_colour = theme_main_presence_attrs(presence); - win_save_print(window, '-', NULL, 0, 0, "", ""); - win_save_print(window, '-', NULL, NO_EOL, presence_colour, "", barejid); - if (name != NULL) { - win_save_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", " (%s)", name); + win_print(window, '-', NULL, 0, 0, "", ""); + win_print(window, '-', NULL, NO_EOL, presence_colour, "", barejid); + if (name) { + win_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", " (%s)", name); } - win_save_print(window, '-', NULL, NO_DATE, 0, "", ":"); + win_print(window, '-', NULL, NO_DATE, 0, "", ":"); - if (sub != NULL) { - win_save_vprint(window, '-', NULL, 0, 0, "", "Subscription: %s", sub); + if (sub) { + win_vprint(window, '-', NULL, 0, 0, "", "Subscription: %s", sub); } - if (last_activity != NULL) { + if (last_activity) { GDateTime *now = g_date_time_new_now_local(); GTimeSpan span = g_date_time_difference(now, last_activity); @@ -678,36 +714,41 @@ win_show_info(ProfWin *window, PContact contact) int seconds = span / G_TIME_SPAN_SECOND; if (hours > 0) { - win_save_vprint(window, '-', NULL, 0, 0, "", "Last activity: %dh%dm%ds", hours, minutes, seconds); + win_vprint(window, '-', NULL, 0, 0, "", "Last activity: %dh%dm%ds", hours, minutes, seconds); } else { - win_save_vprint(window, '-', NULL, 0, 0, "", "Last activity: %dm%ds", minutes, seconds); + win_vprint(window, '-', NULL, 0, 0, "", "Last activity: %dm%ds", minutes, seconds); } g_date_time_unref(now); } - if (resources != NULL) { - win_save_print(window, '-', NULL, 0, 0, "", "Resources:"); + GList *resources = p_contact_get_available_resources(contact); + GList *ordered_resources = NULL; + if (resources) { + win_print(window, '-', NULL, 0, 0, "", "Resources:"); - // sort in order of availabiltiy - while (resources != NULL) { - Resource *resource = resources->data; + // sort in order of availability + GList *curr = resources; + while (curr) { + Resource *resource = curr->data; ordered_resources = g_list_insert_sorted(ordered_resources, resource, (GCompareFunc)resource_compare_availability); - resources = g_list_next(resources); + curr = g_list_next(curr); } } + g_list_free(resources); - while (ordered_resources != NULL) { - Resource *resource = ordered_resources->data; + GList *curr = ordered_resources; + while (curr) { + Resource *resource = curr->data; const char *resource_presence = string_from_resource_presence(resource->presence); theme_item_t presence_colour = theme_main_presence_attrs(resource_presence); - win_save_vprint(window, '-', NULL, NO_EOL, presence_colour, "", " %s (%d), %s", resource->name, resource->priority, resource_presence); - if (resource->status != NULL) { - win_save_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", ", \"%s\"", resource->status); + win_vprint(window, '-', NULL, NO_EOL, presence_colour, "", " %s (%d), %s", resource->name, resource->priority, resource_presence); + if (resource->status) { + win_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", ", \"%s\"", resource->status); } - win_save_newline(window); + win_newline(window); Jid *jidp = jid_create_from_bare_and_resource(barejid, resource->name); Capabilities *caps = caps_lookup(jidp->fulljid); @@ -715,48 +756,49 @@ win_show_info(ProfWin *window, PContact contact) if (caps) { // show identity - if ((caps->category != NULL) || (caps->type != NULL) || (caps->name != NULL)) { - win_save_print(window, '-', NULL, NO_EOL, 0, "", " Identity: "); - if (caps->name != NULL) { - win_save_print(window, '-', NULL, NO_DATE | NO_EOL, 0, "", caps->name); - if ((caps->category != NULL) || (caps->type != NULL)) { - win_save_print(window, '-', NULL, NO_DATE | NO_EOL, 0, "", " "); + if (caps->category || caps->type || caps->name) { + win_print(window, '-', NULL, NO_EOL, 0, "", " Identity: "); + if (caps->name) { + win_print(window, '-', NULL, NO_DATE | NO_EOL, 0, "", caps->name); + if (caps->category || caps->type) { + win_print(window, '-', NULL, NO_DATE | NO_EOL, 0, "", " "); } } - if (caps->type != NULL) { - win_save_print(window, '-', NULL, NO_DATE | NO_EOL, 0, "", caps->type); - if (caps->category != NULL) { - win_save_print(window, '-', NULL, NO_DATE | NO_EOL, 0, "", " "); + if (caps->type) { + win_print(window, '-', NULL, NO_DATE | NO_EOL, 0, "", caps->type); + if (caps->category) { + win_print(window, '-', NULL, NO_DATE | NO_EOL, 0, "", " "); } } - if (caps->category != NULL) { - win_save_print(window, '-', NULL, NO_DATE | NO_EOL, 0, "", caps->category); + if (caps->category) { + win_print(window, '-', NULL, NO_DATE | NO_EOL, 0, "", caps->category); } - win_save_newline(window); + win_newline(window); } - if (caps->software != NULL) { - win_save_vprint(window, '-', NULL, NO_EOL, 0, "", " Software: %s", caps->software); + if (caps->software) { + win_vprint(window, '-', NULL, NO_EOL, 0, "", " Software: %s", caps->software); } - if (caps->software_version != NULL) { - win_save_vprint(window, '-', NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->software_version); + if (caps->software_version) { + win_vprint(window, '-', NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->software_version); } - if ((caps->software != NULL) || (caps->software_version != NULL)) { - win_save_newline(window); + if (caps->software || caps->software_version) { + win_newline(window); } - if (caps->os != NULL) { - win_save_vprint(window, '-', NULL, NO_EOL, 0, "", " OS: %s", caps->os); + if (caps->os) { + win_vprint(window, '-', NULL, NO_EOL, 0, "", " OS: %s", caps->os); } - if (caps->os_version != NULL) { - win_save_vprint(window, '-', NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->os_version); + if (caps->os_version) { + win_vprint(window, '-', NULL, NO_DATE | NO_EOL, 0, "", ", %s", caps->os_version); } - if ((caps->os != NULL) || (caps->os_version != NULL)) { - win_save_newline(window); + if (caps->os || caps->os_version) { + win_newline(window); } caps_destroy(caps); } - ordered_resources = g_list_next(ordered_resources); + curr = g_list_next(curr); } + g_list_free(ordered_resources); } void @@ -767,7 +809,7 @@ win_show_status_string(ProfWin *window, const char * const from, { theme_item_t presence_colour; - if (show != NULL) { + if (show) { presence_colour = theme_main_presence_attrs(show); } else if (strcmp(default_show, "online") == 0) { presence_colour = THEME_ONLINE; @@ -776,14 +818,14 @@ win_show_status_string(ProfWin *window, const char * const from, } - win_save_vprint(window, '-', NULL, NO_EOL, presence_colour, "", "%s %s", pre, from); + win_vprint(window, '-', NULL, NO_EOL, presence_colour, "", "%s %s", pre, from); - if (show != NULL) - win_save_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", " is %s", show); + if (show) + win_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", " is %s", show); else - win_save_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", " is %s", default_show); + win_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", " is %s", default_show); - if (last_activity != NULL) { + if (last_activity) { GDateTime *now = g_date_time_new_now_local(); GTimeSpan span = g_date_time_difference(now, last_activity); g_date_time_unref(now); @@ -795,17 +837,17 @@ win_show_status_string(ProfWin *window, const char * const from, int seconds = span / G_TIME_SPAN_SECOND; if (hours > 0) { - win_save_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", ", idle %dh%dm%ds", hours, minutes, seconds); + win_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", ", idle %dh%dm%ds", hours, minutes, seconds); } else { - win_save_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", ", idle %dm%ds", minutes, seconds); + win_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", ", idle %dm%ds", minutes, seconds); } } - if (status != NULL) - win_save_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", ", \"%s\"", status); + if (status) + win_vprint(window, '-', NULL, NO_DATE | NO_EOL, presence_colour, "", ", \"%s\"", status); - win_save_print(window, '-', NULL, NO_DATE, presence_colour, "", ""); + win_print(window, '-', NULL, NO_DATE, presence_colour, "", ""); } @@ -817,7 +859,7 @@ win_print_incoming_message(ProfWin *window, GTimeVal *tv_stamp, { case WIN_CHAT: case WIN_PRIVATE: - win_save_print(window, '-', tv_stamp, NO_ME, THEME_TEXT_THEM, from, message); + win_print(window, '-', tv_stamp, NO_ME, THEME_TEXT_THEM, from, message); break; default: assert(FALSE); @@ -826,19 +868,19 @@ win_print_incoming_message(ProfWin *window, GTimeVal *tv_stamp, } void -win_save_vprint(ProfWin *window, const char show_char, GTimeVal *tstamp, +win_vprint(ProfWin *window, const char show_char, GTimeVal *tstamp, int flags, theme_item_t theme_item, const char * const from, const char * const message, ...) { va_list arg; va_start(arg, message); GString *fmt_msg = g_string_new(NULL); g_string_vprintf(fmt_msg, message, arg); - win_save_print(window, show_char, tstamp, flags, theme_item, from, fmt_msg->str); + win_print(window, show_char, tstamp, flags, theme_item, from, fmt_msg->str); g_string_free(fmt_msg, TRUE); } void -win_save_print(ProfWin *window, const char show_char, GTimeVal *tstamp, +win_print(ProfWin *window, const char show_char, GTimeVal *tstamp, int flags, theme_item_t theme_item, const char * const from, const char * const message) { GDateTime *time; @@ -849,27 +891,58 @@ win_save_print(ProfWin *window, const char show_char, GTimeVal *tstamp, time = g_date_time_new_from_timeval_utc(tstamp); } - buffer_push(window->layout->buffer, show_char, time, flags, theme_item, from, message); - _win_print(window, show_char, time, flags, theme_item, from, message); + buffer_push(window->layout->buffer, show_char, time, flags, theme_item, from, message, NULL); + _win_print(window, show_char, time, flags, theme_item, from, message, NULL); + // TODO: cross-reference.. this should be replaced by a real event-based system + ui_input_nonblocking(TRUE); +} + +void +win_print_with_receipt(ProfWin *window, const char show_char, GTimeVal *tstamp, + int flags, theme_item_t theme_item, const char * const from, const char * const message, char *id) +{ + GDateTime *time; + + if (tstamp == NULL) { + time = g_date_time_new_now_local(); + } else { + time = g_date_time_new_from_timeval_utc(tstamp); + } + + DeliveryReceipt *receipt = malloc(sizeof(struct delivery_receipt_t)); + receipt->id = strdup(id); + receipt->received = FALSE; + + buffer_push(window->layout->buffer, show_char, time, flags, theme_item, from, message, receipt); + _win_print(window, show_char, time, flags, theme_item, from, message, receipt); // TODO: cross-reference.. this should be replaced by a real event-based system ui_input_nonblocking(TRUE); } void -win_save_println(ProfWin *window, const char * const message) +win_mark_received(ProfWin *window, const char * const id) +{ + gboolean received = buffer_mark_received(window->layout->buffer, id); + if (received) { + win_redraw(window); + } +} + +void +win_println(ProfWin *window, const char * const message) { - win_save_print(window, '-', NULL, 0, 0, "", message); + win_print(window, '-', NULL, 0, 0, "", message); } void -win_save_newline(ProfWin *window) +win_newline(ProfWin *window) { - win_save_print(window, '-', NULL, NO_DATE, 0, "", ""); + win_print(window, '-', NULL, NO_DATE, 0, "", ""); } static void _win_print(ProfWin *window, const char show_char, GDateTime *time, - int flags, theme_item_t theme_item, const char * const from, const char * const message) + int flags, theme_item_t theme_item, const char * const from, const char * const message, DeliveryReceipt *receipt) { // flags : 1st bit = 0/1 - me/not me // 2nd bit = 0/1 - date/no date @@ -907,6 +980,10 @@ _win_print(ProfWin *window, const char show_char, GDateTime *time, colour = 0; } + if (receipt && !receipt->received) { + colour = theme_attrs(THEME_RECEIPT_SENT); + } + wattron(window->layout->win, colour); if (strncmp(message, "/me ", 4) == 0) { wprintw(window->layout->win, "*%s ", from); @@ -919,7 +996,11 @@ _win_print(ProfWin *window, const char show_char, GDateTime *time, } if (!me_message) { - wattron(window->layout->win, theme_attrs(theme_item)); + if (receipt && !receipt->received) { + wattron(window->layout->win, theme_attrs(THEME_RECEIPT_SENT)); + } else { + wattron(window->layout->win, theme_attrs(theme_item)); + } } if (prefs_get_boolean(PREF_WRAP)) { @@ -935,7 +1016,11 @@ _win_print(ProfWin *window, const char show_char, GDateTime *time, if (me_message) { wattroff(window->layout->win, colour); } else { - wattroff(window->layout->win, theme_attrs(theme_item)); + if (receipt && !receipt->received) { + wattroff(window->layout->win, theme_attrs(THEME_RECEIPT_SENT)); + } else { + wattroff(window->layout->win, theme_attrs(theme_item)); + } } } @@ -951,7 +1036,6 @@ _win_indent(WINDOW *win, int size) static void _win_print_wrapped(WINDOW *win, const char * const message) { - int linei = 0; int wordi = 0; char *word = malloc(strlen(message) + 1); @@ -964,18 +1048,26 @@ _win_print_wrapped(WINDOW *win, const char * const message) } free(time_pref); - while (message[linei] != '\0') { - if (message[linei] == ' ') { + gchar *curr_ch = g_utf8_offset_to_pointer(message, 0); + + while (*curr_ch != '\0') { + if (*curr_ch == ' ') { waddch(win, ' '); - linei++; - } else if (message[linei] == '\n') { + curr_ch = g_utf8_next_char(curr_ch); + } else if (*curr_ch == '\n') { waddch(win, '\n'); _win_indent(win, indent); - linei++; + curr_ch = g_utf8_next_char(curr_ch); } else { + // get word wordi = 0; - while (message[linei] != ' ' && message[linei] != '\n' && message[linei] != '\0') { - word[wordi++] = message[linei++]; + while (*curr_ch != ' ' && *curr_ch != '\n' && *curr_ch != '\0') { + size_t ch_len = mbrlen(curr_ch, 4, NULL); + int offset = 0; + while (offset < ch_len) { + word[wordi++] = curr_ch[offset++]; + } + curr_ch = g_utf8_next_char(curr_ch); } word[wordi] = '\0'; @@ -983,17 +1075,27 @@ _win_print_wrapped(WINDOW *win, const char * const message) int maxx = getmaxx(win); // word larger than line - if (strlen(word) > (maxx - indent)) { - int i; - for (i = 0; i < wordi; i++) { + if (utf8_display_len(word) > (maxx - indent)) { + gchar *word_ch = g_utf8_offset_to_pointer(word, 0); + while(*word_ch != '\0') { curx = getcurx(win); if (curx < indent) { _win_indent(win, indent); } - waddch(win, word[i]); + + gchar copy[wordi++]; + g_utf8_strncpy(copy, word_ch, 1); + + if (curx + utf8_display_len(copy) > maxx) { + waddch(win, '\n'); + _win_indent(win, indent); + } + waddstr(win, copy); + + word_ch = g_utf8_next_char(word_ch); } } else { - if (curx + strlen(word) > maxx) { + if (curx + utf8_display_len(word) > maxx) { waddch(win, '\n'); _win_indent(win, indent); } @@ -1017,7 +1119,7 @@ win_redraw(ProfWin *window) for (i = 0; i < size; i++) { ProfBuffEntry *e = buffer_yield_entry(window->layout->buffer, i); - _win_print(window, e->show_char, e->time, e->flags, e->theme_item, e->from, e->message); + _win_print(window, e->show_char, e->time, e->flags, e->theme_item, e->from, e->message, e->receipt); } } diff --git a/src/ui/window.h b/src/ui/window.h index fd10a1d7..d5e57971 100644 --- a/src/ui/window.h +++ b/src/ui/window.h @@ -1,7 +1,7 @@ /* * window.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -99,6 +99,11 @@ typedef enum { WIN_XML } win_type_t; +typedef enum { + PROF_ENC_NONE, + PROF_ENC_OTR +} prof_enc_t; + typedef struct prof_win_t { win_type_t type; ProfLayout *layout; @@ -113,7 +118,7 @@ typedef struct prof_chat_win_t { char *barejid; int unread; ChatState *state; - gboolean is_otr; + prof_enc_t enc_mode; gboolean is_trusted; char *resource_override; gboolean history_shown; @@ -124,6 +129,7 @@ typedef struct prof_muc_win_t { ProfWin window; char *roomjid; int unread; + gboolean showjid; unsigned long memcheck; } ProfMucWin; @@ -168,19 +174,27 @@ void win_print_incoming_message(ProfWin *window, GTimeVal *tv_stamp, const char * const from, const char * const message); void win_show_info(ProfWin *window, PContact contact); void win_show_occupant_info(ProfWin *window, const char * const room, Occupant *occupant); -void win_save_vprint(ProfWin *window, const char show_char, GTimeVal *tstamp, int flags, theme_item_t theme_item, const char * const from, const char * const message, ...); -void win_save_print(ProfWin *window, const char show_char, GTimeVal *tstamp, int flags, theme_item_t theme_item, const char * const from, const char * const message); -void win_save_println(ProfWin *window, const char * const message); -void win_save_newline(ProfWin *window); +void win_vprint(ProfWin *window, const char show_char, GTimeVal *tstamp, int flags, theme_item_t theme_item, const char * const from, const char * const message, ...); +void win_print(ProfWin *window, const char show_char, GTimeVal *tstamp, int flags, theme_item_t theme_item, const char * const from, const char * const message); +void win_print_with_receipt(ProfWin *window, const char show_char, GTimeVal *tstamp, int flags, + theme_item_t theme_item, const char * const from, const char * const message, char *id); +void win_println(ProfWin *window, const char * const message); +void win_newline(ProfWin *window); void win_redraw(ProfWin *window); void win_hide_subwin(ProfWin *window); void win_show_subwin(ProfWin *window); int win_roster_cols(void); int win_occpuants_cols(void); void win_printline_nowrap(WINDOW *win, char *msg); -void win_handle_page(ProfWin *current, const wint_t ch, const int result); +void win_mouse(ProfWin *current, const wint_t ch, const int result); +void win_mark_received(ProfWin *window, const char * const id); int win_unread(ProfWin *window); gboolean win_has_active_subwin(ProfWin *window); +void win_page_up(ProfWin *window); +void win_page_down(ProfWin *window); +void win_sub_page_down(ProfWin *window); +void win_sub_page_up(ProfWin *window); + #endif diff --git a/src/ui/windows.c b/src/ui/windows.c index 5ecada12..2334efc8 100644 --- a/src/ui/windows.c +++ b/src/ui/windows.c @@ -1,7 +1,7 @@ /* * windows.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -53,6 +53,7 @@ #include "ui/statusbar.h" #include "ui/window.h" #include "ui/windows.h" +#include "event/ui_events.h" static GHashTable *windows; static int current; @@ -83,7 +84,7 @@ wins_get_chat(const char * const barejid) GList *values = g_hash_table_get_values(windows); GList *curr = values; - while (curr != NULL) { + while (curr) { ProfWin *window = curr->data; if (window->type == WIN_CHAT) { ProfChatWin *chatwin = (ProfChatWin*)window; @@ -105,7 +106,7 @@ wins_get_muc_conf(const char * const roomjid) GList *values = g_hash_table_get_values(windows); GList *curr = values; - while (curr != NULL) { + while (curr) { ProfWin *window = curr->data; if (window->type == WIN_MUC_CONFIG) { ProfMucConfWin *confwin = (ProfMucConfWin*)window; @@ -127,11 +128,12 @@ wins_get_muc(const char * const roomjid) GList *values = g_hash_table_get_values(windows); GList *curr = values; - while (curr != NULL) { + while (curr) { ProfWin *window = curr->data; if (window->type == WIN_MUC) { ProfMucWin *mucwin = (ProfMucWin*)window; if (g_strcmp0(mucwin->roomjid, roomjid) == 0) { + g_list_free(values); return mucwin; } } @@ -148,11 +150,12 @@ wins_get_private(const char * const fulljid) GList *values = g_hash_table_get_values(windows); GList *curr = values; - while (curr != NULL) { + while (curr) { ProfWin *window = curr->data; if (window->type == WIN_PRIVATE) { ProfPrivateWin *privatewin = (ProfPrivateWin*)window; if (g_strcmp0(privatewin->fulljid, fulljid) == 0) { + g_list_free(values); return privatewin; } } @@ -166,7 +169,7 @@ wins_get_private(const char * const fulljid) ProfWin * wins_get_current(void) { - if (windows != NULL) { + if (windows) { return g_hash_table_lookup(windows, GINT_TO_POINTER(current)); } else { return NULL; @@ -283,7 +286,7 @@ wins_get_next(void) GList *curr = keys; // find our place in the list - while (curr != NULL) { + while (curr) { if (current == GPOINTER_TO_INT(curr->data)) { break; } @@ -292,7 +295,7 @@ wins_get_next(void) // if there is a next window return it curr = g_list_next(curr); - if (curr != NULL) { + if (curr) { int next = GPOINTER_TO_INT(curr->data); g_list_free(keys); return wins_get_by_num(next); @@ -312,7 +315,7 @@ wins_get_previous(void) GList *curr = keys; // find our place in the list - while (curr != NULL) { + while (curr) { if (current == GPOINTER_TO_INT(curr->data)) { break; } @@ -321,7 +324,7 @@ wins_get_previous(void) // if there is a previous window return it curr = g_list_previous(curr); - if (curr != NULL) { + if (curr) { int previous = GPOINTER_TO_INT(curr->data); g_list_free(keys); return wins_get_by_num(previous); @@ -339,7 +342,7 @@ wins_get_num(ProfWin *window) GList *keys = g_hash_table_get_keys(windows); GList *curr = keys; - while (curr != NULL) { + while (curr) { gconstpointer num_p = curr->data; ProfWin *curr_win = g_hash_table_lookup(windows, num_p); if (curr_win == window) { @@ -408,9 +411,9 @@ wins_new_xmlconsole(void) { GList *keys = g_hash_table_get_keys(windows); int result = get_next_available_win_num(keys); + g_list_free(keys); ProfWin *newwin = win_create_xmlconsole(); g_hash_table_insert(windows, GINT_TO_POINTER(result), newwin); - g_list_free(keys); return newwin; } @@ -419,9 +422,9 @@ wins_new_chat(const char * const barejid) { GList *keys = g_hash_table_get_keys(windows); int result = get_next_available_win_num(keys); + g_list_free(keys); ProfWin *newwin = win_create_chat(barejid); g_hash_table_insert(windows, GINT_TO_POINTER(result), newwin); - g_list_free(keys); return newwin; } @@ -430,9 +433,9 @@ wins_new_muc(const char * const roomjid) { GList *keys = g_hash_table_get_keys(windows); int result = get_next_available_win_num(keys); + g_list_free(keys); ProfWin *newwin = win_create_muc(roomjid); g_hash_table_insert(windows, GINT_TO_POINTER(result), newwin); - g_list_free(keys); return newwin; } @@ -441,9 +444,9 @@ wins_new_muc_config(const char * const roomjid, DataForm *form) { GList *keys = g_hash_table_get_keys(windows); int result = get_next_available_win_num(keys); + g_list_free(keys); ProfWin *newwin = win_create_muc_config(roomjid, form); g_hash_table_insert(windows, GINT_TO_POINTER(result), newwin); - g_list_free(keys); return newwin; } @@ -452,9 +455,9 @@ wins_new_private(const char * const fulljid) { GList *keys = g_hash_table_get_keys(windows); int result = get_next_available_win_num(keys); + g_list_free(keys); ProfWin *newwin = win_create_private(fulljid); g_hash_table_insert(windows, GINT_TO_POINTER(result), newwin); - g_list_free(keys); return newwin; } @@ -465,7 +468,7 @@ wins_get_total_unread(void) GList *values = g_hash_table_get_values(windows); GList *curr = values; - while (curr != NULL) { + while (curr) { ProfWin *window = curr->data; result += win_unread(window); curr = g_list_next(curr); @@ -481,7 +484,7 @@ wins_resize_all(void) GList *values = g_hash_table_get_values(windows); GList *curr = values; - while (curr != NULL) { + while (curr) { ProfWin *window = curr->data; int subwin_cols = 0; @@ -495,7 +498,13 @@ wins_resize_all(void) } wresize(layout->base.win, PAD_SIZE, cols - subwin_cols); wresize(layout->subwin, PAD_SIZE, subwin_cols); - rosterwin_roster(); + if (window->type == WIN_CONSOLE) { + rosterwin_roster(); + } else if (window->type == WIN_MUC) { + ProfMucWin *mucwin = (ProfMucWin *)window; + assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); + occupantswin_occupants(mucwin->roomjid); + } } else { wresize(layout->base.win, PAD_SIZE, cols); } @@ -555,7 +564,7 @@ wins_get_xmlconsole(void) GList *values = g_hash_table_get_values(windows); GList *curr = values; - while (curr != NULL) { + while (curr) { ProfWin *window = curr->data; if (window->type == WIN_XML) { ProfXMLWin *xmlwin = (ProfXMLWin*)window; @@ -577,7 +586,7 @@ wins_get_chat_recipients(void) GList *values = g_hash_table_get_values(windows); GList *curr = values; - while (curr != NULL) { + while (curr) { ProfWin *window = curr->data; if (window->type == WIN_CHAT) { ProfChatWin *chatwin = (ProfChatWin*)window; @@ -596,7 +605,7 @@ wins_get_prune_wins(void) GList *values = g_hash_table_get_values(windows); GList *curr = values; - while (curr != NULL) { + while (curr) { ProfWin *window = curr->data; if (win_unread(window) == 0 && window->type != WIN_MUC && @@ -617,10 +626,10 @@ wins_lost_connection(void) GList *values = g_hash_table_get_values(windows); GList *curr = values; - while (curr != NULL) { + while (curr) { ProfWin *window = curr->data; if (window->type != WIN_CONSOLE) { - win_save_print(window, '-', NULL, 0, THEME_ERROR, "", "Lost connection."); + win_print(window, '-', NULL, 0, THEME_ERROR, "", "Lost connection."); // if current win, set current_win_dirty if (wins_is_current(window)) { @@ -636,22 +645,24 @@ gboolean wins_swap(int source_win, int target_win) { ProfWin *source = g_hash_table_lookup(windows, GINT_TO_POINTER(source_win)); + ProfWin *console = wins_get_console(); - if (source != NULL) { + if (source) { ProfWin *target = g_hash_table_lookup(windows, GINT_TO_POINTER(target_win)); // target window empty - if (target == NULL) { + if (!target) { g_hash_table_steal(windows, GINT_TO_POINTER(source_win)); - status_bar_inactive(source_win); g_hash_table_insert(windows, GINT_TO_POINTER(target_win), source); + status_bar_inactive(source_win); if (win_unread(source) > 0) { status_bar_new(target_win); } else { status_bar_active(target_win); } - if ((wins_get_current_num() == source_win) || (wins_get_current_num() == target_win)) { - ui_switch_win(1); + if (wins_get_current_num() == source_win) { + wins_set_current_by_num(target_win); + ui_ev_focus_win(console); } return TRUE; @@ -672,7 +683,7 @@ wins_swap(int source_win, int target_win) status_bar_active(source_win); } if ((wins_get_current_num() == source_win) || (wins_get_current_num() == target_win)) { - ui_switch_win(1); + ui_ev_focus_win(console); } return TRUE; } @@ -708,7 +719,7 @@ wins_tidy(void) int num = 1; GList *curr = keys; - while (curr != NULL) { + while (curr) { ProfWin *window = g_hash_table_lookup(windows, curr->data); if (num == 10) { g_hash_table_insert(new_windows, GINT_TO_POINTER(0), window); @@ -731,7 +742,8 @@ wins_tidy(void) windows = new_windows; current = 1; - ui_switch_win(1); + ProfWin *console = wins_get_console(); + ui_ev_focus_win(console); g_list_free(keys); return TRUE; } else { @@ -749,7 +761,7 @@ wins_create_summary(void) keys = g_list_sort(keys, cmp_win_num); GList *curr = keys; - while (curr != NULL) { + while (curr) { ProfWin *window = g_hash_table_lookup(windows, curr->data); int ui_index = GPOINTER_TO_INT(curr->data); diff --git a/src/ui/windows.h b/src/ui/windows.h index c144a5a2..97183d51 100644 --- a/src/ui/windows.h +++ b/src/ui/windows.h @@ -1,7 +1,7 @@ /* * windows.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/bookmark.c b/src/xmpp/bookmark.c index 94adabea..68e66569 100644 --- a/src/xmpp/bookmark.c +++ b/src/xmpp/bookmark.c @@ -1,7 +1,7 @@ /* * bookmark.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -42,7 +42,7 @@ #include "common.h" #include "log.h" #include "muc.h" -#include "server_events.h" +#include "event/server_events.h" #include "xmpp/connection.h" #include "xmpp/stanza.h" #include "xmpp/xmpp.h" @@ -74,7 +74,7 @@ bookmark_request(void) autocomplete_free(bookmark_ac); bookmark_ac = autocomplete_new(); - if (bookmark_list != NULL) { + if (bookmark_list) { g_list_free_full(bookmark_list, _bookmark_item_destroy); bookmark_list = NULL; } @@ -96,12 +96,12 @@ bookmark_add(const char *jid, const char *nick, const char *password, const char } else { Bookmark *item = malloc(sizeof(*item)); item->jid = strdup(jid); - if (nick != NULL) { + if (nick) { item->nick = strdup(nick); } else { item->nick = NULL; } - if (password != NULL) { + if (password) { item->password = strdup(password); } else { item->password = NULL; @@ -136,15 +136,15 @@ bookmark_update(const char *jid, const char *nick, const char *password, const c return FALSE; } else { Bookmark *bm = found->data; - if (nick != NULL) { + if (nick) { free(bm->nick); bm->nick = strdup(nick); } - if (password != NULL) { + if (password) { free(bm->password); bm->password = strdup(password); } - if (autojoin_str != NULL) { + if (autojoin_str) { if (g_strcmp0(autojoin_str, "on") == 0) { bm->autojoin = TRUE; } else if (g_strcmp0(autojoin_str, "off") == 0) { @@ -228,7 +228,7 @@ bookmark_find(const char * const search_str) void bookmark_autocomplete_reset(void) { - if (bookmark_ac != NULL) { + if (bookmark_ac) { autocomplete_reset(bookmark_ac); } } @@ -413,14 +413,14 @@ _send_bookmarks(void) xmpp_stanza_set_ns(storage, "storage:bookmarks"); GList *curr = bookmark_list; - while (curr != NULL) { + while (curr) { Bookmark *bookmark = curr->data; xmpp_stanza_t *conference = xmpp_stanza_new(ctx); xmpp_stanza_set_name(conference, STANZA_NAME_CONFERENCE); xmpp_stanza_set_attribute(conference, STANZA_ATTR_JID, bookmark->jid); Jid *jidp = jid_create(bookmark->jid); - if (jidp->localpart != NULL) { + if (jidp->localpart) { xmpp_stanza_set_attribute(conference, STANZA_ATTR_NAME, jidp->localpart); } jid_destroy(jidp); @@ -431,7 +431,7 @@ _send_bookmarks(void) xmpp_stanza_set_attribute(conference, STANZA_ATTR_AUTOJOIN, "false"); } - if (bookmark->nick != NULL) { + if (bookmark->nick) { xmpp_stanza_t *nick_st = xmpp_stanza_new(ctx); xmpp_stanza_set_name(nick_st, STANZA_NAME_NICK); xmpp_stanza_t *nick_text = xmpp_stanza_new(ctx); @@ -443,7 +443,7 @@ _send_bookmarks(void) xmpp_stanza_release(nick_st); } - if (bookmark->password != NULL) { + if (bookmark->password) { xmpp_stanza_t *password_st = xmpp_stanza_new(ctx); xmpp_stanza_set_name(password_st, STANZA_NAME_PASSWORD); xmpp_stanza_t *password_text = xmpp_stanza_new(ctx); diff --git a/src/xmpp/bookmark.h b/src/xmpp/bookmark.h index f9392182..c8de8147 100644 --- a/src/xmpp/bookmark.h +++ b/src/xmpp/bookmark.h @@ -1,7 +1,7 @@ /* * bookmark.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/capabilities.c b/src/xmpp/capabilities.c index 164313e1..56475da1 100644 --- a/src/xmpp/capabilities.c +++ b/src/xmpp/capabilities.c @@ -1,7 +1,7 @@ /* * capabilities.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -154,56 +154,56 @@ _caps_by_ver(const char * const ver) char *category = g_key_file_get_string(cache, ver, "category", NULL); if (category) { - new_caps->category = strdup(category); + new_caps->category = category; } else { new_caps->category = NULL; } char *type = g_key_file_get_string(cache, ver, "type", NULL); if (type) { - new_caps->type = strdup(type); + new_caps->type = type; } else { new_caps->type = NULL; } char *name = g_key_file_get_string(cache, ver, "name", NULL); if (name) { - new_caps->name = strdup(name); + new_caps->name = name; } else { new_caps->name = NULL; } char *software = g_key_file_get_string(cache, ver, "software", NULL); if (software) { - new_caps->software = strdup(software); + new_caps->software = software; } else { new_caps->software = NULL; } char *software_version = g_key_file_get_string(cache, ver, "software_version", NULL); if (software_version) { - new_caps->software_version = strdup(software_version); + new_caps->software_version = software_version; } else { new_caps->software_version = NULL; } char *os = g_key_file_get_string(cache, ver, "os", NULL); if (os) { - new_caps->os = strdup(os); + new_caps->os = os; } else { new_caps->os = NULL; } char *os_version = g_key_file_get_string(cache, ver, "os_version", NULL); if (os_version) { - new_caps->os_version = strdup(os_version); + new_caps->os_version = os_version; } else { new_caps->os_version = NULL; } gsize features_len = 0; gchar **features = g_key_file_get_string_list(cache, ver, "features", &features_len, NULL); - if (features != NULL && features_len > 0) { + if (features && features_len > 0) { GSList *features_list = NULL; int i; for (i = 0; i < features_len; i++) { @@ -395,16 +395,16 @@ caps_create(xmpp_stanza_t *query) GSList *features = NULL; xmpp_stanza_t *softwareinfo = xmpp_stanza_get_child_by_ns(query, STANZA_NS_DATA); - if (softwareinfo != NULL) { + if (softwareinfo) { DataForm *form = form_create(softwareinfo); FormField *formField = NULL; char *form_type = form_get_form_type_field(form); if (g_strcmp0(form_type, STANZA_DATAFORM_SOFTWARE) == 0) { GSList *field = form->fields; - while (field != NULL) { + while (field) { formField = field->data; - if (formField->values != NULL) { + if (formField->values) { if (strcmp(formField->var, "software") == 0) { software = strdup(formField->values->data); } else if (strcmp(formField->var, "software_version") == 0) { @@ -424,7 +424,7 @@ caps_create(xmpp_stanza_t *query) xmpp_stanza_t *child = xmpp_stanza_get_children(query); GSList *identity_stanzas = NULL; - while (child != NULL) { + while (child) { if (g_strcmp0(xmpp_stanza_get_name(child), "feature") == 0) { features = g_slist_append(features, strdup(xmpp_stanza_get_attribute(child, "var"))); } @@ -490,42 +490,42 @@ caps_create(xmpp_stanza_t *query) Capabilities *new_caps = malloc(sizeof(struct capabilities_t)); - if (category != NULL) { + if (category) { new_caps->category = strdup(category); } else { new_caps->category = NULL; } - if (type != NULL) { + if (type) { new_caps->type = strdup(type); } else { new_caps->type = NULL; } - if (name != NULL) { + if (name) { new_caps->name = strdup(name); } else { new_caps->name = NULL; } - if (software != NULL) { + if (software) { new_caps->software = software; } else { new_caps->software = NULL; } - if (software_version != NULL) { + if (software_version) { new_caps->software_version = software_version; } else { new_caps->software_version = NULL; } - if (os != NULL) { + if (os) { new_caps->os = os; } else { new_caps->os = NULL; } - if (os_version != NULL) { + if (os_version) { new_caps->os_version = os_version; } else { new_caps->os_version = NULL; } - if (features != NULL) { + if (features) { new_caps->features = features; } else { new_caps->features = NULL; @@ -635,7 +635,7 @@ caps_close(void) void caps_destroy(Capabilities *caps) { - if (caps != NULL) { + if (caps) { free(caps->category); free(caps->type); free(caps->name); @@ -643,7 +643,7 @@ caps_destroy(Capabilities *caps) free(caps->software_version); free(caps->os); free(caps->os_version); - if (caps->features != NULL) { + if (caps->features) { g_slist_free_full(caps->features, free); } free(caps); diff --git a/src/xmpp/capabilities.h b/src/xmpp/capabilities.h index 692ac49d..85f1d989 100644 --- a/src/xmpp/capabilities.h +++ b/src/xmpp/capabilities.h @@ -1,7 +1,7 @@ /* * capabilities.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/connection.c b/src/xmpp/connection.c index 915525e4..70d49b7c 100644 --- a/src/xmpp/connection.c +++ b/src/xmpp/connection.c @@ -1,7 +1,7 @@ /* * connection.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -45,7 +45,7 @@ #include "log.h" #include "muc.h" #include "profanity.h" -#include "server_events.h" +#include "event/server_events.h" #include "xmpp/bookmark.h" #include "xmpp/capabilities.h" #include "xmpp/connection.h" @@ -129,11 +129,11 @@ jabber_connect_with_account(const ProfAccount * const account) log_info("Connecting using account: %s", account->name); // save account name and password for reconnect - if (saved_account.name != NULL) { + if (saved_account.name) { free(saved_account.name); } saved_account.name = strdup(account->name); - if (saved_account.passwd != NULL) { + if (saved_account.passwd) { free(saved_account.passwd); } saved_account.passwd = strdup(account->password); @@ -157,7 +157,7 @@ jabber_connect_with_details(const char * const jid, // save details for reconnect, remember name for account creating on success saved_details.name = strdup(jid); saved_details.passwd = strdup(passwd); - if (altdomain != NULL) { + if (altdomain) { saved_details.altdomain = strdup(altdomain); } else { saved_details.altdomain = NULL; @@ -199,11 +199,11 @@ jabber_disconnect(void) _connection_free_saved_account(); _connection_free_saved_details(); _connection_free_session_data(); - if (jabber_conn.conn != NULL) { + if (jabber_conn.conn) { xmpp_conn_release(jabber_conn.conn); jabber_conn.conn = NULL; } - if (jabber_conn.ctx != NULL) { + if (jabber_conn.ctx) { xmpp_ctx_free(jabber_conn.ctx); jabber_conn.ctx = NULL; } @@ -238,7 +238,7 @@ jabber_process_events(void) break; case JABBER_DISCONNECTED: reconnect_sec = prefs_get_reconnect(); - if ((reconnect_sec != 0) && (reconnect_timer != NULL)) { + if ((reconnect_sec != 0) && reconnect_timer) { int elapsed_sec = g_timer_elapsed(reconnect_timer, NULL); if (elapsed_sec > reconnect_sec) { _jabber_reconnect(); @@ -302,7 +302,7 @@ void connection_set_presence_message(const char * const message) { FREE_SET_NULL(jabber_conn.presence_message); - if (message != NULL) { + if (message) { jabber_conn.presence_message = strdup(message); } } @@ -371,15 +371,15 @@ _jabber_connect(const char * const fulljid, const char * const passwd, jid_destroy(jid); log_info("Connecting as %s", fulljid); - if (jabber_conn.log != NULL) { + if (jabber_conn.log) { free(jabber_conn.log); } jabber_conn.log = _xmpp_get_file_logger(); - if (jabber_conn.conn != NULL) { + if (jabber_conn.conn) { xmpp_conn_release(jabber_conn.conn); } - if (jabber_conn.ctx != NULL) { + if (jabber_conn.ctx) { xmpp_ctx_free(jabber_conn.ctx); } jabber_conn.ctx = xmpp_ctx_new(NULL, jabber_conn.log); @@ -436,9 +436,9 @@ _connection_handler(xmpp_conn_t * const conn, log_debug("Connection handler: XMPP_CONN_CONNECT"); // logged in with account - if (saved_account.name != NULL) { + if (saved_account.name) { log_debug("Connection handler: logged in with account name: %s", saved_account.name); - handle_login_account_success(saved_account.name); + sv_ev_login_account_success(saved_account.name); // logged in without account, use details to create new account } else { @@ -446,7 +446,7 @@ _connection_handler(xmpp_conn_t * const conn, accounts_add(saved_details.name, saved_details.altdomain, saved_details.port); accounts_set_jid(saved_details.name, saved_details.jid); - handle_login_account_success(saved_details.name); + sv_ev_login_account_success(saved_details.name); saved_account.name = strdup(saved_details.name); saved_account.passwd = strdup(saved_details.passwd); @@ -466,10 +466,15 @@ _connection_handler(xmpp_conn_t * const conn, roster_request(); bookmark_request(); + + if (prefs_get_boolean(PREF_CARBONS)){ + iq_enable_carbons(); + } + jabber_conn.conn_status = JABBER_CONNECTED; if (prefs_get_reconnect() != 0) { - if (reconnect_timer != NULL) { + if (reconnect_timer) { g_timer_destroy(reconnect_timer); reconnect_timer = NULL; } @@ -481,7 +486,7 @@ _connection_handler(xmpp_conn_t * const conn, // lost connection for unknown reason if (jabber_conn.conn_status == JABBER_CONNECTED) { log_debug("Connection handler: Lost connection for unknown reason"); - handle_lost_connection(); + sv_ev_lost_connection(); if (prefs_get_reconnect() != 0) { assert(reconnect_timer == NULL); reconnect_timer = g_timer_new(); @@ -498,7 +503,7 @@ _connection_handler(xmpp_conn_t * const conn, log_debug("Connection handler: Login failed"); if (reconnect_timer == NULL) { log_debug("Connection handler: No reconnect timer"); - handle_failed_login(); + sv_ev_failed_login(); _connection_free_saved_account(); _connection_free_saved_details(); _connection_free_session_data(); @@ -558,7 +563,7 @@ _xmpp_file_logger(void * const userdata, const xmpp_log_level_t level, log_level_t prof_level = _get_log_level(level); log_msg(prof_level, area, msg); if ((g_strcmp0(area, "xmpp") == 0) || (g_strcmp0(area, "conn")) == 0) { - handle_xmpp_stanza(msg); + sv_ev_xmpp_stanza(msg); } } diff --git a/src/xmpp/connection.h b/src/xmpp/connection.h index f9e2cf22..63f7cde0 100644 --- a/src/xmpp/connection.h +++ b/src/xmpp/connection.h @@ -1,7 +1,7 @@ /* * connection.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/form.c b/src/xmpp/form.c index 1facc754..e6213b64 100644 --- a/src/xmpp/form.c +++ b/src/xmpp/form.c @@ -1,7 +1,7 @@ /* * form.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -211,7 +211,7 @@ form_create(xmpp_stanza_t * const form_stanza) field->var = _get_attr(field_stanza, "var"); - if (field->type_t != FIELD_HIDDEN && field->var != NULL) { + if (field->type_t != FIELD_HIDDEN && field->var) { GString *tag = g_string_new(""); g_string_printf(tag, "field%d", tag_num++); g_hash_table_insert(form->var_to_tag, strdup(field->var), strdup(tag->str)); diff --git a/src/xmpp/form.h b/src/xmpp/form.h index fa14e1c5..86cd4b7b 100644 --- a/src/xmpp/form.h +++ b/src/xmpp/form.h @@ -1,7 +1,7 @@ /* * form.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index 7fedf0ed..18abad36 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -1,7 +1,7 @@ /* * iq.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -47,8 +47,9 @@ #include "log.h" #include "muc.h" #include "profanity.h" +#include "ui/ui.h" #include "config/preferences.h" -#include "server_events.h" +#include "event/server_events.h" #include "xmpp/capabilities.h" #include "xmpp/connection.h" #include "xmpp/stanza.h" @@ -58,48 +59,35 @@ #define HANDLE(ns, type, func) xmpp_handler_add(conn, func, ns, STANZA_NAME_IQ, type, ctx) -static int _error_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _ping_get_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _version_get_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _disco_info_get_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _disco_info_response_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _version_result_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _disco_items_result_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _disco_items_get_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _destroy_room_result_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _room_config_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _room_config_submit_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _room_affiliation_list_result_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _room_affiliation_set_result_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _room_role_set_result_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _room_role_list_result_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _room_kick_result_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _manual_pong_handler(xmpp_conn_t *const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _ping_timed_handler(xmpp_conn_t * const conn, - void * const userdata); -static int _caps_response_handler(xmpp_conn_t *const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _caps_response_handler_for_jid(xmpp_conn_t *const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _caps_response_handler_legacy(xmpp_conn_t *const conn, - xmpp_stanza_t * const stanza, void * const userdata); +typedef struct p_room_info_data_t { + char *room; + gboolean display; +} ProfRoomInfoData; + +static int _error_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _ping_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _version_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _disco_info_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _disco_info_response_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _room_info_response_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _version_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _disco_items_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _disco_items_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _destroy_room_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _room_config_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _room_config_submit_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _room_affiliation_list_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _room_affiliation_set_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _room_role_set_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _room_role_list_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _room_kick_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _enable_carbons_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _disable_carbons_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _manual_pong_handler(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _ping_timed_handler(xmpp_conn_t * const conn, void * const userdata); +static int _caps_response_handler(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _caps_response_handler_for_jid(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _caps_response_handler_legacy(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, void * const userdata); void iq_add_handlers(void) @@ -153,6 +141,34 @@ iq_room_list_request(gchar *conferencejid) } void +iq_enable_carbons() +{ + xmpp_conn_t * const conn = connection_get_conn(); + xmpp_ctx_t * const ctx = connection_get_ctx(); + xmpp_stanza_t *iq = stanza_enable_carbons(ctx); + char *id = xmpp_stanza_get_id(iq); + + xmpp_id_handler_add(conn, _enable_carbons_handler, id, NULL); + + xmpp_send(conn, iq); + xmpp_stanza_release(iq); +} + +void +iq_disable_carbons() +{ + xmpp_conn_t * const conn = connection_get_conn(); + xmpp_ctx_t * const ctx = connection_get_ctx(); + xmpp_stanza_t *iq = stanza_disable_carbons(ctx); + char *id = xmpp_stanza_get_id(iq); + + xmpp_id_handler_add(conn, _disable_carbons_handler, id, NULL); + + xmpp_send(conn, iq); + xmpp_stanza_release(iq); +} + +void iq_disco_info_request(gchar *jid) { xmpp_conn_t * const conn = connection_get_conn(); @@ -169,14 +185,18 @@ iq_disco_info_request(gchar *jid) } void -iq_room_info_request(gchar *room) +iq_room_info_request(const char * const room, gboolean display_result) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); char *id = create_unique_id("room_disco_info"); xmpp_stanza_t *iq = stanza_create_disco_info_iq(ctx, id, room, NULL); - xmpp_id_handler_add(conn, _disco_info_response_handler, id, room); + ProfRoomInfoData *cb_data = malloc(sizeof(ProfRoomInfoData)); + cb_data->room = strdup(room); + cb_data->display = display_result; + + xmpp_id_handler_add(conn, _room_info_response_handler, id, cb_data); free(id); @@ -456,7 +476,7 @@ _error_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); char *error_msg = stanza_get_error_message(stanza); - if (id != NULL) { + if (id) { log_debug("IQ error handler fired, id: %s, error: %s", id, error_msg); log_error("IQ error received, id: %s, error: %s", id, error_msg); } else { @@ -476,13 +496,13 @@ _pong_handler(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, char *id = xmpp_stanza_get_id(stanza); char *type = xmpp_stanza_get_type(stanza); - if (id != NULL) { + if (id) { log_debug("IQ pong handler fired, id: %s.", id); } else { log_debug("IQ pong handler fired."); } - if (id != NULL && type != NULL) { + if (id && type) { // show warning if error if (strcmp(type, STANZA_TYPE_ERROR) == 0) { char *error_msg = stanza_get_error_message(stanza); @@ -491,12 +511,13 @@ _pong_handler(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, // turn off autoping if error type is 'cancel' xmpp_stanza_t *error = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_ERROR); - if (error != NULL) { + if (error) { char *errtype = xmpp_stanza_get_type(error); - if (errtype != NULL) { + if (errtype) { if (strcmp(errtype, "cancel") == 0) { log_warning("Server ping (id=%s) error type 'cancel', disabling autoping.", id); - handle_autoping_cancel(); + prefs_set_autoping(0); + cons_show_error("Server ping not supported, autoping disabled."); xmpp_timed_handler_delete(conn, _ping_timed_handler); } } @@ -586,12 +607,14 @@ static int _caps_response_handler_for_jid(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, void * const userdata) { + char *jid = (char *)userdata; const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); char *type = xmpp_stanza_get_type(stanza); // ignore non result if ((g_strcmp0(type, "get") == 0) || (g_strcmp0(type, "set") == 0)) { + free(jid); return 1; } @@ -604,6 +627,7 @@ _caps_response_handler_for_jid(xmpp_conn_t *const conn, xmpp_stanza_t * const st const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (!from) { log_info("No from attribute"); + free(jid); return 0; } @@ -612,25 +636,29 @@ _caps_response_handler_for_jid(xmpp_conn_t *const conn, xmpp_stanza_t * const st char *error_message = stanza_get_error_message(stanza); log_warning("Error received for capabilities response from %s: ", from, error_message); free(error_message); + free(jid); return 0; } if (query == NULL) { log_warning("No query element found."); + free(jid); return 0; } char *node = xmpp_stanza_get_attribute(query, STANZA_ATTR_NODE); if (node == NULL) { log_warning("No node attribute found"); + free(jid); return 0; } - char *jid = (char *)userdata; log_info("Associating capabilities with: %s", jid); Capabilities *capabilities = caps_create(query); caps_add_by_jid(jid, capabilities); + free(jid); + return 0; } @@ -640,10 +668,12 @@ _caps_response_handler_legacy(xmpp_conn_t *const conn, xmpp_stanza_t * const sta { const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); + char *expected_node = (char *)userdata; char *type = xmpp_stanza_get_type(stanza); // ignore non result if ((g_strcmp0(type, "get") == 0) || (g_strcmp0(type, "set") == 0)) { + free(expected_node); return 1; } @@ -656,6 +686,7 @@ _caps_response_handler_legacy(xmpp_conn_t *const conn, xmpp_stanza_t * const sta const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); if (!from) { log_info("No from attribute"); + free(expected_node); return 0; } @@ -664,22 +695,23 @@ _caps_response_handler_legacy(xmpp_conn_t *const conn, xmpp_stanza_t * const sta char *error_message = stanza_get_error_message(stanza); log_warning("Error received for capabilities response from %s: ", from, error_message); free(error_message); + free(expected_node); return 0; } if (query == NULL) { log_warning("No query element found."); + free(expected_node); return 0; } char *node = xmpp_stanza_get_attribute(query, STANZA_ATTR_NODE); if (node == NULL) { log_warning("No node attribute found"); + free(expected_node); return 0; } - char *expected_node = (char *)userdata; - // nodes match if (g_strcmp0(expected_node, node) == 0) { log_info("Legacy capabilities, nodes match %s", node); @@ -704,6 +736,36 @@ _caps_response_handler_legacy(xmpp_conn_t *const conn, xmpp_stanza_t * const sta } static int +_enable_carbons_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) +{ + char *type = xmpp_stanza_get_type(stanza); + if (g_strcmp0(type, "error") == 0) { + char *error_message = stanza_get_error_message(stanza); + cons_show_error("Server error enabling message carbons: %s", error_message); + log_debug("Error enabling carbons: %s", error_message); + } else { + log_debug("Message carbons enabled."); + } + + return 0; +} + +static int +_disable_carbons_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) +{ + char *type = xmpp_stanza_get_type(stanza); + if (g_strcmp0(type, "error") == 0) { + char *error_message = stanza_get_error_message(stanza); + cons_show_error("Server error disabling message carbons: %s", error_message); + log_debug("Error disabling carbons: %s", error_message); + } else { + log_debug("Message carbons disabled."); + } + + return 0; +} + +static int _manual_pong_handler(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, void * const userdata) { @@ -714,7 +776,12 @@ _manual_pong_handler(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); - handle_ping_error_result(from, error_message); + if (!error_message) { + cons_show_error("Error returned from pinging %s.", from); + } else { + cons_show_error("Error returned from pinging %s: %s.", from, error_message); + } + free(error_message); g_date_time_unref(sent); return 0; @@ -728,7 +795,11 @@ _manual_pong_handler(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza, g_date_time_unref(sent); g_date_time_unref(now); - handle_ping_result(from, elapsed_millis); + if (from == NULL) { + cons_show("Ping response from server: %dms.", elapsed_millis); + } else { + cons_show("Ping response from %s: %dms.", from, elapsed_millis); + } return 0; } @@ -759,7 +830,7 @@ _version_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, { char *id = xmpp_stanza_get_id(stanza); - if (id != NULL) { + if (id) { log_debug("IQ version result handler fired, id: %s.", id); } else { log_debug("IQ version result handler fired."); @@ -784,13 +855,13 @@ _version_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, xmpp_stanza_t *version = xmpp_stanza_get_child_by_name(query, "version"); xmpp_stanza_t *os = xmpp_stanza_get_child_by_name(query, "os"); - if (name != NULL) { + if (name) { name_str = xmpp_stanza_get_text(name); } - if (version != NULL) { + if (version) { version_str = xmpp_stanza_get_text(version); } - if (os != NULL) { + if (os) { os_str = xmpp_stanza_get_text(os); } @@ -805,7 +876,7 @@ _version_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, presence = string_from_resource_presence(resource->presence); } - handle_software_version_result(jid, presence, name_str, version_str, os_str); + cons_show_software_version(jid, presence, name_str, version_str, os_str); jid_destroy(jidp); @@ -821,7 +892,7 @@ _ping_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, const char *to = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_TO); const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); - if (id != NULL) { + if (id) { log_debug("IQ ping get handler fired, id: %s.", id); } else { log_debug("IQ ping get handler fired."); @@ -837,7 +908,7 @@ _ping_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, xmpp_stanza_set_attribute(pong, STANZA_ATTR_FROM, to); xmpp_stanza_set_attribute(pong, STANZA_ATTR_TYPE, STANZA_TYPE_RESULT); - if (id != NULL) { + if (id) { xmpp_stanza_set_attribute(pong, STANZA_ATTR_ID, id); } @@ -855,16 +926,16 @@ _version_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); - if (id != NULL) { + if (id) { log_debug("IQ version get handler fired, id: %s.", id); } else { log_debug("IQ version get handler fired."); } - if (from != NULL) { + if (from) { xmpp_stanza_t *response = xmpp_stanza_new(ctx); xmpp_stanza_set_name(response, STANZA_NAME_IQ); - if (id != NULL) { + if (id) { xmpp_stanza_set_id(response, id); } xmpp_stanza_set_attribute(response, STANZA_ATTR_TO, from); @@ -923,13 +994,13 @@ _disco_items_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); - if (id != NULL) { + if (id) { log_debug("IQ disco items get handler fired, id: %s.", id); } else { log_debug("IQ disco items get handler fired."); } - if (from != NULL) { + if (from) { xmpp_stanza_t *response = xmpp_stanza_new(ctx); xmpp_stanza_set_name(response, STANZA_NAME_IQ); xmpp_stanza_set_id(response, xmpp_stanza_get_id(stanza)); @@ -960,20 +1031,20 @@ _disco_info_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); - if (id != NULL) { + if (id) { log_debug("IQ disco info get handler fired, id: %s.", id); } else { log_debug("IQ disco info get handler fired."); } - if (from != NULL) { + if (from) { xmpp_stanza_t *response = xmpp_stanza_new(ctx); xmpp_stanza_set_name(response, STANZA_NAME_IQ); xmpp_stanza_set_id(response, xmpp_stanza_get_id(stanza)); xmpp_stanza_set_attribute(response, STANZA_ATTR_TO, from); xmpp_stanza_set_type(response, STANZA_TYPE_RESULT); xmpp_stanza_t *query = caps_create_query_response_stanza(ctx); - if (node_str != NULL) { + if (node_str) { xmpp_stanza_set_attribute(query, STANZA_ATTR_NODE, node_str); } xmpp_stanza_add_child(response, query); @@ -992,7 +1063,7 @@ _destroy_room_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const sta { const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); - if (id != NULL) { + if (id) { log_debug("IQ destroy room result handler fired, id: %s.", id); } else { log_debug("IQ destroy room result handler fired."); @@ -1002,7 +1073,7 @@ _destroy_room_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const sta if (from == NULL) { log_error("No from attribute for IQ destroy room result"); } else { - handle_room_destroy(from); + sv_ev_room_destroy(from); } return 0; @@ -1016,7 +1087,7 @@ _room_config_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, const char *type = xmpp_stanza_get_type(stanza); const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); - if (id != NULL) { + if (id) { log_debug("IQ room config handler fired, id: %s.", id); } else { log_debug("IQ room config handler fired."); @@ -1025,40 +1096,40 @@ _room_config_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); - handle_room_configuration_form_error(from, error_message); + ui_handle_room_configuration_form_error(from, error_message); free(error_message); return 0; } if (from == NULL) { log_warning("No from attribute for IQ config request result"); - handle_room_configuration_form_error(from, "No from attribute for room cofig response."); + ui_handle_room_configuration_form_error(from, "No from attribute for room cofig response."); return 0; } xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); if (query == NULL) { log_warning("No query element found parsing room config response"); - handle_room_configuration_form_error(from, "No query element found parsing room config response"); + ui_handle_room_configuration_form_error(from, "No query element found parsing room config response"); return 0; } xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(query, STANZA_NS_DATA); if (x == NULL) { log_warning("No x element found with %s namespace parsing room config response", STANZA_NS_DATA); - handle_room_configuration_form_error(from, "No form configuration options available"); + ui_handle_room_configuration_form_error(from, "No form configuration options available"); return 0; } char *form_type = xmpp_stanza_get_attribute(x, STANZA_ATTR_TYPE); if (g_strcmp0(form_type, "form") != 0) { log_warning("x element not of type 'form' parsing room config response"); - handle_room_configuration_form_error(from, "Form not of type 'form' parsing room config response."); + ui_handle_room_configuration_form_error(from, "Form not of type 'form' parsing room config response."); return 0; } DataForm *form = form_create(x); - handle_room_configure(from, form); + ui_handle_room_configuration(from, form); return 0; } @@ -1071,7 +1142,7 @@ static int _room_affiliation_set_result_handler(xmpp_conn_t * const conn, xmpp_s const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); struct privilege_set_t *affiliation_set = (struct privilege_set_t *)userdata; - if (id != NULL) { + if (id) { log_debug("IQ affiliation set handler fired, id: %s.", id); } else { log_debug("IQ affiliation set handler fired."); @@ -1080,7 +1151,8 @@ static int _room_affiliation_set_result_handler(xmpp_conn_t * const conn, xmpp_s // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); - handle_room_affiliation_set_error(from, affiliation_set->item, affiliation_set->privilege, error_message); + log_debug("Error setting affiliation %s list for room %s, user %s: %s", affiliation_set->privilege, from, affiliation_set->item, error_message); + ui_handle_room_affiliation_set_error(from, affiliation_set->item, affiliation_set->privilege, error_message); free(error_message); } @@ -1099,7 +1171,7 @@ static int _room_role_set_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); struct privilege_set_t *role_set = (struct privilege_set_t *)userdata; - if (id != NULL) { + if (id) { log_debug("IQ role set handler fired, id: %s.", id); } else { log_debug("IQ role set handler fired."); @@ -1108,7 +1180,8 @@ static int _room_role_set_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); - handle_room_role_set_error(from, role_set->item, role_set->privilege, error_message); + log_debug("Error setting role %s list for room %s, user %s: %s", role_set->privilege, from, role_set->item, error_message); + ui_handle_room_role_set_error(from, role_set->item, role_set->privilege, error_message); free(error_message); } @@ -1127,7 +1200,7 @@ _room_affiliation_list_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); char *affiliation = (char *)userdata; - if (id != NULL) { + if (id) { log_debug("IQ affiliation list result handler fired, id: %s.", id); } else { log_debug("IQ affiliation list result handler fired."); @@ -1136,7 +1209,8 @@ _room_affiliation_list_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); - handle_room_affiliation_list_result_error(from, affiliation, error_message); + log_debug("Error retrieving %s list for room %s: %s", affiliation, from, error_message); + ui_handle_room_affiliation_list_error(from, affiliation, error_message); free(error_message); free(affiliation); return 0; @@ -1158,7 +1232,8 @@ _room_affiliation_list_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * } } - handle_room_affiliation_list(from, affiliation, jids); + muc_jid_autocomplete_add_all(from, jids); + ui_handle_room_affiliation_list(from, affiliation, jids); free(affiliation); g_slist_free(jids); @@ -1173,7 +1248,7 @@ _room_role_list_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const s const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); char *role = (char *)userdata; - if (id != NULL) { + if (id) { log_debug("IQ role list result handler fired, id: %s.", id); } else { log_debug("IQ role list result handler fired."); @@ -1182,7 +1257,8 @@ _room_role_list_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const s // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); - handle_room_role_list_result_error(from, role, error_message); + log_debug("Error retrieving %s list for room %s: %s", role, from, error_message); + ui_handle_room_role_list_error(from, role, error_message); free(error_message); free(role); return 0; @@ -1204,7 +1280,7 @@ _room_role_list_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const s } } - handle_room_role_list(from, role, nicks); + ui_handle_room_role_list(from, role, nicks); free(role); g_slist_free(nicks); @@ -1219,7 +1295,7 @@ _room_config_submit_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stan const char *type = xmpp_stanza_get_type(stanza); const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); - if (id != NULL) { + if (id) { log_debug("IQ room config submit handler fired, id: %s.", id); } else { log_debug("IQ room config submit handler fired."); @@ -1228,12 +1304,12 @@ _room_config_submit_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stan // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); - handle_room_config_submit_result_error(from, error_message); + ui_handle_room_config_submit_result_error(from, error_message); free(error_message); return 0; } - handle_room_config_submit_result(from); + ui_handle_room_config_submit_result(from); return 0; } @@ -1246,7 +1322,7 @@ _room_kick_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); char *nick = (char *)userdata; - if (id != NULL) { + if (id) { log_debug("IQ kick result handler fired, id: %s.", id); } else { log_debug("IQ kick result handler fired."); @@ -1255,7 +1331,7 @@ _room_kick_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); - handle_room_kick_result_error(from, nick, error_message); + ui_handle_room_kick_error(from, nick, error_message); free(error_message); free(nick); return 0; @@ -1269,7 +1345,7 @@ _room_kick_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza static void _identity_destroy(DiscoIdentity *identity) { - if (identity != NULL) { + if (identity) { free(identity->name); free(identity->type); free(identity->category); @@ -1280,7 +1356,7 @@ _identity_destroy(DiscoIdentity *identity) static void _item_destroy(DiscoItem *item) { - if (item != NULL) { + if (item) { free(item->jid); free(item->name); free(item); @@ -1288,32 +1364,104 @@ _item_destroy(DiscoItem *item) } static int +_room_info_response_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, + void * const userdata) +{ + const char *type = xmpp_stanza_get_type(stanza); + ProfRoomInfoData *cb_data = (ProfRoomInfoData *)userdata; + log_info("Received diso#info response for room: %s", cb_data->room); + + // handle error responses + if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { + if (cb_data->display) { + char *error_message = stanza_get_error_message(stanza); + ui_handle_room_info_error(cb_data->room, error_message); + free(error_message); + } + free(cb_data->room); + free(cb_data); + return 0; + } + + xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); + + if (query) { + xmpp_stanza_t *child = xmpp_stanza_get_children(query); + GSList *identities = NULL; + GSList *features = NULL; + while (child) { + const char *stanza_name = xmpp_stanza_get_name(child); + if (g_strcmp0(stanza_name, STANZA_NAME_FEATURE) == 0) { + const char *var = xmpp_stanza_get_attribute(child, STANZA_ATTR_VAR); + if (var) { + features = g_slist_append(features, strdup(var)); + } + } else if (g_strcmp0(stanza_name, STANZA_NAME_IDENTITY) == 0) { + const char *name = xmpp_stanza_get_attribute(child, STANZA_ATTR_NAME); + const char *type = xmpp_stanza_get_attribute(child, STANZA_ATTR_TYPE); + const char *category = xmpp_stanza_get_attribute(child, STANZA_ATTR_CATEGORY); + + if (name || category || type) { + DiscoIdentity *identity = malloc(sizeof(struct disco_identity_t)); + + if (name) { + identity->name = strdup(name); + } else { + identity->name = NULL; + } + if (category) { + identity->category = strdup(category); + } else { + identity->category = NULL; + } + if (type) { + identity->type = strdup(type); + } else { + identity->type = NULL; + } + + identities = g_slist_append(identities, identity); + } + } + + child = xmpp_stanza_get_next(child); + } + + muc_set_features(cb_data->room, features); + if (cb_data->display) { + ui_show_room_disco_info(cb_data->room, identities, features); + } + + g_slist_free_full(features, free); + g_slist_free_full(identities, (GDestroyNotify)_identity_destroy); + } + + free(cb_data->room); + free(cb_data); + + return 0; +} + +static int _disco_info_response_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); const char *type = xmpp_stanza_get_type(stanza); - char *room = NULL; - if (userdata) { - room = (char *) userdata; - log_info("Received diso#info response for room: %s", room); + if (from) { + log_info("Received diso#info response from: %s", from); } else { - room = NULL; - if (from) { - log_info("Received diso#info response from: %s", from); - } else { - log_info("Received diso#info response"); - } + log_info("Received diso#info response"); } // handle error responses if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { char *error_message = stanza_get_error_message(stanza); - if (room) { - handle_room_info_error(room, error_message); + if (from) { + cons_show_error("Service discovery failed for %s: %s", from, error_message); } else { - handle_disco_info_error(from, error_message); + cons_show_error("Service discovery failed: %s", error_message); } free(error_message); return 0; @@ -1321,15 +1469,15 @@ _disco_info_response_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const sta xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); - if (query != NULL) { + if (query) { xmpp_stanza_t *child = xmpp_stanza_get_children(query); GSList *identities = NULL; GSList *features = NULL; - while (child != NULL) { + while (child) { const char *stanza_name = xmpp_stanza_get_name(child); if (g_strcmp0(stanza_name, STANZA_NAME_FEATURE) == 0) { const char *var = xmpp_stanza_get_attribute(child, STANZA_ATTR_VAR); - if (var != NULL) { + if (var) { features = g_slist_append(features, strdup(var)); } } else if (g_strcmp0(stanza_name, STANZA_NAME_IDENTITY) == 0) { @@ -1337,20 +1485,20 @@ _disco_info_response_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const sta const char *type = xmpp_stanza_get_attribute(child, STANZA_ATTR_TYPE); const char *category = xmpp_stanza_get_attribute(child, STANZA_ATTR_CATEGORY); - if ((name != NULL) || (category != NULL) || (type != NULL)) { + if (name || category || type) { DiscoIdentity *identity = malloc(sizeof(struct disco_identity_t)); - if (name != NULL) { + if (name) { identity->name = strdup(name); } else { identity->name = NULL; } - if (category != NULL) { + if (category) { identity->category = strdup(category); } else { identity->category = NULL; } - if (type != NULL) { + if (type) { identity->type = strdup(type); } else { identity->type = NULL; @@ -1363,16 +1511,13 @@ _disco_info_response_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const sta child = xmpp_stanza_get_next(child); } - if (room) { - handle_room_disco_info(room, identities, features); - } else { - handle_disco_info(from, identities, features); - } + cons_show_disco_info(from, identities, features); g_slist_free_full(features, free); g_slist_free_full(identities, (GDestroyNotify)_identity_destroy); } - return 1; + + return 0; } static int @@ -1389,17 +1534,17 @@ _disco_items_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stan log_debug("Response to query: %s", id); xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); - if (query != NULL) { + if (query) { xmpp_stanza_t *child = xmpp_stanza_get_children(query); - while (child != NULL) { + while (child) { const char *stanza_name = xmpp_stanza_get_name(child); - if ((stanza_name != NULL) && (g_strcmp0(stanza_name, STANZA_NAME_ITEM) == 0)) { + if (stanza_name && (g_strcmp0(stanza_name, STANZA_NAME_ITEM) == 0)) { const char *item_jid = xmpp_stanza_get_attribute(child, STANZA_ATTR_JID); - if (item_jid != NULL) { + if (item_jid) { DiscoItem *item = malloc(sizeof(struct disco_item_t)); item->jid = strdup(item_jid); const char *item_name = xmpp_stanza_get_attribute(child, STANZA_ATTR_NAME); - if (item_name != NULL) { + if (item_name) { item->name = strdup(item_name); } else { item->name = NULL; @@ -1414,9 +1559,9 @@ _disco_items_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stan } if (g_strcmp0(id, "confreq") == 0) { - handle_room_list(items, from); + cons_show_room_list(items, from); } else if (g_strcmp0(id, "discoitemsreq") == 0) { - handle_disco_items(items, from); + cons_show_disco_items(items, from); } g_slist_free_full(items, (GDestroyNotify)_item_destroy); diff --git a/src/xmpp/iq.h b/src/xmpp/iq.h index 8c803ab5..d3a22fe4 100644 --- a/src/xmpp/iq.h +++ b/src/xmpp/iq.h @@ -1,7 +1,7 @@ /* * iq.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/message.c b/src/xmpp/message.c index e96c1a74..bc702199 100644 --- a/src/xmpp/message.c +++ b/src/xmpp/message.c @@ -1,7 +1,7 @@ /* * message.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -42,7 +42,8 @@ #include "log.h" #include "muc.h" #include "profanity.h" -#include "server_events.h" +#include "ui/ui.h" +#include "event/server_events.h" #include "xmpp/connection.h" #include "xmpp/message.h" #include "xmpp/roster.h" @@ -52,18 +53,13 @@ #define HANDLE(ns, type, func) xmpp_handler_add(conn, func, ns, STANZA_NAME_MESSAGE, type, ctx) -static int _groupchat_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _chat_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _muc_user_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _conference_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _captcha_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata); -static int _message_error_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata); +static int _groupchat_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _chat_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _muc_user_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _conference_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _captcha_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _message_error_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _receipt_received_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); void message_add_handlers(void) @@ -77,34 +73,89 @@ message_add_handlers(void) HANDLE(STANZA_NS_MUC_USER, NULL, _muc_user_handler); HANDLE(STANZA_NS_CONFERENCE, NULL, _conference_handler); HANDLE(STANZA_NS_CAPTCHA, NULL, _captcha_handler); + HANDLE(STANZA_NS_RECEIPTS, NULL, _receipt_received_handler); } -void +char * message_send_chat(const char * const barejid, const char * const msg) { - xmpp_stanza_t *message; xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); ChatSession *session = chat_session_get(barejid); + char *state = NULL; + char *jid = NULL; + if (session) { + if (prefs_get_boolean(PREF_STATES) && session->send_states) { + state = STANZA_NAME_ACTIVE; + } + Jid *jidp = jid_create_from_bare_and_resource(session->barejid, session->resource); + jid = strdup(jidp->fulljid); + jid_destroy(jidp); + + } else { + if (prefs_get_boolean(PREF_STATES)) { + state = STANZA_NAME_ACTIVE; + } + jid = strdup(barejid); + } + + char *id = create_unique_id("msg"); + xmpp_stanza_t *message = stanza_create_message(ctx, id, jid, STANZA_TYPE_CHAT, msg); + free(jid); + + if (state) { + stanza_attach_state(ctx, message, state); + } + if (prefs_get_boolean(PREF_RECEIPTS_REQUEST)) { + stanza_attach_receipt_request(ctx, message); + } + + xmpp_send(conn, message); + xmpp_stanza_release(message); + + return id; +} + +char * +message_send_chat_encrypted(const char * const barejid, const char * const msg) +{ + xmpp_conn_t * const conn = connection_get_conn(); + xmpp_ctx_t * const ctx = connection_get_ctx(); + + ChatSession *session = chat_session_get(barejid); + char *state = NULL; + char *jid = NULL; if (session) { - char *state = NULL; if (prefs_get_boolean(PREF_STATES) && session->send_states) { state = STANZA_NAME_ACTIVE; } Jid *jidp = jid_create_from_bare_and_resource(session->barejid, session->resource); - message = stanza_create_message(ctx, jidp->fulljid, STANZA_TYPE_CHAT, msg, state); + jid = strdup(jidp->fulljid); jid_destroy(jidp); } else { - char *state = NULL; if (prefs_get_boolean(PREF_STATES)) { state = STANZA_NAME_ACTIVE; } - message = stanza_create_message(ctx, barejid, STANZA_TYPE_CHAT, msg, state); + jid = strdup(barejid); + } + + char *id = create_unique_id("msg"); + xmpp_stanza_t *message = stanza_create_message(ctx, id, barejid, STANZA_TYPE_CHAT, msg); + free(jid); + + if (state) { + stanza_attach_state(ctx, message, state); + } + stanza_attach_carbons_private(ctx, message); + if (prefs_get_boolean(PREF_RECEIPTS_REQUEST)) { + stanza_attach_receipt_request(ctx, message); } xmpp_send(conn, message); xmpp_stanza_release(message); + + return id; } void @@ -112,7 +163,9 @@ message_send_private(const char * const fulljid, const char * const msg) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); - xmpp_stanza_t *message = stanza_create_message(ctx, fulljid, STANZA_TYPE_CHAT, msg, NULL); + char *id = create_unique_id("prv"); + xmpp_stanza_t *message = stanza_create_message(ctx, id, fulljid, STANZA_TYPE_CHAT, msg); + free(id); xmpp_send(conn, message); xmpp_stanza_release(message); @@ -123,7 +176,9 @@ message_send_groupchat(const char * const roomjid, const char * const msg) { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); - xmpp_stanza_t *message = stanza_create_message(ctx, roomjid, STANZA_TYPE_GROUPCHAT, msg, NULL); + char *id = create_unique_id("muc"); + xmpp_stanza_t *message = stanza_create_message(ctx, id, roomjid, STANZA_TYPE_GROUPCHAT, msg); + free(id); xmpp_send(conn, message); xmpp_stanza_release(message); @@ -146,7 +201,18 @@ message_send_invite(const char * const roomjid, const char * const contact, { xmpp_conn_t * const conn = connection_get_conn(); xmpp_ctx_t * const ctx = connection_get_ctx(); - xmpp_stanza_t *stanza = stanza_create_invite(ctx, roomjid, contact, reason); + xmpp_stanza_t *stanza; + + + muc_member_type_t member_type = muc_member_type(roomjid); + if (member_type == MUC_MEMBER_TYPE_PUBLIC) { + log_debug("Sending direct invite to %s, for %s", contact, roomjid); + char *password = muc_password(roomjid); + stanza = stanza_create_invite(ctx, roomjid, contact, reason, password); + } else { + log_debug("Sending mediated invite to %s, for %s", contact, roomjid); + stanza = stanza_create_mediated_invite(ctx, roomjid, contact, reason); + } xmpp_send(conn, stanza); xmpp_stanza_release(stanza); @@ -196,14 +262,13 @@ message_send_gone(const char * const jid) } static int -_message_error_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, - void * const userdata) +_message_error_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { char *id = xmpp_stanza_get_id(stanza); char *jid = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); xmpp_stanza_t *error_stanza = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_ERROR); char *type = NULL; - if (error_stanza != NULL) { + if (error_stanza) { type = xmpp_stanza_get_attribute(error_stanza, STANZA_ATTR_TYPE); } @@ -211,15 +276,15 @@ _message_error_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, char *err_msg = stanza_get_error_message(stanza); GString *log_msg = g_string_new("message stanza error received"); - if (id != NULL) { + if (id) { g_string_append(log_msg, " id="); g_string_append(log_msg, id); } - if (jid != NULL) { + if (jid) { g_string_append(log_msg, " from="); g_string_append(log_msg, jid); } - if (type != NULL) { + if (type) { g_string_append(log_msg, " type="); g_string_append(log_msg, type); } @@ -230,7 +295,16 @@ _message_error_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, g_string_free(log_msg, TRUE); - handle_message_error(jid, type, err_msg); + if (!jid) { + ui_handle_error(err_msg); + } else if (type && (strcmp(type, "cancel") == 0)) { + log_info("Recipient %s not found: %s", jid, err_msg); + Jid *jidp = jid_create(jid); + chat_session_remove(jidp->barejid); + jid_destroy(jidp); + } else { + ui_handle_recipient_error(jid, err_msg); + } free(err_msg); @@ -238,113 +312,120 @@ _message_error_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, } static int -_muc_user_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, - void * const userdata) +_muc_user_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { xmpp_ctx_t *ctx = connection_get_ctx(); xmpp_stanza_t *xns_muc_user = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER); char *room = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); - if (room == NULL) { + if (!room) { log_warning("Message received with no from attribute, ignoring"); return 1; } // XEP-0045 xmpp_stanza_t *invite = xmpp_stanza_get_child_by_name(xns_muc_user, STANZA_NAME_INVITE); - if (invite != NULL) { - char *invitor_jid = xmpp_stanza_get_attribute(invite, STANZA_ATTR_FROM); - if (invitor_jid == NULL) { - log_warning("Chat room invite received with no from attribute"); - return 1; - } + if (!invite) { + return 1; + } - Jid *jidp = jid_create(invitor_jid); - if (jidp == NULL) { - return 1; - } - char *invitor = jidp->barejid; + char *invitor_jid = xmpp_stanza_get_attribute(invite, STANZA_ATTR_FROM); + if (!invitor_jid) { + log_warning("Chat room invite received with no from attribute"); + return 1; + } - char *reason = NULL; - xmpp_stanza_t *reason_st = xmpp_stanza_get_child_by_name(invite, STANZA_NAME_REASON); - if (reason_st != NULL) { - reason = xmpp_stanza_get_text(reason_st); - } + Jid *jidp = jid_create(invitor_jid); + if (!jidp) { + return 1; + } + char *invitor = jidp->barejid; - handle_room_invite(INVITE_MEDIATED, invitor, room, reason); - jid_destroy(jidp); - if (reason != NULL) { - xmpp_free(ctx, reason); - } + char *reason = NULL; + xmpp_stanza_t *reason_st = xmpp_stanza_get_child_by_name(invite, STANZA_NAME_REASON); + if (reason_st) { + reason = xmpp_stanza_get_text(reason_st); + } + + char *password = NULL; + xmpp_stanza_t *password_st = xmpp_stanza_get_child_by_name(xns_muc_user, STANZA_NAME_PASSWORD); + if (password_st) { + password = xmpp_stanza_get_text(password_st); + } + + sv_ev_room_invite(INVITE_MEDIATED, invitor, room, reason, password); + jid_destroy(jidp); + if (reason) { + xmpp_free(ctx, reason); + } + if (password) { + xmpp_free(ctx, password); } return 1; } static int -_conference_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, - void * const userdata) +_conference_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { xmpp_stanza_t *xns_conference = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_CONFERENCE); - char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); - char *room = NULL; - char *invitor = NULL; - char *reason = NULL; - if (from == NULL) { + char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); + if (!from) { log_warning("Message received with no from attribute, ignoring"); return 1; } - // XEP-0429 - room = xmpp_stanza_get_attribute(xns_conference, STANZA_ATTR_JID); - if (room == NULL) { + Jid *jidp = jid_create(from); + if (!jidp) { return 1; } - Jid *jidp = jid_create(from); - if (jidp == NULL) { + // XEP-0249 + char *room = xmpp_stanza_get_attribute(xns_conference, STANZA_ATTR_JID); + if (!room) { return 1; } - invitor = jidp->barejid; - reason = xmpp_stanza_get_attribute(xns_conference, STANZA_ATTR_REASON); - - handle_room_invite(INVITE_DIRECT, invitor, room, reason); + char *reason = xmpp_stanza_get_attribute(xns_conference, STANZA_ATTR_REASON); + char *password = xmpp_stanza_get_attribute(xns_conference, STANZA_ATTR_PASSWORD); + sv_ev_room_invite(INVITE_DIRECT, jidp->barejid, room, reason, password); jid_destroy(jidp); return 1; } static int -_captcha_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, - void * const userdata) +_captcha_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { xmpp_ctx_t *ctx = connection_get_ctx(); char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); - if (from == NULL) { + if (!from) { log_warning("Message received with no from attribute, ignoring"); return 1; } // XEP-0158 xmpp_stanza_t *body = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_BODY); - if (body != NULL) { - char *message = xmpp_stanza_get_text(body); - if (message != NULL) { - handle_room_broadcast(from, message); - xmpp_free(ctx, message); - } + if (!body) { + return 1; } + char *message = xmpp_stanza_get_text(body); + if (!message) { + return 1; + } + + sv_ev_room_broadcast(from, message); + xmpp_free(ctx, message); + return 1; } static int -_groupchat_handler(xmpp_conn_t * const conn, - xmpp_stanza_t * const stanza, void * const userdata) +_groupchat_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { xmpp_ctx_t *ctx = connection_get_ctx(); char *message = NULL; @@ -353,9 +434,9 @@ _groupchat_handler(xmpp_conn_t * const conn, // handle room subject xmpp_stanza_t *subject = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_SUBJECT); - if (subject != NULL) { + if (subject) { message = xmpp_stanza_get_text(subject); - handle_room_subject(jid->barejid, jid->resourcepart, message); + sv_ev_room_subject(jid->barejid, jid->resourcepart, message); xmpp_free(ctx, message); jid_destroy(jid); @@ -363,16 +444,22 @@ _groupchat_handler(xmpp_conn_t * const conn, } // handle room broadcasts - if (jid->resourcepart == NULL) { + if (!jid->resourcepart) { xmpp_stanza_t *body = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_BODY); - if (body != NULL) { - message = xmpp_stanza_get_text(body); - if (message != NULL) { - handle_room_broadcast(room_jid, message); - xmpp_free(ctx, message); - } + if (!body) { + jid_destroy(jid); + return 1; } + message = xmpp_stanza_get_text(body); + if (!message) { + jid_destroy(jid); + return 1; + } + + sv_ev_room_broadcast(room_jid, message); + xmpp_free(ctx, message); + jid_destroy(jid); return 1; } @@ -390,32 +477,191 @@ _groupchat_handler(xmpp_conn_t * const conn, return 1; } + xmpp_stanza_t *body = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_BODY); + + // check for and deal with message + if (!body) { + jid_destroy(jid); + return 1; + } + + message = xmpp_stanza_get_text(body); + if (!message) { + jid_destroy(jid); + return 1; + } + // determine if the notifications happened whilst offline GTimeVal tv_stamp; gboolean delayed = stanza_get_delay(stanza, &tv_stamp); + if (delayed) { + sv_ev_room_history(jid->barejid, jid->resourcepart, tv_stamp, message); + } else { + sv_ev_room_message(jid->barejid, jid->resourcepart, message); + } + + xmpp_free(ctx, message); + jid_destroy(jid); + + return 1; +} + +void +_message_send_receipt(const char * const fulljid, const char * const message_id) +{ + xmpp_conn_t * const conn = connection_get_conn(); + xmpp_ctx_t * const ctx = connection_get_ctx(); + xmpp_stanza_t *message = xmpp_stanza_new(ctx); + char *id = create_unique_id("receipt"); + xmpp_stanza_set_name(message, STANZA_NAME_MESSAGE); + xmpp_stanza_set_id(message, id); + xmpp_stanza_set_attribute(message, STANZA_ATTR_TO, fulljid); + + xmpp_stanza_t *receipt = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(receipt, "received"); + xmpp_stanza_set_ns(receipt, STANZA_NS_RECEIPTS); + xmpp_stanza_set_attribute(receipt, STANZA_ATTR_ID, message_id); + + xmpp_stanza_add_child(message, receipt); + xmpp_stanza_release(receipt); + + xmpp_send(conn, message); + xmpp_stanza_release(message); +} + +static int +_receipt_received_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) +{ + xmpp_stanza_t *receipt = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_RECEIPTS); + char *name = xmpp_stanza_get_name(receipt); + if (g_strcmp0(name, "received") != 0) { + return 1; + } + + char *id = xmpp_stanza_get_attribute(receipt, STANZA_ATTR_ID); + if (!id) { + return 1; + } + + char *fulljid = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); + if (!fulljid) { + return 1; + } + + Jid *jidp = jid_create(fulljid); + sv_ev_message_receipt(jidp->barejid, id); + jid_destroy(jidp); + + return 1; +} + +void +_receipt_request_handler(xmpp_stanza_t * const stanza) +{ + if (!prefs_get_boolean(PREF_RECEIPTS_SEND)) { + return; + } + + char *id = xmpp_stanza_get_id(stanza); + if (!id) { + return; + } + + xmpp_stanza_t *receipts = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_RECEIPTS); + if (!receipts) { + return; + } + + char *receipts_name = xmpp_stanza_get_name(receipts); + if (g_strcmp0(receipts_name, "request") != 0) { + return; + } + + gchar *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); + Jid *jid = jid_create(from); + _message_send_receipt(jid->fulljid, id); + jid_destroy(jid); +} + +void +_private_chat_handler(xmpp_stanza_t * const stanza, const char * const fulljid) +{ xmpp_stanza_t *body = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_BODY); + if (!body) { + return; + } - // check for and deal with message - if (body != NULL) { - message = xmpp_stanza_get_text(body); - if (message != NULL) { - if (delayed) { - handle_room_history(jid->barejid, jid->resourcepart, tv_stamp, message); - } else { - handle_room_message(jid->barejid, jid->resourcepart, message); + char *message = xmpp_stanza_get_text(body); + if (!message) { + return; + } + + GTimeVal tv_stamp; + gboolean delayed = stanza_get_delay(stanza, &tv_stamp); + if (delayed) { + sv_ev_delayed_private_message(fulljid, message, tv_stamp); + } else { + sv_ev_incoming_private_message(fulljid, message); + } + + xmpp_ctx_t *ctx = connection_get_ctx(); + xmpp_free(ctx, message); +} + +static gboolean +_handle_carbons(xmpp_stanza_t * const stanza) +{ + xmpp_stanza_t *carbons = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_CARBONS); + if (!carbons) { + return FALSE; + } + + char *name = xmpp_stanza_get_name(carbons); + if ((g_strcmp0(name, "received") == 0) || (g_strcmp0(name, "sent")) == 0) { + xmpp_stanza_t *forwarded = xmpp_stanza_get_child_by_ns(carbons, STANZA_NS_FORWARD); + xmpp_stanza_t *message = xmpp_stanza_get_child_by_name(forwarded, STANZA_NAME_MESSAGE); + + xmpp_ctx_t *ctx = connection_get_ctx(); + + gchar *to = xmpp_stanza_get_attribute(message, STANZA_ATTR_TO); + gchar *from = xmpp_stanza_get_attribute(message, STANZA_ATTR_FROM); + + // happens when receive a carbon of a self sent message + if (!to) to = from; + + Jid *jid_from = jid_create(from); + Jid *jid_to = jid_create(to); + Jid *my_jid = jid_create(jabber_get_fulljid()); + + // check for and deal with message + xmpp_stanza_t *body = xmpp_stanza_get_child_by_name(message, STANZA_NAME_BODY); + if (body) { + char *message = xmpp_stanza_get_text(body); + if (message) { + // if we are the recipient, treat as standard incoming message + if(g_strcmp0(my_jid->barejid, jid_to->barejid) == 0){ + sv_ev_incoming_message(jid_from->barejid, jid_from->resourcepart, message); + } + // else treat as a sent message + else{ + sv_ev_carbon(jid_to->barejid, message); + } + xmpp_free(ctx, message); } - xmpp_free(ctx, message); } - } - jid_destroy(jid); + jid_destroy(jid_from); + jid_destroy(jid_to); + jid_destroy(my_jid); - return 1; + return TRUE; + } + + return FALSE; } static int -_chat_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, - void * const userdata) +_chat_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { // ignore if type not chat or absent char *type = xmpp_stanza_get_type(stanza); @@ -423,6 +669,12 @@ _chat_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, return 1; } + // check if carbon message + gboolean res = _handle_carbons(stanza); + if (res) { + return 1; + } + // ignore handled namespaces xmpp_stanza_t *conf = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_CONFERENCE); xmpp_stanza_t *mucuser = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER); @@ -431,76 +683,57 @@ _chat_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, return 1; } - xmpp_ctx_t *ctx = connection_get_ctx(); gchar *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); - Jid *jid = jid_create(from); // private message from chat room use full jid (room/nick) if (muc_active(jid->barejid)) { - // determine if the notifications happened whilst offline - GTimeVal tv_stamp; - gboolean delayed = stanza_get_delay(stanza, &tv_stamp); - - // check for and deal with message - xmpp_stanza_t *body = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_BODY); - if (body != NULL) { - char *message = xmpp_stanza_get_text(body); - if (message != NULL) { - if (delayed) { - handle_delayed_private_message(jid->str, message, tv_stamp); - } else { - handle_incoming_private_message(jid->str, message); - } - xmpp_free(ctx, message); - } - } - - jid_destroy(jid); + _private_chat_handler(stanza, jid->fulljid); return 1; + } // standard chat message, use jid without resource - } else { - // determine if the notifications happened whilst offline - GTimeVal tv_stamp; - gboolean delayed = stanza_get_delay(stanza, &tv_stamp); - - // check for and deal with message - xmpp_stanza_t *body = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_BODY); - if (body != NULL) { - char *message = xmpp_stanza_get_text(body); - if (message != NULL) { - if (delayed) { - handle_delayed_message(jid->barejid, message, tv_stamp); - } else { - handle_incoming_message(jid->barejid, jid->resourcepart, message); - } - xmpp_free(ctx, message); - } - } + GTimeVal tv_stamp; + gboolean delayed = stanza_get_delay(stanza, &tv_stamp); - // handle chat sessions and states - if (!delayed && jid->resourcepart) { - gboolean gone = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_GONE) != NULL; - gboolean typing = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_COMPOSING) != NULL; - gboolean paused = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_PAUSED) != NULL; - gboolean inactive = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_INACTIVE) != NULL; - if (gone) { - handle_gone(jid->barejid, jid->resourcepart); - } else if (typing) { - handle_typing(jid->barejid, jid->resourcepart); - } else if (paused) { - handle_paused(jid->barejid, jid->resourcepart); - } else if (inactive) { - handle_inactive(jid->barejid, jid->resourcepart); - } else if (stanza_contains_chat_state(stanza)) { - handle_activity(jid->barejid, jid->resourcepart, TRUE); + xmpp_stanza_t *body = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_BODY); + if (body) { + char *message = xmpp_stanza_get_text(body); + if (message) { + if (delayed) { + sv_ev_delayed_message(jid->barejid, message, tv_stamp); } else { - handle_activity(jid->barejid, jid->resourcepart, FALSE); + sv_ev_incoming_message(jid->barejid, jid->resourcepart, message); } + + _receipt_request_handler(stanza); + + xmpp_ctx_t *ctx = connection_get_ctx(); + xmpp_free(ctx, message); } + } - jid_destroy(jid); - return 1; + // handle chat sessions and states + if (!delayed && jid->resourcepart) { + gboolean gone = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_GONE) != NULL; + gboolean typing = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_COMPOSING) != NULL; + gboolean paused = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_PAUSED) != NULL; + gboolean inactive = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_INACTIVE) != NULL; + if (gone) { + sv_ev_gone(jid->barejid, jid->resourcepart); + } else if (typing) { + sv_ev_typing(jid->barejid, jid->resourcepart); + } else if (paused) { + sv_ev_paused(jid->barejid, jid->resourcepart); + } else if (inactive) { + sv_ev_inactive(jid->barejid, jid->resourcepart); + } else if (stanza_contains_chat_state(stanza)) { + sv_ev_activity(jid->barejid, jid->resourcepart, TRUE); + } else { + sv_ev_activity(jid->barejid, jid->resourcepart, FALSE); + } } -} \ No newline at end of file + + jid_destroy(jid); + return 1; +} diff --git a/src/xmpp/message.h b/src/xmpp/message.h index b3410dc9..6fbc27bd 100644 --- a/src/xmpp/message.h +++ b/src/xmpp/message.h @@ -1,7 +1,7 @@ /* * message.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/presence.c b/src/xmpp/presence.c index 65384a0d..e46730e3 100644 --- a/src/xmpp/presence.c +++ b/src/xmpp/presence.c @@ -1,7 +1,7 @@ /* * presence.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -44,7 +44,8 @@ #include "log.h" #include "muc.h" #include "profanity.h" -#include "server_events.h" +#include "ui/ui.h" +#include "event/server_events.h" #include "xmpp/capabilities.h" #include "xmpp/connection.h" #include "xmpp/stanza.h" @@ -170,7 +171,7 @@ presence_sub_request_exists(const char * const bare_jid) GSList *requests_p = autocomplete_create_list(sub_requests_ac); GSList *requests = requests_p; - while (requests != NULL) { + while (requests) { if (strcmp(requests->data, bare_jid) == 0) { result = TRUE; break; @@ -178,7 +179,7 @@ presence_sub_request_exists(const char * const bare_jid) requests = g_slist_next(requests); } - if (requests_p != NULL) { + if (requests_p) { g_slist_free_full(requests_p, free); } @@ -192,27 +193,22 @@ presence_reset_sub_request_search(void) } void -presence_update(const resource_presence_t presence_type, const char * const msg, - const int idle) +presence_send(const resource_presence_t presence_type, const char * const msg, const int idle) { if (jabber_get_connection_status() != JABBER_CONNECTED) { log_warning("Error setting presence, not connected."); return; } - if (msg != NULL) { - log_debug("Updating presence: %s, \"%s\"", - string_from_resource_presence(presence_type), msg); + if (msg) { + log_debug("Updating presence: %s, \"%s\"", string_from_resource_presence(presence_type), msg); } else { - log_debug("Updating presence: %s", - string_from_resource_presence(presence_type)); + log_debug("Updating presence: %s", string_from_resource_presence(presence_type)); } xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_conn_t * const conn = connection_get_conn(); - const int pri = - accounts_get_priority_for_presence_type(jabber_get_account_name(), - presence_type); + const int pri = accounts_get_priority_for_presence_type(jabber_get_account_name(), presence_type); const char *show = stanza_get_presence_string_from_type(presence_type); connection_set_presence_message(msg); @@ -245,11 +241,11 @@ _send_room_presence(xmpp_conn_t *conn, xmpp_stanza_t *presence) GList *rooms_p = muc_rooms(); GList *rooms = rooms_p; - while (rooms != NULL) { + while (rooms) { const char *room = rooms->data; const char *nick = muc_nick(room); - if (nick != NULL) { + if (nick) { char *full_room_jid = create_fulljid(room, nick); xmpp_stanza_set_attribute(presence, STANZA_ATTR_TO, full_room_jid); @@ -261,7 +257,7 @@ _send_room_presence(xmpp_conn_t *conn, xmpp_stanza_t *presence) rooms = g_list_next(rooms); } - if (rooms_p != NULL) { + if (rooms_p) { g_list_free(rooms_p); } } @@ -333,7 +329,7 @@ presence_leave_chat_room(const char * const room_jid) xmpp_conn_t *conn = connection_get_conn(); char *nick = muc_nick(room_jid); - if (nick != NULL) { + if (nick) { xmpp_stanza_t *presence = stanza_create_room_leave_presence(ctx, room_jid, nick); xmpp_send(conn, presence); @@ -350,11 +346,11 @@ _presence_error_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, xmpp_stanza_t *error_stanza = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_ERROR); xmpp_stanza_t *x = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_X); char *xmlns = NULL; - if (x != NULL) { + if (x) { xmlns = xmpp_stanza_get_ns(x); } char *type = NULL; - if (error_stanza != NULL) { + if (error_stanza) { type = xmpp_stanza_get_attribute(error_stanza, STANZA_ATTR_TYPE); } @@ -364,7 +360,7 @@ _presence_error_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, char *error_cond = NULL; xmpp_stanza_t *reason_st = xmpp_stanza_get_child_by_ns(error_stanza, STANZA_NS_STANZAS); - if (reason_st != NULL) { + if (reason_st) { error_cond = xmpp_stanza_get_name(reason_st); } if (error_cond == NULL) { @@ -372,7 +368,10 @@ _presence_error_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, } log_info("Error joining room: %s, reason: %s", fulljid->barejid, error_cond); - handle_room_join_error(fulljid->barejid, error_cond); + if (muc_active(fulljid->barejid)) { + muc_leave(fulljid->barejid); + } + ui_handle_room_join_error(fulljid->barejid, error_cond); jid_destroy(fulljid); return 1; } @@ -381,15 +380,15 @@ _presence_error_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, char *err_msg = stanza_get_error_message(stanza); GString *log_msg = g_string_new("presence stanza error received"); - if (id != NULL) { + if (id) { g_string_append(log_msg, " id="); g_string_append(log_msg, id); } - if (from != NULL) { + if (from) { g_string_append(log_msg, " from="); g_string_append(log_msg, from); } - if (type != NULL) { + if (type) { g_string_append(log_msg, " type="); g_string_append(log_msg, type); } @@ -400,7 +399,11 @@ _presence_error_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, g_string_free(log_msg, TRUE); - handle_presence_error(from, type, err_msg); + if (from) { + ui_handle_recipient_error(from, err_msg); + } else { + ui_handle_error(err_msg); + } free(err_msg); @@ -416,7 +419,7 @@ _unsubscribed_handler(xmpp_conn_t * const conn, Jid *from_jid = jid_create(from); log_debug("Unsubscribed presence handler fired for %s", from); - handle_subscription(from_jid->barejid, PRESENCE_UNSUBSCRIBED); + sv_ev_subscription(from_jid->barejid, PRESENCE_UNSUBSCRIBED); autocomplete_remove(sub_requests_ac, from_jid->barejid); jid_destroy(from_jid); @@ -432,7 +435,7 @@ _subscribed_handler(xmpp_conn_t * const conn, Jid *from_jid = jid_create(from); log_debug("Subscribed presence handler fired for %s", from); - handle_subscription(from_jid->barejid, PRESENCE_SUBSCRIBED); + sv_ev_subscription(from_jid->barejid, PRESENCE_SUBSCRIBED); autocomplete_remove(sub_requests_ac, from_jid->barejid); jid_destroy(from_jid); @@ -452,7 +455,7 @@ _subscribe_handler(xmpp_conn_t * const conn, return 1; } - handle_subscription(from_jid->barejid, PRESENCE_SUBSCRIBE); + sv_ev_subscription(from_jid->barejid, PRESENCE_SUBSCRIBE); autocomplete_add(sub_requests_ac, from_jid->barejid); jid_destroy(from_jid); @@ -464,6 +467,8 @@ static int _unavailable_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { + ui_input_nonblocking(TRUE); + const char *jid = xmpp_conn_get_jid(conn); char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); log_debug("Unavailable presence handler fired for %s", from); @@ -479,15 +484,15 @@ _unavailable_handler(xmpp_conn_t * const conn, char *status_str = stanza_get_status(stanza, NULL); if (strcmp(my_jid->barejid, from_jid->barejid) !=0) { - if (from_jid->resourcepart != NULL) { - handle_contact_offline(from_jid->barejid, from_jid->resourcepart, status_str); + if (from_jid->resourcepart) { + sv_ev_contact_offline(from_jid->barejid, from_jid->resourcepart, status_str); // hack for servers that do not send full jid with unavailable presence } else { - handle_contact_offline(from_jid->barejid, "__prof_default", status_str); + sv_ev_contact_offline(from_jid->barejid, "__prof_default", status_str); } } else { - if (from_jid->resourcepart != NULL) { + if (from_jid->resourcepart) { connection_remove_available_resource(from_jid->resourcepart); } } @@ -517,7 +522,7 @@ _handle_caps(char *jid, XMPPCaps *caps) } } - // unsupported hash, xep-0115, assoiciate with JID, no cache + // unsupported hash, xep-0115, associate with JID, no cache } else if (caps->hash) { log_info("Hash %s not supported: %s, sending service discovery request", caps->hash, jid); char *id = create_unique_id("caps"); @@ -539,6 +544,8 @@ static int _available_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { + ui_input_nonblocking(TRUE); + // handler still fires if error if (g_strcmp0(xmpp_stanza_get_type(stanza), STANZA_TYPE_ERROR) == 0) { return 1; @@ -596,7 +603,7 @@ _available_handler(xmpp_conn_t * const conn, if (g_strcmp0(xmpp_presence->jid->barejid, my_jid->barejid) == 0) { connection_add_available_resource(resource); } else { - handle_contact_online(xmpp_presence->jid->barejid, resource, xmpp_presence->last_activity); + sv_ev_contact_online(xmpp_presence->jid->barejid, resource, xmpp_presence->last_activity); } jid_destroy(my_jid); @@ -611,7 +618,7 @@ _send_caps_request(char *node, char *caps_key, char *id, char *from) xmpp_ctx_t *ctx = connection_get_ctx(); xmpp_conn_t *conn = connection_get_conn(); - if (node != NULL) { + if (node) { log_debug("Node string: %s.", node); if (!caps_contains(caps_key)) { log_debug("Capabilities not cached for '%s', sending discovery IQ.", from); @@ -629,6 +636,8 @@ _send_caps_request(char *node, char *caps_key, char *id, char *from) static int _muc_user_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { + ui_input_nonblocking(TRUE); + char *type = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_TYPE); char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); @@ -682,27 +691,27 @@ _muc_user_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * char *new_jid = stanza_get_muc_destroy_alternative_room(stanza); char *password = stanza_get_muc_destroy_alternative_password(stanza); char *reason = stanza_get_muc_destroy_reason(stanza); - handle_room_destroyed(room, new_jid, password, reason); + sv_ev_room_destroyed(room, new_jid, password, reason); free(password); free(reason); // kicked from room - } else if (g_slist_find_custom(status_codes, "307", (GCompareFunc)g_strcmp0) != NULL) { + } else if (g_slist_find_custom(status_codes, "307", (GCompareFunc)g_strcmp0)) { char *actor = stanza_get_actor(stanza); char *reason = stanza_get_reason(stanza); - handle_room_kicked(room, actor, reason); + sv_ev_room_kicked(room, actor, reason); free(reason); // banned from room - } else if (g_slist_find_custom(status_codes, "301", (GCompareFunc)g_strcmp0) != NULL) { + } else if (g_slist_find_custom(status_codes, "301", (GCompareFunc)g_strcmp0)) { char *actor = stanza_get_actor(stanza); char *reason = stanza_get_reason(stanza); - handle_room_banned(room, actor, reason); + sv_ev_room_banned(room, actor, reason); free(reason); // normal exit } else { - handle_leave_room(room); + sv_ev_leave_room(room); } g_slist_free_full(status_codes, free); @@ -713,7 +722,7 @@ _muc_user_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * gboolean config_required = stanza_muc_requires_config(stanza); char *actor = stanza_get_actor(stanza); char *reason = stanza_get_reason(stanza); - handle_muc_self_online(room, nick, config_required, role, affiliation, actor, reason, jid, show_str, status_str); + sv_ev_muc_self_online(room, nick, config_required, role, affiliation, actor, reason, jid, show_str, status_str); } // handle presence from room members @@ -732,22 +741,22 @@ _muc_user_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * GSList *status_codes = stanza_get_status_codes_by_ns(stanza, STANZA_NS_MUC_USER); // kicked from room - if (g_slist_find_custom(status_codes, "307", (GCompareFunc)g_strcmp0) != NULL) { + if (g_slist_find_custom(status_codes, "307", (GCompareFunc)g_strcmp0)) { char *actor = stanza_get_actor(stanza); char *reason = stanza_get_reason(stanza); - handle_room_occupent_kicked(room, nick, actor, reason); + sv_ev_room_occupent_kicked(room, nick, actor, reason); free(reason); // banned from room - } else if (g_slist_find_custom(status_codes, "301", (GCompareFunc)g_strcmp0) != NULL) { + } else if (g_slist_find_custom(status_codes, "301", (GCompareFunc)g_strcmp0)) { char *actor = stanza_get_actor(stanza); char *reason = stanza_get_reason(stanza); - handle_room_occupent_banned(room, nick, actor, reason); + sv_ev_room_occupent_banned(room, nick, actor, reason); free(reason); // normal exit } else { - handle_room_occupant_offline(room, nick, "offline", status_str); + sv_ev_room_occupant_offline(room, nick, "offline", status_str); } g_slist_free_full(status_codes, free); @@ -765,7 +774,7 @@ _muc_user_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * char *actor = stanza_get_actor(stanza); char *reason = stanza_get_reason(stanza); - handle_muc_occupant_online(room, nick, jid, role, affiliation, actor, reason, show_str, status_str); + sv_ev_muc_occupant_online(room, nick, jid, role, affiliation, actor, reason, show_str, status_str); } } diff --git a/src/xmpp/presence.h b/src/xmpp/presence.h index e704aea0..90b83473 100644 --- a/src/xmpp/presence.h +++ b/src/xmpp/presence.h @@ -1,7 +1,7 @@ /* * presence.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/roster.c b/src/xmpp/roster.c index 3449c8d5..5c9fa5d4 100644 --- a/src/xmpp/roster.c +++ b/src/xmpp/roster.c @@ -1,7 +1,7 @@ /* * roster.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -41,7 +41,9 @@ #include "log.h" #include "profanity.h" -#include "server_events.h" +#include "ui/ui.h" +#include "event/server_events.h" +#include "event/client_events.h" #include "tools/autocomplete.h" #include "xmpp/connection.h" #include "xmpp/roster.h" @@ -131,7 +133,7 @@ roster_send_add_to_group(const char * const group, PContact contact) { GSList *groups = p_contact_groups(contact); GSList *new_groups = NULL; - while (groups != NULL) { + while (groups) { new_groups = g_slist_append(new_groups, strdup(groups->data)); groups = g_slist_next(groups); } @@ -141,7 +143,7 @@ roster_send_add_to_group(const char * const group, PContact contact) char *unique_id = create_unique_id(NULL); GroupData *data = malloc(sizeof(GroupData)); data->group = strdup(group); - if (p_contact_name(contact) != NULL) { + if (p_contact_name(contact)) { data->name = strdup(p_contact_name(contact)); } else { data->name = strdup(p_contact_barejid(contact)); @@ -161,9 +163,9 @@ static int _group_add_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { - if (userdata != NULL) { + if (userdata) { GroupData *data = userdata; - handle_group_add(data->name, data->group); + ui_group_added(data->name, data->group); free(data->name); free(data->group); free(userdata); @@ -176,7 +178,7 @@ roster_send_remove_from_group(const char * const group, PContact contact) { GSList *groups = p_contact_groups(contact); GSList *new_groups = NULL; - while (groups != NULL) { + while (groups) { if (strcmp(groups->data, group) != 0) { new_groups = g_slist_append(new_groups, strdup(groups->data)); } @@ -190,7 +192,7 @@ roster_send_remove_from_group(const char * const group, PContact contact) char *unique_id = create_unique_id(NULL); GroupData *data = malloc(sizeof(GroupData)); data->group = strdup(group); - if (p_contact_name(contact) != NULL) { + if (p_contact_name(contact)) { data->name = strdup(p_contact_name(contact)); } else { data->name = strdup(p_contact_barejid(contact)); @@ -208,9 +210,9 @@ static int _group_remove_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { - if (userdata != NULL) { + if (userdata) { GroupData *data = userdata; - handle_group_remove(data->name, data->group); + ui_group_removed(data->name, data->group); free(data->name); free(data->group); free(userdata); @@ -234,13 +236,14 @@ _roster_set_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, // if from attribute exists and it is not current users barejid, ignore push Jid *my_jid = jid_create(jabber_get_fulljid()); const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM); - if ((from != NULL) && (strcmp(from, my_jid->barejid) != 0)) { + if (from && (strcmp(from, my_jid->barejid) != 0)) { jid_destroy(my_jid); return 1; } jid_destroy(my_jid); const char *barejid = xmpp_stanza_get_attribute(item, STANZA_ATTR_JID); + gchar *barejid_lower = g_utf8_strdown(barejid, -1); const char *name = xmpp_stanza_get_attribute(item, STANZA_ATTR_NAME); const char *sub = xmpp_stanza_get_attribute(item, STANZA_ATTR_SUBSCRIPTION); const char *ask = xmpp_stanza_get_attribute(item, STANZA_ATTR_ASK); @@ -254,83 +257,83 @@ _roster_set_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, if (g_strcmp0(sub, "remove") == 0) { // remove barejid and name if (name == NULL) { - name = barejid; + name = barejid_lower; } - - roster_remove(name, barejid); - - handle_roster_remove(barejid); + roster_remove(name, barejid_lower); + ui_roster_remove(barejid_lower); // otherwise update local roster } else { // check for pending out subscriptions gboolean pending_out = FALSE; - if ((ask != NULL) && (strcmp(ask, "subscribe") == 0)) { + if (ask && (strcmp(ask, "subscribe") == 0)) { pending_out = TRUE; } GSList *groups = _get_groups_from_item(item); // update the local roster - PContact contact = roster_get_contact(barejid); + PContact contact = roster_get_contact(barejid_lower); if (contact == NULL) { - gboolean added = roster_add(barejid, name, groups, sub, pending_out); + gboolean added = roster_add(barejid_lower, name, groups, sub, pending_out); if (added) { - handle_roster_add(barejid, name); + ui_roster_add(barejid_lower, name); } } else { - handle_roster_update(barejid, name, groups, sub, pending_out); + sv_ev_roster_update(barejid_lower, name, groups, sub, pending_out); } } + g_free(barejid_lower); + return 1; } static int -_roster_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, - void * const userdata) +_roster_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) { const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID); + if (g_strcmp0(id, "roster") != 0) { + return 1; + } + // handle initial roster response - if (g_strcmp0(id, "roster") == 0) { - xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); - xmpp_stanza_t *item = xmpp_stanza_get_children(query); - - while (item != NULL) { - const char *barejid = xmpp_stanza_get_attribute(item, STANZA_ATTR_JID); - const char *name = xmpp_stanza_get_attribute(item, STANZA_ATTR_NAME); - const char *sub = xmpp_stanza_get_attribute(item, STANZA_ATTR_SUBSCRIPTION); - - // do not set nickname to empty string, set to NULL instead - if (name && (strlen(name) == 0)) { - name = NULL; - } + xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); + xmpp_stanza_t *item = xmpp_stanza_get_children(query); - gboolean pending_out = FALSE; - const char *ask = xmpp_stanza_get_attribute(item, STANZA_ATTR_ASK); - if (g_strcmp0(ask, "subscribe") == 0) { - pending_out = TRUE; - } + while (item) { + const char *barejid = xmpp_stanza_get_attribute(item, STANZA_ATTR_JID); + gchar *barejid_lower = g_utf8_strdown(barejid, -1); + const char *name = xmpp_stanza_get_attribute(item, STANZA_ATTR_NAME); + const char *sub = xmpp_stanza_get_attribute(item, STANZA_ATTR_SUBSCRIPTION); - GSList *groups = _get_groups_from_item(item); + // do not set nickname to empty string, set to NULL instead + if (name && (strlen(name) == 0)) name = NULL; - gboolean added = roster_add(barejid, name, groups, sub, pending_out); + gboolean pending_out = FALSE; + const char *ask = xmpp_stanza_get_attribute(item, STANZA_ATTR_ASK); + if (g_strcmp0(ask, "subscribe") == 0) { + pending_out = TRUE; + } - if (!added) { - log_warning("Attempt to add contact twice: %s", barejid); - } + GSList *groups = _get_groups_from_item(item); - item = xmpp_stanza_get_next(item); + gboolean added = roster_add(barejid_lower, name, groups, sub, pending_out); + if (!added) { + log_warning("Attempt to add contact twice: %s", barejid_lower); } - handle_roster_received(); - - resource_presence_t conn_presence = accounts_get_login_presence(jabber_get_account_name()); - presence_update(conn_presence, NULL, 0); + g_free(barejid_lower); + item = xmpp_stanza_get_next(item); } + sv_ev_roster_received(); + + resource_presence_t conn_presence = accounts_get_login_presence(jabber_get_account_name()); + cl_ev_presence_send(conn_presence, NULL, 0); + return 1; } @@ -340,10 +343,10 @@ _get_groups_from_item(xmpp_stanza_t *item) GSList *groups = NULL; xmpp_stanza_t *group_element = xmpp_stanza_get_children(item); - while (group_element != NULL) { + while (group_element) { if (strcmp(xmpp_stanza_get_name(group_element), STANZA_NAME_GROUP) == 0) { char *groupname = xmpp_stanza_get_text(group_element); - if (groupname != NULL) { + if (groupname) { groups = g_slist_append(groups, groupname); } } diff --git a/src/xmpp/roster.h b/src/xmpp/roster.h index c29a674a..68811a5c 100644 --- a/src/xmpp/roster.h +++ b/src/xmpp/roster.h @@ -1,7 +1,7 @@ /* * roster.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index 4f1d412d..1f25239b 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -1,7 +1,7 @@ /* * stanza.c * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -141,7 +141,7 @@ stanza_create_bookmarks_pubsub_add(xmpp_ctx_t *ctx, const char * const jid, xmpp_stanza_set_attribute(conference, STANZA_ATTR_AUTOJOIN, "false"); } - if (nick != NULL) { + if (nick) { xmpp_stanza_t *nick_st = xmpp_stanza_new(ctx); xmpp_stanza_set_name(nick_st, STANZA_NAME_NICK); xmpp_stanza_set_text(nick_st, nick); @@ -199,6 +199,44 @@ stanza_create_bookmarks_pubsub_add(xmpp_ctx_t *ctx, const char * const jid, #endif xmpp_stanza_t * +stanza_enable_carbons(xmpp_ctx_t *ctx){ + xmpp_stanza_t *iq = xmpp_stanza_new(ctx); + char *id = create_unique_id("carbons"); + + xmpp_stanza_set_name(iq, STANZA_NAME_IQ); + xmpp_stanza_set_type(iq, STANZA_TYPE_SET); + xmpp_stanza_set_id(iq, id); + free(id); + + xmpp_stanza_t *carbons_enable = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(carbons_enable, STANZA_NAME_ENABLE); + xmpp_stanza_set_ns(carbons_enable, STANZA_NS_CARBONS); + + xmpp_stanza_add_child(iq, carbons_enable); + + return iq; +} + +xmpp_stanza_t * +stanza_disable_carbons(xmpp_ctx_t *ctx){ + xmpp_stanza_t *iq = xmpp_stanza_new(ctx); + char *id = create_unique_id("carbons"); + + xmpp_stanza_set_name(iq, STANZA_NAME_IQ); + xmpp_stanza_set_type(iq, STANZA_TYPE_SET); + xmpp_stanza_set_id(iq, id); + free(id); + + xmpp_stanza_t *carbons_disable = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(carbons_disable, STANZA_NAME_DISABLE); + xmpp_stanza_set_ns(carbons_disable, STANZA_NS_CARBONS); + + xmpp_stanza_add_child(iq, carbons_disable); + + return iq; +} + +xmpp_stanza_t * stanza_create_chat_state(xmpp_ctx_t *ctx, const char * const fulljid, const char * const state) { xmpp_stanza_t *msg, *chat_state; @@ -244,9 +282,44 @@ stanza_create_room_subject_message(xmpp_ctx_t *ctx, const char * const room, con } xmpp_stanza_t * -stanza_create_message(xmpp_ctx_t *ctx, const char * const recipient, - const char * const type, const char * const message, - const char * const state) +stanza_attach_state(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza, const char * const state) +{ + xmpp_stanza_t *chat_state = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(chat_state, state); + xmpp_stanza_set_ns(chat_state, STANZA_NS_CHATSTATES); + xmpp_stanza_add_child(stanza, chat_state); + xmpp_stanza_release(chat_state); + + return stanza; +} + +xmpp_stanza_t * +stanza_attach_carbons_private(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza) +{ + xmpp_stanza_t *private_carbon = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(private_carbon, "private"); + xmpp_stanza_set_ns(private_carbon, STANZA_NS_CARBONS); + xmpp_stanza_add_child(stanza, private_carbon); + xmpp_stanza_release(private_carbon); + + return stanza; +} + +xmpp_stanza_t * +stanza_attach_receipt_request(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza) +{ + xmpp_stanza_t *receipet_request = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(receipet_request, "request"); + xmpp_stanza_set_ns(receipet_request, STANZA_NS_RECEIPTS); + xmpp_stanza_add_child(stanza, receipet_request); + xmpp_stanza_release(receipet_request); + + return stanza; +} + +xmpp_stanza_t * +stanza_create_message(xmpp_ctx_t *ctx, char *id, const char * const recipient, + const char * const type, const char * const message) { xmpp_stanza_t *msg, *body, *text; @@ -254,9 +327,7 @@ stanza_create_message(xmpp_ctx_t *ctx, const char * const recipient, xmpp_stanza_set_name(msg, STANZA_NAME_MESSAGE); xmpp_stanza_set_type(msg, type); xmpp_stanza_set_attribute(msg, STANZA_ATTR_TO, recipient); - char *id = create_unique_id(NULL); xmpp_stanza_set_id(msg, id); - free(id); body = xmpp_stanza_new(ctx); xmpp_stanza_set_name(body, STANZA_NAME_BODY); @@ -268,14 +339,6 @@ stanza_create_message(xmpp_ctx_t *ctx, const char * const recipient, xmpp_stanza_add_child(msg, body); xmpp_stanza_release(body); - if (state != NULL) { - xmpp_stanza_t *chat_state = xmpp_stanza_new(ctx); - xmpp_stanza_set_name(chat_state, state); - xmpp_stanza_set_ns(chat_state, STANZA_NS_CHATSTATES); - xmpp_stanza_add_child(msg, chat_state); - xmpp_stanza_release(chat_state); - } - return msg; } @@ -311,7 +374,7 @@ stanza_create_roster_set(xmpp_ctx_t *ctx, const char * const id, xmpp_stanza_t *iq = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_SET); - if (id != NULL) { + if (id) { xmpp_stanza_set_id(iq, id); } @@ -323,13 +386,13 @@ stanza_create_roster_set(xmpp_ctx_t *ctx, const char * const id, xmpp_stanza_set_name(item, STANZA_NAME_ITEM); xmpp_stanza_set_attribute(item, STANZA_ATTR_JID, jid); - if (handle != NULL) { + if (handle) { xmpp_stanza_set_attribute(item, STANZA_ATTR_NAME, handle); } else { xmpp_stanza_set_attribute(item, STANZA_ATTR_NAME, ""); } - while (groups != NULL) { + while (groups) { xmpp_stanza_t *group = xmpp_stanza_new(ctx); xmpp_stanza_t *groupname = xmpp_stanza_new(ctx); xmpp_stanza_set_name(group, STANZA_NAME_GROUP); @@ -351,7 +414,7 @@ stanza_create_roster_set(xmpp_ctx_t *ctx, const char * const id, xmpp_stanza_t * stanza_create_invite(xmpp_ctx_t *ctx, const char * const room, - const char * const contact, const char * const reason) + const char * const contact, const char * const reason, const char * const password) { xmpp_stanza_t *message, *x; @@ -367,10 +430,53 @@ stanza_create_invite(xmpp_ctx_t *ctx, const char * const room, xmpp_stanza_set_ns(x, STANZA_NS_CONFERENCE); xmpp_stanza_set_attribute(x, STANZA_ATTR_JID, room); - if (reason != NULL) { + if (reason) { xmpp_stanza_set_attribute(x, STANZA_ATTR_REASON, reason); } + if (password) { + xmpp_stanza_set_attribute(x, STANZA_ATTR_PASSWORD, password); + } + + xmpp_stanza_add_child(message, x); + xmpp_stanza_release(x); + + return message; +} + +xmpp_stanza_t * +stanza_create_mediated_invite(xmpp_ctx_t *ctx, const char * const room, + const char * const contact, const char * const reason) +{ + xmpp_stanza_t *message, *x, *invite; + + message = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(message, STANZA_NAME_MESSAGE); + xmpp_stanza_set_attribute(message, STANZA_ATTR_TO, room); + char *id = create_unique_id(NULL); + xmpp_stanza_set_id(message, id); + free(id); + + x = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(x, STANZA_NAME_X); + xmpp_stanza_set_ns(x, STANZA_NS_MUC_USER); + + invite = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(invite, STANZA_NAME_INVITE); + xmpp_stanza_set_attribute(invite, STANZA_ATTR_TO, contact); + + if (reason) { + xmpp_stanza_t *reason_st = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(reason_st, STANZA_NAME_REASON); + xmpp_stanza_t *reason_txt = xmpp_stanza_new(ctx); + xmpp_stanza_set_text(reason_txt, reason); + xmpp_stanza_add_child(reason_st, reason_txt); + xmpp_stanza_release(reason_txt); + xmpp_stanza_add_child(invite, reason_st); + xmpp_stanza_release(reason_st); + } + xmpp_stanza_add_child(x, invite); + xmpp_stanza_release(invite); xmpp_stanza_add_child(message, x); xmpp_stanza_release(x); @@ -393,7 +499,7 @@ stanza_create_room_join_presence(xmpp_ctx_t * const ctx, xmpp_stanza_set_ns(x, STANZA_NS_MUC); // if a password was given - if (passwd != NULL) { + if (passwd) { xmpp_stanza_t *pass = xmpp_stanza_new(ctx); xmpp_stanza_set_name(pass, "password"); xmpp_stanza_t *text = xmpp_stanza_new(ctx); @@ -787,7 +893,7 @@ stanza_create_disco_info_iq(xmpp_ctx_t *ctx, const char * const id, const char * xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, XMPP_NS_DISCO_INFO); - if (node != NULL) { + if (node) { xmpp_stanza_set_attribute(query, STANZA_ATTR_NODE, node); } @@ -858,7 +964,7 @@ stanza_create_ping_iq(xmpp_ctx_t *ctx, const char * const target) xmpp_stanza_t *iq = xmpp_stanza_new(ctx); xmpp_stanza_set_name(iq, STANZA_NAME_IQ); xmpp_stanza_set_type(iq, STANZA_TYPE_GET); - if (target != NULL) { + if (target) { xmpp_stanza_set_attribute(iq, STANZA_ATTR_TO, target); } char *id = create_unique_id("ping"); @@ -881,11 +987,11 @@ stanza_get_delay(xmpp_stanza_t * const stanza, GTimeVal *tv_stamp) { // first check for XEP-0203 delayed delivery xmpp_stanza_t *delay = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_DELAY); - if (delay != NULL) { + if (delay) { char *xmlns = xmpp_stanza_get_attribute(delay, STANZA_ATTR_XMLNS); - if ((xmlns != NULL) && (strcmp(xmlns, "urn:xmpp:delay") == 0)) { + if (xmlns && (strcmp(xmlns, "urn:xmpp:delay") == 0)) { char *stamp = xmpp_stanza_get_attribute(delay, STANZA_ATTR_STAMP); - if ((stamp != NULL) && (g_time_val_from_iso8601(stamp, tv_stamp))) { + if (stamp && (g_time_val_from_iso8601(stamp, tv_stamp))) { return TRUE; } } @@ -894,11 +1000,11 @@ stanza_get_delay(xmpp_stanza_t * const stanza, GTimeVal *tv_stamp) // otherwise check for XEP-0091 legacy delayed delivery // stanp format : CCYYMMDDThh:mm:ss xmpp_stanza_t *x = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_X); - if (x != NULL) { + if (x) { char *xmlns = xmpp_stanza_get_attribute(x, STANZA_ATTR_XMLNS); - if ((xmlns != NULL) && (strcmp(xmlns, "jabber:x:delay") == 0)) { + if (xmlns && (strcmp(xmlns, "jabber:x:delay") == 0)) { char *stamp = xmpp_stanza_get_attribute(x, STANZA_ATTR_STAMP); - if ((stamp != NULL) && (g_time_val_from_iso8601(stamp, tv_stamp))) { + if (stamp && (g_time_val_from_iso8601(stamp, tv_stamp))) { return TRUE; } } @@ -914,17 +1020,17 @@ stanza_get_status(xmpp_stanza_t *stanza, char *def) xmpp_stanza_t *status = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_STATUS); - if (status != NULL) { + if (status) { // xmpp_free and free may be different functions so convert all to // libc malloc char *s1, *s2 = NULL; s1 = xmpp_stanza_get_text(status); - if (s1 != NULL) { + if (s1) { s2 = strdup(s1); xmpp_free(ctx, s1); } return s2; - } else if (def != NULL) { + } else if (def) { return strdup(def); } else { return NULL; @@ -938,17 +1044,17 @@ stanza_get_show(xmpp_stanza_t *stanza, char *def) xmpp_stanza_t *show = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_SHOW); - if (show != NULL) { + if (show) { // xmpp_free and free may be different functions so convert all to // libc malloc char *s1, *s2 = NULL; s1 = xmpp_stanza_get_text(show); - if (s1 != NULL) { + if (s1) { s2 = strdup(s1); xmpp_free(ctx, s1); } return s2; - } else if (def != NULL) { + } else if (def) { return strdup(def); } else { return NULL; @@ -984,7 +1090,7 @@ stanza_muc_requires_config(xmpp_stanza_t * const stanza) // muc user namespaced x element xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER); - if (x != NULL) { + if (x) { // check for item element with owner affiliation xmpp_stanza_t *item = xmpp_stanza_get_child_by_name(x, "item"); @@ -998,7 +1104,7 @@ stanza_muc_requires_config(xmpp_stanza_t * const stanza) // check for status code 201 xmpp_stanza_t *x_children = xmpp_stanza_get_children(x); - while (x_children != NULL) { + while (x_children) { if (g_strcmp0(xmpp_stanza_get_name(x_children), STANZA_NAME_STATUS) == 0) { char *code = xmpp_stanza_get_attribute(x_children, STANZA_ATTR_CODE); if (g_strcmp0(code, "201") == 0) { @@ -1240,11 +1346,11 @@ stanza_is_room_nick_change(xmpp_stanza_t * const stanza) // muc user namespaced x element xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_MUC_USER); - if (x != NULL) { + if (x) { // check for status child element with 303 code xmpp_stanza_t *x_children = xmpp_stanza_get_children(x); - while (x_children != NULL) { + while (x_children) { if (g_strcmp0(xmpp_stanza_get_name(x_children), STANZA_NAME_STATUS) == 0) { char *code = xmpp_stanza_get_attribute(x_children, STANZA_ATTR_CODE); if (g_strcmp0(code, "303") == 0) { @@ -1268,7 +1374,7 @@ stanza_get_new_nick(xmpp_stanza_t * const stanza) xmpp_stanza_t *x = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_X); xmpp_stanza_t *x_children = xmpp_stanza_get_children(x); - while (x_children != NULL) { + while (x_children) { if (strcmp(xmpp_stanza_get_name(x_children), STANZA_NAME_ITEM) == 0) { char *nick = xmpp_stanza_get_attribute(x_children, STANZA_ATTR_NICK); if (nick) { @@ -1382,9 +1488,9 @@ stanza_get_error_message(xmpp_stanza_t *stanza) xmpp_stanza_t *text_stanza = xmpp_stanza_get_child_by_name(error_stanza, STANZA_NAME_TEXT); // check for text - if (text_stanza != NULL) { + if (text_stanza) { gchar *err_msg = xmpp_stanza_get_text(text_stanza); - if (err_msg != NULL) { + if (err_msg) { char *result = strdup(err_msg); xmpp_free(ctx, err_msg); return result; @@ -1419,7 +1525,7 @@ stanza_get_error_message(xmpp_stanza_t *stanza) int i; for (i = 0; i < ARRAY_SIZE(defined_conditions); i++) { xmpp_stanza_t *cond_stanza = xmpp_stanza_get_child_by_name(error_stanza, defined_conditions[i]); - if (cond_stanza != NULL) { + if (cond_stanza) { char *result = strdup(xmpp_stanza_get_name(cond_stanza)); return result; } @@ -1456,7 +1562,7 @@ void stanza_attach_show(xmpp_ctx_t * const ctx, xmpp_stanza_t * const presence, const char * const show) { - if (show != NULL) { + if (show) { xmpp_stanza_t *show_stanza = xmpp_stanza_new(ctx); xmpp_stanza_set_name(show_stanza, STANZA_NAME_SHOW); xmpp_stanza_t *text = xmpp_stanza_new(ctx); @@ -1472,7 +1578,7 @@ void stanza_attach_status(xmpp_ctx_t * const ctx, xmpp_stanza_t * const presence, const char * const status) { - if (status != NULL) { + if (status) { xmpp_stanza_t *status_stanza = xmpp_stanza_new(ctx); xmpp_stanza_set_name(status_stanza, STANZA_NAME_STATUS); xmpp_stanza_t *text = xmpp_stanza_new(ctx); @@ -1619,9 +1725,9 @@ stanza_parse_presence(xmpp_stanza_t *stanza, int *err) result->priority = 0; xmpp_stanza_t *priority_stanza = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_PRIORITY); - if (priority_stanza != NULL) { + if (priority_stanza) { char *priority_str = xmpp_stanza_get_text(priority_stanza); - if (priority_str != NULL) { + if (priority_str) { result->priority = atoi(priority_str); } free(priority_str); diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index 84282401..89dbda57 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -1,7 +1,7 @@ /* * stanza.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -77,6 +77,8 @@ #define STANZA_NAME_VALUE "value" #define STANZA_NAME_DESTROY "destroy" #define STANZA_NAME_ACTOR "actor" +#define STANZA_NAME_ENABLE "enable" +#define STANZA_NAME_DISABLE "disable" // error conditions #define STANZA_NAME_BAD_REQUEST "bad-request" @@ -133,6 +135,7 @@ #define STANZA_ATTR_CATEGORY "category" #define STANZA_ATTR_REASON "reason" #define STANZA_ATTR_AUTOJOIN "autojoin" +#define STANZA_ATTR_PASSWORD "password" #define STANZA_TEXT_AWAY "away" #define STANZA_TEXT_DND "dnd" @@ -154,6 +157,9 @@ #define STANZA_NS_CONFERENCE "jabber:x:conference" #define STANZA_NS_CAPTCHA "urn:xmpp:captcha" #define STANZA_NS_PUBSUB "http://jabber.org/protocol/pubsub" +#define STANZA_NS_CARBONS "urn:xmpp:carbons:2" +#define STANZA_NS_FORWARD "urn:xmpp:forward:0" +#define STANZA_NS_RECEIPTS "urn:xmpp:receipts" #define STANZA_DATAFORM_SOFTWARE "urn:xmpp:dataforms:softwareinfo" @@ -178,12 +184,19 @@ typedef enum { xmpp_stanza_t* stanza_create_bookmarks_storage_request(xmpp_ctx_t *ctx); +xmpp_stanza_t * stanza_enable_carbons(xmpp_ctx_t *ctx); + +xmpp_stanza_t * stanza_disable_carbons(xmpp_ctx_t *ctx); + xmpp_stanza_t* stanza_create_chat_state(xmpp_ctx_t *ctx, const char * const fulljid, const char * const state); -xmpp_stanza_t* stanza_create_message(xmpp_ctx_t *ctx, - const char * const recipient, const char * const type, - const char * const message, const char * const state); +xmpp_stanza_t * stanza_attach_state(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza, const char * const state); +xmpp_stanza_t * stanza_attach_carbons_private(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza); +xmpp_stanza_t * stanza_attach_receipt_request(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza); + +xmpp_stanza_t* stanza_create_message(xmpp_ctx_t *ctx, char *id, + const char * const recipient, const char * const type, const char * const message); xmpp_stanza_t* stanza_create_room_join_presence(xmpp_ctx_t * const ctx, const char * const full_room_jid, const char * const passwd); @@ -202,6 +215,8 @@ xmpp_stanza_t* stanza_create_disco_info_iq(xmpp_ctx_t *ctx, const char * const i const char * const to, const char * const node); xmpp_stanza_t* stanza_create_invite(xmpp_ctx_t *ctx, const char * const room, + const char * const contact, const char * const reason, const char * const password); +xmpp_stanza_t* stanza_create_mediated_invite(xmpp_ctx_t *ctx, const char * const room, const char * const contact, const char * const reason); gboolean stanza_contains_chat_state(xmpp_stanza_t *stanza); diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index a004a4bf..398c9f46 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -1,7 +1,7 @@ /* * xmpp.h * - * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com> + * Copyright (C) 2012 - 2015 James Booth <boothj5@gmail.com> * * This file is part of Profanity. * @@ -145,7 +145,8 @@ char* jabber_get_account_name(void); GList * jabber_get_available_resources(void); // message functions -void message_send_chat(const char * const barejid, const char * const msg); +char* message_send_chat(const char * const barejid, const char * const msg); +char* message_send_chat_encrypted(const char * const barejid, const char * const msg); void message_send_private(const char * const fulljid, const char * const msg); void message_send_groupchat(const char * const roomjid, const char * const msg); void message_send_groupchat_subject(const char * const roomjid, const char * const subject); @@ -167,11 +168,13 @@ char * presence_sub_request_find(const char * const search_str); void presence_join_room(char *room, char *nick, char * passwd); void presence_change_room_nick(const char * const room, const char * const nick); void presence_leave_chat_room(const char * const room_jid); -void presence_update(resource_presence_t status, const char * const msg, +void presence_send(resource_presence_t status, const char * const msg, int idle); gboolean presence_sub_request_exists(const char * const bare_jid); // iq functions +void iq_enable_carbons(); +void iq_disable_carbons(); void iq_send_software_version(const char * const fulljid); void iq_room_list_request(gchar *conferencejid); void iq_disco_info_request(gchar *jid); @@ -189,7 +192,7 @@ void iq_send_caps_request_for_jid(const char * const to, const char * const id, const char * const node, const char * const ver); void iq_send_caps_request_legacy(const char * const to, const char * const id, const char * const node, const char * const ver); -void iq_room_info_request(gchar *room); +void iq_room_info_request(const char * const room, gboolean display_result); void iq_room_affiliation_list(const char * const room, char *affiliation); void iq_room_affiliation_set(const char * const room, const char * const jid, char *affiliation, const char * const reason); diff --git a/tests/helpers.c b/tests/helpers.c index 10310886..564b2716 100644 --- a/tests/helpers.c +++ b/tests/helpers.c @@ -85,6 +85,24 @@ void close_chat_sessions(void **state) close_preferences(NULL); } +int +utf8_pos_to_col(char *str, int utf8_pos) +{ + int col = 0; + + int i = 0; + for (i = 0; i<utf8_pos; i++) { + col++; + gchar *ch = g_utf8_offset_to_pointer(str, i); + gunichar uni = g_utf8_get_char(ch); + if (g_unichar_iswide(uni)) { + col++; + } + } + + return col; +} + static GCompareFunc cmp_func; void diff --git a/tests/helpers.h b/tests/helpers.h index 2d7af6e7..75d446d0 100644 --- a/tests/helpers.h +++ b/tests/helpers.h @@ -6,5 +6,7 @@ void close_preferences(void **state); void init_chat_sessions(void **state); void close_chat_sessions(void **state); +int utf8_pos_to_col(char *str, int utf8_pos); + void glist_set_cmp(GCompareFunc func); int glist_contents_equal(const void *actual, const void *expected); \ No newline at end of file diff --git a/tests/log/stub_log.c b/tests/log/stub_log.c index 8ace164a..f88871a7 100644 --- a/tests/log/stub_log.c +++ b/tests/log/stub_log.c @@ -50,8 +50,14 @@ log_level_t log_level_from_string(char *log_level) } void chat_log_init(void) {} -void chat_log_chat(const gchar * const login, gchar *other, - const gchar * const msg, chat_log_direction_t direction, GTimeVal *tv_stamp) {} + +void chat_log_msg_out(const char * const barejid, const char * const msg) {} +void chat_log_otr_msg_out(const char * const barejid, const char * const msg) {} + +void chat_log_msg_in(const char * const barejid, const char * const msg) {} +void chat_log_msg_in_delayed(const char * const barejid, const char * msg, GTimeVal *tv_stamp) {} +void chat_log_otr_msg_in(const char * const barejid, const char * const msg, gboolean was_decrypted) {} + void chat_log_close(void) {} GSList * chat_log_get_previous(const gchar * const login, const gchar * const recipient) diff --git a/tests/otr/stub_otr.c b/tests/otr/stub_otr.c index 82994034..482f0a7f 100644 --- a/tests/otr/stub_otr.c +++ b/tests/otr/stub_otr.c @@ -41,6 +41,8 @@ char* otr_start_query(void) void otr_poll(void) {} void otr_on_connect(ProfAccount *account) {} +void otr_on_message_recv(const char * const barejid, const char * const resource, const char * const message) {} +void otr_on_message_send(ProfChatWin *chatwin, const char * const message) {} void otr_keygen(ProfAccount *account) { @@ -52,6 +54,11 @@ gboolean otr_key_loaded(void) return (gboolean)mock(); } +char* otr_tag_message(const char * const msg) +{ + return NULL; +} + gboolean otr_is_secure(const char * const recipient) { return FALSE; @@ -98,4 +105,4 @@ void otr_free_message(char *message) {} prof_otrpolicy_t otr_get_policy(const char * const recipient) { return PROF_OTRPOLICY_MANUAL; -} \ No newline at end of file +} diff --git a/tests/test_cmd_account.c b/tests/test_cmd_account.c index d02fc5ba..bddc4c6d 100644 --- a/tests/test_cmd_account.c +++ b/tests/test_cmd_account.c @@ -941,9 +941,9 @@ void cmd_account_set_priority_updates_presence_when_account_connected_with_prese will_return(jabber_get_presence_message, "Free to chat"); - expect_value(presence_update, status, RESOURCE_ONLINE); - expect_string(presence_update, msg, "Free to chat"); - expect_value(presence_update, idle, 0); + expect_value(presence_send, status, RESOURCE_ONLINE); + expect_string(presence_send, msg, "Free to chat"); + expect_value(presence_send, idle, 0); expect_cons_show("Updated online priority for account a_account: 10"); expect_cons_show(""); diff --git a/tests/test_cmd_join.c b/tests/test_cmd_join.c index 10ffa547..19824b3a 100644 --- a/tests/test_cmd_join.c +++ b/tests/test_cmd_join.c @@ -50,23 +50,6 @@ void cmd_join_shows_message_when_undefined(void **state) test_with_connection_status(JABBER_UNDEFINED); } -void cmd_join_shows_usage_when_no_args(void **state) -{ - CommandHelp *help = malloc(sizeof(CommandHelp)); - help->usage = "some usage"; - gchar *args[] = { NULL }; - - will_return(jabber_get_connection_status, JABBER_CONNECTED); - - expect_cons_show("Usage: some usage"); - expect_cons_show(""); - - gboolean result = cmd_join(args, *help); - assert_true(result); - - free(help); -} - void cmd_join_shows_error_message_when_invalid_room_jid(void **state) { CommandHelp *help = malloc(sizeof(CommandHelp)); diff --git a/tests/test_cmd_join.h b/tests/test_cmd_join.h index 812aee87..a96fa435 100644 --- a/tests/test_cmd_join.h +++ b/tests/test_cmd_join.h @@ -2,7 +2,6 @@ void cmd_join_shows_message_when_disconnecting(void **state); void cmd_join_shows_message_when_connecting(void **state); void cmd_join_shows_message_when_disconnected(void **state); void cmd_join_shows_message_when_undefined(void **state); -void cmd_join_shows_usage_when_no_args(void **state); void cmd_join_shows_error_message_when_invalid_room_jid(void **state); void cmd_join_uses_account_mucservice_when_no_service_specified(void **state); void cmd_join_uses_supplied_nick(void **state); diff --git a/tests/test_cmd_otr.c b/tests/test_cmd_otr.c index c6c6f7cf..dae17947 100644 --- a/tests/test_cmd_otr.c +++ b/tests/test_cmd_otr.c @@ -551,8 +551,8 @@ cmd_otr_start_sends_otr_query_message_to_current_recipeint(void **state) will_return(otr_key_loaded, TRUE); will_return(otr_start_query, query_message); - expect_string(message_send_chat, barejid, chatwin->barejid); - expect_string(message_send_chat, msg, query_message); + expect_string(message_send_chat_encrypted, barejid, chatwin->barejid); + expect_string(message_send_chat_encrypted, msg, query_message); gboolean result = cmd_otr(args, *help); assert_true(result); diff --git a/tests/test_cmd_win.c b/tests/test_cmd_win.c deleted file mode 100644 index bc19ebf3..00000000 --- a/tests/test_cmd_win.c +++ /dev/null @@ -1,41 +0,0 @@ -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <cmocka.h> -#include <stdlib.h> -#include <glib.h> - -#include "ui/ui.h" -#include "ui/stub_ui.h" - -#include "command/commands.h" - -void cmd_win_shows_message_when_win_doesnt_exist(void **state) -{ - CommandHelp *help = malloc(sizeof(CommandHelp)); - gchar *args[] = { "3", NULL }; - - expect_value(ui_switch_win, i, 3); - will_return(ui_switch_win, FALSE); - - expect_cons_show("Window 3 does not exist."); - - gboolean result = cmd_win(args, *help); - assert_true(result); - - free(help); -} - -void cmd_win_switches_to_given_win_when_exists(void **state) -{ - CommandHelp *help = malloc(sizeof(CommandHelp)); - gchar *args[] = { "12", NULL }; - - expect_value(ui_switch_win, i, 12); - will_return(ui_switch_win, TRUE); - - gboolean result = cmd_win(args, *help); - assert_true(result); - - free(help); -} diff --git a/tests/test_cmd_win.h b/tests/test_cmd_win.h deleted file mode 100644 index a0f61a6b..00000000 --- a/tests/test_cmd_win.h +++ /dev/null @@ -1,2 +0,0 @@ -void cmd_win_shows_message_when_win_doesnt_exist(void **state); -void cmd_win_switches_to_given_win_when_exists(void **state); diff --git a/tests/test_common.c b/tests/test_common.c index 0c4530a0..980f2198 100644 --- a/tests/test_common.c +++ b/tests/test_common.c @@ -587,3 +587,47 @@ void utf8_display_len_all_wide(void **state) assert_int_equal(8, result); } +void strip_quotes_does_nothing_when_no_quoted(void **state) +{ + char *input = "/cmd test string"; + + char *result = strip_arg_quotes(input); + + assert_string_equal("/cmd test string", result); + + free(result); +} + +void strip_quotes_strips_first(void **state) +{ + char *input = "/cmd \"test string"; + + char *result = strip_arg_quotes(input); + + assert_string_equal("/cmd test string", result); + + free(result); +} + +void strip_quotes_strips_last(void **state) +{ + char *input = "/cmd test string\""; + + char *result = strip_arg_quotes(input); + + assert_string_equal("/cmd test string", result); + + free(result); +} + +void strip_quotes_strips_both(void **state) +{ + char *input = "/cmd \"test string\""; + + char *result = strip_arg_quotes(input); + + assert_string_equal("/cmd test string", result); + + free(result); +} + diff --git a/tests/test_common.h b/tests/test_common.h index 1866e73d..b4b98e5a 100644 --- a/tests/test_common.h +++ b/tests/test_common.h @@ -51,4 +51,8 @@ void utf8_display_len_1_non_wide(void **state); void utf8_display_len_1_wide(void **state); void utf8_display_len_non_wide(void **state); void utf8_display_len_wide(void **state); -void utf8_display_len_all_wide(void **state); \ No newline at end of file +void utf8_display_len_all_wide(void **state); +void strip_quotes_does_nothing_when_no_quoted(void **state); +void strip_quotes_strips_first(void **state); +void strip_quotes_strips_last(void **state); +void strip_quotes_strips_both(void **state); diff --git a/tests/test_history.c b/tests/test_history.c deleted file mode 100644 index 1584b390..00000000 --- a/tests/test_history.c +++ /dev/null @@ -1,219 +0,0 @@ -#include <stdarg.h> -#include <stddef.h> -#include <setjmp.h> -#include <cmocka.h> -#include <stdlib.h> - -#include "tools/history.h" - -void previous_on_empty_returns_null(void **state) -{ - History history = history_new(10); - char *item = history_previous(history, "inp"); - - assert_null(item); -} - -void next_on_empty_returns_null(void **state) -{ - History history = history_new(10); - char *item = history_next(history, "inp"); - - assert_null(item); -} - -void previous_once_returns_last(void **state) -{ - History history = history_new(10); - history_append(history, "Hello"); - - char *item = history_previous(history, "inp"); - - assert_string_equal("Hello", item); -} - -void previous_twice_when_one_returns_first(void **state) -{ - History history = history_new(10); - history_append(history, "Hello"); - - char *item1 = history_previous(history, NULL); - char *item2 = history_previous(history, item1); - - assert_string_equal("Hello", item2); -} - -void previous_always_stops_at_first(void **state) -{ - History history = history_new(10); - history_append(history, "Hello"); - - char *item1 = history_previous(history, NULL); - char *item2 = history_previous(history, item1); - char *item3 = history_previous(history, item2); - char *item4 = history_previous(history, item3); - char *item5 = history_previous(history, item4); - char *item6 = history_previous(history, item5); - - assert_string_equal("Hello", item6); -} - -void previous_goes_to_correct_element(void **state) -{ - History history = history_new(10); - history_append(history, "Hello"); - history_append(history, "world"); - history_append(history, "whats"); - history_append(history, "going"); - history_append(history, "on"); - history_append(history, "here"); - - char *item1 = history_previous(history, NULL); - char *item2 = history_previous(history, item1); - char *item3 = history_previous(history, item2); - - assert_string_equal("going", item3); -} - -void prev_then_next_returns_empty(void **state) -{ - History history = history_new(10); - history_append(history, "Hello"); - - char *item1 = history_previous(history, NULL); - char *item2 = history_next(history, item1); - - assert_string_equal("", item2); -} - -void prev_with_val_then_next_returns_val(void **state) -{ - History history = history_new(10); - history_append(history, "Hello"); - - char *item1 = history_previous(history, "Oioi"); - char *item2 = history_next(history, item1); - - assert_string_equal("Oioi", item2); -} - -void prev_with_val_then_next_twice_returns_null(void **state) -{ - History history = history_new(10); - history_append(history, "Hello"); - - char *item1 = history_previous(history, "Oioi"); - char *item2 = history_next(history, item1); - char *item3 = history_next(history, item2); - - assert_null(item3); -} - -void navigate_then_append_new(void **state) -{ - History history = history_new(10); - history_append(history, "Hello"); - history_append(history, "again"); - history_append(history, "testing"); - history_append(history, "history"); - history_append(history, "append"); - - char *item1 = history_previous(history, "new text"); - assert_string_equal("append", item1); - - char *item2 = history_previous(history, item1); - assert_string_equal("history", item2); - - char *item3 = history_previous(history, item2); - assert_string_equal("testing", item3); - - char *item4 = history_next(history, item3); - assert_string_equal("history", item4); - - char *item5 = history_next(history, item4); - assert_string_equal("append", item5); - - char *item6 = history_next(history, item5); - assert_string_equal("new text", item6); -} - -void edit_item_mid_history(void **state) -{ - History history = history_new(10); - history_append(history, "Hello"); - history_append(history, "again"); - history_append(history, "testing"); - history_append(history, "history"); - history_append(history, "append"); - - char *item1 = history_previous(history, "new item"); - assert_string_equal("append", item1); - - char *item2 = history_previous(history, item1); - assert_string_equal("history", item2); - - char *item3 = history_previous(history, item2); - assert_string_equal("testing", item3); - - char *item4 = history_previous(history, "EDITED"); - assert_string_equal("again", item4); - - char *item5 = history_previous(history, item4); - assert_string_equal("Hello", item5); - - char *item6 = history_next(history, item5); - assert_string_equal("again", item6); - - char *item7 = history_next(history, item6); - assert_string_equal("EDITED", item7); - - char *item8 = history_next(history, item7); - assert_string_equal("history", item8); - - char *item9 = history_next(history, item8); - assert_string_equal("append", item9); - - char *item10 = history_next(history, item9); - assert_string_equal("new item", item10); -} - -void edit_previous_and_append(void **state) -{ - History history = history_new(10); - history_append(history, "Hello"); - history_append(history, "again"); - history_append(history, "testing"); - history_append(history, "history"); - history_append(history, "append"); - - char *item1 = history_previous(history, "new item"); - assert_string_equal("append", item1); - - char *item2 = history_previous(history, item1); - assert_string_equal("history", item2); - - char *item3 = history_previous(history, item2); - assert_string_equal("testing", item3); - - history_append(history, "EDITED"); - - char *item4 = history_previous(history, NULL); - assert_string_equal("EDITED", item4); -} - -void start_session_add_new_submit_previous(void **state) -{ - History history = history_new(10); - history_append(history, "hello"); - - char *item1 = history_previous(history, NULL); - assert_string_equal("hello", item1); - - char *item2 = history_next(history, item1); - assert_string_equal("", item2); - - char *item3 = history_previous(history, "new text"); - assert_string_equal("hello", item3); - - history_append(history, item3); -} diff --git a/tests/test_history.h b/tests/test_history.h deleted file mode 100644 index e6e8ec3f..00000000 --- a/tests/test_history.h +++ /dev/null @@ -1,13 +0,0 @@ -void previous_on_empty_returns_null(void **state); -void next_on_empty_returns_null(void **state); -void previous_once_returns_last(void **state); -void previous_twice_when_one_returns_first(void **state); -void previous_always_stops_at_first(void **state); -void previous_goes_to_correct_element(void **state); -void prev_then_next_returns_empty(void **state); -void prev_with_val_then_next_returns_val(void **state); -void prev_with_val_then_next_twice_returns_null(void **state); -void navigate_then_append_new(void **state); -void edit_item_mid_history(void **state); -void edit_previous_and_append(void **state); -void start_session_add_new_submit_previous(void **state); diff --git a/tests/test_keyhandlers.c b/tests/test_keyhandlers.c new file mode 100644 index 00000000..a6d39143 --- /dev/null +++ b/tests/test_keyhandlers.c @@ -0,0 +1,734 @@ +#include <stdarg.h> +#include <stddef.h> +#include <setjmp.h> +#include <cmocka.h> +#include <stdlib.h> +#include <string.h> + +#include <locale.h> + +#include "ui/keyhandlers.h" +#include "ui/inputwin.h" +#include "tests/helpers.h" + +static char line[INP_WIN_MAX]; + +// append + +void append_to_empty(void **state) +{ + setlocale(LC_ALL, ""); + line[0] = '\0'; + int line_utf8_pos = 0; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_printable(line, &line_utf8_pos, &col, &pad_start, 'a', 80); + + assert_string_equal("a", line); + assert_int_equal(line_utf8_pos, 1); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void append_wide_to_empty(void **state) +{ + setlocale(LC_ALL, ""); + line[0] = '\0'; + int line_utf8_pos = 0; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_printable(line, &line_utf8_pos, &col, &pad_start, 0x56DB, 80); + + assert_string_equal("四", line); + assert_int_equal(line_utf8_pos, 1); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void append_to_single(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "a", 1); + line[1] = '\0'; + int line_utf8_pos = 1; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_printable(line, &line_utf8_pos, &col, &pad_start, 'b', 80); + + assert_string_equal("ab", line); + assert_int_equal(line_utf8_pos, 2); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + + +void append_wide_to_single_non_wide(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "a", 1); + line[1] = '\0'; + int line_utf8_pos = 1; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_printable(line, &line_utf8_pos, &col, &pad_start, 0x56DB, 80); + + assert_string_equal("a四", line); + assert_int_equal(line_utf8_pos, 2); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void append_non_wide_to_single_wide(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "四", 1); + line[strlen(line)] = '\0'; + int line_utf8_pos = 1; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_printable(line, &line_utf8_pos, &col, &pad_start, 'b', 80); + + assert_string_equal("四b", line); + assert_int_equal(line_utf8_pos, 2); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void append_wide_to_single_wide(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "四", 1); + line[strlen(line)] = '\0'; + int line_utf8_pos = 1; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_printable(line, &line_utf8_pos, &col, &pad_start, 0x4E09, 80); + + assert_string_equal("四三", line); + assert_int_equal(line_utf8_pos, 2); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void append_non_wide_when_overrun(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "0123456789四1234567", 18); + line[strlen(line)] = '\0'; + int line_utf8_pos = 18; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_printable(line, &line_utf8_pos, &col, &pad_start, 'z', 20); + key_printable(line, &line_utf8_pos, &col, &pad_start, 'z', 20); + key_printable(line, &line_utf8_pos, &col, &pad_start, 'z', 20); + + assert_string_equal("0123456789四1234567zzz", line); + assert_int_equal(line_utf8_pos, 21); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 3); +} + +void insert_non_wide_to_non_wide(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "abcd", 4); + line[strlen(line)] = '\0'; + int line_utf8_pos = 2; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_printable(line, &line_utf8_pos, &col, &pad_start, '0', 80); + + assert_string_equal("ab0cd", line); + assert_int_equal(line_utf8_pos, 3); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void insert_single_non_wide_when_pad_scrolled(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "AAAAAAAAAAAAAAA", 15); + line[strlen(line)] = '\0'; + int line_utf8_pos = 2; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 2; + + key_printable(line, &line_utf8_pos, &col, &pad_start, 'B', 12); + + assert_string_equal("AABAAAAAAAAAAAAA", line); + assert_int_equal(line_utf8_pos, 3); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 2); +} + +void insert_many_non_wide_when_pad_scrolled(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "AAAAAAAAAAAAAAA", 15); + line[strlen(line)] = '\0'; + int line_utf8_pos = 2; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 2; + + key_printable(line, &line_utf8_pos, &col, &pad_start, 'B', 12); + key_printable(line, &line_utf8_pos, &col, &pad_start, 'C', 12); + key_printable(line, &line_utf8_pos, &col, &pad_start, 'D', 12); + + assert_string_equal("AABCDAAAAAAAAAAAAA", line); + assert_int_equal(line_utf8_pos, 5); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 2); +} + +void insert_single_non_wide_last_column(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "abcdefghijklmno", 15); + line[strlen(line)] = '\0'; + int line_utf8_pos = 7; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 2; + + key_printable(line, &line_utf8_pos, &col, &pad_start, '1', 5); + + assert_string_equal("abcdefg1hijklmno", line); + assert_int_equal(line_utf8_pos, 8); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 3); +} + +void insert_many_non_wide_last_column(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "abcdefghijklmno", 15); + line[strlen(line)] = '\0'; + int line_utf8_pos = 7; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 2; + + key_printable(line, &line_utf8_pos, &col, &pad_start, '1', 5); + key_printable(line, &line_utf8_pos, &col, &pad_start, '2', 5); + + assert_string_equal("abcdefg12hijklmno", line); + assert_int_equal(line_utf8_pos, 9); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 4); +} + +void ctrl_left_when_no_input(void **state) +{ + setlocale(LC_ALL, ""); + line[0] = '\0'; + int line_utf8_pos = 0; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 0); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_left_when_at_start(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); + line[strlen(line)] = '\0'; + int line_utf8_pos = 0; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 0); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_left_when_in_first_word(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); + line[strlen(line)] = '\0'; + int line_utf8_pos = 2; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 0); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_left_when_in_first_space(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); + line[strlen(line)] = '\0'; + int line_utf8_pos = 4; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 0); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_left_when_at_start_of_second_word(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); + line[strlen(line)] = '\0'; + int line_utf8_pos = 5; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 0); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_left_when_in_second_word(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); + line[strlen(line)] = '\0'; + int line_utf8_pos = 8; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 5); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_left_when_at_end_of_second_word(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); + line[strlen(line)] = '\0'; + int line_utf8_pos = 10; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 5); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_left_when_in_second_space(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); + line[strlen(line)] = '\0'; + int line_utf8_pos = 11; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 5); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_left_when_at_start_of_third_word(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); + line[strlen(line)] = '\0'; + int line_utf8_pos = 12; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 5); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_left_when_in_third_word(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); + line[strlen(line)] = '\0'; + int line_utf8_pos = 14; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 12); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_left_when_at_end_of_third_word(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); + line[strlen(line)] = '\0'; + int line_utf8_pos = 15; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 12); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_left_when_in_third_space(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); + line[strlen(line)] = '\0'; + int line_utf8_pos = 16; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 12); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_left_when_at_end(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "abcd efghij klmn opqr", 21); + line[strlen(line)] = '\0'; + int line_utf8_pos = 20; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 17); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_left_when_in_only_whitespace(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, " ", 7); + line[strlen(line)] = '\0'; + int line_utf8_pos = 5; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 0); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_left_when_start_whitespace_start_of_word(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, " hello", 9); + line[strlen(line)] = '\0'; + int line_utf8_pos = 4; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 0); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_left_when_start_whitespace_middle_of_word(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, " hello", 9); + line[strlen(line)] = '\0'; + int line_utf8_pos = 7; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 4); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_left_in_whitespace_between_words(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "hey hello", 12); + line[strlen(line)] = '\0'; + int line_utf8_pos = 5; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 0); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_left_in_whitespace_between_words_start_of_word(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "hey hello", 12); + line[strlen(line)] = '\0'; + int line_utf8_pos = 7; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 0); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_left_in_whitespace_between_words_middle_of_word(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "hey hello", 12); + line[strlen(line)] = '\0'; + int line_utf8_pos = 9; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 7); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_left_when_word_overrun_to_left(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "someword anotherword", 20); + line[strlen(line)] = '\0'; + int line_utf8_pos = 18; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 14; + + key_ctrl_left(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 9); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 9); +} + +void ctrl_right_when_no_input(void **state) +{ + setlocale(LC_ALL, ""); + line[0] = '\0'; + int line_utf8_pos = 0; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 0); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_right_when_at_end(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "someword anotherword", 20); + line[strlen(line)] = '\0'; + int line_utf8_pos = 20; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 20); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_right_one_word_at_start(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "someword", 8); + line[strlen(line)] = '\0'; + int line_utf8_pos = 0; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 8); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_right_one_word_in_middle(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "someword", 8); + line[strlen(line)] = '\0'; + int line_utf8_pos = 3; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 8); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_right_one_word_at_end(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "someword", 8); + line[strlen(line)] = '\0'; + int line_utf8_pos = 7; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 8); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_right_two_words_from_middle_first(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "someword anotherword", 20); + line[strlen(line)] = '\0'; + int line_utf8_pos = 4; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 8); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_right_two_words_from_end_first(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "someword anotherword", 20); + line[strlen(line)] = '\0'; + int line_utf8_pos = 7; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 8); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_right_two_words_from_space(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "someword anotherword", 20); + line[strlen(line)] = '\0'; + int line_utf8_pos = 8; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 20); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_right_two_words_from_start_second(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "someword anotherword", 20); + line[strlen(line)] = '\0'; + int line_utf8_pos = 9; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 20); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_right_one_word_leading_whitespace(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, " someword", 15); + line[strlen(line)] = '\0'; + int line_utf8_pos = 3; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 15); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_right_two_words_in_whitespace(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, " someword adfasdf", 30); + line[strlen(line)] = '\0'; + int line_utf8_pos = 19; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 30); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} + +void ctrl_right_trailing_whitespace_from_middle(void **state) +{ + setlocale(LC_ALL, ""); + g_utf8_strncpy(line, "someword ", 16); + line[strlen(line)] = '\0'; + int line_utf8_pos = 3; + int col = utf8_pos_to_col(line, line_utf8_pos); + int pad_start = 0; + + key_ctrl_right(line, &line_utf8_pos, &col, &pad_start, 80); + + assert_int_equal(line_utf8_pos, 8); + assert_int_equal(col, utf8_pos_to_col(line, line_utf8_pos)); + assert_int_equal(pad_start, 0); +} \ No newline at end of file diff --git a/tests/test_keyhandlers.h b/tests/test_keyhandlers.h new file mode 100644 index 00000000..4be429a9 --- /dev/null +++ b/tests/test_keyhandlers.h @@ -0,0 +1,47 @@ +void append_to_empty(void **state); +void append_wide_to_empty(void **state); +void append_to_single(void **state); +void append_wide_to_single_non_wide(void **state); +void append_non_wide_to_single_wide(void **state); +void append_wide_to_single_wide(void **state); +void append_non_wide_when_overrun(void **state); + +void insert_non_wide_to_non_wide(void **state); +void insert_single_non_wide_when_pad_scrolled(void **state); +void insert_many_non_wide_when_pad_scrolled(void **state); +void insert_single_non_wide_last_column(void **state); +void insert_many_non_wide_last_column(void **state); + +void ctrl_left_when_no_input(void **state); +void ctrl_left_when_at_start(void **state); +void ctrl_left_when_in_first_word(void **state); +void ctrl_left_when_in_first_space(void **state); +void ctrl_left_when_at_start_of_second_word(void **state); +void ctrl_left_when_in_second_word(void **state); +void ctrl_left_when_at_end_of_second_word(void **state); +void ctrl_left_when_in_second_space(void **state); +void ctrl_left_when_at_start_of_third_word(void **state); +void ctrl_left_when_in_third_word(void **state); +void ctrl_left_when_at_end_of_third_word(void **state); +void ctrl_left_when_in_third_space(void **state); +void ctrl_left_when_at_end(void **state); +void ctrl_left_when_in_only_whitespace(void **state); +void ctrl_left_when_start_whitespace_start_of_word(void **state); +void ctrl_left_when_start_whitespace_middle_of_word(void **state); +void ctrl_left_in_whitespace_between_words(void **state); +void ctrl_left_in_whitespace_between_words_start_of_word(void **state); +void ctrl_left_in_whitespace_between_words_middle_of_word(void **state); +void ctrl_left_when_word_overrun_to_left(void **state); + +void ctrl_right_when_no_input(void **state); +void ctrl_right_when_at_end(void **state); +void ctrl_right_one_word_at_start(void **state); +void ctrl_right_one_word_in_middle(void **state); +void ctrl_right_one_word_at_end(void **state); +void ctrl_right_two_words_from_middle_first(void **state); +void ctrl_right_two_words_from_end_first(void **state); +void ctrl_right_two_words_from_space(void **state); +void ctrl_right_two_words_from_start_second(void **state); +void ctrl_right_one_word_leading_whitespace(void **state); +void ctrl_right_two_words_in_whitespace(void **state); +void ctrl_right_trailing_whitespace_from_middle(void **state); \ No newline at end of file diff --git a/tests/test_muc.c b/tests/test_muc.c index 5566c17e..e3b7f9b0 100644 --- a/tests/test_muc.c +++ b/tests/test_muc.c @@ -19,7 +19,7 @@ void muc_after_test(void **state) void test_muc_invites_add(void **state) { char *room = "room@conf.server"; - muc_invites_add(room); + muc_invites_add(room, NULL); gboolean invite_exists = muc_invites_contain(room); @@ -29,7 +29,7 @@ void test_muc_invites_add(void **state) void test_muc_remove_invite(void **state) { char *room = "room@conf.server"; - muc_invites_add(room); + muc_invites_add(room, NULL); muc_invites_remove(room); gboolean invite_exists = muc_invites_contain(room); @@ -46,11 +46,11 @@ void test_muc_invites_count_0(void **state) void test_muc_invites_count_5(void **state) { - muc_invites_add("room1@conf.server"); - muc_invites_add("room2@conf.server"); - muc_invites_add("room3@conf.server"); - muc_invites_add("room4@conf.server"); - muc_invites_add("room5@conf.server"); + muc_invites_add("room1@conf.server", NULL); + muc_invites_add("room2@conf.server", NULL); + muc_invites_add("room3@conf.server", NULL); + muc_invites_add("room4@conf.server", NULL); + muc_invites_add("room5@conf.server", NULL); int invite_count = muc_invites_count(); diff --git a/tests/test_server_events.c b/tests/test_server_events.c index ce54b4f2..58489807 100644 --- a/tests/test_server_events.c +++ b/tests/test_server_events.c @@ -6,7 +6,7 @@ #include <string.h> #include <glib.h> -#include "server_events.h" +#include "event/server_events.h" #include "roster_list.h" #include "chat_session.h" #include "config/preferences.h" @@ -14,31 +14,19 @@ #include "ui/stub_ui.h" #include "muc.h" -void console_doesnt_show_online_presence_when_set_none(void **state) -{ - prefs_set_string(PREF_STATUSES_CONSOLE, "none"); - roster_init(); - roster_add("test1@server", "bob", NULL, "both", FALSE); - Resource *resource = resource_new("resource", RESOURCE_ONLINE, NULL, 10); - - handle_contact_online("test1@server", resource, NULL); - - roster_clear(); -} - void console_shows_online_presence_when_set_online(void **state) { prefs_set_string(PREF_STATUSES_CONSOLE, "online"); roster_init(); - roster_add("test1@server", "bob", NULL, "both", FALSE); + char *barejid = "test1@server"; + roster_add(barejid, "bob", NULL, "both", FALSE); Resource *resource = resource_new("resource", RESOURCE_ONLINE, NULL, 10); - PContact contact = roster_get_contact("test1@server"); - expect_memory(cons_show_contact_online, contact, contact, sizeof(contact)); - expect_memory(cons_show_contact_online, resource, resource, sizeof(resource)); - expect_value(cons_show_contact_online, last_activity, NULL); + expect_memory(ui_contact_online, barejid, barejid, sizeof(barejid)); + expect_memory(ui_contact_online, resource, resource, sizeof(resource)); + expect_value(ui_contact_online, last_activity, NULL); - handle_contact_online("test1@server", resource, NULL); + sv_ev_contact_online(barejid, resource, NULL); roster_clear(); } @@ -47,39 +35,15 @@ void console_shows_online_presence_when_set_all(void **state) { prefs_set_string(PREF_STATUSES_CONSOLE, "all"); roster_init(); - roster_add("test1@server", "bob", NULL, "both", FALSE); + char *barejid = "test1@server"; + roster_add(barejid, "bob", NULL, "both", FALSE); Resource *resource = resource_new("resource", RESOURCE_ONLINE, NULL, 10); - PContact contact = roster_get_contact("test1@server"); - - expect_memory(cons_show_contact_online, contact, contact, sizeof(contact)); - expect_memory(cons_show_contact_online, resource, resource, sizeof(resource)); - expect_value(cons_show_contact_online, last_activity, NULL); - - handle_contact_online("test1@server", resource, NULL); - - roster_clear(); -} - -void console_doesnt_show_dnd_presence_when_set_none(void **state) -{ - prefs_set_string(PREF_STATUSES_CONSOLE, "none"); - roster_init(); - roster_add("test1@server", "bob", NULL, "both", FALSE); - Resource *resource = resource_new("resource", RESOURCE_DND, NULL, 10); - - handle_contact_online("test1@server", resource, NULL); - - roster_clear(); -} -void console_doesnt_show_dnd_presence_when_set_online(void **state) -{ - prefs_set_string(PREF_STATUSES_CONSOLE, "online"); - roster_init(); - roster_add("test1@server", "bob", NULL, "both", FALSE); - Resource *resource = resource_new("resource", RESOURCE_DND, NULL, 10); + expect_memory(ui_contact_online, barejid, barejid, sizeof(barejid)); + expect_memory(ui_contact_online, resource, resource, sizeof(resource)); + expect_value(ui_contact_online, last_activity, NULL); - handle_contact_online("test1@server", resource, NULL); + sv_ev_contact_online(barejid, resource, NULL); roster_clear(); } @@ -88,95 +52,19 @@ void console_shows_dnd_presence_when_set_all(void **state) { prefs_set_string(PREF_STATUSES_CONSOLE, "all"); roster_init(); - roster_add("test1@server", "bob", NULL, "both", FALSE); + char *barejid = "test1@server"; + roster_add(barejid, "bob", NULL, "both", FALSE); Resource *resource = resource_new("resource", RESOURCE_ONLINE, NULL, 10); - PContact contact = roster_get_contact("test1@server"); - expect_memory(cons_show_contact_online, contact, contact, sizeof(contact)); - expect_memory(cons_show_contact_online, resource, resource, sizeof(resource)); - expect_value(cons_show_contact_online, last_activity, NULL); + expect_memory(ui_contact_online, barejid, barejid, sizeof(barejid)); + expect_memory(ui_contact_online, resource, resource, sizeof(resource)); + expect_value(ui_contact_online, last_activity, NULL); - handle_contact_online("test1@server", resource, NULL); + sv_ev_contact_online(barejid, resource, NULL); roster_clear(); } -void handle_message_error_when_no_recipient(void **state) -{ - char *err_msg = "Some error."; - char *from = NULL; - char *type = "cancel"; - - expect_string(ui_handle_error, err_msg, err_msg); - - handle_message_error(from, type, err_msg); -} - -void handle_message_error_when_recipient_cancel(void **state) -{ - char *err_msg = "Some error."; - char *from = "bob@server.com"; - char *type = "cancel"; - - prefs_set_boolean(PREF_STATES, FALSE); - chat_sessions_init(); - - handle_message_error(from, type, err_msg); -} - -void handle_message_error_when_recipient_cancel_disables_chat_session(void **state) -{ - char *err_msg = "Some error."; - char *barejid = "bob@server.com"; - char *resource = "resource"; - char *type = "cancel"; - - prefs_set_boolean(PREF_STATES, TRUE); - chat_sessions_init(); - chat_session_recipient_active(barejid, resource, FALSE); - - handle_message_error(barejid, type, err_msg); - ChatSession *session = chat_session_get(barejid); - - assert_null(session); - chat_sessions_clear(); -} - -void handle_message_error_when_recipient_and_no_type(void **state) -{ - char *err_msg = "Some error."; - char *from = "bob@server.com"; - char *type = NULL; - - expect_string(ui_handle_recipient_error, recipient, from); - expect_string(ui_handle_recipient_error, err_msg, err_msg); - - handle_message_error(from, type, err_msg); -} - -void handle_presence_error_when_no_recipient(void **state) -{ - char *err_msg = "Some error."; - char *from = NULL; - char *type = NULL; - - expect_string(ui_handle_error, err_msg, err_msg); - - handle_presence_error(from, type, err_msg); -} - -void handle_presence_error_when_from_recipient(void **state) -{ - char *err_msg = "Some error."; - char *from = "bob@server.com"; - char *type = NULL; - - expect_string(ui_handle_recipient_error, recipient, from); - expect_string(ui_handle_recipient_error, err_msg, err_msg); - - handle_presence_error(from, type, err_msg); -} - void handle_offline_removes_chat_session(void **state) { chat_sessions_init(); @@ -187,7 +75,7 @@ void handle_offline_removes_chat_session(void **state) Resource *resourcep = resource_new(resource, RESOURCE_ONLINE, NULL, 10); roster_update_presence(barejid, resourcep, NULL); chat_session_recipient_active(barejid, resource, FALSE); - handle_contact_offline(barejid, resource, NULL); + sv_ev_contact_offline(barejid, resource, NULL); ChatSession *session = chat_session_get(barejid); assert_null(session); @@ -203,7 +91,7 @@ void lost_connection_clears_chat_sessions(void **state) chat_session_recipient_active("steve@server.org", "mobile", FALSE); expect_any_cons_show_error(); - handle_lost_connection(); + sv_ev_lost_connection(); ChatSession *session1 = chat_session_get("bob@server.org"); ChatSession *session2 = chat_session_get("steve@server.org"); diff --git a/tests/testsuite.c b/tests/testsuite.c index cf511c59..3f860178 100644 --- a/tests/testsuite.c +++ b/tests/testsuite.c @@ -21,7 +21,6 @@ #include "test_cmd_sub.h" #include "test_cmd_statuses.h" #include "test_cmd_otr.h" -#include "test_history.h" #include "test_jid.h" #include "test_parser.h" #include "test_roster_list.h" @@ -32,7 +31,6 @@ #include "test_cmd_join.h" #include "test_muc.h" #include "test_cmd_roster.h" -#include "test_cmd_win.h" #include "test_cmd_disconnect.h" #include "test_form.h" @@ -91,6 +89,10 @@ int main(int argc, char* argv[]) { unit_test(utf8_display_len_non_wide), unit_test(utf8_display_len_wide), unit_test(utf8_display_len_all_wide), + unit_test(strip_quotes_does_nothing_when_no_quoted), + unit_test(strip_quotes_strips_first), + unit_test(strip_quotes_strips_last), + unit_test(strip_quotes_strips_both), unit_test(clear_empty), unit_test(reset_after_create), @@ -103,20 +105,6 @@ int main(int argc, char* argv[]) { unit_test(add_two_same_adds_one), unit_test(add_two_same_updates), - unit_test(previous_on_empty_returns_null), - unit_test(next_on_empty_returns_null), - unit_test(previous_once_returns_last), - unit_test(previous_twice_when_one_returns_first), - unit_test(previous_always_stops_at_first), - unit_test(previous_goes_to_correct_element), - unit_test(prev_then_next_returns_empty), - unit_test(prev_with_val_then_next_returns_val), - unit_test(prev_with_val_then_next_twice_returns_null), - unit_test(navigate_then_append_new), - unit_test(edit_item_mid_history), - unit_test(edit_previous_and_append), - unit_test(start_session_add_new_submit_previous), - unit_test(create_jid_from_null_returns_null), unit_test(create_jid_from_empty_string_returns_null), unit_test(create_jid_from_full_returns_full), @@ -342,9 +330,11 @@ int main(int argc, char* argv[]) { unit_test(cmd_account_set_eval_password_when_password_set), unit_test(cmd_account_set_muc_sets_muc), unit_test(cmd_account_set_nick_sets_nick), +#ifdef HAVE_LIBOTR unit_test(cmd_account_show_message_for_missing_otr_policy), unit_test(cmd_account_show_message_for_invalid_otr_policy), unit_test(cmd_account_set_otr_sets_otr), +#endif unit_test(cmd_account_set_status_shows_message_when_invalid_status), unit_test(cmd_account_set_status_sets_status_when_valid), unit_test(cmd_account_set_status_sets_status_when_last), @@ -435,34 +425,15 @@ int main(int argc, char* argv[]) { load_preferences, close_preferences), - unit_test_setup_teardown(console_doesnt_show_online_presence_when_set_none, - load_preferences, - close_preferences), unit_test_setup_teardown(console_shows_online_presence_when_set_online, load_preferences, close_preferences), unit_test_setup_teardown(console_shows_online_presence_when_set_all, load_preferences, close_preferences), - unit_test_setup_teardown(console_doesnt_show_dnd_presence_when_set_none, - load_preferences, - close_preferences), - unit_test_setup_teardown(console_doesnt_show_dnd_presence_when_set_online, - load_preferences, - close_preferences), unit_test_setup_teardown(console_shows_dnd_presence_when_set_all, load_preferences, close_preferences), - unit_test(handle_message_error_when_no_recipient), - unit_test_setup_teardown(handle_message_error_when_recipient_cancel, - load_preferences, - close_preferences), - unit_test_setup_teardown(handle_message_error_when_recipient_cancel_disables_chat_session, - load_preferences, - close_preferences), - unit_test(handle_message_error_when_recipient_and_no_type), - unit_test(handle_presence_error_when_no_recipient), - unit_test(handle_presence_error_when_from_recipient), unit_test(handle_offline_removes_chat_session), unit_test(lost_connection_clears_chat_sessions), @@ -572,7 +543,6 @@ int main(int argc, char* argv[]) { unit_test(cmd_join_shows_message_when_connecting), unit_test(cmd_join_shows_message_when_disconnected), unit_test(cmd_join_shows_message_when_undefined), - unit_test(cmd_join_shows_usage_when_no_args), unit_test(cmd_join_shows_error_message_when_invalid_room_jid), unit_test(cmd_join_uses_account_mucservice_when_no_service_specified), unit_test(cmd_join_uses_supplied_nick), @@ -596,9 +566,6 @@ int main(int argc, char* argv[]) { unit_test(cmd_roster_clearnick_shows_message_when_no_contact_exists), unit_test(cmd_roster_clearnick_sends_name_change_request_with_empty_nick), - unit_test(cmd_win_shows_message_when_win_doesnt_exist), - unit_test(cmd_win_switches_to_given_win_when_exists), - unit_test(get_form_type_field_returns_null_no_fields), unit_test(get_form_type_field_returns_null_when_not_present), unit_test(get_form_type_field_returns_value_when_present), diff --git a/tests/ui/stub_ui.c b/tests/ui/stub_ui.c index 51b82d42..52c38570 100644 --- a/tests/ui/stub_ui.c +++ b/tests/ui/stub_ui.c @@ -64,15 +64,7 @@ GSList* ui_get_chat_recipients(void) return NULL; } -gboolean ui_switch_win(const int i) -{ - check_expected(i); - return (gboolean)mock(); - return FALSE; -} - -void ui_next_win(void) {} -void ui_previous_win(void) {} +void ui_switch_win(ProfWin *win) {} void ui_gone_secure(const char * const barejid, gboolean trusted) {} void ui_gone_insecure(const char * const barejid) {} @@ -91,6 +83,7 @@ void ui_smp_answer_failure(const char * const barejid) {} void ui_otr_authenticating(const char * const barejid) {} void ui_otr_authetication_waiting(const char * const recipient) {} +void ui_sigwinch_handler(int sig) {} unsigned long ui_get_idle_time(void) { @@ -98,8 +91,16 @@ unsigned long ui_get_idle_time(void) } void ui_reset_idle_time(void) {} -void ui_new_chat_win(const char * const barejid) {} -void ui_new_private_win(const char * const fulljid) {} +ProfPrivateWin* ui_new_private_win(const char * const fulljid) +{ + return NULL; +} + +ProfChatWin* ui_new_chat_win(const char * const barejid) +{ + return NULL; +} + void ui_print_system_msg_from_recipient(const char * const barejid, const char *message) {} gint ui_unread(void) { @@ -125,11 +126,6 @@ win_type_t ui_current_win_type(void) return (win_type_t)mock(); } -int ui_current_win_index(void) -{ - return 0; -} - gboolean ui_current_win_is_otr(void) { return (gboolean)mock(); @@ -161,6 +157,8 @@ void ui_current_print_formatted_line(const char show_char, int attrs, const char } void ui_current_error_line(const char * const msg) {} +void ui_win_error_line(ProfWin *window, const char * const msg) {} + win_type_t ui_win_type(int index) { @@ -168,16 +166,17 @@ win_type_t ui_win_type(int index) } void ui_close_win(int index) {} -gboolean ui_win_exists(int index) -{ - return FALSE; -} int ui_win_unread(int index) { return 0; } +void ui_page_up(void) {} +void ui_page_down(void) {} +void ui_subwin_page_up(void) {} +void ui_subwin_page_down(void) {} + char * ui_ask_password(void) { return mock_ptr_type(char *); @@ -186,17 +185,25 @@ char * ui_ask_password(void) void ui_handle_stanza(const char * const msg) {} // ui events +void ui_contact_online(char *barejid, Resource *resource, GDateTime *last_activity) +{ + check_expected(barejid); + check_expected(resource); + check_expected(last_activity); +} + void ui_contact_typing(const char * const barejid, const char * const resource) {} void ui_incoming_msg(const char * const from, const char * const resource, const char * const message, GTimeVal *tv_stamp) {} +void ui_message_receipt(const char * const barejid, const char * const id) {} + void ui_incoming_private_msg(const char * const fulljid, const char * const message, GTimeVal *tv_stamp) {} void ui_disconnected(void) {} void ui_recipient_gone(const char * const barejid, const char * const resource) {} -void ui_outgoing_chat_msg(const char * const from, const char * const barejid, - const char * const message) {} -void ui_outgoing_private_msg(const char * const from, const char * const fulljid, - const char * const message) {} +void ui_outgoing_chat_msg(ProfChatWin *chatwin, const char * const message, char *id) {} +void ui_outgoing_chat_msg_carbon(const char * const barejid, const char * const message) {} +void ui_outgoing_private_msg(ProfPrivateWin *privwin, const char * const message) {} void ui_room_join(const char * const roomjid, gboolean focus) {} void ui_switch_to_room(const char * const roomjid) {} @@ -245,6 +252,7 @@ void ui_room_member_nick_change(const char * const roomjid, void ui_room_nick_change(const char * const roomjid, const char * const nick) {} void ui_room_member_presence(const char * const roomjid, const char * const nick, const char * const show, const char * const status) {} +void ui_room_update_occupants(const char * const roomjid) {} void ui_room_show_occupants(const char * const roomjid) {} void ui_room_hide_occupants(const char * const roomjid) {} void ui_show_roster(void) {} @@ -323,7 +331,7 @@ void ui_update_presence(const resource_presence_t resource_presence, void ui_about(void) {} void ui_statusbar_new(const int win) {} -char * ui_readline(void) +char* ui_readline(void) { return NULL; } @@ -348,6 +356,9 @@ gboolean ui_win_has_unsaved_form(int num) return FALSE; } +void +ui_write(char *line, int offset) {} + // console window actions void cons_show(const char * const msg, ...) @@ -457,6 +468,8 @@ void cons_outtype_setting(void) {} void cons_intype_setting(void) {} void cons_gone_setting(void) {} void cons_history_setting(void) {} +void cons_carbons_setting(void) {} +void cons_receipts_setting(void) {} void cons_log_setting(void) {} void cons_chlog_setting(void) {} void cons_grlog_setting(void) {} @@ -487,7 +500,7 @@ void occupantswin_occupants(const char * const room) {} void notifier_uninit(void) {} void notify_typing(const char * const handle) {} -void notify_message(const char * const handle, int win, const char * const text) {} +void notify_message(ProfWin *window, const char * const name, const char * const text) {} void notify_room_message(const char * const handle, const char * const room, int win, const char * const text) {} void notify_remind(void) {} diff --git a/tests/xmpp/stub_xmpp.c b/tests/xmpp/stub_xmpp.c index 281857f0..cc9580bf 100644 --- a/tests/xmpp/stub_xmpp.c +++ b/tests/xmpp/stub_xmpp.c @@ -58,10 +58,18 @@ GList * jabber_get_available_resources(void) } // message functions -void message_send_chat(const char * const barejid, const char * const msg) +char* message_send_chat(const char * const barejid, const char * const msg) { check_expected(barejid); check_expected(msg); + return NULL; +} + +char* message_send_chat_encrypted(const char * const barejid, const char * const msg) +{ + check_expected(barejid); + check_expected(msg); + return NULL; } void message_send_private(const char * const fulljid, const char * const msg) {} @@ -106,7 +114,7 @@ void presence_join_room(char *room, char *nick, char * passwd) void presence_change_room_nick(const char * const room, const char * const nick) {} void presence_leave_chat_room(const char * const room_jid) {} -void presence_update(resource_presence_t status, const char * const msg, int idle) +void presence_send(resource_presence_t status, const char * const msg, int idle) { check_expected(status); check_expected(msg); @@ -119,6 +127,8 @@ gboolean presence_sub_request_exists(const char * const bare_jid) } // iq functions +void iq_disable_carbons() {}; +void iq_enable_carbons() {}; void iq_send_software_version(const char * const fulljid) {} void iq_room_list_request(gchar *conferencejid) @@ -141,7 +151,7 @@ void iq_send_caps_request_for_jid(const char * const to, const char * const id, const char * const node, const char * const ver) {} void iq_send_caps_request_legacy(const char * const to, const char * const id, const char * const node, const char * const ver) {} -void iq_room_info_request(gchar *room) {} +void iq_room_info_request(const char * const room, gboolean display) {} void iq_room_affiliation_list(const char * const room, char *affiliation) {} void iq_room_affiliation_set(const char * const room, const char * const jid, char *affiliation, const char * const reason) {} diff --git a/theme_template b/theme_template new file mode 100644 index 00000000..c088e181 --- /dev/null +++ b/theme_template @@ -0,0 +1,74 @@ +[colours] +bkgnd= +titlebar= +titlebar.text= +titlebar.brackets= +titlebar.unencrypted= +titlebar.encrypted= +titlebar.untrusted= +titlebar.trusted= +titlebar.online= +titlebar.offline= +titlebar.away= +titlebar.chat= +titlebar.dnd= +titlebar.xa= +statusbar= +statusbar.text= +statusbar.brackets= +statusbar.active= +statusbar.new= +main.text= +main.text.me= +main.text.them= +main.splash= +main.time= +input.text= +subscribed= +unsubscribed= +otr.started.trusted= +otr.started.untrusted= +otr.ended= +otr.trusted= +otr.untrusted= +online= +away= +chat= +dnd= +xa= +offline= +incoming= +typing= +gone= +error= +roominfo= +roommention= +me= +them= +roster.header= +occupants.header= +receipt.sent= + +[ui] +beep= +flash= +splash= +wrap= +time= +privileges= +presence= +intype= +otr.warn= +resource.title= +resource.message= +statuses.console= +statuses.chat= +statuses.muc= +roster= +roster.offline= +roster.resource= +roster.by= +roster.size= +occupants= +occupants.size= +occupants.jid= diff --git a/themes/advanced b/themes/advanced deleted file mode 100644 index a00948d8..00000000 --- a/themes/advanced +++ /dev/null @@ -1,69 +0,0 @@ -[colours] -bkgnd=default -titlebar=blue -statusbar=blue -titlebar.text=bold_white -titlebar.brackets=white -statusbar.text=bold_white -statusbar.brackets=white -statusbar.active=bold_cyan -statusbar.new=bold_green -main.text=white -main.text.me=cyan -main.text.them=bold_white -input.text=bold_green -main.time=yellow -main.splash=bold_red -online=bold_green -away=bold_cyan -chat=bold_white -dnd=magenta -xa=bold_blue -offline=red -typing=yellow -gone=red -error=red -incoming=bold_yellow -roominfo=yellow -roommention=bold_red -me=blue -them=bold_green -titlebar.unencrypted=bold_red -titlebar.encrypted=bold_white -titlebar.untrusted=bold_yellow -titlebar.trusted=bold_white -titlebar.online=bold_green -titlebar.offline=bold_red -titlebar.away=bold_cyan -titlebar.xa=bold_cyan -titlebar.dnd=bold_red -titlebar.chat=bold_green -otr.started.trusted=green -otr.started.untrusted=yellow -otr.ended=red -otr.trusted=green -otr.untrusted=yellow -roster.header=bold_yellow -occupants.header=bold_yellow - -[ui] -intype=true -beep=false -flash=false -privileges=true -presence=true -wrap=true -time=minutes -statuses.muc=off -statuses.chat=online -statuses.console=off -occupants=true -occupants.size=15 -roster=true -roster.size=25 -roster.offline=true -roster.resource=true -roster.by=presence -otr.warn=true - - diff --git a/themes/aqua b/themes/aqua index 7474d072..11c250f4 100644 --- a/themes/aqua +++ b/themes/aqua @@ -1,9 +1,19 @@ [colours] bkgnd=default titlebar=blue -statusbar=blue titlebar.text=bold_white titlebar.brackets=white +titlebar.unencrypted=cyan +titlebar.encrypted=white +titlebar.untrusted=cyan +titlebar.trusted=white +titlebar.online=bold_white +titlebar.offline=cyan +titlebar.away=white +titlebar.chat=bold_white +titlebar.dnd=cyan +titlebar.xa=bold_cyan +statusbar=blue statusbar.text=bold_white statusbar.brackets=white statusbar.active=cyan @@ -11,31 +21,30 @@ statusbar.new=white main.text=blue main.text.me=bold_cyan main.text.them=bold_white -input.text=white -main.time=cyan main.splash=bold_white +main.time=cyan +input.text=white +subscribed=bold_cyan +unsubscribed=blue +otr.started.trusted=white +otr.started.untrusted=cyan +otr.ended=cyan +otr.trusted=white +otr.untrusted=cyan online=bold_cyan away=bold_blue chat=white dnd=blue xa=cyan offline=bold_black +incoming=bold_cyan typing=cyan gone=blue error=bold_white -incoming=bold_cyan roominfo=white roommention=bold_blue me=cyan them=white -titlebar.unencrypted=cyan -titlebar.encrypted=white -titlebar.untrusted=cyan -titlebar.trusted=white -otr.started.trusted=white -otr.started.untrusted=cyan -otr.ended=cyan -otr.trusted=white -otr.untrusted=cyan roster.header=bold_white occupants.header=bold_white +receipt.sent=white diff --git a/themes/batman b/themes/batman index fc8ce1be..4d346ac1 100644 --- a/themes/batman +++ b/themes/batman @@ -17,14 +17,13 @@ away=yellow chat=green dnd=green xa=yellow -offline=grey +offline=bold_black typing=cyan gone=red error=red incoming=yellow roominfo=green -roommention=cyan -me=black +me=black_bold them=yellow titlebar.unencrypted=red titlebar.encrypted=green @@ -35,3 +34,17 @@ otr.started.untrusted=red otr.ended=yellow otr.trusted=green otr.untrusted=red +titlebar.online=magenta +titlebar.offline=black +titlebar.away=magenta +titlebar.chat=magenta +titlebar.dnd=magenta +titlebar.xa=magenta +main.text.me=white +main.text.them=white +subscribed=magenta +unsubscribed=black_bold +roommention=cyan +roster.header=yellow +occupants.header=yellow +receipt.sent=red diff --git a/themes/boothj5 b/themes/boothj5 index 3e086903..9ed3fe69 100644 --- a/themes/boothj5 +++ b/themes/boothj5 @@ -1,9 +1,19 @@ [colours] bkgnd=default titlebar=blue -statusbar=blue titlebar.text=bold_white titlebar.brackets=white +titlebar.unencrypted=bold_red +titlebar.encrypted=bold_white +titlebar.untrusted=bold_yellow +titlebar.trusted=bold_white +titlebar.online=bold_green +titlebar.offline=bold_red +titlebar.away=bold_cyan +titlebar.xa=bold_cyan +titlebar.dnd=bold_red +titlebar.chat=bold_green +statusbar=blue statusbar.text=bold_white statusbar.brackets=white statusbar.active=bold_cyan @@ -11,59 +21,55 @@ statusbar.new=bold_green main.text=white main.text.me=cyan main.text.them=bold_white -input.text=bold_green -main.time=yellow main.splash=bold_red +main.time=yellow +input.text=bold_green +subscribed=bold_green +unsubscribed=red +otr.started.trusted=green +otr.started.untrusted=yellow +otr.ended=red +otr.trusted=green +otr.untrusted=yellow online=bold_green away=bold_cyan chat=bold_white dnd=magenta xa=bold_blue offline=red +incoming=bold_yellow typing=yellow gone=red error=red -incoming=bold_yellow roominfo=yellow roommention=bold_red me=blue them=bold_green -titlebar.unencrypted=bold_red -titlebar.encrypted=bold_white -titlebar.untrusted=bold_yellow -titlebar.trusted=bold_white -titlebar.online=bold_green -titlebar.offline=bold_red -titlebar.away=bold_cyan -titlebar.xa=bold_cyan -titlebar.dnd=bold_red -titlebar.chat=bold_green -otr.started.trusted=green -otr.started.untrusted=yellow -otr.ended=red -otr.trusted=green -otr.untrusted=yellow roster.header=bold_yellow occupants.header=bold_yellow +receipt.sent=bold_black [ui] -intype=true beep=false flash=false +splash=true +wrap=true +time=seconds +time.statusbar=seconds privileges=true presence=true -wrap=true -time=minutes -statuses.muc=none -statuses.chat=none -statuses.console=none -occupants=true -occupants.size=15 +intype=true +otr.warn=true +resource.title=true +resource.message=true +statuses.console=all +statuses.chat=all +statuses.muc=all roster=true -roster.size=25 roster.offline=true roster.resource=true roster.by=presence -otr.warn=true - - +roster.size=25 +occupants=true +occupants.size=15 +occupants.jid=true diff --git a/themes/complex b/themes/complex new file mode 100644 index 00000000..a5510baa --- /dev/null +++ b/themes/complex @@ -0,0 +1,24 @@ +[ui] +beep=false +flash=false +splash=true +wrap=true +time=seconds +time.statusbar=seconds +resource.title=true +resource.message=true +statuses.console=all +statuses.chat=all +statuses.muc=all +occupants=true +occupants.size=15 +occupants.jid=true +roster=true +roster.offline=true +roster.resource=true +roster.by=presence +roster.size=25 +privileges=true +presence=true +intype=true +otr.warn=true diff --git a/themes/forest b/themes/forest index fd170162..be3f3a82 100644 --- a/themes/forest +++ b/themes/forest @@ -1,9 +1,19 @@ [colours] bkgnd=default titlebar=cyan -statusbar=green titlebar.text=black titlebar.brackets=black +titlebar.unencrypted=black +titlebar.encrypted=white +titlebar.untrusted=white +titlebar.trusted=white +titlebar.online=white +titlebar.offline=white +titlebar.away=white +titlebar.chat=white +titlebar.dnd=white +titlebar.xa=white +statusbar=green statusbar.text=black statusbar.brackets=black statusbar.active=bold_green @@ -11,39 +21,30 @@ statusbar.new=white main.text=bold_cyan main.text.me=yellow main.text.them=green -input.text=bold_blue -main.time=bold_green main.splash=bold_yellow +main.time=bold_green +input.text=bold_blue subscribed=green unsubscribed=bold_black +otr.started.trusted=green +otr.started.untrusted=yellow +otr.ended=red +otr.trusted=green +otr.untrusted=yellow online=green away=blue chat=green dnd=bold_black xa=blue offline=bold_black +incoming=bold_yellow typing=yellow gone=bold_black error=bold_black -incoming=bold_yellow roominfo=yellow roommention=bold_cyan me=blue them=bold_blue -titlebar.unencrypted=black -titlebar.encrypted=white -titlebar.untrusted=white -titlebar.trusted=white -titlebar.online=white -titlebar.offline=white -titlebar.away=white -titlebar.xa=white -titlebar.dnd=white -titlebar.chat=white -otr.started.trusted=green -otr.started.untrusted=yellow -otr.ended=red -otr.trusted=green -otr.untrusted=yellow roster.header=bold_green occupants.header=bold_green +receipt.sent=bold_black \ No newline at end of file diff --git a/themes/hacker b/themes/hacker index 09928f61..6486126f 100644 --- a/themes/hacker +++ b/themes/hacker @@ -1,9 +1,19 @@ [colours] bkgnd=default titlebar=green -statusbar=green titlebar.text=black titlebar.brackets=black +titlebar.unencrypted=black +titlebar.encrypted=black +titlebar.untrusted=black +titlebar.trusted=black +titlebar.online=black +titlebar.offline=black +titlebar.away=black +titlebar.chat=black +titlebar.dnd=black +titlebar.xa=black +statusbar=green statusbar.text=black statusbar.brackets=black statusbar.active=black @@ -11,37 +21,30 @@ statusbar.new=black main.text=green main.text.me=green main.text.them=green -input.text=bold_green -main.time=bold_green main.splash=bold_green +main.time=bold_green +input.text=bold_green +subscribed=bold_green +unsubscribed=green +otr.started.trusted=green +otr.started.untrusted=green +otr.ended=green +otr.trusted=green +otr.untrusted=green online=bold_green away=green chat=bold_green dnd=green xa=green offline=green +incoming=bold_green typing=green gone=green error=bold_green -incoming=bold_green roominfo=green roommention=bold_green me=green them=bold_green -titlebar.unencrypted=black -titlebar.encrypted=black -titlebar.untrusted=black -titlebar.trusted=black -titlebar.online=black -titlebar.offline=black -titlebar.away=black -titlebar.xa=black -titlebar.dnd=black -titlebar.chat=black -otr.started.trusted=green -otr.started.untrusted=green -otr.ended=green -otr.trusted=green -otr.untrusted=green roster.header=bold_green occupants.header=bold_green +receipt.sent=bold_black \ No newline at end of file diff --git a/themes/headache b/themes/headache index ea5738ce..5c06ca78 100644 --- a/themes/headache +++ b/themes/headache @@ -1,36 +1,50 @@ [colours] bkgnd=default titlebar=magenta -statusbar=default titlebar.text=white titlebar.brackets=white +titlebar.unencrypted=black +titlebar.encrypted=cyan +titlebar.untrusted=yellow +titlebar.trusted=cyan +titlebar.online=white +titlebar.offline=black +titlebar.away=white +titlebar.chat=white +titlebar.dnd=black +titlebar.xa=white +statusbar=default statusbar.text=white statusbar.brackets=red statusbar.active=cyan statusbar.new=white main.text=blue -input.text=yellow -main.time=green +main.text.me=white +main.text.them=bold_white main.splash=red +main.time=green +input.text=yellow +subscribed=bold_magenta +unsubscribed=bold_black +otr.started.trusted=cyan +otr.started.untrusted=yellow +otr.ended=blue +otr.trusted=cyan +otr.untrusted=yellow online=red away=cyan chat=green dnd=megenta xa=cyan offline=green +incoming=yellow typing=magenta gone=yellow error=red -incoming=yellow roominfo=white +roommention=bold_green me=white them=white -titlebar.unencrypted=black -titlebar.encrypted=cyan -titlebar.untrusted=yellow -titlebar.trusted=cyan -otr.started.trusted=cyan -otr.started.untrusted=yellow -otr.ended=blue -otr.trusted=cyan -otr.untrusted=yellow +roster.header=bold_cyan +occupants.header=bold_cyan +receipt.sent=red \ No newline at end of file diff --git a/themes/joker b/themes/joker index 3c8adc39..59e9ed94 100644 --- a/themes/joker +++ b/themes/joker @@ -1,36 +1,50 @@ [colours] bkgnd=default titlebar=magenta -statusbar=magenta titlebar.text=white titlebar.brackets=cyan +titlebar.unencrypted=red +titlebar.encrypted=green +titlebar.untrusted=red +titlebar.trusted=green +titlebar.online=white +titlebar.offline=black +titlebar.away=white +titlebar.chat=white +titlebar.dnd=black +titlebar.xa=white +statusbar=magenta statusbar.text=green statusbar.brackets=cyan statusbar.active=green statusbar.new=white main.text=white -input.text=green -main.time=white +main.text.me=white +main.text.them=white main.splash=green +main.time=white +input.text=green +subscribed=green +unsubscribed=white +otr.started.trusted=green +otr.started.untrusted=red +otr.ended=yellow +otr.trusted=green +otr.untrusted=red online=green away=yellow chat=green dnd=green xa=yellow -offline=grey +offline=bold_black +incoming=yellow typing=green gone=red error=red -incoming=yellow roominfo=green +roommention=green me=magenta them=green -titlebar.unencrypted=red -titlebar.encrypted=green -titlebar.untrusted=red -titlebar.trusted=green -otr.started.trusted=green -otr.started.untrusted=red -otr.ended=yellow -otr.trusted=green -otr.untrusted=red +roster.header=magenta +occupants.header=magenta +receipt.sent=red \ No newline at end of file diff --git a/themes/minimal b/themes/minimal deleted file mode 100644 index cabf1887..00000000 --- a/themes/minimal +++ /dev/null @@ -1,62 +0,0 @@ -[colours] -bkgnd=default -titlebar=blue -statusbar=blue -titlebar.text=bold_white -titlebar.brackets=white -statusbar.text=bold_white -statusbar.brackets=white -statusbar.active=bold_cyan -statusbar.new=bold_green -main.text=white -main.text.me=cyan -main.text.them=bold_white -input.text=bold_green -main.time=yellow -main.splash=bold_red -online=bold_green -away=bold_cyan -chat=bold_white -dnd=magenta -xa=bold_blue -offline=red -typing=yellow -gone=red -error=red -incoming=bold_yellow -roominfo=yellow -roommention=bold_red -me=blue -them=bold_green -titlebar.unencrypted=bold_red -titlebar.encrypted=bold_white -titlebar.untrusted=bold_yellow -titlebar.trusted=bold_white -titlebar.online=bold_green -titlebar.offline=bold_red -titlebar.away=bold_cyan -titlebar.xa=bold_cyan -titlebar.dnd=bold_red -titlebar.chat=bold_green -otr.started.trusted=green -otr.started.untrusted=yellow -otr.ended=red -otr.trusted=green -otr.untrusted=yellow -roster.header=bold_yellow -occupants.header=bold_yellow - -[ui] -intype=true -beep=false -flash=false -privileges=false -presence=false -wrap=false -time=off -statuses.muc=all -statuses.chat=all -statuses.console=all -occupants=false -roster=false -otr.warn=false diff --git a/themes/mono b/themes/mono index 42beb174..8efd7369 100644 --- a/themes/mono +++ b/themes/mono @@ -1,9 +1,19 @@ [colours] bkgnd=default titlebar=white -statusbar=white titlebar.text=black titlebar.brackets=black +titlebar.unencrypted=black +titlebar.encrypted=black +titlebar.untrusted=black +titlebar.trusted=black +titlebar.online=black +titlebar.offline=black +titlebar.away=black +titlebar.chat=black +titlebar.dnd=black +titlebar.xa=black +statusbar=white statusbar.text=black statusbar.brackets=black statusbar.active=black @@ -11,37 +21,30 @@ statusbar.new=black main.text=white main.text.me=white main.text.them=white -input.text=white -main.time=white main.splash=white +main.time=white +input.text=white +subscribed=white +unsubscribed=white +otr.started.trusted=white +otr.started.untrusted=white +otr.ended=white +otr.trusted=white +otr.untrusted=white online=white away=white chat=white dnd=white xa=white offline=white +incoming=white typing=white gone=white error=white -incoming=white roominfo=white roommention=white me=white them=white -titlebar.unencrypted=black -titlebar.encrypted=black -titlebar.untrusted=black -titlebar.trusted=black -titlebar.online=black -titlebar.offline=black -titlebar.away=black -titlebar.xa=black -titlebar.dnd=black -titlebar.chat=black -otr.started.trusted=white -otr.started.untrusted=white -otr.ended=white -otr.trusted=white -otr.untrusted=white roster.header=white occupants.header=white +receipt.sent=white \ No newline at end of file diff --git a/themes/orange b/themes/orange index cff5f58b..5fc6ddf2 100644 --- a/themes/orange +++ b/themes/orange @@ -3,6 +3,16 @@ bkgnd=yellow titlebar=red titlebar.text=black titlebar.brackets=blue +titlebar.unencrypted=black +titlebar.encrypted=white +titlebar.untrusted=white +titlebar.trusted=green +titlebar.online=white +titlebar.offline=black +titlebar.away=white +titlebar.chat=white +titlebar.dnd=black +titlebar.xa=white statusbar=green statusbar.text=black statusbar.brackets=blue @@ -11,32 +21,30 @@ statusbar.new=white main.text=black main.text.me=black main.text.them=green -main.time=blue main.splash=blue +main.time=blue input.text=black subscribed=blue -unsubscribed=red +unsubscribed=white +otr.started.trusted=green +otr.started.untrusted=white +otr.ended=red +otr.trusted=green +otr.untrusted=white online=blue away=white chat=blue dnd=white xa=white offline=white +incoming=blue typing=black gone=green error=red -incoming=blue roominfo=blue -me=blue -them=green -titlebar.unencrypted=black -titlebar.encrypted=white -titlebar.untrusted=white -titlebar.trusted=green -otr.started.trusted=green -otr.started.untrusted=white -otr.ended=red -otr.trusted=green -otr.untrusted=white +roommention=blue +me=black +them=black roster.header=black occupants.header=black +receipt.sent=red \ No newline at end of file diff --git a/themes/original b/themes/original index db0818c5..d1c0b26a 100644 --- a/themes/original +++ b/themes/original @@ -1,9 +1,19 @@ [colours] bkgnd=default titlebar=blue -statusbar=blue titlebar.text=white titlebar.brackets=cyan +titlebar.unencrypted=red +titlebar.encrypted=white +titlebar.untrusted=yellow +titlebar.trusted=white +titlebar.online=white +titlebar.offline=white +titlebar.away=white +titlebar.chat=white +titlebar.dnd=white +titlebar.xa=white +statusbar=blue statusbar.text=white statusbar.brackets=cyan statusbar.active=cyan @@ -11,39 +21,30 @@ statusbar.new=white main.text=white main.text.me=white main.text.them=white -input.text=white -main.time=white main.splash=cyan +main.time=white +input.text=white subscribed=green unsubscribed=red +otr.started.trusted=green +otr.started.untrusted=yellow +otr.ended=red +otr.trusted=green +otr.untrusted=yellow online=green away=cyan chat=green dnd=red xa=cyan offline=red +incoming=yellow typing=yellow -gone=red +gone=yellow error=red -incoming=yellow roominfo=yellow roommention=yellow me=yellow them=green -titlebar.unencrypted=red -titlebar.encrypted=white -titlebar.untrusted=yellow -titlebar.trusted=white -titlebar.online=white -titlebar.offline=white -titlebar.away=white -titlebar.xa=white -titlebar.dnd=white -titlebar.chat=white -otr.started.trusted=green -otr.started.untrusted=yellow -otr.ended=red -otr.trusted=green -otr.untrusted=yellow roster.header=yellow occupants.header=yellow +receipt.sent=red \ No newline at end of file diff --git a/themes/original_bright b/themes/original_bright index ffe0c12c..c584ff60 100644 --- a/themes/original_bright +++ b/themes/original_bright @@ -1,9 +1,19 @@ [colours] bkgnd=default titlebar=blue -statusbar=blue titlebar.text=bold_white titlebar.brackets=bold_cyan +titlebar.unencrypted=bold_red +titlebar.encrypted=bold_white +titlebar.untrusted=bold_yellow +titlebar.trusted=bold_white +titlebar.online=bold_white +titlebar.offline=bold_white +titlebar.away=bold_white +titlebar.chat=bold_white +titlebar.dnd=bold_white +titlebar.xa=bold_white +statusbar=blue statusbar.text=bold_white statusbar.brackets=bold_cyan statusbar.active=bold_cyan @@ -11,39 +21,30 @@ statusbar.new=bold_white main.text=bold_white main.text.me=bold_white main.text.them=bold_white -input.text=bold_white -main.time=bold_white main.splash=bold_cyan +main.time=bold_white +input.text=bold_white subscribed=bold_green unsubscribed=bold_red +otr.started.trusted=bold_green +otr.started.untrusted=bold_yellow +otr.ended=bold_red +otr.trusted=bold_green +otr.untrusted=bold_yellow online=bold_green away=bold_cyan chat=bold_green dnd=bold_red xa=bold_cyan offline=bold_red +incoming=bold_yellow typing=bold_yellow -gone=bold_red +gone=bold_yellow error=bold_red -incoming=bold_yellow roominfo=bold_yellow roommention=bold_yellow me=bold_yellow them=bold_green -titlebar.unencrypted=bold_red -titlebar.encrypted=bold_white -titlebar.untrusted=bold_yellow -titlebar.trusted=bold_white -titlebar.online=bold_white -titlebar.offline=bold_white -titlebar.away=bold_white -titlebar.xa=bold_white -titlebar.dnd=bold_white -titlebar.chat=bold_white -otr.started.trusted=bold_green -otr.started.untrusted=bold_yellow -otr.ended=bold_red -otr.trusted=bold_green -otr.untrusted=bold_yellow roster.header=bold_yellow occupants.header=bold_yellow +receipt.sent=bold_red diff --git a/themes/shade b/themes/shade index 0b61a0f7..38d42860 100644 --- a/themes/shade +++ b/themes/shade @@ -1,36 +1,50 @@ [colours] bkgnd=default titlebar=default -statusbar=default titlebar.text=white titlebar.brackets=magenta +titlebar.unencrypted=red +titlebar.encrypted=green +titlebar.untrusted=red +titlebar.trusted=green +titlebar.online=green +titlebar.offline=red +titlebar.away=green +titlebar.chat=green +titlebar.dnd=red +titlebar.xa=green +statusbar=default statusbar.text=magenta statusbar.brackets=magenta statusbar.active=white statusbar.new=green main.text=white -input.text=white -main.time=magenta +main.text.me=white +main.text.them=white main.splash=magenta +main.time=magenta +input.text=white +subscribed=green +unsubscribed=yallow +otr.started.trusted=green +otr.started.untrusted=red +otr.ended=yellow +otr.trusted=green +otr.untrusted=red online=green away=yellow chat=green dnd=green xa=yellow offline=white +incoming=yellow typing=green gone=red error=red -incoming=yellow roominfo=green -me=black +roommention=green +me=bold_black them=magenta -titlebar.unencrypted=red -titlebar.encrypted=green -titlebar.untrusted=red -titlebar.trusted=green -otr.started.trusted=green -otr.started.untrusted=red -otr.ended=yellow -otr.trusted=green -otr.untrusted=red +roster.header=magenta +occupants.header=magenta +receipt.sent=red \ No newline at end of file diff --git a/themes/simple b/themes/simple index 44c6977b..2885db12 100644 --- a/themes/simple +++ b/themes/simple @@ -1,67 +1,23 @@ -[colours] -bkgnd=default -titlebar=blue -statusbar=blue -titlebar.text=bold_white -titlebar.brackets=white -statusbar.text=bold_white -statusbar.brackets=white -statusbar.active=bold_cyan -statusbar.new=bold_green -main.text=white -main.text.me=cyan -main.text.them=bold_white -input.text=bold_green -main.time=yellow -main.splash=bold_red -online=bold_green -away=bold_cyan -chat=bold_white -dnd=magenta -xa=bold_blue -offline=red -typing=yellow -gone=red -error=red -incoming=bold_yellow -roominfo=yellow -roommention=bold_red -me=blue -them=bold_green -titlebar.unencrypted=bold_red -titlebar.encrypted=bold_white -titlebar.untrusted=bold_yellow -titlebar.trusted=bold_white -titlebar.online=bold_green -titlebar.offline=bold_red -titlebar.away=bold_cyan -titlebar.xa=bold_cyan -titlebar.dnd=bold_red -titlebar.chat=bold_green -otr.started.trusted=green -otr.started.untrusted=yellow -otr.ended=red -otr.trusted=green -otr.untrusted=yellow -roster.header=bold_yellow -occupants.header=bold_yellow - [ui] -intype=false beep=false flash=false -privileges=false -presence=false +splash=true wrap=true time=minutes -statuses.muc=off -statuses.chat=online -statuses.console=off +time.statusbar=off +resource.title=false +resource.message=false +statuses.console=none +statuses.chat=none +statuses.muc=none occupants=true occupants.size=15 roster=true -roster.size=25 roster.offline=false roster.resource=false roster.by=presence +roster.size=25 +privileges=false +presence=false +intype=false otr.warn=false diff --git a/themes/spawn b/themes/spawn index 0b403905..b32862d3 100644 --- a/themes/spawn +++ b/themes/spawn @@ -1,37 +1,50 @@ [colours] bkgnd=default titlebar=red -statusbar=red titlebar.text=yellow titlebar.brackets=green +titlebar.unencrypted=red +titlebar.encrypted=green +titlebar.untrusted=red +titlebar.trusted=green +titlebar.online=green +titlebar.offline=red +titlebar.away=green +titlebar.chat=green +titlebar.dnd=red +titlebar.xa=green +statusbar=red statusbar.text=yellow statusbar.brackets=green statusbar.active=white statusbar.new=green main.text=white -input.text=green -main.time=red +main.text.me=white +main.text.them=white main.splash=red +main.time=red +input.text=green +subscribed=green +unsubscribed=red +otr.started.trusted=green +otr.started.untrusted=red +otr.ended=yellow +otr.trusted=green +otr.untrusted=red online=green away=yellow chat=green dnd=green xa=yellow -offline=grey +offline=bold_black +incoming=yellow typing=green gone=red error=red -incoming=yellow roominfo=green roommention=red me=green them=yellow -titlebar.unencrypted=red -titlebar.encrypted=green -titlebar.untrusted=red -titlebar.trusted=green -otr.started.trusted=green -otr.started.untrusted=red -otr.ended=yellow -otr.trusted=green -otr.untrusted=red +roster.header=white +occupants.header=white +receipt.sent=red \ No newline at end of file diff --git a/themes/whiteness b/themes/whiteness index 597c9c83..30b5e0e7 100644 --- a/themes/whiteness +++ b/themes/whiteness @@ -1,36 +1,50 @@ [colours] bkgnd=white titlebar=blue -statusbar=blue titlebar.text=white titlebar.brackets=white +titlebar.unencrypted=red +titlebar.encrypted=white +titlebar.untrusted=yellow +titlebar.trusted=white +titlebar.online=white +titlebar.offline=red +titlebar.away=white +titlebar.chat=white +titlebar.dnd=red +titlebar.xa=white +statusbar=blue statusbar.text=white statusbar.brackets=white statusbar.active=megenta statusbar.new=red main.text=black -input.text=black -main.time=black +main.text.me=black +main.text.them=black main.splash=black +main.time=black +input.text=black +subscribed=green +unsubscribed=red +otr.started.trusted=green +otr.started.untrusted=yellow +otr.ended=red +otr.trusted=green +otr.untrusted=yellow online=green away=cyan chat=green dnd=red xa=cyan offline=red +incoming=yellow typing=yellow gone=red error=red -incoming=yellow roominfo=yellow -me=yellow -them=green -titlebar.unencrypted=red -titlebar.encrypted=white -titlebar.untrusted=yellow -titlebar.trusted=white -otr.started.trusted=green -otr.started.untrusted=yellow -otr.ended=red -otr.trusted=green -otr.untrusted=yellow +roommention=yellow +me=black +them=black +roster.header=black +occupants.header=black +receipt.sent=red \ No newline at end of file |