2018-08-23 00:12:26 +02:00
// mautrix-whatsapp - A Matrix-WhatsApp puppeting bridge.
2021-10-22 19:14:34 +02:00
// Copyright (C) 2021 Tulir Asokan
2018-08-23 00:12:26 +02:00
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package database
import (
2018-08-26 21:53:13 +02:00
"database/sql"
2021-11-03 20:34:06 +01:00
"errors"
2021-02-09 22:41:14 +01:00
"strings"
2021-05-18 19:09:12 +02:00
"time"
2018-08-26 21:53:13 +02:00
2019-01-11 20:17:31 +01:00
log "maunium.net/go/maulogger/v2"
2021-10-26 16:01:10 +02:00
2020-05-08 21:32:22 +02:00
"maunium.net/go/mautrix/id"
2021-10-22 19:14:34 +02:00
"go.mau.fi/whatsmeow/types"
2018-08-23 00:12:26 +02:00
)
type MessageQuery struct {
db * Database
log log . Logger
}
func ( mq * MessageQuery ) New ( ) * Message {
return & Message {
db : mq . db ,
log : mq . log ,
}
}
2021-10-27 17:31:33 +02:00
const (
getAllMessagesQuery = `
SELECT chat_jid , chat_receiver , jid , mxid , sender , timestamp , sent , decryption_error FROM message
WHERE chat_jid = $ 1 AND chat_receiver = $ 2
`
getMessageByJIDQuery = `
SELECT chat_jid , chat_receiver , jid , mxid , sender , timestamp , sent , decryption_error FROM message
WHERE chat_jid = $ 1 AND chat_receiver = $ 2 AND jid = $ 3
`
getMessageByMXIDQuery = `
SELECT chat_jid , chat_receiver , jid , mxid , sender , timestamp , sent , decryption_error FROM message
WHERE mxid = $ 1
`
getLastMessageInChatQuery = `
SELECT chat_jid , chat_receiver , jid , mxid , sender , timestamp , sent , decryption_error FROM message
WHERE chat_jid = $ 1 AND chat_receiver = $ 2 AND timestamp <= $ 3 AND sent = true ORDER BY timestamp DESC LIMIT 1
`
getFirstMessageInChatQuery = `
SELECT chat_jid , chat_receiver , jid , mxid , sender , timestamp , sent , decryption_error FROM message
WHERE chat_jid = $ 1 AND chat_receiver = $ 2 AND sent = true ORDER BY timestamp ASC LIMIT 1
`
)
2018-08-28 23:40:54 +02:00
func ( mq * MessageQuery ) GetAll ( chat PortalKey ) ( messages [ ] * Message ) {
2021-10-27 17:31:33 +02:00
rows , err := mq . db . Query ( getAllMessagesQuery , chat . JID , chat . Receiver )
2018-08-23 00:12:26 +02:00
if err != nil || rows == nil {
return nil
}
for rows . Next ( ) {
messages = append ( messages , mq . New ( ) . Scan ( rows ) )
}
return
}
2021-10-22 19:14:34 +02:00
func ( mq * MessageQuery ) GetByJID ( chat PortalKey , jid types . MessageID ) * Message {
2021-10-27 17:31:33 +02:00
return mq . maybeScan ( mq . db . QueryRow ( getMessageByJIDQuery , chat . JID , chat . Receiver , jid ) )
2018-08-23 00:12:26 +02:00
}
2020-05-08 21:32:22 +02:00
func ( mq * MessageQuery ) GetByMXID ( mxid id . EventID ) * Message {
2021-10-27 17:31:33 +02:00
return mq . maybeScan ( mq . db . QueryRow ( getMessageByMXIDQuery , mxid ) )
2019-05-22 15:46:18 +02:00
}
func ( mq * MessageQuery ) GetLastInChat ( chat PortalKey ) * Message {
2021-10-27 17:31:33 +02:00
return mq . GetLastInChatBefore ( chat , time . Now ( ) . Add ( 60 * time . Second ) )
2021-05-18 19:09:12 +02:00
}
2021-10-26 16:01:10 +02:00
func ( mq * MessageQuery ) GetLastInChatBefore ( chat PortalKey , maxTimestamp time . Time ) * Message {
2021-10-27 17:31:33 +02:00
msg := mq . maybeScan ( mq . db . QueryRow ( getLastMessageInChatQuery , chat . JID , chat . Receiver , maxTimestamp . Unix ( ) ) )
2021-10-26 16:01:10 +02:00
if msg == nil || msg . Timestamp . IsZero ( ) {
2019-05-22 15:46:18 +02:00
// Old db, we don't know what the last message is.
return nil
}
return msg
2018-08-23 00:12:26 +02:00
}
2021-10-26 16:01:10 +02:00
func ( mq * MessageQuery ) GetFirstInChat ( chat PortalKey ) * Message {
2021-10-27 17:31:33 +02:00
return mq . maybeScan ( mq . db . QueryRow ( getFirstMessageInChatQuery , chat . JID , chat . Receiver ) )
2021-10-26 16:01:10 +02:00
}
2021-10-27 17:31:33 +02:00
func ( mq * MessageQuery ) maybeScan ( row * sql . Row ) * Message {
2018-08-23 00:12:26 +02:00
if row == nil {
return nil
}
return mq . New ( ) . Scan ( row )
}
type Message struct {
db * Database
log log . Logger
2019-05-22 15:46:18 +02:00
Chat PortalKey
2021-10-22 19:14:34 +02:00
JID types . MessageID
2020-05-08 21:32:22 +02:00
MXID id . EventID
2021-10-22 19:14:34 +02:00
Sender types . JID
2021-10-26 16:01:10 +02:00
Timestamp time . Time
2021-02-17 00:22:06 +01:00
Sent bool
2021-10-27 17:31:33 +02:00
DecryptionError bool
2018-08-23 00:12:26 +02:00
}
2021-02-09 22:41:14 +01:00
func ( msg * Message ) IsFakeMXID ( ) bool {
return strings . HasPrefix ( msg . MXID . String ( ) , "net.maunium.whatsapp.fake::" )
}
2021-11-02 14:46:31 +01:00
func ( msg * Message ) IsFakeJID ( ) bool {
return strings . HasPrefix ( msg . JID , "FAKE::" )
}
2018-08-23 00:12:26 +02:00
func ( msg * Message ) Scan ( row Scannable ) * Message {
2021-10-26 16:01:10 +02:00
var ts int64
2021-10-27 17:31:33 +02:00
err := row . Scan ( & msg . Chat . JID , & msg . Chat . Receiver , & msg . JID , & msg . MXID , & msg . Sender , & ts , & msg . Sent , & msg . DecryptionError )
2018-08-23 00:12:26 +02:00
if err != nil {
2021-11-03 20:34:06 +01:00
if ! errors . Is ( err , sql . ErrNoRows ) {
2018-08-26 00:55:21 +02:00
msg . log . Errorln ( "Database scan failed:" , err )
2018-08-23 00:12:26 +02:00
}
return nil
}
2021-10-26 16:01:10 +02:00
if ts != 0 {
msg . Timestamp = time . Unix ( ts , 0 )
}
2018-08-23 00:12:26 +02:00
return msg
}
2019-01-21 22:55:16 +01:00
func ( msg * Message ) Insert ( ) {
2021-10-26 20:30:42 +02:00
var sender interface { } = msg . Sender
// Slightly hacky hack to allow inserting empty senders (used for post-backfill dummy events)
if msg . Sender . IsEmpty ( ) {
sender = ""
}
2021-02-17 00:22:06 +01:00
_ , err := msg . db . Exec ( ` INSERT INTO message
2021-10-27 17:31:33 +02:00
( chat_jid , chat_receiver , jid , mxid , sender , timestamp , sent , decryption_error )
VALUES ( $ 1 , $ 2 , $ 3 , $ 4 , $ 5 , $ 6 , $ 7 , $ 8 ) ` ,
msg . Chat . JID , msg . Chat . Receiver , msg . JID , msg . MXID , sender , msg . Timestamp . Unix ( ) , msg . Sent , msg . DecryptionError )
2018-08-23 00:12:26 +02:00
if err != nil {
2018-09-01 22:38:03 +02:00
msg . log . Warnfln ( "Failed to insert %s@%s: %v" , msg . Chat , msg . JID , err )
2018-08-23 00:12:26 +02:00
}
}
2019-05-16 00:59:36 +02:00
2021-10-31 22:36:41 +01:00
func ( msg * Message ) MarkSent ( ts time . Time ) {
2021-02-17 00:22:06 +01:00
msg . Sent = true
2021-10-31 22:36:41 +01:00
msg . Timestamp = ts
2021-11-07 22:42:23 +01:00
_ , err := msg . db . Exec ( "UPDATE message SET sent=true, timestamp=$1 WHERE chat_jid=$2 AND chat_receiver=$3 AND jid=$4" , ts . Unix ( ) , msg . Chat . JID , msg . Chat . Receiver , msg . JID )
2021-02-17 00:22:06 +01:00
if err != nil {
msg . log . Warnfln ( "Failed to update %s@%s: %v" , msg . Chat , msg . JID , err )
}
}
2021-10-27 17:31:33 +02:00
func ( msg * Message ) UpdateMXID ( mxid id . EventID , stillDecryptionError bool ) {
msg . MXID = mxid
msg . DecryptionError = stillDecryptionError
2021-11-07 22:42:23 +01:00
_ , err := msg . db . Exec ( "UPDATE message SET mxid=$1, decryption_error=$2 WHERE chat_jid=$3 AND chat_receiver=$4 AND jid=$5" , mxid , stillDecryptionError , msg . Chat . JID , msg . Chat . Receiver , msg . JID )
2021-10-27 17:31:33 +02:00
if err != nil {
msg . log . Warnfln ( "Failed to update %s@%s: %v" , msg . Chat , msg . JID , err )
}
}
2019-05-16 00:59:36 +02:00
func ( msg * Message ) Delete ( ) {
_ , err := msg . db . Exec ( "DELETE FROM message WHERE chat_jid=$1 AND chat_receiver=$2 AND jid=$3" , msg . Chat . JID , msg . Chat . Receiver , msg . JID )
if err != nil {
msg . log . Warnfln ( "Failed to delete %s@%s: %v" , msg . Chat , msg . JID , err )
}
}