Serverside comment/texture send-on-demand

This commit is contained in:
Thorvald Natvig 2010-01-17 03:49:32 +01:00
parent ad0f30f6d1
commit 60e71510bf
8 changed files with 168 additions and 33 deletions

View File

@ -52,6 +52,7 @@ class Channel : public QObject {
Channel *cParent;
QString qsName;
QString qsDesc;
QByteArray qbaDescHash;
QList<Channel *> qlChannels;
QList<User *> qlUsers;
QHash<QString, Group *> qhGroups;

View File

@ -57,7 +57,8 @@
MUMBLE_MH_MSG(VoiceTarget) \
MUMBLE_MH_MSG(PermissionQuery) \
MUMBLE_MH_MSG(CodecVersion) \
MUMBLE_MH_MSG(UserStats)
MUMBLE_MH_MSG(UserStats) \
MUMBLE_MH_MSG(RequestBlob)
class MessageHandler {
public:
@ -83,6 +84,22 @@ inline ::std::string u8(const QString &str) {
return ::std::string(qba.constData(), qba.length());
}
inline QByteArray blob(const ::std::string &str) {
return QByteArray(str.data(), static_cast<int>(str.length()));
}
inline ::std::string blob(const QByteArray &str) {
return ::std::string(str.constData(), str.length());
}
inline QByteArray sha1(const QByteArray &blob) {
return QCryptographicHash::hash(blob, QCryptographicHash::Sha1);
}
inline QByteArray sha1(const QString &str) {
return QCryptographicHash::hash(str.toUtf8(), QCryptographicHash::Sha1);
}
#else
class Message;
#endif

View File

@ -71,6 +71,7 @@ message ChannelState {
repeated uint32 links_remove = 7;
optional bool temporary = 8 [default = false];
optional int32 position = 9 [default = 0];
optional bytes description_hash = 10;
}
message UserRemove {
@ -96,6 +97,8 @@ message UserState {
optional string plugin_identity = 13;
optional string comment = 14;
optional string hash = 15;
optional bytes comment_hash = 16;
optional bytes texture_hash = 17;
}
message BanList {
@ -256,3 +259,9 @@ message UserStats {
optional uint32 idlesecs = 17;
optional bool strong_certificate = 18 [default = false];
}
message RequestBlob {
repeated uint32 session_texture = 1;
repeated uint32 session_comment = 2;
repeated uint32 channel_description = 3;
}

View File

@ -43,11 +43,13 @@ class User {
int iId;
QString qsName;
QString qsComment;
QByteArray qbaCommentHash;
QString qsHash;
bool bMute, bDeaf, bSuppress;
bool bSelfMute, bSelfDeaf;
Channel *cChannel;
QByteArray qbaTexture;
QByteArray qbaTextureHash;
User();
virtual ~User() {};

View File

@ -220,7 +220,7 @@ void Server::msgAuthenticate(ServerUser *uSource, MumbleProto::Authenticate &msg
uSource->qlCodecs.append(static_cast<qint32>(0x8000000a));
}
recheckCodecVersions();
MumbleProto::CodecVersion mpcv;
mpcv.set_alpha(iCodecAlpha);
mpcv.set_beta(iCodecBeta);
@ -245,10 +245,14 @@ void Server::msgAuthenticate(ServerUser *uSource, MumbleProto::Authenticate &msg
mpcs.set_name(u8(qsRegName.isEmpty() ? QLatin1String("Root") : qsRegName));
else
mpcs.set_name(u8(c->qsName));
if (! c->qsDesc.isEmpty())
mpcs.set_description(u8(c->qsDesc));
mpcs.set_position(c->iPosition);
if ((uSource->uiVersion >= 0x010202) && ! c->qbaDescHash.isEmpty())
mpcs.set_description_hash(blob(c->qbaDescHash));
else if (! c->qsDesc.isEmpty())
mpcs.set_description(u8(c->qsDesc));
sendMessage(uSource, mpcs);
foreach(c, c->qlChannels)
@ -281,20 +285,27 @@ void Server::msgAuthenticate(ServerUser *uSource, MumbleProto::Authenticate &msg
lc = root;
userEnterChannel(uSource, lc, mpus);
uSource->sState = ServerUser::Authenticated;
mpus.set_session(uSource->uiSession);
mpus.set_name(u8(uSource->qsName));
if (uSource->iId >= 0) {
uSource->qbaTexture = getUserTexture(uSource->iId);
mpus.set_user_id(uSource->iId);
if (! uSource->qbaTexture.isEmpty())
hashAssign(uSource->qbaTexture, uSource->qbaTextureHash, getUserTexture(uSource->iId));
if (! uSource->qbaTextureHash.isEmpty())
mpus.set_texture_hash(blob(uSource->qbaTextureHash));
else if (! uSource->qbaTexture.isEmpty())
mpus.set_texture(std::string(uSource->qbaTexture.constData(), uSource->qbaTexture.size()));
const QMap<int, QString> &info = getRegistration(uSource->iId);
if (info.contains(ServerDB::User_Comment)) {
uSource->qsComment = info.value(ServerDB::User_Comment);
mpus.set_comment(u8(uSource->qsComment));
hashAssign(uSource->qsComment, uSource->qbaCommentHash, info.value(ServerDB::User_Comment));
if (! uSource->qbaCommentHash.isEmpty())
mpus.set_comment_hash(blob(uSource->qbaCommentHash));
else if (! uSource->qsComment.isEmpty())
mpus.set_comment(u8(uSource->qsComment));
}
}
if (! uSource->qsHash.isEmpty())
@ -302,7 +313,13 @@ void Server::msgAuthenticate(ServerUser *uSource, MumbleProto::Authenticate &msg
if (uSource->cChannel->iId != 0)
mpus.set_channel_id(uSource->cChannel->iId);
sendAll(mpus);
sendAll(mpus, 0x010202);
if (! uSource->qbaTexture.isEmpty())
mpus.set_texture(blob(uSource->qbaTexture));
if (! uSource->qsComment.isEmpty())
mpus.set_comment(u8(uSource->qsComment));
sendAll(mpus, ~ 0x010202);
// Transmit other users profiles
foreach(ServerUser *u, qhUsers) {
@ -333,7 +350,9 @@ void Server::msgAuthenticate(ServerUser *uSource, MumbleProto::Authenticate &msg
mpus.set_self_deaf(true);
else if (u->bSelfMute)
mpus.set_self_mute(true);
if (! u->qsComment.isEmpty())
if ((uSource->uiVersion >= 0x010202) && ! u->qbaCommentHash.isEmpty())
mpus.set_comment_hash(blob(u->qbaCommentHash));
else if (! u->qsComment.isEmpty())
mpus.set_comment(u8(u->qsComment));
if (! u->qsHash.isEmpty())
mpus.set_hash(u8(u->qsHash));
@ -543,9 +562,11 @@ void Server::msgUserState(ServerUser *uSource, MumbleProto::UserState &msg) {
if (msg.has_comment()) {
pDstServerUser->qsComment = u8(msg.comment());
if (! bAllowHTML) {
pDstServerUser->qsComment = toPlainText(pDstServerUser->qsComment);
if (bAllowHTML) {
hashAssign(pDstServerUser->qsComment, pDstServerUser->qbaCommentHash, u8(msg.comment()));
} else {
hashAssign(pDstServerUser->qsComment, pDstServerUser->qbaCommentHash, toPlainText(u8(msg.comment())));
msg.set_comment(u8(pDstServerUser->qsComment));
}
@ -603,8 +624,18 @@ void Server::msgUserState(ServerUser *uSource, MumbleProto::UserState &msg) {
}
}
if (! bNoBroadcast)
sendAll(msg);
if (! bNoBroadcast) {
sendAll(msg, ~ 0x010202);
if (msg.has_texture() && ! pDstServerUser->qbaTextureHash.isEmpty()) {
msg.clear_texture();
msg.set_texture_hash(blob(pDstServerUser->qbaTextureHash));
}
if (msg.has_comment() && ! pDstServerUser->qbaCommentHash.isEmpty()) {
msg.clear_comment();
msg.set_comment_hash(blob(pDstServerUser->qbaCommentHash));
}
sendAll(msg, 0x010202);
}
emit userStateChanged(pDstServerUser);
}
@ -732,7 +763,7 @@ void Server::msgChannelState(ServerUser *uSource, MumbleProto::ChannelState &msg
}
c = addChannel(p, qsName, msg.temporary(), msg.position());
c->qsDesc = qsDesc;
hashAssign(c->qsDesc, c->qbaDescHash, qsDesc);
if (uSource->iId >= 0) {
Group *g = new Group(c, "admin");
@ -757,7 +788,13 @@ void Server::msgChannelState(ServerUser *uSource, MumbleProto::ChannelState &msg
msg.set_channel_id(c->iId);
log(uSource, QString("Added channel %1 under %2").arg(QString(*c), QString(*p)));
emit channelCreated(c);
sendAll(msg);
sendAll(msg, ~ 0x010202);
if (! c->qbaDescHash.isEmpty()) {
msg.clear_description();
msg.set_description_hash(blob(c->qbaDescHash));
}
sendAll(msg, 0x010202);
if (c->bTemporary) {
// If a temporary channel has been created move the creator right in there
@ -875,7 +912,7 @@ void Server::msgChannelState(ServerUser *uSource, MumbleProto::ChannelState &msg
c->qsName = qsName;
}
if (! qsDesc.isNull())
c->qsDesc = qsDesc;
hashAssign(c->qsDesc, c->qbaDescHash, qsDesc);
if (msg.has_position())
c->iPosition = msg.position();
@ -889,7 +926,13 @@ void Server::msgChannelState(ServerUser *uSource, MumbleProto::ChannelState &msg
updateChannel(c);
emit channelStateChanged(c);
sendAll(msg);
sendAll(msg, ~ 0x010202);
if (msg.has_description() && ! c->qbaDescHash.isEmpty()) {
msg.clear_description();
msg.set_description_hash(blob(c->qbaDescHash));
}
sendAll(msg, 0x010202);
}
}
@ -1444,3 +1487,45 @@ void Server::msgUserStats(ServerUser*uSource, MumbleProto::UserStats &msg) {
sendMessage(uSource, msg);
}
void Server::msgRequestBlob(ServerUser *uSource, MumbleProto::RequestBlob &msg) {
int ntextures = msg.session_texture_size();
int ncomments = msg.session_comment_size();
int ndescriptions = msg.channel_description_size();
if (ndescriptions) {
MumbleProto::ChannelState mpcs;
for(int i=0;i<ndescriptions;++i) {
int id = msg.channel_description(i);
Channel *c = qhChannels.value(id);
if (c && ! c->qsDesc.isEmpty()) {
mpcs.set_channel_id(id);
mpcs.set_description(u8(c->qsDesc));
sendMessage(uSource, mpcs);
}
}
}
if (ntextures || ncomments) {
MumbleProto::UserState mpus;
for(int i=0;i<ntextures;++i) {
int session = msg.session_texture(i);
ServerUser *su = qhUsers.value(session);
if (su && ! su->qbaTexture.isEmpty()) {
mpus.set_session(session);
mpus.set_texture(std::string(su->qbaTexture.constData(), su->qbaTexture.length()));
sendMessage(uSource, mpus);
}
}
if (ntextures)
mpus.clear_texture();
for(int i=0;i<ncomments;++i) {
int session = msg.session_comment(i);
ServerUser *su = qhUsers.value(session);
if (su && ! su->qsComment.isEmpty()) {
mpus.set_session(session);
mpus.set_comment(u8(su->qsComment));
sendMessage(uSource, mpus);
}
}
}
}

View File

@ -108,7 +108,7 @@ Server::Server(int snum, QObject *p) : QThread(p) {
iCodecAlpha = iCodecBeta = 0;
bPreferAlpha = false;
qnamNetwork = NULL;
readParams();
@ -1230,15 +1230,16 @@ void Server::sendProtoMessage(ServerUser *u, const ::google::protobuf::Message &
u->sendMessage(msg, msgType, cache);
}
void Server::sendProtoAll(const ::google::protobuf::Message &msg, unsigned int msgType) {
sendProtoExcept(NULL, msg, msgType);
void Server::sendProtoAll(const ::google::protobuf::Message &msg, unsigned int msgType, unsigned int minversion) {
sendProtoExcept(NULL, msg, msgType, minversion);
}
void Server::sendProtoExcept(ServerUser *u, const ::google::protobuf::Message &msg, unsigned int msgType) {
void Server::sendProtoExcept(ServerUser *u, const ::google::protobuf::Message &msg, unsigned int msgType, unsigned int minversion) {
QByteArray cache;
foreach(ServerUser *usr, qhUsers)
if ((usr != u) && (usr->sState == ServerUser::Authenticated))
usr->sendMessage(msg, msgType, cache);
if ((minversion == 0) || (usr->uiVersion >= minversion) || ((minversion & 0x80000000) && (usr->uiVersion < (~minversion))))
usr->sendMessage(msg, msgType, cache);
}
void Server::removeChannel(int id) {
@ -1501,6 +1502,7 @@ void Server::recheckCodecVersions() {
QMap<int, unsigned int> qmCodecUsercount;
QMap<int, unsigned int>::const_iterator i;
int users = 0;
// Count how many users use which codec
foreach(ServerUser *u, qhUsers) {
if (u->qlCodecs.isEmpty())
@ -1553,3 +1555,19 @@ void Server::recheckCodecVersions() {
log(QString::fromLatin1("CELT codec switch %1 %2 (prefer %3)").arg(iCodecAlpha,0,16).arg(iCodecBeta,0,16).arg(bPreferAlpha ? iCodecAlpha : iCodecBeta,0,16));
}
void Server::hashAssign(QString &dest, QByteArray &hash, const QString &src) {
dest = src;
if (src.length() > 128)
hash = sha1(dest);
else
hash = QByteArray();
}
void Server::hashAssign(QByteArray &dest, QByteArray &hash, const QByteArray &src) {
dest = src;
if (src.length() > 128)
hash = sha1(dest);
else
hash = QByteArray();
}

View File

@ -294,18 +294,21 @@ class Server : public QThread {
void flushClientPermissionCache(ServerUser *u, MumbleProto::PermissionQuery &mpqq);
void clearACLCache(User *p = NULL);
void sendProtoAll(const ::google::protobuf::Message &msg, unsigned int msgType);
void sendProtoExcept(ServerUser *, const ::google::protobuf::Message &msg, unsigned int msgType);
void sendProtoAll(const ::google::protobuf::Message &msg, unsigned int msgType, unsigned int minversion);
void sendProtoExcept(ServerUser *, const ::google::protobuf::Message &msg, unsigned int msgType, unsigned int minversion);
void sendProtoMessage(ServerUser *, const ::google::protobuf::Message &msg, unsigned int msgType);
#define MUMBLE_MH_MSG(x) \
void sendAll(const MumbleProto:: x &msg) { sendProtoAll(msg, MessageHandler:: x); } \
void sendExcept(ServerUser *u, const MumbleProto:: x &msg) { sendProtoExcept(u, msg, MessageHandler:: x); } \
void sendAll(const MumbleProto:: x &msg, unsigned int v = 0) { sendProtoAll(msg, MessageHandler:: x, v); } \
void sendExcept(ServerUser *u, const MumbleProto:: x &msg, unsigned int v = 0) { sendProtoExcept(u, msg, MessageHandler:: x, v); } \
void sendMessage(ServerUser *u, const MumbleProto:: x &msg) { sendProtoMessage(u, msg, MessageHandler:: x); }
MUMBLE_MH_ALL
#undef MUMBLE_MH_MSG
static void hashAssign(QString &destination, QByteArray &hash, const QString &str);
static void hashAssign(QByteArray &destination, QByteArray &hash, const QByteArray &source);
void setLiveConf(const QString &key, const QString &value);
QString addressToString(const QHostAddress &, unsigned short port);

View File

@ -762,7 +762,7 @@ int Server::authenticate(QString &name, const QString &pw, const QStringList &em
if (query.next()) {
res = -1;
QString storedpw = query.value(2).toString();
QString hashedpw = QString::fromLatin1(QCryptographicHash::hash(pw.toUtf8(), QCryptographicHash::Sha1).toHex());
QString hashedpw = QString::fromLatin1(sha1(pw).toHex());
if (! storedpw.isEmpty() && (storedpw == hashedpw)) {
name = query.value(1).toString();
@ -932,8 +932,8 @@ bool Server::setTexture(int id, const QByteArray &texture) {
tex = qCompress(tex);
ServerUser *u = qhUsers.value(id);
if (u)
u->qbaTexture = tex;
if (u)
hashAssign(u->qbaTexture, u->qbaTextureHash, tex);
int res = -2;
emit setTextureSig(res, id, tex);
@ -1248,7 +1248,7 @@ void Server::readChannelPrivs(Channel *c) {
int key = query.value(0).toInt();
const QString &value = query.value(1).toString();
if (key == ServerDB::Channel_Description) {
c->qsDesc = value;
hashAssign(c->qsDesc, c->qbaDescHash, value);
} else if (key == ServerDB::Channel_Position) {
c->iPosition = QVariant(value).toInt(); // If the conversion fails it'll return the default value 0
}