#include <QDataStream>
-Message::Message(const BufferInfo &bufferInfo, Type type, const QString &contents, const QString &sender, const QString &senderPrefixes, Flags flags)
+Message::Message(const BufferInfo &bufferInfo, Type type, const QString &contents, const QString &sender,
+ const QString &senderPrefixes, const QString &realName, const QString &avatarUrl, Flags flags)
: _timestamp(QDateTime::currentDateTime().toUTC()),
_bufferInfo(bufferInfo),
_contents(contents),
_sender(sender),
_senderPrefixes(senderPrefixes),
+ _realName(realName),
+ _avatarUrl(avatarUrl),
_type(type),
_flags(flags)
{
}
-Message::Message(const QDateTime &ts, const BufferInfo &bufferInfo, Type type, const QString &contents, const QString &sender, const QString &senderPrefixes, Flags flags)
+Message::Message(const QDateTime &ts, const BufferInfo &bufferInfo, Type type, const QString &contents,
+ const QString &sender, const QString &senderPrefixes, const QString &realName,
+ const QString &avatarUrl, Flags flags)
: _timestamp(ts),
_bufferInfo(bufferInfo),
_contents(contents),
_sender(sender),
_senderPrefixes(senderPrefixes),
+ _realName(realName),
+ _avatarUrl(avatarUrl),
_type(type),
_flags(flags)
{
if (SignalProxy::current()->targetPeer()->hasFeature(Quassel::Feature::SenderPrefixes))
out << msg.senderPrefixes().toUtf8();
+ if (SignalProxy::current()->targetPeer()->hasFeature(Quassel::Feature::RichMessages)) {
+ out << msg.realName().toUtf8();
+ out << msg.avatarUrl().toUtf8();
+ }
+
out << msg.contents().toUtf8();
return out;
}
in >> senderPrefixes;
msg._senderPrefixes = QString::fromUtf8(senderPrefixes);
+ QByteArray realName;
+ QByteArray avatarUrl;
+ if (SignalProxy::current()->sourcePeer()->hasFeature(Quassel::Feature::RichMessages)) {
+ in >> realName;
+ in >> avatarUrl;
+ }
+ msg._realName = QString::fromUtf8(realName);
+ msg._avatarUrl = QString::fromUtf8(avatarUrl);
+
QByteArray contents;
in >> contents;
msg._contents = QString::fromUtf8(contents);
dbg.nospace() << qPrintable(QString("Message(MsgId:")) << msg.msgId()
<< qPrintable(QString(",")) << msg.timestamp()
<< qPrintable(QString(", Type:")) << msg.type()
+ << qPrintable(QString(", RealName:")) << msg.realName()
+ << qPrintable(QString(", AvatarURL:")) << msg.avatarUrl()
<< qPrintable(QString(", Flags:")) << msg.flags() << qPrintable(QString(")"))
- << msg.sender() << ":" << msg.contents();
+ << msg.senderPrefixes() << msg.sender() << ":" << msg.contents();
return dbg;
}
Q_DECLARE_FLAGS(Flags, Flag)
Message(const BufferInfo &bufferInfo = BufferInfo(), Type type = Plain, const QString &contents = {},
- const QString &sender = {}, const QString &senderPrefixes = {}, Flags flags = None);
+ const QString &sender = {}, const QString &senderPrefixes = {}, const QString &realName = {},
+ const QString &avatarUrl = {}, Flags flags = None);
Message(const QDateTime &ts, const BufferInfo &buffer = BufferInfo(), Type type = Plain,
const QString &contents = {}, const QString &sender = {}, const QString &senderPrefixes = {},
- Flags flags = None);
+ const QString &realName = {}, const QString &avatarUrl = {}, Flags flags = None);
inline static Message ChangeOfDay(const QDateTime &day) { return Message(day, BufferInfo(), DayChange); }
inline const MsgId &msgId() const { return _msgId; }
inline const QString &contents() const { return _contents; }
inline const QString &sender() const { return _sender; }
inline const QString &senderPrefixes() const { return _senderPrefixes; }
+ inline const QString &realName() const { return _realName; }
+ inline const QString &avatarUrl() const { return _avatarUrl; }
inline Type type() const { return _type; }
inline Flags flags() const { return _flags; }
inline void setFlags(Flags flags) { _flags = flags; }
QString _contents;
QString _sender;
QString _senderPrefixes;
+ QString _realName;
+ QString _avatarUrl;
Type _type;
Flags _flags;
RemoteDisconnect, ///< Allow this peer to be remotely disconnected
ExtendedFeatures, ///< Extended features
LongMessageTime, ///< Serialize message time as 64-bit
+ RichMessages, ///< Real Name and Avatar URL in backlog
#if QT_VERSION >= 0x050500
EcdsaCertfpKeys, ///< ECDSA keys for CertFP in identities
#endif
-INSERT INTO sender (sender)
-VALUES ($1)
+INSERT INTO sender (sender, realname, avatarurl)
+VALUES ($1, $2, $3)
RETURNING senderid
-INSERT INTO sender (senderid, sender)
-VALUES (?, ?)
+INSERT INTO sender (senderid, sender, realname, avatarurl)
+VALUES (?, ?, ?, ?)
-SELECT messageid, bufferid, time, type, flags, sender, senderprefixes, message
+SELECT messageid, bufferid, time, type, flags, sender, senderprefixes, realname, avatarurl, message
FROM backlog
JOIN sender ON backlog.senderid = sender.senderid
WHERE backlog.bufferid IN (SELECT bufferid FROM buffer WHERE userid = :userid)
-SELECT messageid, bufferid, time, type, flags, sender, senderprefixes, message
+SELECT messageid, bufferid, time, type, flags, sender, senderprefixes, realname, avatarurl, message
FROM backlog
JOIN sender ON backlog.senderid = sender.senderid
WHERE backlog.bufferid IN (SELECT bufferid FROM buffer WHERE userid = :userid)
-SELECT messageid, time, type, flags, sender, senderprefixes, message
+SELECT messageid, time, type, flags, sender, senderprefixes, realname, avatarurl, message
FROM backlog
JOIN sender ON backlog.senderid = sender.senderid
WHERE backlog.messageid >= $1
-SELECT messageid, time, type, flags, sender, senderprefixes, message
+SELECT messageid, time, type, flags, sender, senderprefixes, realname, avatarurl, message
FROM backlog
JOIN sender ON backlog.senderid = sender.senderid
WHERE bufferid = $1
-SELECT messageid, time, type, flags, sender, senderprefixes, message
+SELECT messageid, time, type, flags, sender, senderprefixes, realname, avatarurl, message
FROM backlog
JOIN sender ON backlog.senderid = sender.senderid
WHERE backlog.messageid >= $1
SELECT senderid
FROM sender
-WHERE sender = $1
+WHERE sender = $1 AND realname = $2 AND avatarurl = $3
CREATE TABLE sender ( -- THE SENDER OF IRC MESSAGES
senderid serial NOT NULL PRIMARY KEY,
- sender varchar(128) UNIQUE NOT NULL
-)
+ sender varchar(128) NOT NULL,
+ realname TEXT,
+ avatarurl TEXT
+);
--- /dev/null
+CREATE UNIQUE INDEX sender_sender_realname_avatarurl_uindex ON sender(sender, realname, avatarurl);
--- /dev/null
+ALTER TABLE sender ADD realname TEXT NULL;
--- /dev/null
+ALTER TABLE sender ADD avatarurl TEXT NULL;
--- /dev/null
+CREATE UNIQUE INDEX sender_sender_realname_avatarurl_uindex ON sender(sender, realname, avatarurl);
--- /dev/null
+ALTER TABLE sender DROP CONSTRAINT sender_sender_key;
-INSERT INTO sender (sender)
-VALUES (:sender)
\ No newline at end of file
+INSERT INTO sender (sender, realname, avatarurl)
+VALUES (:sender, :realname, :avatarurl)
-SELECT senderid, sender
+SELECT senderid, sender, realname, avatarurl
FROM sender
WHERE senderid > ? AND senderid <= ?
ORDER BY senderid ASC
-
-SELECT messageid, bufferid, time, type, flags, sender, senderprefixes, message
+SELECT messageid, bufferid, time, type, flags, sender, senderprefixes, realname, avatarurl, message
FROM backlog
JOIN sender ON backlog.senderid = sender.senderid
WHERE backlog.bufferid IN (SELECT bufferid FROM buffer WHERE userid = :userid)
-SELECT messageid, bufferid, time, type, flags, sender, senderprefixes, message
+SELECT messageid, bufferid, time, type, flags, sender, senderprefixes, realname, avatarurl, message
FROM backlog
JOIN sender ON backlog.senderid = sender.senderid
WHERE backlog.bufferid IN (SELECT bufferid FROM buffer WHERE userid = :userid)
-SELECT messageid, time, type, flags, sender, senderprefixes, message
+SELECT messageid, time, type, flags, sender, senderprefixes, realname, avatarurl, message
FROM backlog
JOIN sender ON backlog.senderid = sender.senderid
WHERE backlog.messageid >= :firstmsg
-SELECT messageid, time, type, flags, sender, senderprefixes, message
+SELECT messageid, time, type, flags, sender, senderprefixes, realname, avatarurl, message
FROM backlog
JOIN sender ON backlog.senderid = sender.senderid
WHERE bufferid = :bufferid
-SELECT messageid, time, type, flags, sender, senderprefixes, message
+SELECT messageid, time, type, flags, sender, senderprefixes, realname, avatarurl, message
FROM backlog
JOIN sender ON backlog.senderid = sender.senderid
WHERE bufferid = :bufferid
CREATE TABLE sender ( -- THE SENDER OF IRC MESSAGES
senderid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- sender TEXT UNIQUE NOT NULL
-)
-
-
+ sender TEXT NOT NULL,
+ realname TEXT,
+ avatarurl TEXT
+);
--- /dev/null
+CREATE UNIQUE INDEX sender_index ON sender(sender, realname, avatarurl);
--- /dev/null
+CREATE TABLE sender_tmp (senderid INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, sender TEXT NOT NULL, realname TEXT, avatarurl TEXT);
--- /dev/null
+INSERT INTO sender_tmp SELECT senderid, sender, NULL as realname, NULL as avatarurl FROM sender;
--- /dev/null
+DROP TABLE sender;
--- /dev/null
+ALTER TABLE sender_tmp RENAME TO sender;
--- /dev/null
+CREATE UNIQUE INDEX sender_index ON sender(sender, realname, avatarurl);
qDebug() << "Done.";
return true;
}
+
+uint qHash(const SenderData &key) {
+ return qHash(QString(key.sender + "\n" + key.realname + "\n" + key.avatarurl));
+}
+
+bool operator==(const SenderData &a, const SenderData &b) {
+ return a.sender == b.sender &&
+ a.realname == b.realname &&
+ a.avatarurl == b.avatarurl;
+}
QHash<QThread *, Connection *> _connectionPool;
};
+struct SenderData {
+ QString sender;
+ QString realname;
+ QString avatarurl;
+
+ friend uint qHash(const SenderData &key);
+ friend bool operator==(const SenderData &a, const SenderData &b);
+};
// ========================================
// AbstractSqlStorage::Connection
struct SenderMO {
int senderId;
QString sender;
+ QString realname;
+ QString avatarurl;
SenderMO() : senderId(0) {}
};
Q_ASSERT(!createBuffer);
bufferInfo = Core::bufferInfo(user(), rawMsg.networkId, BufferInfo::StatusBuffer, "");
}
- Message msg(bufferInfo, rawMsg.type, rawMsg.text, rawMsg.sender,
- senderPrefixes(rawMsg.sender, bufferInfo), rawMsg.flags);
+ Message msg(bufferInfo, rawMsg.type, rawMsg.text, rawMsg.sender, senderPrefixes(rawMsg.sender, bufferInfo),
+ realName(rawMsg.sender, rawMsg.networkId), avatarUrl(rawMsg.sender, rawMsg.networkId),
+ rawMsg.flags);
if(Core::storeMessage(msg))
emit displayMsg(msg);
}
}
bufferInfoCache[rawMsg.networkId][rawMsg.target] = bufferInfo;
}
- Message msg(bufferInfo, rawMsg.type, rawMsg.text, rawMsg.sender,
- senderPrefixes(rawMsg.sender, bufferInfo), rawMsg.flags);
+ Message msg(bufferInfo, rawMsg.type, rawMsg.text, rawMsg.sender, senderPrefixes(rawMsg.sender, bufferInfo),
+ realName(rawMsg.sender, rawMsg.networkId), avatarUrl(rawMsg.sender, rawMsg.networkId),
+ rawMsg.flags);
messages << msg;
}
// add the StatusBuffer to the Cache in case there are more Messages for the original target
bufferInfoCache[rawMsg.networkId][rawMsg.target] = bufferInfo;
}
- Message msg(bufferInfo, rawMsg.type, rawMsg.text, rawMsg.sender,
- senderPrefixes(rawMsg.sender, bufferInfo), rawMsg.flags);
+ Message msg(bufferInfo, rawMsg.type, rawMsg.text, rawMsg.sender, senderPrefixes(rawMsg.sender, bufferInfo),
+ realName(rawMsg.sender, rawMsg.networkId), avatarUrl(rawMsg.sender, rawMsg.networkId),
+ rawMsg.flags);
messages << msg;
}
return currentNetwork->modesToPrefixes(modes);
}
+QString CoreSession::realName(const QString &sender, NetworkId networkId) const
+{
+ CoreNetwork *currentNetwork = network(networkId);
+ if (!currentNetwork) {
+ return {};
+ }
+
+ IrcUser *currentUser = currentNetwork->ircUser(nickFromMask(sender));
+ if (!currentUser) {
+ return {};
+ }
+
+ return currentUser->realName();
+}
+
+QString CoreSession::avatarUrl(const QString &sender, NetworkId networkId) const
+{
+ Q_UNUSED(sender);
+ Q_UNUSED(networkId);
+ // Currently we do not have a way to retrieve this value yet.
+ //
+ // This likely will require implementing IRCv3's METADATA spec.
+ // See https://ircv3.net/irc/
+ // And https://blog.irccloud.com/avatars/
+ return "";
+}
+
Protocol::SessionState CoreSession::sessionState() const
{
QVariantList bufferInfos;
* @param bufferInfo The BufferInfo object of the buffer
*/
QString senderPrefixes(const QString &sender, const BufferInfo &bufferInfo) const;
+
+ /**
+ * This method obtains the realname of the message's sender.
+ * @param sender The hostmask of the sender
+ * @param networkId The network the user is on
+ */
+ QString realName(const QString &sender, NetworkId networkId) const;
+
+ /**
+ * This method obtains the avatar of the message's sender.
+ * @param sender The hostmask of the sender
+ * @param networkId The network the user is on
+ */
+ QString avatarUrl(const QString &sender, NetworkId networkId) const;
QList<RawMessage> _messageQueue;
bool _processMessages;
CoreIgnoreListManager _ignoreListManager;
return false;
}
- QSqlQuery getSenderIdQuery = executePreparedQuery("select_senderid", msg.sender(), db);
+ QVariantList senderParams;
+ senderParams << msg.sender()
+ << msg.realName()
+ << msg.avatarUrl();
+ QSqlQuery getSenderIdQuery = executePreparedQuery("select_senderid", senderParams, db);
int senderId;
if (getSenderIdQuery.first()) {
senderId = getSenderIdQuery.value(0).toInt();
// it's possible that the sender was already added by another thread
// since the insert might fail we're setting a savepoint
savePoint("sender_sp1", db);
- QSqlQuery addSenderQuery = executePreparedQuery("insert_sender", msg.sender(), db);
+ QSqlQuery addSenderQuery = executePreparedQuery("insert_sender", senderParams, db);
if (addSenderQuery.lastError().isValid()) {
rollbackSavePoint("sender_sp1", db);
- getSenderIdQuery = executePreparedQuery("select_senderid", msg.sender(), db);
+ getSenderIdQuery = executePreparedQuery("select_senderid", senderParams, db);
watchQuery(getSenderIdQuery);
getSenderIdQuery.first();
senderId = getSenderIdQuery.value(0).toInt();
}
QList<int> senderIdList;
- QHash<QString, int> senderIds;
+ QHash<SenderData, int> senderIds;
QSqlQuery addSenderQuery;
QSqlQuery selectSenderQuery;;
for (int i = 0; i < msgs.count(); i++) {
- const QString &sender = msgs.at(i).sender();
+ auto &msg = msgs.at(i);
+ SenderData sender = { msg.sender(), msg.realName(), msg.avatarUrl() };
if (senderIds.contains(sender)) {
senderIdList << senderIds[sender];
continue;
}
- selectSenderQuery = executePreparedQuery("select_senderid", sender, db);
+ QVariantList senderParams;
+ senderParams << sender.sender
+ << sender.realname
+ << sender.avatarurl;
+
+ selectSenderQuery = executePreparedQuery("select_senderid", senderParams, db);
if (selectSenderQuery.first()) {
senderIdList << selectSenderQuery.value(0).toInt();
senderIds[sender] = selectSenderQuery.value(0).toInt();
}
else {
savePoint("sender_sp", db);
- addSenderQuery = executePreparedQuery("insert_sender", sender, db);
+ addSenderQuery = executePreparedQuery("insert_sender", senderParams, db);
if (addSenderQuery.lastError().isValid()) {
// seems it was inserted meanwhile... by a different thread
rollbackSavePoint("sender_sp", db);
- selectSenderQuery = executePreparedQuery("select_senderid", sender, db);
+ selectSenderQuery = executePreparedQuery("select_senderid", senderParams, db);
watchQuery(selectSenderQuery);
selectSenderQuery.first();
senderIdList << selectSenderQuery.value(0).toInt();
Message msg(timestamp,
bufferInfo,
(Message::Type)query.value(2).toUInt(),
- query.value(6).toString(),
+ query.value(8).toString(),
query.value(4).toString(),
query.value(5).toString(),
+ query.value(6).toString(),
+ query.value(7).toString(),
(Message::Flags)query.value(3).toUInt());
msg.setMsgId(query.value(0).toInt());
messagelist << msg;
Message msg(timestamp,
bufferInfoHash[query.value(1).toInt()],
(Message::Type)query.value(3).toUInt(),
- query.value(7).toString(),
+ query.value(9).toString(),
query.value(5).toString(),
query.value(6).toString(),
+ query.value(7).toString(),
+ query.value(8).toString(),
(Message::Flags)query.value(4).toUInt());
msg.setMsgId(query.value(0).toInt());
messagelist << msg;
{
bindValue(0, sender.senderId);
bindValue(1, sender.sender);
+ bindValue(2, sender.realname);
+ bindValue(3, sender.avatarurl);
return exec();
}
<file>./SQL/PostgreSQL/setup_110_alter_sender_seq.sql</file>
<file>./SQL/PostgreSQL/setup_120_alter_messageid_seq.sql</file>
<file>./SQL/PostgreSQL/setup_130_function_lastmsgid.sql</file>
+ <file>./SQL/PostgreSQL/setup_140_sender_idx.sql</file>
<file>./SQL/PostgreSQL/update_backlog_bufferid.sql</file>
<file>./SQL/PostgreSQL/update_buffer_bufferactivity.sql</file>
<file>./SQL/PostgreSQL/update_buffer_cipher.sql</file>
<file>./SQL/PostgreSQL/version/24/upgrade_000_alter_buffer_add_bufferactivity.sql</file>
<file>./SQL/PostgreSQL/version/25/upgrade_000_alter_buffer_add_cipher.sql</file>
<file>./SQL/PostgreSQL/version/26/upgrade_000_alter_buffer_add_highlightcount.sql</file>
+ <file>./SQL/PostgreSQL/version/27/upgrade_000_update_sender_add_realname.sql</file>
+ <file>./SQL/PostgreSQL/version/27/upgrade_010_update_sender_add_avatarurl.sql</file>
+ <file>./SQL/PostgreSQL/version/27/upgrade_020_update_sender_add_new_constraint.sql</file>
+ <file>./SQL/PostgreSQL/version/27/upgrade_030_upgrade_sender_drop_old_constraint.sql</file>
<file>./SQL/SQLite/delete_backlog_by_uid.sql</file>
<file>./SQL/SQLite/delete_backlog_for_buffer.sql</file>
<file>./SQL/SQLite/delete_backlog_for_network.sql</file>
<file>./SQL/SQLite/setup_120_user_setting.sql</file>
<file>./SQL/SQLite/setup_130_identity.sql</file>
<file>./SQL/SQLite/setup_140_identity_nick.sql</file>
+ <file>./SQL/SQLite/setup_150_sender_idx.sql</file>
<file>./SQL/SQLite/update_backlog_bufferid.sql</file>
<file>./SQL/SQLite/update_buffer_bufferactivity.sql</file>
<file>./SQL/SQLite/update_buffer_cipher.sql</file>
<file>./SQL/SQLite/version/26/upgrade_000_create_buffer_idx.sql</file>
<file>./SQL/SQLite/version/27/upgrade_000_alter_buffer_add_cipher.sql</file>
<file>./SQL/SQLite/version/28/upgrade_000_alter_buffer_add_highlightcount.sql</file>
+ <file>./SQL/SQLite/version/29/upgrade_000_create_sender_tmp.sql</file>
+ <file>./SQL/SQLite/version/29/upgrade_010_copy_sender_sender_tmp.sql</file>
+ <file>./SQL/SQLite/version/29/upgrade_020_drop_sender.sql</file>
+ <file>./SQL/SQLite/version/29/upgrade_030_rename_sender_tmp_sender.sql</file>
+ <file>./SQL/SQLite/version/29/upgrade_040_update_sender_add_realname_avatarurl.sql</file>
</qresource>
</RCC>
QSqlQuery addSenderQuery(db);
addSenderQuery.prepare(queryString("insert_sender"));
addSenderQuery.bindValue(":sender", msg.sender());
+ addSenderQuery.bindValue(":realname", msg.realName());
+ addSenderQuery.bindValue(":avatarurl", msg.avatarUrl());
safeExec(addSenderQuery);
safeExec(logMessageQuery);
error = !watchQuery(logMessageQuery);
db.transaction();
{
- QSet<QString> senders;
+ QSet<SenderData> senders;
QSqlQuery addSenderQuery(db);
addSenderQuery.prepare(queryString("insert_sender"));
lockForWrite();
for (int i = 0; i < msgs.count(); i++) {
- const QString &sender = msgs.at(i).sender();
+ auto &msg = msgs.at(i);
+ SenderData sender = { msg.sender(), msg.realName(), msg.avatarUrl() };
if (senders.contains(sender))
continue;
senders << sender;
- addSenderQuery.bindValue(":sender", sender);
+ addSenderQuery.bindValue(":sender", sender.sender);
+ addSenderQuery.bindValue(":realname", sender.realname);
+ addSenderQuery.bindValue(":avatarurl", sender.avatarurl);
safeExec(addSenderQuery);
}
}
Message msg(QDateTime::fromTime_t(query.value(1).toInt()),
bufferInfo,
(Message::Type)query.value(2).toUInt(),
- query.value(6).toString(),
+ query.value(8).toString(),
query.value(4).toString(),
query.value(5).toString(),
+ query.value(6).toString(),
+ query.value(7).toString(),
(Message::Flags)query.value(3).toUInt());
msg.setMsgId(query.value(0).toInt());
messagelist << msg;
Message msg(QDateTime::fromTime_t(query.value(2).toInt()),
bufferInfoHash[query.value(1).toInt()],
(Message::Type)query.value(3).toUInt(),
- query.value(7).toString(),
+ query.value(9).toString(),
query.value(5).toString(),
query.value(6).toString(),
+ query.value(7).toString(),
+ query.value(8).toString(),
(Message::Flags)query.value(4).toUInt());
msg.setMsgId(query.value(0).toInt());
messagelist << msg;
sender.senderId = value(0).toInt();
sender.sender = value(1).toString();
+ sender.realname = value(2).toString();
+ sender.avatarurl = value(3).toString();
return true;
}