2013-01-28 17:24:47 -05:00
/*
2013-02-02 14:47:41 -05:00
* presence . c
2019-11-13 06:11:05 -05:00
* vim : expandtab : ts = 4 : sts = 4 : sw = 4
2013-01-28 17:24:47 -05:00
*
2019-01-22 05:31:45 -05:00
* Copyright ( C ) 2012 - 2019 James Booth < boothj5 @ gmail . com >
2013-01-28 17:24:47 -05:00
*
* 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
2016-07-23 20:14:49 -04:00
* along with Profanity . If not , see < https : //www.gnu.org/licenses/>.
2013-01-28 17:24:47 -05:00
*
2014-08-24 15:57:39 -04:00
* 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 .
*
2013-01-28 17:24:47 -05:00
*/
2016-03-31 16:05:02 -04:00
# include "config.h"
2015-09-21 16:40:04 -04:00
2013-02-10 18:29:37 -05:00
# include <assert.h>
2013-01-28 17:24:47 -05:00
# include <stdlib.h>
# include <string.h>
# include <glib.h>
2013-03-07 13:37:44 -05:00
# include <glib/gprintf.h>
2013-01-28 17:24:47 -05:00
2015-09-21 16:40:04 -04:00
# include <strophe.h>
2020-07-07 07:53:30 -04:00
# include "profanity.h"
# include "log.h"
2013-01-28 17:55:26 -05:00
# include "common.h"
2013-02-02 16:59:29 -05:00
# include "config/preferences.h"
2015-04-19 11:54:16 -04:00
# include "event/server_events.h"
2016-07-24 10:43:51 -04:00
# include "plugins/plugins.h"
# include "ui/ui.h"
2023-04-13 11:16:24 -04:00
# include "ui/window.h"
# include "ui/window_list.h"
2016-05-05 18:51:49 -04:00
# include "xmpp/connection.h"
2020-07-07 07:53:30 -04:00
# include "xmpp/capabilities.h"
2016-05-05 17:10:10 -04:00
# include "xmpp/session.h"
2013-02-02 15:55:58 -05:00
# include "xmpp/stanza.h"
2020-07-07 07:53:30 -04:00
# include "xmpp/iq.h"
2013-02-02 15:55:58 -05:00
# include "xmpp/xmpp.h"
2020-07-07 07:53:30 -04:00
# include "xmpp/muc.h"
2013-01-28 17:24:47 -05:00
2013-05-05 18:20:27 -04:00
static Autocomplete sub_requests_ac ;
2013-01-28 19:04:49 -05:00
2020-07-07 08:18:57 -04:00
static int _presence_handler ( xmpp_conn_t * const conn , xmpp_stanza_t * const stanza , void * const userdata ) ;
2015-10-25 20:14:23 -04:00
2020-07-07 08:18:57 -04:00
static void _presence_error_handler ( xmpp_stanza_t * const stanza ) ;
static void _unavailable_handler ( xmpp_stanza_t * const stanza ) ;
static void _subscribe_handler ( xmpp_stanza_t * const stanza ) ;
static void _subscribed_handler ( xmpp_stanza_t * const stanza ) ;
static void _unsubscribed_handler ( xmpp_stanza_t * const stanza ) ;
static void _muc_user_handler ( xmpp_stanza_t * const stanza ) ;
static void _available_handler ( xmpp_stanza_t * const stanza ) ;
2013-01-28 17:24:47 -05:00
2020-07-07 08:18:57 -04:00
void _send_caps_request ( char * node , char * caps_key , char * id , char * from ) ;
static void _send_room_presence ( xmpp_stanza_t * presence ) ;
static void _send_presence_stanza ( xmpp_stanza_t * const stanza ) ;
2016-03-26 11:50:16 -04:00
2013-01-28 17:24:47 -05:00
void
2013-05-05 19:33:33 -04:00
presence_sub_requests_init ( void )
2013-01-28 17:24:47 -05:00
{
2013-05-05 18:20:27 -04:00
sub_requests_ac = autocomplete_new ( ) ;
2013-01-28 17:24:47 -05:00
}
2013-01-28 19:04:49 -05:00
void
2016-05-02 17:34:26 -04:00
presence_handlers_init ( void )
2013-01-28 19:04:49 -05:00
{
2020-07-07 08:18:57 -04:00
xmpp_conn_t * const conn = connection_get_conn ( ) ;
xmpp_ctx_t * const ctx = connection_get_ctx ( ) ;
2016-03-27 20:25:48 -04:00
xmpp_handler_add ( conn , _presence_handler , NULL , STANZA_NAME_PRESENCE , NULL , ctx ) ;
2013-01-28 19:04:49 -05:00
}
2014-12-22 17:13:42 -05:00
void
2020-07-07 08:18:57 -04:00
presence_subscription ( const char * const jid , const jabber_subscr_t action )
2013-01-28 17:24:47 -05:00
{
2013-02-10 18:29:37 -05:00
assert ( jid ! = NULL ) ;
2023-07-13 09:11:30 -04:00
auto_jid Jid * jidp = jid_create ( jid ) ;
2013-05-05 18:20:27 -04:00
autocomplete_remove ( sub_requests_ac , jidp - > barejid ) ;
2013-02-10 18:29:37 -05:00
2020-07-07 08:18:57 -04:00
const char * type = NULL ;
switch ( action ) {
case PRESENCE_SUBSCRIBE :
log_debug ( " Sending presence subscribe: %s " , jid ) ;
type = STANZA_TYPE_SUBSCRIBE ;
break ;
case PRESENCE_SUBSCRIBED :
log_debug ( " Sending presence subscribed: %s " , jid ) ;
type = STANZA_TYPE_SUBSCRIBED ;
break ;
case PRESENCE_UNSUBSCRIBED :
log_debug ( " Sending presence usubscribed: %s " , jid ) ;
type = STANZA_TYPE_UNSUBSCRIBED ;
break ;
default :
break ;
2013-01-28 17:24:47 -05:00
}
2016-08-20 18:31:27 -04:00
if ( ! type ) {
log_error ( " Attempt to send unknown subscription action: %s " , jid ) ;
return ;
}
2013-01-28 17:24:47 -05:00
2020-07-07 08:18:57 -04:00
xmpp_ctx_t * const ctx = connection_get_ctx ( ) ;
xmpp_stanza_t * presence = xmpp_presence_new ( ctx ) ;
2016-08-20 18:31:27 -04:00
2023-07-11 07:23:58 -04:00
auto_char char * id = connection_create_stanza_id ( ) ;
2014-01-28 15:55:02 -05:00
xmpp_stanza_set_id ( presence , id ) ;
2016-08-20 18:31:27 -04:00
2013-01-28 17:24:47 -05:00
xmpp_stanza_set_type ( presence , type ) ;
2016-08-20 13:16:51 -04:00
xmpp_stanza_set_to ( presence , jidp - > barejid ) ;
2016-08-20 18:31:27 -04:00
2016-03-27 20:25:48 -04:00
_send_presence_stanza ( presence ) ;
2013-02-10 18:29:37 -05:00
2016-08-20 18:31:27 -04:00
xmpp_stanza_release ( presence ) ;
2013-01-28 17:24:47 -05:00
}
2017-03-31 19:27:11 -04:00
GList *
2014-12-22 17:13:42 -05:00
presence_get_subscription_requests ( void )
2013-01-28 17:24:47 -05:00
{
2014-09-25 19:06:50 -04:00
return autocomplete_create_list ( sub_requests_ac ) ;
2013-01-28 17:24:47 -05:00
}
2014-12-22 17:13:42 -05:00
gint
presence_sub_request_count ( void )
2013-04-27 18:57:51 -04:00
{
2013-05-05 18:20:27 -04:00
return autocomplete_length ( sub_requests_ac ) ;
2013-04-27 18:57:51 -04:00
}
2013-05-05 19:33:33 -04:00
void
presence_clear_sub_requests ( void )
{
autocomplete_clear ( sub_requests_ac ) ;
}
2015-10-25 20:14:23 -04:00
char *
2020-07-07 08:18:57 -04:00
presence_sub_request_find ( const char * const search_str , gboolean previous , void * context )
2013-05-05 18:42:11 -04:00
{
2017-03-31 19:27:11 -04:00
return autocomplete_complete ( sub_requests_ac , search_str , TRUE , previous ) ;
2013-05-05 18:42:11 -04:00
}
2014-12-22 17:13:42 -05:00
gboolean
2020-07-07 08:18:57 -04:00
presence_sub_request_exists ( const char * const bare_jid )
2013-06-01 18:27:46 -04:00
{
2013-08-03 07:38:38 -04:00
gboolean result = FALSE ;
2020-07-07 08:18:57 -04:00
GList * requests = autocomplete_create_list ( sub_requests_ac ) ;
GList * curr = requests ;
2016-08-20 18:31:27 -04:00
while ( curr ) {
if ( strcmp ( curr - > data , bare_jid ) = = 0 ) {
2013-08-03 07:38:38 -04:00
result = TRUE ;
break ;
2013-06-01 18:27:46 -04:00
}
2017-03-31 19:27:11 -04:00
curr = g_list_next ( curr ) ;
2013-08-03 07:38:38 -04:00
}
2017-03-31 19:27:11 -04:00
g_list_free_full ( requests , free ) ;
2013-08-03 07:38:38 -04:00
return result ;
2013-06-01 18:27:46 -04:00
}
2014-12-22 17:13:42 -05:00
void
presence_reset_sub_request_search ( void )
2013-05-05 18:42:11 -04:00
{
autocomplete_reset ( sub_requests_ac ) ;
}
2014-12-22 17:13:42 -05:00
void
2020-07-07 08:18:57 -04:00
presence_send ( const resource_presence_t presence_type , const int idle , char * signed_status )
2013-01-28 17:55:26 -05:00
{
2016-05-05 18:51:49 -04:00
if ( connection_get_status ( ) ! = JABBER_CONNECTED ) {
2013-02-10 18:29:37 -05:00
log_warning ( " Error setting presence, not connected. " ) ;
2013-01-28 17:55:26 -05:00
return ;
2013-02-10 18:29:37 -05:00
}
2023-12-09 09:08:47 -05:00
const char * msg = connection_get_presence_msg ( ) ;
2015-05-04 18:21:06 -04:00
if ( msg ) {
2015-05-07 18:12:49 -04:00
log_debug ( " Updating presence: %s, \" %s \" " , string_from_resource_presence ( presence_type ) , msg ) ;
2013-02-10 18:29:37 -05:00
} else {
2015-05-07 18:12:49 -04:00
log_debug ( " Updating presence: %s " , string_from_resource_presence ( presence_type ) ) ;
2013-02-10 18:29:37 -05:00
}
2016-08-20 18:31:27 -04:00
const int pri = accounts_get_priority_for_presence_type ( session_get_account_name ( ) , presence_type ) ;
2013-02-03 17:40:54 -05:00
connection_set_priority ( pri ) ;
2013-01-28 17:55:26 -05:00
2020-07-07 08:18:57 -04:00
xmpp_ctx_t * const ctx = connection_get_ctx ( ) ;
xmpp_stanza_t * presence = xmpp_presence_new ( ctx ) ;
2016-08-20 18:31:27 -04:00
2023-07-11 07:23:58 -04:00
auto_char char * id = connection_create_stanza_id ( ) ;
2014-01-28 15:55:02 -05:00
xmpp_stanza_set_id ( presence , id ) ;
2016-08-20 18:31:27 -04:00
2020-07-07 08:18:57 -04:00
const char * show = stanza_get_presence_string_from_type ( presence_type ) ;
2013-02-03 21:19:31 -05:00
stanza_attach_show ( ctx , presence , show ) ;
2015-03-23 19:38:06 -04:00
2013-02-03 21:19:31 -05:00
stanza_attach_status ( ctx , presence , msg ) ;
2015-03-23 19:38:06 -04:00
2015-05-07 19:07:21 -04:00
if ( signed_status ) {
2020-07-07 08:18:57 -04:00
xmpp_stanza_t * x = xmpp_stanza_new ( ctx ) ;
2015-05-07 19:07:21 -04:00
xmpp_stanza_set_name ( x , STANZA_NAME_X ) ;
xmpp_stanza_set_ns ( x , STANZA_NS_SIGNED ) ;
2016-08-20 18:31:27 -04:00
2020-07-07 08:18:57 -04:00
xmpp_stanza_t * signed_text = xmpp_stanza_new ( ctx ) ;
2015-05-07 19:07:21 -04:00
xmpp_stanza_set_text ( signed_text , signed_status ) ;
2016-08-20 18:31:27 -04:00
2015-05-07 19:07:21 -04:00
xmpp_stanza_add_child ( x , signed_text ) ;
xmpp_stanza_release ( signed_text ) ;
2016-08-20 18:31:27 -04:00
2015-05-07 19:07:21 -04:00
xmpp_stanza_add_child ( presence , x ) ;
xmpp_stanza_release ( x ) ;
2015-03-23 19:38:06 -04:00
}
2013-02-03 15:09:56 -05:00
stanza_attach_priority ( ctx , presence , pri ) ;
2016-08-20 18:31:27 -04:00
2015-10-14 16:12:26 -04:00
if ( idle > 0 ) {
stanza_attach_last_activity ( ctx , presence , idle ) ;
}
2016-08-20 18:31:27 -04:00
2013-02-03 15:09:56 -05:00
stanza_attach_caps ( ctx , presence ) ;
2016-08-20 18:31:27 -04:00
2016-03-27 20:25:48 -04:00
_send_presence_stanza ( presence ) ;
_send_room_presence ( presence ) ;
2016-08-20 18:31:27 -04:00
2013-02-10 18:29:37 -05:00
xmpp_stanza_release ( presence ) ;
2013-01-28 17:55:26 -05:00
2013-02-10 18:29:37 -05:00
// set last presence for account
2020-07-07 08:18:57 -04:00
const char * last = show ;
2013-02-10 18:29:37 -05:00
if ( last = = NULL ) {
last = STANZA_TEXT_ONLINE ;
}
2016-08-20 18:31:27 -04:00
2020-07-07 08:18:57 -04:00
char * account = session_get_account_name ( ) ;
2015-09-27 18:08:30 -04:00
accounts_set_last_presence ( account , last ) ;
accounts_set_last_status ( account , msg ) ;
2013-02-10 18:29:37 -05:00
}
static void
2020-07-07 08:18:57 -04:00
_send_room_presence ( xmpp_stanza_t * presence )
2013-02-10 18:29:37 -05:00
{
2020-07-07 08:18:57 -04:00
GList * rooms = muc_rooms ( ) ;
GList * curr = rooms ;
2016-07-25 18:13:09 -04:00
while ( curr ) {
2020-07-07 08:18:57 -04:00
const char * room = curr - > data ;
const char * nick = muc_nick ( room ) ;
2013-01-28 17:55:26 -05:00
2015-05-04 18:21:06 -04:00
if ( nick ) {
2023-07-11 07:23:58 -04:00
auto_char char * full_room_jid = create_fulljid ( room , nick ) ;
2016-08-20 13:16:51 -04:00
xmpp_stanza_set_to ( presence , full_room_jid ) ;
2013-08-03 07:38:38 -04:00
log_debug ( " Sending presence to room: %s " , full_room_jid ) ;
2016-08-20 18:31:27 -04:00
_send_presence_stanza ( presence ) ;
2013-08-03 07:38:38 -04:00
}
2013-01-28 17:55:26 -05:00
2016-07-25 18:13:09 -04:00
curr = g_list_next ( curr ) ;
2013-01-28 17:55:26 -05:00
}
2016-07-25 18:13:09 -04:00
g_list_free ( rooms ) ;
2013-01-28 17:55:26 -05:00
}
2014-12-22 17:13:42 -05:00
void
2020-07-07 08:18:57 -04:00
presence_join_room ( const char * const room , const char * const nick , const char * const passwd )
2013-02-03 15:09:56 -05:00
{
2023-07-13 09:11:30 -04:00
auto_jid Jid * jid = jid_create_from_bare_and_resource ( room , nick ) ;
2013-02-10 18:29:37 -05:00
log_debug ( " Sending room join presence to: %s " , jid - > fulljid ) ;
2016-08-20 18:31:27 -04:00
resource_presence_t presence_type = accounts_get_last_presence ( session_get_account_name ( ) ) ;
2020-07-07 08:18:57 -04:00
const char * show = stanza_get_presence_string_from_type ( presence_type ) ;
2023-12-09 09:08:47 -05:00
const char * status = connection_get_presence_msg ( ) ;
2016-08-20 18:31:27 -04:00
int pri = accounts_get_priority_for_presence_type ( session_get_account_name ( ) , presence_type ) ;
2013-02-03 15:09:56 -05:00
2020-07-07 08:18:57 -04:00
xmpp_ctx_t * ctx = connection_get_ctx ( ) ;
xmpp_stanza_t * presence = stanza_create_room_join_presence ( ctx , jid - > fulljid , passwd ) ;
2013-02-03 21:19:31 -05:00
stanza_attach_show ( ctx , presence , show ) ;
stanza_attach_status ( ctx , presence , status ) ;
2013-02-03 15:09:56 -05:00
stanza_attach_priority ( ctx , presence , pri ) ;
stanza_attach_caps ( ctx , presence ) ;
2016-03-27 20:25:48 -04:00
_send_presence_stanza ( presence ) ;
2013-02-03 15:09:56 -05:00
2016-08-20 18:31:27 -04:00
xmpp_stanza_release ( presence ) ;
2013-02-03 15:09:56 -05:00
}
2014-12-22 17:13:42 -05:00
void
2020-07-07 08:18:57 -04:00
presence_change_room_nick ( const char * const room , const char * const nick )
2013-02-03 15:09:56 -05:00
{
2013-02-10 18:29:37 -05:00
assert ( room ! = NULL ) ;
assert ( nick ! = NULL ) ;
log_debug ( " Sending room nickname change to: %s, nick: %s " , room , nick ) ;
2016-08-20 18:31:27 -04:00
resource_presence_t presence_type = accounts_get_last_presence ( session_get_account_name ( ) ) ;
2020-07-07 08:18:57 -04:00
const char * show = stanza_get_presence_string_from_type ( presence_type ) ;
2023-12-09 09:08:47 -05:00
const char * status = connection_get_presence_msg ( ) ;
2016-08-20 18:31:27 -04:00
int pri = accounts_get_priority_for_presence_type ( session_get_account_name ( ) , presence_type ) ;
2023-07-11 07:23:58 -04:00
auto_char char * full_room_jid = create_fulljid ( room , nick ) ;
2016-08-20 18:31:27 -04:00
2020-07-07 08:18:57 -04:00
xmpp_ctx_t * ctx = connection_get_ctx ( ) ;
xmpp_stanza_t * presence = stanza_create_room_newnick_presence ( ctx , full_room_jid ) ;
2013-02-03 21:33:25 -05:00
stanza_attach_show ( ctx , presence , show ) ;
stanza_attach_status ( ctx , presence , status ) ;
stanza_attach_priority ( ctx , presence , pri ) ;
stanza_attach_caps ( ctx , presence ) ;
2016-03-27 20:25:48 -04:00
_send_presence_stanza ( presence ) ;
2013-02-03 15:09:56 -05:00
2016-08-20 18:31:27 -04:00
xmpp_stanza_release ( presence ) ;
2013-02-03 15:09:56 -05:00
}
2014-12-22 17:13:42 -05:00
void
2020-07-07 08:18:57 -04:00
presence_leave_chat_room ( const char * const room_jid )
2013-02-03 15:09:56 -05:00
{
2013-02-10 18:29:37 -05:00
assert ( room_jid ! = NULL ) ;
2020-07-07 08:18:57 -04:00
char * nick = muc_nick ( room_jid ) ;
2016-08-20 18:31:27 -04:00
if ( ! nick ) {
log_error ( " Could not get nickname for room: %s " , room_jid ) ;
return ;
}
2013-02-10 18:29:37 -05:00
log_debug ( " Sending room leave presence to: %s " , room_jid ) ;
2016-08-20 18:31:27 -04:00
2020-07-07 08:18:57 -04:00
xmpp_ctx_t * ctx = connection_get_ctx ( ) ;
xmpp_stanza_t * presence = stanza_create_room_leave_presence ( ctx , room_jid , nick ) ;
2016-08-20 18:31:27 -04:00
_send_presence_stanza ( presence ) ;
xmpp_stanza_release ( presence ) ;
}
static int
2020-07-07 08:18:57 -04:00
_presence_handler ( xmpp_conn_t * const conn , xmpp_stanza_t * const stanza , void * const userdata )
2016-08-20 18:31:27 -04:00
{
log_debug ( " Presence stanza handler fired " ) ;
2023-05-22 10:58:57 -04:00
autoping_timer_extend ( ) ;
2016-08-20 18:31:27 -04:00
2020-07-07 08:18:57 -04:00
char * text = NULL ;
2016-08-20 18:31:27 -04:00
size_t text_size ;
xmpp_stanza_to_text ( stanza , & text , & text_size ) ;
gboolean cont = plugins_on_presence_stanza_receive ( text ) ;
xmpp_free ( connection_get_ctx ( ) , text ) ;
if ( ! cont ) {
return 1 ;
}
2020-07-07 08:18:57 -04:00
const char * type = xmpp_stanza_get_type ( stanza ) ;
2016-08-20 18:31:27 -04:00
if ( g_strcmp0 ( type , STANZA_TYPE_ERROR ) = = 0 ) {
_presence_error_handler ( stanza ) ;
}
if ( g_strcmp0 ( type , STANZA_TYPE_UNAVAILABLE ) = = 0 ) {
_unavailable_handler ( stanza ) ;
}
if ( g_strcmp0 ( type , STANZA_TYPE_SUBSCRIBE ) = = 0 ) {
_subscribe_handler ( stanza ) ;
}
if ( g_strcmp0 ( type , STANZA_TYPE_SUBSCRIBED ) = = 0 ) {
_subscribed_handler ( stanza ) ;
}
if ( g_strcmp0 ( type , STANZA_TYPE_UNSUBSCRIBED ) = = 0 ) {
_unsubscribed_handler ( stanza ) ;
}
2013-02-03 15:09:56 -05:00
2020-07-07 08:18:57 -04:00
xmpp_stanza_t * mucuser = xmpp_stanza_get_child_by_ns ( stanza , STANZA_NS_MUC_USER ) ;
2016-08-20 18:31:27 -04:00
if ( mucuser ) {
_muc_user_handler ( stanza ) ;
2013-09-21 20:26:40 -04:00
}
2016-08-20 18:31:27 -04:00
_available_handler ( stanza ) ;
return 1 ;
2013-02-03 15:09:56 -05:00
}
2016-03-27 20:25:48 -04:00
static void
2020-07-07 08:18:57 -04:00
_presence_error_handler ( xmpp_stanza_t * const stanza )
2014-01-27 16:42:34 -05:00
{
2020-07-07 08:18:57 -04:00
const char * xmlns = NULL ;
xmpp_stanza_t * x = xmpp_stanza_get_child_by_name ( stanza , STANZA_NAME_X ) ;
2015-05-04 18:21:06 -04:00
if ( x ) {
2014-05-05 17:01:27 -04:00
xmlns = xmpp_stanza_get_ns ( x ) ;
}
2016-08-20 18:31:27 -04:00
2020-07-07 08:18:57 -04:00
const char * from = xmpp_stanza_get_from ( stanza ) ;
xmpp_stanza_t * error_stanza = xmpp_stanza_get_child_by_name ( stanza , STANZA_NAME_ERROR ) ;
2014-01-27 16:42:34 -05:00
2014-04-20 19:37:04 -04:00
// handle MUC join errors
if ( g_strcmp0 ( xmlns , STANZA_NS_MUC ) = = 0 ) {
2020-07-07 08:18:57 -04:00
const char * error_cond = NULL ;
xmpp_stanza_t * reason_st = xmpp_stanza_get_child_by_ns ( error_stanza , STANZA_NS_STANZAS ) ;
2015-05-04 18:21:06 -04:00
if ( reason_st ) {
2014-04-20 19:37:04 -04:00
error_cond = xmpp_stanza_get_name ( reason_st ) ;
}
if ( error_cond = = NULL ) {
error_cond = " unknown " ;
}
2023-07-13 09:11:30 -04:00
auto_jid Jid * fulljid = jid_create ( from ) ;
2014-04-20 19:37:04 -04:00
log_info ( " Error joining room: %s, reason: %s " , fulljid - > barejid , error_cond ) ;
2015-04-30 19:55:40 -04:00
if ( muc_active ( fulljid - > barejid ) ) {
muc_leave ( fulljid - > barejid ) ;
}
2015-11-02 16:11:47 -05:00
cons_show_error ( " Error joining room %s, reason: %s " , fulljid - > barejid , error_cond ) ;
2016-08-20 18:31:27 -04:00
2016-03-27 20:25:48 -04:00
return ;
2014-04-20 19:37:04 -04:00
}
2020-07-07 08:18:57 -04:00
GString * log_msg = g_string_new ( " presence stanza error received " ) ;
const char * id = xmpp_stanza_get_id ( stanza ) ;
2015-05-04 18:21:06 -04:00
if ( id ) {
2014-01-27 17:35:04 -05:00
g_string_append ( log_msg , " id= " ) ;
g_string_append ( log_msg , id ) ;
}
2015-05-04 18:21:06 -04:00
if ( from ) {
2014-01-27 17:35:04 -05:00
g_string_append ( log_msg , " from= " ) ;
g_string_append ( log_msg , from ) ;
}
2016-08-20 18:31:27 -04:00
2020-07-07 08:18:57 -04:00
const char * type = NULL ;
2016-08-20 18:31:27 -04:00
if ( error_stanza ) {
type = xmpp_stanza_get_type ( error_stanza ) ;
}
2015-05-04 18:21:06 -04:00
if ( type ) {
2014-01-27 17:35:04 -05:00
g_string_append ( log_msg , " type= " ) ;
g_string_append ( log_msg , type ) ;
}
2016-08-20 18:31:27 -04:00
// stanza_get_error never returns NULL
2023-07-11 07:23:58 -04:00
auto_char char * err_msg = stanza_get_error_message ( stanza ) ;
2014-01-27 17:35:04 -05:00
g_string_append ( log_msg , " error= " ) ;
g_string_append ( log_msg , err_msg ) ;
2014-01-27 16:42:34 -05:00
2014-01-27 17:35:04 -05:00
log_info ( log_msg - > str ) ;
2014-01-27 16:42:34 -05:00
2014-01-27 17:35:04 -05:00
g_string_free ( log_msg , TRUE ) ;
2014-01-27 16:42:34 -05:00
2015-05-04 18:21:06 -04:00
if ( from ) {
2015-04-30 19:55:40 -04:00
ui_handle_recipient_error ( from , err_msg ) ;
} else {
ui_handle_error ( err_msg ) ;
}
2014-01-27 16:42:34 -05:00
}
2016-03-27 20:25:48 -04:00
static void
2020-07-07 08:18:57 -04:00
_unsubscribed_handler ( xmpp_stanza_t * const stanza )
2013-02-10 14:39:19 -05:00
{
2020-07-07 08:18:57 -04:00
const char * from = xmpp_stanza_get_from ( stanza ) ;
2016-08-20 18:31:27 -04:00
if ( ! from ) {
log_warning ( " Unsubscribed presence handler received with no from attribute " ) ;
return ;
}
2013-02-10 18:29:37 -05:00
log_debug ( " Unsubscribed presence handler fired for %s " , from ) ;
2013-02-10 14:39:19 -05:00
2023-07-13 09:11:30 -04:00
auto_jid Jid * from_jid = jid_create ( from ) ;
2015-04-28 18:38:56 -04:00
sv_ev_subscription ( from_jid - > barejid , PRESENCE_UNSUBSCRIBED ) ;
2013-05-05 18:20:27 -04:00
autocomplete_remove ( sub_requests_ac , from_jid - > barejid ) ;
2013-02-10 14:39:19 -05:00
}
2016-03-27 20:25:48 -04:00
static void
2020-07-07 08:18:57 -04:00
_subscribed_handler ( xmpp_stanza_t * const stanza )
2013-02-10 14:39:19 -05:00
{
2020-07-07 08:18:57 -04:00
const char * from = xmpp_stanza_get_from ( stanza ) ;
2016-08-20 18:31:27 -04:00
if ( ! from ) {
log_warning ( " Subscribed presence handler received with no from attribute " ) ;
return ;
}
2013-02-10 18:29:37 -05:00
log_debug ( " Subscribed presence handler fired for %s " , from ) ;
2013-02-10 14:39:19 -05:00
2023-07-13 09:11:30 -04:00
auto_jid Jid * from_jid = jid_create ( from ) ;
2015-04-28 18:38:56 -04:00
sv_ev_subscription ( from_jid - > barejid , PRESENCE_SUBSCRIBED ) ;
2013-05-05 18:20:27 -04:00
autocomplete_remove ( sub_requests_ac , from_jid - > barejid ) ;
2013-02-10 14:39:19 -05:00
}
2016-03-27 20:25:48 -04:00
static void
2020-07-07 08:18:57 -04:00
_subscribe_handler ( xmpp_stanza_t * const stanza )
2013-02-10 14:39:19 -05:00
{
2020-07-07 08:18:57 -04:00
const char * from = xmpp_stanza_get_from ( stanza ) ;
2016-08-20 18:31:27 -04:00
if ( ! from ) {
log_warning ( " Subscribe presence handler received with no from attribute " , from ) ;
}
2013-02-10 18:29:37 -05:00
log_debug ( " Subscribe presence handler fired for %s " , from ) ;
2013-02-10 14:39:19 -05:00
2023-07-13 09:11:30 -04:00
auto_jid Jid * from_jid = jid_create ( from ) ;
2013-08-03 07:38:38 -04:00
if ( from_jid = = NULL ) {
2016-03-27 20:25:48 -04:00
return ;
2013-08-03 07:38:38 -04:00
}
2015-04-28 18:38:56 -04:00
sv_ev_subscription ( from_jid - > barejid , PRESENCE_SUBSCRIBE ) ;
2013-08-25 20:29:50 -04:00
autocomplete_add ( sub_requests_ac , from_jid - > barejid ) ;
2013-02-10 14:39:19 -05:00
}
2013-01-28 17:55:26 -05:00
2016-03-27 20:25:48 -04:00
static void
2020-07-07 08:18:57 -04:00
_unavailable_handler ( xmpp_stanza_t * const stanza )
2013-01-28 17:24:47 -05:00
{
2015-11-01 13:56:34 -05:00
inp_nonblocking ( TRUE ) ;
2015-05-06 17:02:50 -04:00
2020-07-07 08:18:57 -04:00
xmpp_conn_t * conn = connection_get_conn ( ) ;
const char * jid = xmpp_conn_get_jid ( conn ) ;
const char * from = xmpp_stanza_get_from ( stanza ) ;
2016-08-20 18:31:27 -04:00
if ( ! from ) {
log_warning ( " Unavailable presence received with no from attribute " ) ;
}
2013-02-10 18:29:37 -05:00
log_debug ( " Unavailable presence handler fired for %s " , from ) ;
2013-01-28 17:24:47 -05:00
2023-07-13 09:11:30 -04:00
auto_jid Jid * my_jid = jid_create ( jid ) ;
auto_jid Jid * from_jid = jid_create ( from ) ;
2013-08-03 07:38:38 -04:00
if ( my_jid = = NULL | | from_jid = = NULL ) {
2016-03-27 20:25:48 -04:00
return ;
2013-08-03 07:38:38 -04:00
}
2013-01-28 17:24:47 -05:00
2020-07-07 08:18:57 -04:00
if ( strcmp ( my_jid - > barejid , from_jid - > barejid ) ! = 0 ) {
2023-07-11 07:23:58 -04:00
auto_char char * status_str = stanza_get_status ( stanza , NULL ) ;
2015-05-04 18:21:06 -04:00
if ( from_jid - > resourcepart ) {
2015-04-28 18:38:56 -04:00
sv_ev_contact_offline ( from_jid - > barejid , from_jid - > resourcepart , status_str ) ;
2013-04-07 14:19:02 -04:00
2020-07-07 08:18:57 -04:00
// hack for servers that do not send full jid with unavailable presence
2013-04-07 14:19:02 -04:00
} else {
2015-04-28 18:38:56 -04:00
sv_ev_contact_offline ( from_jid - > barejid , " __prof_default " , status_str ) ;
2013-02-24 10:18:15 -05:00
}
2013-02-18 17:51:05 -05:00
} else {
2015-05-04 18:21:06 -04:00
if ( from_jid - > resourcepart ) {
2016-05-07 18:04:50 -04:00
connection_remove_available_resource ( from_jid - > resourcepart ) ;
2013-02-24 10:18:15 -05:00
}
2013-01-28 17:24:47 -05:00
}
2013-02-10 14:39:19 -05:00
}
2013-01-28 17:24:47 -05:00
2014-09-20 20:57:09 -04:00
static void
2020-07-07 08:18:57 -04:00
_handle_caps ( const char * const jid , XMPPCaps * caps )
2014-09-20 20:57:09 -04:00
{
2014-11-29 19:37:36 -05:00
// hash supported, xep-0115, cache against ver
2014-11-26 16:59:36 -05:00
if ( g_strcmp0 ( caps - > hash , " sha-1 " ) = = 0 ) {
2020-04-14 12:29:15 -04:00
log_debug ( " Hash %s supported for %s " , caps - > hash , jid ) ;
2014-11-26 16:59:36 -05:00
if ( caps - > ver ) {
2016-08-13 18:45:58 -04:00
if ( caps_cache_contains ( caps - > ver ) ) {
2020-04-14 12:29:15 -04:00
log_debug ( " Capabilities cache hit: %s, for %s. " , caps - > ver , jid ) ;
2014-11-26 20:08:02 -05:00
caps_map_jid_to_ver ( jid , caps - > ver ) ;
2014-09-20 20:57:09 -04:00
} else {
2020-04-14 12:29:15 -04:00
log_debug ( " Capabilities cache miss: %s, for %s, sending service discovery request " , caps - > ver , jid ) ;
2023-07-11 07:23:58 -04:00
auto_char char * id = connection_create_stanza_id ( ) ;
2014-11-26 16:59:36 -05:00
iq_send_caps_request ( jid , id , caps - > node , caps - > ver ) ;
2014-09-20 20:57:09 -04:00
}
}
2014-11-26 16:59:36 -05:00
2020-07-07 08:18:57 -04:00
// unsupported hash, xep-0115, associate with JID, no cache
2014-11-26 16:59:36 -05:00
} else if ( caps - > hash ) {
2014-11-26 20:08:02 -05:00
log_info ( " Hash %s not supported: %s, sending service discovery request " , caps - > hash , jid ) ;
2023-07-11 07:23:58 -04:00
auto_char char * id = connection_create_stanza_id ( ) ;
2014-11-26 20:08:02 -05:00
iq_send_caps_request_for_jid ( jid , id , caps - > node , caps - > ver ) ;
2020-07-07 08:18:57 -04:00
// no hash, legacy caps, cache against node#ver
} else if ( caps - > node & & caps - > ver ) {
2014-11-29 19:37:36 -05:00
log_info ( " No hash specified: %s, legacy request made for %s#%s " , jid , caps - > node , caps - > ver ) ;
2023-07-11 07:23:58 -04:00
auto_char char * id = connection_create_stanza_id ( ) ;
2014-11-29 19:37:36 -05:00
iq_send_caps_request_legacy ( jid , id , caps - > node , caps - > ver ) ;
2014-11-26 16:59:36 -05:00
} else {
2016-04-01 06:09:35 -04:00
log_info ( " No hash specified: %s, could not create ver string, not sending service discovery request. " , jid ) ;
2014-09-20 20:57:09 -04:00
}
}
2016-03-27 20:25:48 -04:00
static void
2020-07-07 08:18:57 -04:00
_available_handler ( xmpp_stanza_t * const stanza )
2013-02-10 14:39:19 -05:00
{
2015-11-01 13:56:34 -05:00
inp_nonblocking ( TRUE ) ;
2015-05-06 17:02:50 -04:00
2013-02-10 14:39:19 -05:00
// handler still fires if error
if ( g_strcmp0 ( xmpp_stanza_get_type ( stanza ) , STANZA_TYPE_ERROR ) = = 0 ) {
2016-03-27 20:25:48 -04:00
return ;
2013-02-10 14:39:19 -05:00
}
2013-01-28 17:24:47 -05:00
2013-02-10 14:39:19 -05:00
// handler still fires if other types
2020-07-07 08:18:57 -04:00
if ( ( g_strcmp0 ( xmpp_stanza_get_type ( stanza ) , STANZA_TYPE_UNAVAILABLE ) = = 0 ) | | ( g_strcmp0 ( xmpp_stanza_get_type ( stanza ) , STANZA_TYPE_SUBSCRIBE ) = = 0 ) | | ( g_strcmp0 ( xmpp_stanza_get_type ( stanza ) , STANZA_TYPE_SUBSCRIBED ) = = 0 ) | | ( g_strcmp0 ( xmpp_stanza_get_type ( stanza ) , STANZA_TYPE_UNSUBSCRIBED ) = = 0 ) ) {
2016-03-27 20:25:48 -04:00
return ;
2013-02-10 14:39:19 -05:00
}
2013-01-28 17:24:47 -05:00
2013-02-10 18:29:37 -05:00
// handler still fires for muc presence
if ( stanza_is_muc_presence ( stanza ) ) {
2016-03-27 20:25:48 -04:00
return ;
2013-02-10 18:29:37 -05:00
}
2014-11-26 16:07:46 -05:00
int err = 0 ;
2020-07-07 08:18:57 -04:00
XMPPPresence * xmpp_presence = stanza_parse_presence ( stanza , & err ) ;
2014-11-26 16:07:46 -05:00
if ( ! xmpp_presence ) {
2020-07-07 08:18:57 -04:00
const char * from = NULL ;
switch ( err ) {
case STANZA_PARSE_ERROR_NO_FROM :
log_warning ( " Available presence handler fired with no from attribute. " ) ;
break ;
case STANZA_PARSE_ERROR_INVALID_FROM :
from = xmpp_stanza_get_from ( stanza ) ;
log_warning ( " Available presence handler fired with invalid from attribute: %s " , from ) ;
break ;
default :
log_warning ( " Available presence handler fired, could not parse stanza. " ) ;
break ;
2014-11-26 16:07:46 -05:00
}
2016-03-27 20:25:48 -04:00
return ;
2014-11-26 16:07:46 -05:00
} else {
2020-07-07 08:18:57 -04:00
char * jid = jid_fulljid_or_barejid ( xmpp_presence - > jid ) ;
2014-11-26 16:59:36 -05:00
log_debug ( " Presence available handler fired for: %s " , jid ) ;
2014-09-18 16:36:43 -04:00
}
2013-01-28 17:24:47 -05:00
2020-07-07 08:18:57 -04:00
xmpp_conn_t * conn = connection_get_conn ( ) ;
const char * my_jid_str = xmpp_conn_get_jid ( conn ) ;
2023-07-13 09:11:30 -04:00
auto_jid Jid * my_jid = jid_create ( my_jid_str ) ;
2014-11-26 16:59:36 -05:00
2020-07-07 08:18:57 -04:00
XMPPCaps * caps = stanza_parse_caps ( stanza ) ;
2014-11-26 16:59:36 -05:00
if ( ( g_strcmp0 ( my_jid - > fulljid , xmpp_presence - > jid - > fulljid ) ! = 0 ) & & caps ) {
2020-04-14 12:29:15 -04:00
log_debug ( " Presence contains capabilities. " ) ;
2020-07-07 08:18:57 -04:00
char * jid = jid_fulljid_or_barejid ( xmpp_presence - > jid ) ;
2014-11-26 16:59:36 -05:00
_handle_caps ( jid , caps ) ;
2014-09-18 16:36:43 -04:00
}
2014-11-26 16:59:36 -05:00
stanza_free_caps ( caps ) ;
2013-04-07 14:19:02 -04:00
2020-07-07 08:18:57 -04:00
Resource * resource = stanza_resource_from_presence ( xmpp_presence ) ;
2013-03-17 17:53:34 -04:00
2014-11-26 16:07:46 -05:00
if ( g_strcmp0 ( xmpp_presence - > jid - > barejid , my_jid - > barejid ) = = 0 ) {
2016-05-07 18:04:50 -04:00
connection_add_available_resource ( resource ) ;
2023-04-13 11:16:24 -04:00
const char * account_name = session_get_account_name ( ) ;
int max_sessions = accounts_get_max_sessions ( account_name ) ;
if ( max_sessions > 0 ) {
2023-07-13 11:04:59 -04:00
const gchar * cur_resource = accounts_get_resource ( account_name ) ;
2023-04-13 11:16:24 -04:00
int res_count = connection_count_available_resources ( ) ;
if ( res_count > max_sessions & & g_strcmp0 ( cur_resource , resource - > name ) ) {
ProfWin * console = wins_get_console ( ) ;
ProfWin * current_window = wins_get_current ( ) ;
auto_gchar gchar * message = g_strdup_printf ( " Max sessions alarm! (%d/%d devices in use) " , res_count , max_sessions ) ;
win_println ( console , THEME_RED , " | " , " %s " , message ) ;
if ( console ! = current_window ) {
win_println ( current_window , THEME_RED , " | " , " %s - check the console for more details! " , message ) ;
}
notify ( message , 10000 , " Security alert " ) ;
const char * resource_presence = string_from_resource_presence ( resource - > presence ) ;
win_print ( console , THEME_DEFAULT , " | " , " New device info: \n %s (%d), %s " , resource - > name , resource - > priority , resource_presence ) ;
if ( resource - > status ) {
win_append ( console , THEME_DEFAULT , " , \" %s \" " , resource - > status ) ;
}
win_appendln ( console , THEME_DEFAULT , " " ) ;
auto_jid Jid * jidp = jid_create_from_bare_and_resource ( my_jid - > barejid , resource - > name ) ;
EntityCapabilities * caps = caps_lookup ( jidp - > fulljid ) ;
if ( caps ) {
if ( caps - > identity ) {
DiscoIdentity * identity = caps - > identity ;
win_print ( console , THEME_DEFAULT , " | " , " %s %s %s " , identity - > name , identity - > type , identity - > category ) ;
win_newline ( console ) ;
}
if ( caps - > software_version ) {
SoftwareVersion * software_version = caps - > software_version ;
if ( software_version - > software ) {
win_print ( console , THEME_DEFAULT , " | " , " Software: %s " , software_version - > software ) ;
}
if ( software_version - > software_version ) {
win_append ( console , THEME_DEFAULT , " , %s " , software_version - > software_version ) ;
}
if ( software_version - > software | | software_version - > software_version ) {
win_newline ( console ) ;
}
if ( software_version - > os ) {
win_print ( console , THEME_DEFAULT , " | " , " OS: %s " , software_version - > os ) ;
}
if ( software_version - > os_version ) {
win_append ( console , THEME_DEFAULT , " , %s " , software_version - > os_version ) ;
}
if ( software_version - > os | | software_version - > os_version ) {
win_newline ( console ) ;
}
}
caps_destroy ( caps ) ;
}
win_println ( console , THEME_RED_BOLD , " | " , " If it wasn't you, change your password. Use: /changepassword " ) ;
win_println ( console , THEME_GREEN , " | " , " If it was you, update the `session_alarm` limit that determines when to trigger this alarm, use: /account set %s session_alarm %d " , account_name , res_count ) ;
cons_alert ( NULL ) ;
}
}
2013-04-07 14:19:02 -04:00
} else {
2020-07-07 08:18:57 -04:00
char * pgpsig = NULL ;
xmpp_stanza_t * x = xmpp_stanza_get_child_by_ns ( stanza , STANZA_NS_SIGNED ) ;
2015-05-07 17:22:28 -04:00
if ( x ) {
pgpsig = xmpp_stanza_get_text ( x ) ;
}
sv_ev_contact_online ( xmpp_presence - > jid - > barejid , resource , xmpp_presence - > last_activity , pgpsig ) ;
2020-07-07 08:18:57 -04:00
xmpp_ctx_t * ctx = connection_get_ctx ( ) ;
2015-05-07 17:22:28 -04:00
xmpp_free ( ctx , pgpsig ) ;
2013-01-28 17:24:47 -05:00
}
2014-11-26 16:07:46 -05:00
stanza_free_presence ( xmpp_presence ) ;
2013-01-28 17:24:47 -05:00
}
2013-03-17 19:04:36 -04:00
void
2020-07-07 08:18:57 -04:00
_send_caps_request ( char * node , char * caps_key , char * id , char * from )
2013-03-17 19:04:36 -04:00
{
2016-08-20 18:31:27 -04:00
if ( ! node ) {
2013-03-17 19:04:36 -04:00
log_debug ( " No node string, not sending discovery IQ. " ) ;
2016-08-20 18:31:27 -04:00
return ;
}
log_debug ( " Node string: %s. " , node ) ;
if ( caps_cache_contains ( caps_key ) ) {
log_debug ( " Capabilities already cached, for %s " , caps_key ) ;
return ;
2013-03-17 19:04:36 -04:00
}
2016-08-20 18:31:27 -04:00
log_debug ( " Capabilities not cached for '%s', sending discovery IQ. " , from ) ;
2020-07-07 08:18:57 -04:00
xmpp_ctx_t * ctx = connection_get_ctx ( ) ;
xmpp_stanza_t * iq = stanza_create_disco_info_iq ( ctx , id , from , node ) ;
2016-08-20 18:31:27 -04:00
iq_send_stanza ( iq ) ;
xmpp_stanza_release ( iq ) ;
2013-03-17 19:04:36 -04:00
}
2014-11-26 16:59:36 -05:00
2016-03-27 20:25:48 -04:00
static void
2020-07-07 08:18:57 -04:00
_muc_user_self_handler ( xmpp_stanza_t * stanza )
2013-01-28 17:24:47 -05:00
{
2020-07-07 08:18:57 -04:00
const char * from = xmpp_stanza_get_from ( stanza ) ;
2023-07-13 09:11:30 -04:00
auto_jid Jid * from_jid = jid_create ( from ) ;
2016-08-20 18:31:27 -04:00
log_debug ( " Room self presence received from %s " , from_jid - > fulljid ) ;
2020-07-07 08:18:57 -04:00
char * room = from_jid - > barejid ;
2015-05-06 17:02:50 -04:00
2020-07-07 08:18:57 -04:00
const char * type = xmpp_stanza_get_type ( stanza ) ;
2016-08-20 18:31:27 -04:00
if ( g_strcmp0 ( type , STANZA_TYPE_UNAVAILABLE ) = = 0 ) {
2014-10-06 19:22:39 -04:00
2016-08-20 18:31:27 -04:00
// handle nickname change
2020-07-07 08:18:57 -04:00
const char * new_nick = stanza_get_new_nick ( stanza ) ;
2016-08-20 18:31:27 -04:00
if ( new_nick ) {
muc_nick_change_start ( room , new_nick ) ;
2020-07-07 08:18:57 -04:00
// handle left room
2016-08-20 18:31:27 -04:00
} else {
2020-07-07 08:18:57 -04:00
GSList * status_codes = stanza_get_status_codes_by_ns ( stanza , STANZA_NS_MUC_USER ) ;
2016-08-20 18:31:27 -04:00
// room destroyed
if ( stanza_room_destroyed ( stanza ) ) {
2020-07-07 08:18:57 -04:00
const char * new_jid = stanza_get_muc_destroy_alternative_room ( stanza ) ;
2023-07-11 07:23:58 -04:00
auto_char char * password = stanza_get_muc_destroy_alternative_password ( stanza ) ;
auto_char char * reason = stanza_get_muc_destroy_reason ( stanza ) ;
2016-08-20 18:31:27 -04:00
sv_ev_room_destroyed ( room , new_jid , password , reason ) ;
2020-07-07 08:18:57 -04:00
// kicked from room
2016-08-20 18:31:27 -04:00
} else if ( g_slist_find_custom ( status_codes , " 307 " , ( GCompareFunc ) g_strcmp0 ) ) {
2020-07-07 08:18:57 -04:00
const char * actor = stanza_get_actor ( stanza ) ;
2023-07-11 07:23:58 -04:00
auto_char char * reason = stanza_get_reason ( stanza ) ;
2016-08-20 18:31:27 -04:00
sv_ev_room_kicked ( room , actor , reason ) ;
2020-07-07 08:18:57 -04:00
// banned from room
2016-08-20 18:31:27 -04:00
} else if ( g_slist_find_custom ( status_codes , " 301 " , ( GCompareFunc ) g_strcmp0 ) ) {
2020-07-07 08:18:57 -04:00
const char * actor = stanza_get_actor ( stanza ) ;
2023-07-11 07:23:58 -04:00
auto_char char * reason = stanza_get_reason ( stanza ) ;
2016-08-20 18:31:27 -04:00
sv_ev_room_banned ( room , actor , reason ) ;
2020-07-07 08:18:57 -04:00
// normal exit
2016-08-20 18:31:27 -04:00
} else {
sv_ev_leave_room ( room ) ;
}
g_slist_free_full ( status_codes , free ) ;
}
} else {
2020-07-07 08:18:57 -04:00
char * nick = from_jid - > resourcepart ;
2022-01-27 05:52:23 -05:00
if ( ! nick ) {
log_warning ( " presence: jid without resource " ) ;
return ;
}
2022-05-26 14:57:42 -04:00
muc_nick_change_complete ( room , nick ) ;
2023-07-11 07:23:58 -04:00
auto_char char * reason = stanza_get_reason ( stanza ) ;
auto_char char * show_str = stanza_get_show ( stanza , " online " ) ;
auto_char char * status_str = stanza_get_status ( stanza , NULL ) ;
2022-01-27 05:52:23 -05:00
const char * actor = stanza_get_actor ( stanza ) ;
2020-07-07 08:18:57 -04:00
const char * jid = NULL ;
const char * role = NULL ;
const char * affiliation = NULL ;
2022-01-27 05:52:23 -05:00
gboolean config_required = stanza_muc_requires_config ( stanza ) ;
2020-07-07 08:18:57 -04:00
xmpp_stanza_t * x = xmpp_stanza_get_child_by_ns ( stanza , STANZA_NS_MUC_USER ) ;
2016-08-20 18:31:27 -04:00
if ( x ) {
2020-07-07 08:18:57 -04:00
xmpp_stanza_t * item = xmpp_stanza_get_child_by_name ( x , STANZA_NAME_ITEM ) ;
2016-08-20 18:31:27 -04:00
if ( item ) {
jid = xmpp_stanza_get_attribute ( item , " jid " ) ;
role = xmpp_stanza_get_attribute ( item , " role " ) ;
affiliation = xmpp_stanza_get_attribute ( item , " affiliation " ) ;
}
}
sv_ev_muc_self_online ( room , nick , config_required , role , affiliation , actor , reason , jid , show_str , status_str ) ;
2013-01-28 17:24:47 -05:00
}
2016-08-20 18:31:27 -04:00
}
2013-01-28 17:24:47 -05:00
2016-08-20 18:31:27 -04:00
static void
2020-07-07 08:18:57 -04:00
_muc_user_occupant_handler ( xmpp_stanza_t * stanza )
2016-08-20 18:31:27 -04:00
{
2020-07-07 08:18:57 -04:00
const char * from = xmpp_stanza_get_from ( stanza ) ;
2023-07-11 07:23:58 -04:00
auto_jid Jid * from_jid = jid_create ( from ) ;
2016-08-20 18:31:27 -04:00
log_debug ( " Room presence received from %s " , from_jid - > fulljid ) ;
2013-02-10 14:39:19 -05:00
2020-07-07 08:18:57 -04:00
char * room = from_jid - > barejid ;
char * nick = from_jid - > resourcepart ;
2023-07-11 07:23:58 -04:00
auto_char char * status_str = stanza_get_status ( stanza , NULL ) ;
2014-10-06 20:16:46 -04:00
2022-01-27 05:52:23 -05:00
if ( ! nick ) {
log_warning ( " presence: jid without resource " ) ;
return ;
}
2020-07-07 08:18:57 -04:00
const char * type = xmpp_stanza_get_type ( stanza ) ;
2016-08-20 18:31:27 -04:00
if ( g_strcmp0 ( type , STANZA_TYPE_UNAVAILABLE ) = = 0 ) {
2013-01-28 17:24:47 -05:00
2016-08-20 18:31:27 -04:00
// handle nickname change
2020-07-07 08:18:57 -04:00
const char * new_nick = stanza_get_new_nick ( stanza ) ;
2016-08-20 18:31:27 -04:00
if ( new_nick ) {
muc_occupant_nick_change_start ( room , new_nick , nick ) ;
2013-01-28 17:24:47 -05:00
2020-07-07 08:18:57 -04:00
// handle left room
2016-08-20 18:31:27 -04:00
} else {
2020-07-07 08:18:57 -04:00
GSList * status_codes = stanza_get_status_codes_by_ns ( stanza , STANZA_NS_MUC_USER ) ;
2016-08-20 18:31:27 -04:00
// kicked from room
if ( g_slist_find_custom ( status_codes , " 307 " , ( GCompareFunc ) g_strcmp0 ) ) {
2020-07-07 08:18:57 -04:00
const char * actor = stanza_get_actor ( stanza ) ;
2023-07-11 07:23:58 -04:00
auto_char char * reason = stanza_get_reason ( stanza ) ;
2016-08-20 18:31:27 -04:00
sv_ev_room_occupent_kicked ( room , nick , actor , reason ) ;
2020-07-07 08:18:57 -04:00
// banned from room
2016-08-20 18:31:27 -04:00
} else if ( g_slist_find_custom ( status_codes , " 301 " , ( GCompareFunc ) g_strcmp0 ) ) {
2020-07-07 08:18:57 -04:00
const char * actor = stanza_get_actor ( stanza ) ;
2023-07-11 07:23:58 -04:00
auto_char char * reason = stanza_get_reason ( stanza ) ;
2016-08-20 18:31:27 -04:00
sv_ev_room_occupent_banned ( room , nick , actor , reason ) ;
2020-07-07 08:18:57 -04:00
// normal exit
2013-01-28 17:24:47 -05:00
} else {
2016-08-20 18:31:27 -04:00
sv_ev_room_occupant_offline ( room , nick , " offline " , status_str ) ;
2013-01-28 17:24:47 -05:00
}
2016-08-20 18:31:27 -04:00
g_slist_free_full ( status_codes , free ) ;
2013-01-28 17:24:47 -05:00
}
2020-07-07 08:18:57 -04:00
// room occupant online
2013-01-28 17:24:47 -05:00
} else {
2016-08-20 18:31:27 -04:00
// send disco info for capabilities, if not cached
2020-07-07 08:18:57 -04:00
XMPPCaps * caps = stanza_parse_caps ( stanza ) ;
2016-08-20 18:31:27 -04:00
if ( caps ) {
_handle_caps ( from , caps ) ;
}
stanza_free_caps ( caps ) ;
2020-07-07 08:18:57 -04:00
const char * actor = stanza_get_actor ( stanza ) ;
2023-07-11 07:23:58 -04:00
auto_char char * show_str = stanza_get_show ( stanza , " online " ) ;
auto_char char * reason = stanza_get_reason ( stanza ) ;
2020-07-07 08:18:57 -04:00
const char * jid = NULL ;
const char * role = NULL ;
const char * affiliation = NULL ;
xmpp_stanza_t * x = xmpp_stanza_get_child_by_ns ( stanza , STANZA_NS_MUC_USER ) ;
2016-08-20 18:31:27 -04:00
if ( x ) {
2020-07-07 08:18:57 -04:00
xmpp_stanza_t * item = xmpp_stanza_get_child_by_name ( x , STANZA_NAME_ITEM ) ;
2016-08-20 18:31:27 -04:00
if ( item ) {
jid = xmpp_stanza_get_attribute ( item , " jid " ) ;
role = xmpp_stanza_get_attribute ( item , " role " ) ;
affiliation = xmpp_stanza_get_attribute ( item , " affiliation " ) ;
}
}
sv_ev_muc_occupant_online ( room , nick , jid , role , affiliation , actor , reason , show_str , status_str ) ;
}
}
2014-10-06 19:22:39 -04:00
2016-08-20 18:31:27 -04:00
static void
2020-07-07 08:18:57 -04:00
_muc_user_handler ( xmpp_stanza_t * const stanza )
2016-08-20 18:31:27 -04:00
{
inp_nonblocking ( TRUE ) ;
2014-10-06 19:22:39 -04:00
2020-07-07 08:18:57 -04:00
const char * type = xmpp_stanza_get_type ( stanza ) ;
2016-08-20 18:31:27 -04:00
// handler still fires if error
if ( g_strcmp0 ( type , STANZA_TYPE_ERROR ) = = 0 ) {
return ;
}
2014-09-21 11:51:35 -04:00
2020-07-07 08:18:57 -04:00
const char * from = xmpp_stanza_get_from ( stanza ) ;
2016-08-20 18:31:27 -04:00
if ( ! from ) {
log_warning ( " MUC User stanza received with no from attribute " ) ;
return ;
2013-01-28 17:24:47 -05:00
}
2023-07-13 09:11:30 -04:00
auto_jid Jid * from_jid = jid_create ( from ) ;
2016-08-20 18:31:27 -04:00
if ( from_jid = = NULL | | from_jid - > resourcepart = = NULL ) {
log_warning ( " MUC User stanza received with invalid from attribute: %s " , from ) ;
return ;
}
if ( stanza_is_muc_self_presence ( stanza , connection_get_fulljid ( ) ) ) {
_muc_user_self_handler ( stanza ) ;
} else {
_muc_user_occupant_handler ( stanza ) ;
}
2015-05-10 18:54:48 -04:00
}
2016-03-26 11:50:16 -04:00
static void
2020-07-07 08:18:57 -04:00
_send_presence_stanza ( xmpp_stanza_t * const stanza )
2016-03-26 11:50:16 -04:00
{
2020-07-07 08:18:57 -04:00
char * text ;
2016-03-26 11:50:16 -04:00
size_t text_size ;
xmpp_stanza_to_text ( stanza , & text , & text_size ) ;
2020-07-07 08:18:57 -04:00
xmpp_conn_t * conn = connection_get_conn ( ) ;
2023-07-11 07:23:58 -04:00
auto_char char * plugin_text = plugins_on_presence_stanza_send ( text ) ;
2016-03-26 11:50:16 -04:00
if ( plugin_text ) {
2016-03-26 12:44:02 -04:00
xmpp_send_raw_string ( conn , " %s " , plugin_text ) ;
2016-03-26 11:50:16 -04:00
} else {
2016-03-26 12:44:02 -04:00
xmpp_send_raw_string ( conn , " %s " , text ) ;
2016-03-26 11:50:16 -04:00
}
2016-05-01 19:40:16 -04:00
xmpp_free ( connection_get_ctx ( ) , text ) ;
2016-03-26 11:50:16 -04:00
}