2020-04-28 20:35:52 +00:00
/*
* Squawk messenger .
* Copyright ( C ) 2019 Yury Gubich < blue @ macaw . me >
*
* This program 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 .
*
* This program 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 this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "messagehandler.h"
# include "core/account.h"
2023-11-14 23:23:39 +00:00
static const QMap < QString , QVariant > statePending ( { { " state " , static_cast < uint8_t > ( Shared : : Message : : State : : pending ) } } ) ;
static const QMap < QString , QVariant > stateDelivered ( { { " state " , static_cast < uint8_t > ( Shared : : Message : : State : : delivered ) } } ) ;
static const QMap < QString , QVariant > stateSent ( { { " state " , static_cast < uint8_t > ( Shared : : Message : : State : : sent ) } } ) ;
2020-04-28 20:35:52 +00:00
Core : : MessageHandler : : MessageHandler ( Core : : Account * account ) :
QObject ( ) ,
acc ( account ) ,
pendingStateMessages ( ) ,
uploadingSlotsQueue ( )
2023-08-15 15:28:25 +00:00
{ }
2020-04-28 20:35:52 +00:00
2023-08-15 15:28:25 +00:00
void Core : : MessageHandler : : onMessageReceived ( const QXmppMessage & msg ) {
2023-01-29 17:26:54 +00:00
# if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 5, 0)
# ifdef WITH_OMEMO
switch ( msg . encryptionMethod ( ) ) {
case QXmpp : : NoEncryption :
break ; //just do nothing
case QXmpp : : UnknownEncryption :
qDebug ( ) < < " Account " < < acc - > getName ( ) < < " received a message with unknown encryption type " ;
break ; //let it go the way it is, there is nothing I can do here
case QXmpp : : Otr :
qDebug ( ) < < " Account " < < acc - > getName ( ) < < " received an OTR encrypted message, not supported yet " ;
break ; //let it go the way it is, there is nothing I can do yet
case QXmpp : : LegacyOpenPgp :
qDebug ( ) < < " Account " < < acc - > getName ( ) < < " received an LegacyOpenPgp encrypted message, not supported yet " ;
break ; //let it go the way it is, there is nothing I can do yet
case QXmpp : : Ox :
qDebug ( ) < < " Account " < < acc - > getName ( ) < < " received an Ox encrypted message, not supported yet " ;
break ; //let it go the way it is, there is nothing I can do yet
case QXmpp : : Omemo0 :
qDebug ( ) < < " Account " < < acc - > getName ( ) < < " received an Omemo0 encrypted message, not supported yet " ;
break ; //let it go the way it is, there is nothing I can do yet
case QXmpp : : Omemo1 :
qDebug ( ) < < " Account " < < acc - > getName ( ) < < " received an Omemo1 encrypted message, not supported yet " ;
break ; //let it go the way it is, there is nothing I can do yet
case QXmpp : : Omemo2 :
2023-11-09 22:36:30 +00:00
break ;
2023-01-29 17:26:54 +00:00
}
# endif
# endif
2020-04-28 20:35:52 +00:00
bool handled = false ;
switch ( msg . type ( ) ) {
case QXmppMessage : : Normal :
qDebug ( ) < < " received a message with type \" Normal \" , not sure what to do with it now, skipping " ;
break ;
case QXmppMessage : : Chat :
2023-03-11 22:38:54 +00:00
# if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 5, 0)
handled = handleChatMessage ( msg , false , msg . isCarbonForwarded ( ) , true ) ;
# else
2020-04-28 20:35:52 +00:00
handled = handleChatMessage ( msg ) ;
2023-03-11 22:38:54 +00:00
# endif
2020-04-28 20:35:52 +00:00
break ;
case QXmppMessage : : GroupChat :
handled = handleGroupMessage ( msg ) ;
break ;
2023-11-05 19:29:44 +00:00
case QXmppMessage : : Error :
handled = handlePendingMessageError ( msg . id ( ) , msg . error ( ) . text ( ) ) ;
if ( ! handled )
2020-04-28 20:35:52 +00:00
qDebug ( ) < < " received a message with type \" Error \" , not sure what to do with it now, skipping " ;
2023-11-05 19:29:44 +00:00
break ;
2020-04-28 20:35:52 +00:00
case QXmppMessage : : Headline :
qDebug ( ) < < " received a message with type \" Headline \" , not sure what to do with it now, skipping " ;
break ;
}
2023-08-15 15:28:25 +00:00
if ( ! handled )
2020-04-28 20:35:52 +00:00
logMessage ( msg ) ;
}
2023-11-05 19:29:44 +00:00
bool Core : : MessageHandler : : handlePendingMessageError ( const QString & id , const QString & errorText ) {
2023-11-14 23:23:39 +00:00
return adjustPendingMessage ( id , {
{ " state " , static_cast < uint8_t > ( Shared : : Message : : State : : error ) } ,
2023-11-05 19:29:44 +00:00
{ " errorText " , errorText }
2023-11-14 23:23:39 +00:00
} , true ) ;
2023-11-05 19:29:44 +00:00
}
2023-08-15 15:28:25 +00:00
bool Core : : MessageHandler : : handleChatMessage ( const QXmppMessage & msg , bool outgoing , bool forwarded , bool guessing ) {
2023-11-14 23:23:39 +00:00
if ( msg . body ( ) . isEmpty ( ) & & msg . outOfBandUrl ( ) . isEmpty ( ) )
return false ;
Shared : : Message sMsg ( Shared : : Message : : chat ) ;
initializeMessage ( sMsg , msg , outgoing , forwarded , guessing ) ;
QString jid = sMsg . getPenPalJid ( ) ;
Contact * cnt = acc - > rh - > getContact ( jid ) ;
if ( cnt = = 0 ) {
cnt = acc - > rh - > addOutOfRosterContact ( jid ) ;
qDebug ( ) < < " appending message " < < sMsg . getId ( ) < < " to an out of roster contact " ;
2020-04-28 20:35:52 +00:00
}
2023-11-14 23:23:39 +00:00
if ( sMsg . getOutgoing ( ) ) {
if ( sMsg . getForwarded ( ) )
sMsg . setState ( Shared : : Message : : State : : sent ) ;
} else {
sMsg . setState ( Shared : : Message : : State : : delivered ) ;
}
QString oId = msg . replaceId ( ) ;
if ( oId . size ( ) > 0 ) {
QMap < QString , QVariant > cData = {
{ " body " , sMsg . getBody ( ) } ,
{ " stamp " , sMsg . getTime ( ) }
} ;
cnt - > correctMessageInArchive ( oId , sMsg ) ;
emit acc - > changeMessage ( jid , oId , cData ) ;
} else {
cnt - > appendMessageToArchive ( sMsg ) ;
emit acc - > message ( sMsg ) ;
}
return true ;
2020-04-28 20:35:52 +00:00
}
2023-08-15 15:28:25 +00:00
bool Core : : MessageHandler : : handleGroupMessage ( const QXmppMessage & msg , bool outgoing , bool forwarded , bool guessing ) {
2020-04-28 20:35:52 +00:00
const QString & body ( msg . body ( ) ) ;
2023-11-14 23:23:39 +00:00
if ( body . isEmpty ( ) )
return false ;
Shared : : Message sMsg ( Shared : : Message : : groupChat ) ;
initializeMessage ( sMsg , msg , outgoing , forwarded , guessing ) ;
QString jid = sMsg . getPenPalJid ( ) ;
Conference * cnt = acc - > rh - > getConference ( jid ) ;
if ( cnt = = 0 )
return false ;
bool result = adjustPendingMessage ( msg . id ( ) , stateDelivered , true ) ;
if ( result ) //then it was an echo of my own sent message, nothing else needs to be done
return result ;
QString oId = msg . replaceId ( ) ;
if ( oId . size ( ) > 0 ) {
QMap < QString , QVariant > cData = {
{ " body " , sMsg . getBody ( ) } ,
{ " stamp " , sMsg . getTime ( ) }
} ;
cnt - > correctMessageInArchive ( oId , sMsg ) ;
emit acc - > changeMessage ( jid , oId , cData ) ;
} else {
cnt - > appendMessageToArchive ( sMsg ) ;
QDateTime minAgo = QDateTime : : currentDateTimeUtc ( ) . addSecs ( - 60 ) ;
if ( sMsg . getTime ( ) > minAgo ) //otherwise it's considered a delayed delivery, most probably MUC history initial fetch
emit acc - > message ( sMsg ) ;
}
2020-04-28 20:35:52 +00:00
2023-11-14 23:23:39 +00:00
return true ;
}
2020-04-28 20:35:52 +00:00
2023-08-15 15:28:25 +00:00
void Core : : MessageHandler : : initializeMessage ( Shared : : Message & target , const QXmppMessage & source , bool outgoing , bool forwarded , bool guessing ) const {
2020-04-28 20:35:52 +00:00
const QDateTime & time ( source . stamp ( ) ) ;
QString id ;
# if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 3, 0)
id = source . originId ( ) ;
2023-11-05 19:29:44 +00:00
if ( id . size ( ) = = 0 )
2020-04-28 20:35:52 +00:00
id = source . id ( ) ;
2023-11-05 19:29:44 +00:00
2020-05-21 15:42:40 +00:00
target . setStanzaId ( source . stanzaId ( ) ) ;
2022-01-15 12:36:49 +00:00
qDebug ( ) < < " initializing message with originId: " < < source . originId ( ) < < " , id: " < < source . id ( ) < < " , stansaId: " < < source . stanzaId ( ) ;
2020-04-28 20:35:52 +00:00
# else
id = source . id ( ) ;
# endif
2020-05-21 15:42:40 +00:00
target . setId ( id ) ;
2021-04-18 12:49:20 +00:00
QString messageId = target . getId ( ) ;
if ( messageId . size ( ) = = 0 ) {
2020-05-21 15:42:40 +00:00
target . generateRandomId ( ) ; //TODO out of desperation, I need at least a random ID
2021-04-18 12:49:20 +00:00
messageId = target . getId ( ) ;
2022-01-15 12:36:49 +00:00
qDebug ( ) < < " Had do initialize a message with no id, assigning autogenerated " < < messageId ;
2020-04-28 20:35:52 +00:00
}
target . setFrom ( source . from ( ) ) ;
target . setTo ( source . to ( ) ) ;
target . setBody ( source . body ( ) ) ;
target . setForwarded ( forwarded ) ;
2023-11-06 23:57:08 +00:00
# ifdef WITH_OMEMO
# if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 5, 0)
if ( source . encryptionMethod ( ) = = QXmpp : : EncryptionMethod : : Omemo2 )
target . setEncryption ( Shared : : EncryptionProtocol : : omemo2 ) ;
# endif
# endif
2021-04-18 12:49:20 +00:00
2023-11-05 19:29:44 +00:00
if ( guessing )
outgoing = target . getFromJid ( ) = = acc - > getBareJid ( ) ;
2020-04-28 20:35:52 +00:00
target . setOutgoing ( outgoing ) ;
2023-11-05 19:29:44 +00:00
if ( time . isValid ( ) )
2020-04-28 20:35:52 +00:00
target . setTime ( time ) ;
2023-11-05 19:29:44 +00:00
else
2020-04-28 20:35:52 +00:00
target . setCurrentTime ( ) ;
2023-11-05 19:29:44 +00:00
2021-04-18 12:49:20 +00:00
QString oob = source . outOfBandUrl ( ) ;
2023-11-05 19:29:44 +00:00
if ( oob . size ( ) > 0 )
2021-04-18 12:49:20 +00:00
target . setAttachPath ( acc - > network - > addMessageAndCheckForPath ( oob , acc - > getName ( ) , target . getPenPalJid ( ) , messageId ) ) ;
2023-11-05 19:29:44 +00:00
2021-04-18 12:49:20 +00:00
target . setOutOfBandUrl ( oob ) ;
2020-04-28 20:35:52 +00:00
}
2023-08-15 15:28:25 +00:00
void Core : : MessageHandler : : logMessage ( const QXmppMessage & msg , const QString & reason ) {
2020-04-28 20:35:52 +00:00
qDebug ( ) < < reason ;
qDebug ( ) < < " - from: " < < msg . from ( ) ;
qDebug ( ) < < " - to: " < < msg . to ( ) ;
qDebug ( ) < < " - body: " < < msg . body ( ) ;
qDebug ( ) < < " - type: " < < msg . type ( ) ;
qDebug ( ) < < " - state: " < < msg . state ( ) ;
qDebug ( ) < < " - stamp: " < < msg . stamp ( ) ;
qDebug ( ) < < " - id: " < < msg . id ( ) ;
2020-05-21 15:42:40 +00:00
# if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 3, 0)
qDebug ( ) < < " - stanzaId: " < < msg . stanzaId ( ) ;
# endif
2020-04-28 20:35:52 +00:00
qDebug ( ) < < " - outOfBandUrl: " < < msg . outOfBandUrl ( ) ;
qDebug ( ) < < " ============================== " ;
}
2023-03-11 22:38:54 +00:00
# if (QXMPP_VERSION) < QT_VERSION_CHECK(1, 5, 0)
2023-08-15 15:28:25 +00:00
void Core : : MessageHandler : : onCarbonMessageReceived ( const QXmppMessage & msg ) {
2020-04-28 20:35:52 +00:00
handleChatMessage ( msg , false , true ) ;
}
2023-08-15 15:28:25 +00:00
void Core : : MessageHandler : : onCarbonMessageSent ( const QXmppMessage & msg ) {
2020-04-28 20:35:52 +00:00
handleChatMessage ( msg , true , true ) ;
}
2023-03-11 22:38:54 +00:00
# endif
2020-04-28 20:35:52 +00:00
2023-11-14 23:23:39 +00:00
std : : optional < Shared : : MessageInfo > Core : : MessageHandler : : getOriginalPendingMessageId ( const QString & id , bool clear ) {
2020-04-28 20:35:52 +00:00
std : : map < QString , QString > : : const_iterator itr = pendingStateMessages . find ( id ) ;
if ( itr ! = pendingStateMessages . end ( ) ) {
2023-11-14 23:23:39 +00:00
Shared : : MessageInfo info ( acc - > name , itr - > second , itr - > first ) ;
2022-03-28 20:25:33 +00:00
std : : map < QString , QString > : : const_iterator itrC = pendingCorrectionMessages . find ( id ) ;
if ( itrC ! = pendingCorrectionMessages . end ( ) ) {
2023-08-15 15:28:25 +00:00
if ( itrC - > second . size ( ) > 0 )
2023-11-14 23:23:39 +00:00
info . jid = itrC - > second ;
2023-08-15 15:28:25 +00:00
2023-11-05 19:29:44 +00:00
if ( clear )
pendingCorrectionMessages . erase ( itrC ) ;
2022-03-28 20:25:33 +00:00
}
2023-11-05 19:29:44 +00:00
if ( clear )
pendingStateMessages . erase ( itr ) ;
2023-11-14 23:23:39 +00:00
return info ;
2022-03-28 20:25:33 +00:00
}
2023-11-14 23:23:39 +00:00
return std : : nullopt ;
2022-03-28 20:25:33 +00:00
}
2023-08-15 15:28:25 +00:00
void Core : : MessageHandler : : onReceiptReceived ( const QString & jid , const QString & id ) {
SHARED_UNUSED ( jid ) ;
2023-11-14 23:23:39 +00:00
adjustPendingMessage ( id , { { " state " , static_cast < uint > ( Shared : : Message : : State : : delivered ) } } , true ) ;
2020-04-28 20:35:52 +00:00
}
2023-08-15 15:28:25 +00:00
void Core : : MessageHandler : : sendMessage ( const Shared : : Message & data , bool newMessage , QString originalId ) {
2021-02-07 17:02:11 +00:00
if ( data . getOutOfBandUrl ( ) . size ( ) = = 0 & & data . getAttachPath ( ) . size ( ) > 0 ) {
2022-03-28 20:25:33 +00:00
pendingCorrectionMessages . insert ( std : : make_pair ( data . getId ( ) , originalId ) ) ;
2021-05-22 22:03:14 +00:00
prepareUpload ( data , newMessage ) ;
2021-02-07 17:02:11 +00:00
} else {
2022-03-28 20:25:33 +00:00
performSending ( data , originalId , newMessage ) ;
2021-02-07 17:02:11 +00:00
}
}
2023-08-15 15:28:25 +00:00
void Core : : MessageHandler : : performSending ( Shared : : Message data , const QString & originalId , bool newMessage ) {
2020-04-28 20:35:52 +00:00
QString jid = data . getPenPalJid ( ) ;
QString id = data . getId ( ) ;
2022-03-28 20:25:33 +00:00
qDebug ( ) < < " Sending message with id: " < < id ;
2023-08-15 15:28:25 +00:00
if ( originalId . size ( ) > 0 )
2023-11-05 19:29:44 +00:00
qDebug ( ) < < " To replace the one with id: " < < originalId ;
2023-08-15 15:28:25 +00:00
2020-06-14 21:23:43 +00:00
RosterItem * ri = acc - > rh - > getRosterItem ( jid ) ;
2023-08-15 15:28:25 +00:00
if ( newMessage & & originalId . size ( ) > 0 )
2022-03-28 20:25:33 +00:00
newMessage = false ;
2023-08-15 15:28:25 +00:00
2021-05-22 22:03:14 +00:00
QDateTime sendTime = QDateTime : : currentDateTimeUtc ( ) ;
2023-11-05 19:29:44 +00:00
std : : pair < Shared : : Message : : State , QString > result = scheduleSending ( data , sendTime , originalId ) ;
data . setState ( result . first ) ;
data . setErrorText ( result . second ) ;
2020-04-28 20:35:52 +00:00
2022-03-28 20:25:33 +00:00
QMap < QString , QVariant > changes ( getChanges ( data , sendTime , newMessage , originalId ) ) ;
2023-03-16 19:38:05 +00:00
if ( ri ! = nullptr ) {
2023-08-15 15:28:25 +00:00
if ( newMessage )
2022-03-28 20:25:33 +00:00
ri - > appendMessageToArchive ( data ) ;
2023-08-15 15:28:25 +00:00
else
2023-11-05 19:29:44 +00:00
ri - > changeMessage ( originalId . isEmpty ( ) ? id : originalId , changes ) ;
2023-08-15 15:28:25 +00:00
2023-11-05 19:29:44 +00:00
if ( data . getState ( ) ! = Shared : : Message : : State : : error ) {
2022-03-28 20:25:33 +00:00
pendingStateMessages . insert ( std : : make_pair ( id , jid ) ) ;
2023-08-15 15:28:25 +00:00
if ( originalId . size ( ) > 0 )
2022-03-28 20:25:33 +00:00
pendingCorrectionMessages . insert ( std : : make_pair ( id , originalId ) ) ;
} else {
pendingStateMessages . erase ( id ) ;
pendingCorrectionMessages . erase ( id ) ;
}
}
2023-11-05 19:29:44 +00:00
emit acc - > changeMessage ( jid , originalId . isEmpty ( ) ? id : originalId , changes ) ;
2022-03-28 20:25:33 +00:00
}
2023-11-05 19:29:44 +00:00
std : : pair < Shared : : Message : : State , QString > Core : : MessageHandler : : scheduleSending (
const Shared : : Message & message ,
const QDateTime & sendTime ,
const QString & originalId
) {
if ( acc - > state ! = Shared : : ConnectionState : : connected )
return { Shared : : Message : : State : : error , " You are is offline or reconnecting " } ;
QXmppMessage msg = createPacket ( message , sendTime , originalId ) ;
QString id = msg . id ( ) ;
# ifdef WITH_OMEMO
if ( message . getEncryption ( ) = = Shared : : EncryptionProtocol : : omemo2 ) {
QXmppTask < QXmppE2eeExtension : : MessageEncryptResult > task = acc - > om - > encryptMessage ( std : : move ( msg ) , std : : nullopt ) ;
if ( task . isFinished ( ) ) {
const QXmppE2eeExtension : : MessageEncryptResult & res = task . result ( ) ;
if ( std : : holds_alternative < std : : unique_ptr < QXmppMessage > > ( res ) ) {
2023-11-12 22:55:32 +00:00
qDebug ( ) < < " Successfully encrypted a message " ;
2023-11-05 19:29:44 +00:00
const std : : unique_ptr < QXmppMessage > & encrypted = std : : get < std : : unique_ptr < QXmppMessage > > ( res ) ;
2023-11-10 22:26:16 +00:00
encrypted - > setBody ( QString ( ) ) ;
encrypted - > setOutOfBandUrl ( QString ( ) ) ;
2023-11-05 19:29:44 +00:00
bool success = acc - > client . sendPacket ( * encrypted . get ( ) ) ;
2023-11-12 22:55:32 +00:00
if ( success ) {
qDebug ( ) < < " Successfully sent an encrypted message " ;
2023-11-05 19:29:44 +00:00
return { Shared : : Message : : State : : sent , " " } ;
2023-11-12 22:55:32 +00:00
} else {
qDebug ( ) < < " Couldn't sent an encrypted message " ;
2023-11-05 19:29:44 +00:00
return { Shared : : Message : : State : : error , " Error sending successfully encrypted message " } ;
2023-11-12 22:55:32 +00:00
}
2023-11-05 19:29:44 +00:00
} else if ( std : : holds_alternative < QXmppError > ( res ) ) {
2023-11-12 22:55:32 +00:00
qDebug ( ) < < " Couldn't encrypt a message " ;
2023-11-05 19:29:44 +00:00
const QXmppError & err = std : : get < QXmppError > ( res ) ;
return { Shared : : Message : : State : : error , err . description } ;
} else {
2023-11-12 22:55:32 +00:00
qDebug ( ) < < " Couldn't encrypt a message " ;
2023-11-05 19:29:44 +00:00
return { Shared : : Message : : State : : error , " Unexpected error ecryptng the message " } ;
}
} else {
task . then ( this , [ this , id ] ( QXmppE2eeExtension : : MessageEncryptResult & & result ) {
if ( std : : holds_alternative < std : : unique_ptr < QXmppMessage > > ( result ) ) {
2023-11-12 22:55:32 +00:00
qDebug ( ) < < " Successfully encrypted a message " ;
2023-11-05 19:29:44 +00:00
const std : : unique_ptr < QXmppMessage > & encrypted = std : : get < std : : unique_ptr < QXmppMessage > > ( result ) ;
2023-11-10 22:26:16 +00:00
encrypted - > setBody ( QString ( ) ) ;
encrypted - > setOutOfBandUrl ( QString ( ) ) ;
2023-11-05 19:29:44 +00:00
bool success = acc - > client . sendPacket ( * encrypted . get ( ) ) ;
if ( success ) {
2023-11-12 22:55:32 +00:00
qDebug ( ) < < " Successfully sent an encrypted message " ;
2023-11-14 23:23:39 +00:00
if ( ! adjustPendingMessage ( id , stateSent , false ) )
2023-11-05 19:29:44 +00:00
qDebug ( ) < < " Encrypted message has been successfully sent, but it couldn't be found to update the sate " ;
} else {
2023-11-12 22:55:32 +00:00
qDebug ( ) < < " Couldn't sent an encrypted message " ;
2023-11-05 19:29:44 +00:00
handlePendingMessageError ( id , " Error sending successfully encrypted message " ) ;
}
} else if ( std : : holds_alternative < QXmppError > ( result ) ) {
2023-11-12 22:55:32 +00:00
qDebug ( ) < < " Couldn't encrypt a message " ;
2023-11-05 19:29:44 +00:00
const QXmppError & err = std : : get < QXmppError > ( result ) ;
handlePendingMessageError ( id , err . description ) ;
} else {
2023-11-12 22:55:32 +00:00
qDebug ( ) < < " Couldn't encrypt a message " ;
2023-11-05 19:29:44 +00:00
handlePendingMessageError ( id , " Unexpected error ecryptng the message " ) ;
}
} ) ;
return { Shared : : Message : : State : : pending , " " } ;
}
} else
# endif
{
bool success = acc - > client . sendPacket ( msg ) ;
if ( success )
return { Shared : : Message : : State : : sent , " " } ;
else
return { Shared : : Message : : State : : error , " Error sending message, internal QXMPP error " } ;
}
}
2023-11-14 23:23:39 +00:00
bool Core : : MessageHandler : : adjustPendingMessage ( const QString & messageId , const QMap < QString , QVariant > & data , bool final ) {
std : : optional < Shared : : MessageInfo > info = getOriginalPendingMessageId ( messageId , final ) ;
if ( info ) {
RosterItem * ri = acc - > rh - > getRosterItem ( info - > jid ) ;
if ( ri ! = nullptr )
ri - > changeMessage ( info - > messageId , data ) ;
emit acc - > changeMessage ( info - > jid , info - > messageId , data ) ;
return true ;
}
return false ;
}
2023-11-05 19:29:44 +00:00
2023-08-15 15:28:25 +00:00
QMap < QString , QVariant > Core : : MessageHandler : : getChanges ( Shared : : Message & data , const QDateTime & time , bool newMessage , const QString & originalId ) const {
2022-03-28 20:25:33 +00:00
QMap < QString , QVariant > changes ;
QString oob = data . getOutOfBandUrl ( ) ;
2021-04-23 11:53:48 +00:00
Shared : : Message : : State mstate = data . getState ( ) ;
changes . insert ( " state " , static_cast < uint > ( mstate ) ) ;
2023-08-15 15:28:25 +00:00
if ( mstate = = Shared : : Message : : State : : error )
2021-04-23 11:53:48 +00:00
changes . insert ( " errorText " , data . getErrorText ( ) ) ;
2023-08-15 15:28:25 +00:00
if ( oob . size ( ) > 0 )
2021-04-23 11:53:48 +00:00
changes . insert ( " outOfBandUrl " , oob ) ;
2023-08-15 15:28:25 +00:00
if ( newMessage )
2022-03-28 20:25:33 +00:00
data . setTime ( time ) ;
2023-08-15 15:28:25 +00:00
if ( originalId . size ( ) > 0 )
2022-03-28 20:25:33 +00:00
changes . insert ( " body " , data . getBody ( ) ) ;
2023-08-15 15:28:25 +00:00
2022-03-28 20:25:33 +00:00
changes . insert ( " stamp " , time ) ;
2022-02-18 21:27:09 +00:00
//sometimes (when the image is pasted with ctrl+v)
//I start sending message with one path, then copy it to downloads directory
//so, the final path changes. Let's assume it changes always since it costs me close to nothing
QString attachPath = data . getAttachPath ( ) ;
if ( attachPath . size ( ) > 0 ) {
2022-02-19 18:31:49 +00:00
QString squawkified = Shared : : squawkifyPath ( attachPath ) ;
changes . insert ( " attachPath " , squawkified ) ;
2023-08-15 15:28:25 +00:00
if ( attachPath ! = squawkified )
2022-02-19 18:31:49 +00:00
data . setAttachPath ( squawkified ) ;
2022-02-18 21:27:09 +00:00
}
2022-03-28 20:25:33 +00:00
return changes ;
}
2023-08-15 15:28:25 +00:00
QXmppMessage Core : : MessageHandler : : createPacket ( const Shared : : Message & data , const QDateTime & time , const QString & originalId ) const {
2022-03-28 20:25:33 +00:00
QXmppMessage msg ( acc - > getFullJid ( ) , data . getTo ( ) , data . getBody ( ) , data . getThread ( ) ) ;
QString id ( data . getId ( ) ) ;
2023-08-15 15:28:25 +00:00
if ( originalId . size ( ) > 0 )
2022-03-28 20:25:33 +00:00
msg . setReplaceId ( originalId ) ;
2023-08-15 15:28:25 +00:00
2022-03-28 20:25:33 +00:00
# if (QXMPP_VERSION) >= QT_VERSION_CHECK(1, 3, 0)
msg . setOriginId ( id ) ;
# endif
msg . setId ( id ) ;
msg . setType ( static_cast < QXmppMessage : : Type > ( data . getType ( ) ) ) ; //it is safe here, my type is compatible
msg . setOutOfBandUrl ( data . getOutOfBandUrl ( ) ) ;
msg . setReceiptRequested ( true ) ;
msg . setStamp ( time ) ;
return msg ;
2020-04-28 20:35:52 +00:00
}
2023-08-15 15:28:25 +00:00
void Core : : MessageHandler : : prepareUpload ( const Shared : : Message & data , bool newMessage ) {
2023-11-14 23:23:39 +00:00
if ( acc - > state ! = Shared : : ConnectionState : : connected ) {
2021-04-18 12:49:20 +00:00
handleUploadError ( data . getPenPalJid ( ) , data . getId ( ) , " Account is offline or reconnecting " ) ;
2020-04-28 20:35:52 +00:00
qDebug ( ) < < " An attempt to send message with not connected account " < < acc - > name < < " , skipping " ;
2023-11-14 23:23:39 +00:00
return ;
}
QString jid = data . getPenPalJid ( ) ;
QString id = data . getId ( ) ;
RosterItem * ri = acc - > rh - > getRosterItem ( jid ) ;
if ( ri = = nullptr ) {
qDebug ( ) < < " An attempt to initialize upload in " < < acc - > name < < " for pal " < < jid < < " but the object for this pal wasn't found, something went terrebly wrong, skipping send " ;
return ;
}
QString path = data . getAttachPath ( ) ;
QString url = acc - > network - > getFileRemoteUrl ( path ) ;
if ( url . size ( ) ! = 0 )
return sendMessageWithLocalUploadedFile ( data , url , newMessage ) ;
pendingStateMessages . insert ( std : : make_pair ( id , jid ) ) ;
if ( newMessage ) {
ri - > appendMessageToArchive ( data ) ;
} else {
ri - > changeMessage ( id , statePending ) ;
emit acc - > changeMessage ( jid , id , statePending ) ;
}
//this checks if the file is already uploading, and if so it subscribes to it's success,
//So, I need to do stuff only if the network knows nothing of this file
if ( acc - > network - > checkAndAddToUploading ( acc - > getName ( ) , jid , id , path ) )
return ;
if ( ! acc - > um - > serviceFound ( ) ) {
handleUploadError ( jid , id , " Your server doesn't support file upload service, or it's prohibited for your account " ) ;
qDebug ( ) < < " Requested upload slot in account " < < acc - > name < < " for file " < < path < < " but upload manager didn't discover any upload services " ;
return ;
}
QFileInfo file ( path ) ;
if ( file . exists ( ) & & file . isReadable ( ) ) {
pendingStateMessages . insert ( std : : make_pair ( id , jid ) ) ;
uploadingSlotsQueue . emplace_back ( path , id ) ;
if ( uploadingSlotsQueue . size ( ) = = 1 )
acc - > um - > requestUploadSlot ( file ) ;
} else {
handleUploadError ( jid , id , " Uploading file no longer exists or your system user has no permission to read it " ) ;
qDebug ( ) < < " Requested upload slot in account " < < acc - > name < < " for file " < < path < < " but the file doesn't exist or is not readable " ;
2020-04-28 20:35:52 +00:00
}
}
2023-08-15 15:28:25 +00:00
void Core : : MessageHandler : : onUploadSlotReceived ( const QXmppHttpUploadSlotIq & slot ) {
2020-04-28 20:35:52 +00:00
if ( uploadingSlotsQueue . size ( ) = = 0 ) {
qDebug ( ) < < " HTTP Upload manager of account " < < acc - > name < < " reports about success requesting upload slot, but none was requested " ;
} else {
2021-05-07 18:26:02 +00:00
const std : : pair < QString , QString > & pair = uploadingSlotsQueue . front ( ) ;
const QString & mId = pair . second ;
QString palJid = pendingStateMessages . at ( mId ) ;
acc - > network - > uploadFile ( { acc - > name , palJid , mId } , pair . first , slot . putUrl ( ) , slot . getUrl ( ) , slot . putHeaders ( ) ) ;
2020-04-28 20:35:52 +00:00
2021-04-18 12:49:20 +00:00
uploadingSlotsQueue . pop_front ( ) ;
2023-08-15 15:28:25 +00:00
if ( uploadingSlotsQueue . size ( ) > 0 )
2020-04-28 20:35:52 +00:00
acc - > um - > requestUploadSlot ( uploadingSlotsQueue . front ( ) . first ) ;
}
}
2023-08-15 15:28:25 +00:00
void Core : : MessageHandler : : onUploadSlotRequestFailed ( const QXmppHttpUploadRequestIq & request ) {
2021-04-18 12:49:20 +00:00
QString err ( request . error ( ) . text ( ) ) ;
2020-04-28 20:35:52 +00:00
if ( uploadingSlotsQueue . size ( ) = = 0 ) {
qDebug ( ) < < " HTTP Upload manager of account " < < acc - > name < < " reports about an error requesting upload slot, but none was requested " ;
2021-04-18 12:49:20 +00:00
qDebug ( ) < < err ;
2020-04-28 20:35:52 +00:00
} else {
2021-05-07 18:26:02 +00:00
const std : : pair < QString , QString > & pair = uploadingSlotsQueue . front ( ) ;
2021-04-18 12:49:20 +00:00
qDebug ( ) < < " Error requesting upload slot for file " < < pair . first < < " in account " < < acc - > name < < " : " < < err ;
2021-05-07 18:26:02 +00:00
handleUploadError ( pendingStateMessages . at ( pair . second ) , pair . second , err ) ;
2020-04-28 20:35:52 +00:00
2021-04-18 12:49:20 +00:00
uploadingSlotsQueue . pop_front ( ) ;
2023-08-15 15:28:25 +00:00
if ( uploadingSlotsQueue . size ( ) > 0 )
2020-04-28 20:35:52 +00:00
acc - > um - > requestUploadSlot ( uploadingSlotsQueue . front ( ) . first ) ;
}
}
2023-08-15 15:28:25 +00:00
void Core : : MessageHandler : : onDownloadFileComplete ( const std : : list < Shared : : MessageInfo > & msgs , const QString & path ) {
2021-04-18 12:49:20 +00:00
QMap < QString , QVariant > cData = {
{ " attachPath " , path }
} ;
for ( const Shared : : MessageInfo & info : msgs ) {
2023-11-14 23:23:39 +00:00
if ( info . account ! = acc - > getName ( ) )
continue ;
RosterItem * cnt = acc - > rh - > getRosterItem ( info . jid ) ;
if ( cnt ! = nullptr ) {
bool changed = cnt - > changeMessage ( info . messageId , cData ) ;
if ( changed )
emit acc - > changeMessage ( info . jid , info . messageId , cData ) ;
2021-04-18 12:49:20 +00:00
}
2020-04-28 20:35:52 +00:00
}
}
2023-08-15 15:28:25 +00:00
void Core : : MessageHandler : : onLoadFileError ( const std : : list < Shared : : MessageInfo > & msgs , const QString & text , bool up ) {
2023-11-14 23:23:39 +00:00
if ( ! up )
return ;
for ( const Shared : : MessageInfo & info : msgs )
if ( info . account = = acc - > getName ( ) )
handleUploadError ( info . jid , info . messageId , text ) ;
2021-04-18 12:49:20 +00:00
}
2023-08-15 15:28:25 +00:00
void Core : : MessageHandler : : handleUploadError ( const QString & jid , const QString & messageId , const QString & errorText ) {
2021-05-07 18:26:02 +00:00
emit acc - > uploadFileError ( jid , messageId , " Error requesting slot to upload file: " + errorText ) ;
2022-03-28 20:25:33 +00:00
pendingStateMessages . erase ( messageId ) ;
pendingCorrectionMessages . erase ( messageId ) ;
2021-05-07 18:26:02 +00:00
requestChangeMessage ( jid , messageId , {
{ " state " , static_cast < uint > ( Shared : : Message : : State : : error ) } ,
{ " errorText " , errorText }
} ) ;
2021-04-18 12:49:20 +00:00
}
2023-08-15 15:28:25 +00:00
void Core : : MessageHandler : : onUploadFileComplete ( const std : : list < Shared : : MessageInfo > & msgs , const QString & url , const QString & path ) {
2021-04-18 12:49:20 +00:00
for ( const Shared : : MessageInfo & info : msgs ) {
2023-11-14 23:23:39 +00:00
if ( info . account ! = acc - > getName ( ) )
continue ;
RosterItem * ri = acc - > rh - > getRosterItem ( info . jid ) ;
if ( ri ! = nullptr ) {
Shared : : Message msg = ri - > getMessage ( info . messageId ) ;
msg . setAttachPath ( path ) ;
sendMessageWithLocalUploadedFile ( msg , url , false ) ;
} else {
qDebug ( ) < < " A signal received about complete upload to " < < acc - > name < < " for pal " < < info . jid < < " but the object for this pal wasn't found, something went terrebly wrong, skipping send " ;
2021-04-18 12:49:20 +00:00
}
2020-04-28 20:35:52 +00:00
}
}
2023-08-15 15:28:25 +00:00
void Core : : MessageHandler : : sendMessageWithLocalUploadedFile ( Shared : : Message msg , const QString & url , bool newMessage ) {
2020-04-28 20:35:52 +00:00
msg . setOutOfBandUrl ( url ) ;
2023-11-10 22:26:16 +00:00
if ( msg . getBody ( ) . size ( ) = = 0 ) //not sure why, but most messengers do that
2021-05-07 18:26:02 +00:00
msg . setBody ( url ) ; //they duplicate oob in body, some of them wouldn't even show an attachment if you don't do that
2023-08-15 15:28:25 +00:00
2022-03-28 20:25:33 +00:00
performSending ( msg , pendingCorrectionMessages . at ( msg . getId ( ) ) , newMessage ) ;
2020-04-28 20:35:52 +00:00
//TODO removal/progress update
}
2021-04-28 20:26:19 +00:00
2022-03-28 20:25:33 +00:00
static const std : : set < QString > allowedToChangeKeys ( {
2021-05-07 18:26:02 +00:00
" attachPath " ,
" outOfBandUrl " ,
" state " ,
" errorText "
} ) ;
2023-08-15 15:28:25 +00:00
void Core : : MessageHandler : : requestChangeMessage ( const QString & jid , const QString & messageId , const QMap < QString , QVariant > & data ) {
2021-04-28 20:26:19 +00:00
RosterItem * cnt = acc - > rh - > getRosterItem ( jid ) ;
2023-03-16 19:38:05 +00:00
if ( cnt ! = nullptr ) {
2021-05-07 18:26:02 +00:00
bool allSupported = true ;
QString unsupportedString ;
2022-03-28 20:25:33 +00:00
for ( QMap < QString , QVariant > : : const_iterator itr = data . begin ( ) ; itr ! = data . end ( ) ; + + itr ) { //I need all this madness
if ( allowedToChangeKeys . count ( itr . key ( ) ) ! = 1 ) { //to not allow this method
allSupported = false ; //to make a message to look like if it was edited
unsupportedString = itr . key ( ) ; //basically I needed to control who exaclty calls this method
break ; //because the underlying tech assumes that
} //the change is initiated by user, not by system
2021-05-07 18:26:02 +00:00
}
if ( allSupported ) {
2021-04-28 20:26:19 +00:00
cnt - > changeMessage ( messageId , data ) ;
emit acc - > changeMessage ( jid , messageId , data ) ;
} else {
qDebug ( ) < < " A request to change message " < < messageId < < " of conversation " < < jid < < " with following data " < < data ;
2021-05-07 18:26:02 +00:00
qDebug ( ) < < " only limited set of dataFields are supported yet here, and " < < unsupportedString < < " isn't one of them, skipping " ;
2021-04-28 20:26:19 +00:00
}
}
}
2021-05-22 22:03:14 +00:00
2023-08-15 15:28:25 +00:00
void Core : : MessageHandler : : resendMessage ( const QString & jid , const QString & id ) {
2021-05-22 22:03:14 +00:00
RosterItem * cnt = acc - > rh - > getRosterItem ( jid ) ;
2023-03-16 19:38:05 +00:00
if ( cnt ! = nullptr ) {
2021-05-22 22:03:14 +00:00
try {
Shared : : Message msg = cnt - > getMessage ( id ) ;
if ( msg . getState ( ) = = Shared : : Message : : State : : error ) {
2023-11-14 23:23:39 +00:00
if ( msg . getEdited ( ) ) {
2022-03-28 20:25:33 +00:00
QString originalId = msg . getId ( ) ;
msg . generateRandomId ( ) ;
sendMessage ( msg , false , originalId ) ;
} else {
sendMessage ( msg , false ) ;
}
2021-05-22 22:03:14 +00:00
} else {
qDebug ( ) < < " An attempt to resend a message to " < < jid < < " by account " < < acc - > getName ( ) < < " , but this message seems to have been normally sent, this method was made to retry sending failed to be sent messages, skipping " ;
}
2023-11-02 22:55:11 +00:00
} catch ( const LMDBAL : : NotFound & err ) {
2021-05-22 22:03:14 +00:00
qDebug ( ) < < " An attempt to resend a message to " < < jid < < " by account " < < acc - > getName ( ) < < " , but this message wasn't found in history, skipping " ;
}
} else {
qDebug ( ) < < " An attempt to resend a message to " < < jid < < " by account " < < acc - > getName ( ) < < " , but this jid isn't present in account roster, skipping " ;
}
}