// Copyright 2005-2020 The Mumble Developers. All rights reserved. // Use of this source code is governed by a BSD-style license // that can be found in the LICENSE file at the root of the // Mumble source tree or at . #include #ifdef Q_OS_WIN # include "win.h" #endif #include "DBus.h" #include "Connection.h" #include "Message.h" #include "Server.h" #include "ServerUser.h" #include "ServerDB.h" #include #include #include #include #include #include #include #ifdef Q_OS_WIN # include #else # include #endif QDBusArgument &operator<<(QDBusArgument &a, const PlayerInfo &s) { a.beginStructure(); a << s.session << s.mute << s.deaf << s.suppressed << s.selfMute << s.selfDeaf << s.channel; a.endStructure(); return a; } const QDBusArgument & operator >>(const QDBusArgument &a, PlayerInfo &s) { a.beginStructure(); a >> s.session >> s.mute >> s.deaf >> s.suppressed >> s.selfMute >> s.selfDeaf >> s.channel; a.endStructure(); return a; } QDBusArgument &operator<<(QDBusArgument &a, const PlayerInfoExtended &s) { a.beginStructure(); a << s.session << s.mute << s.deaf << s.suppressed << s.selfMute << s.selfDeaf << s.channel << s.id << s.name << s.onlinesecs << s.bytespersec; a.endStructure(); return a; } const QDBusArgument & operator >>(const QDBusArgument &a, PlayerInfoExtended &s) { a.beginStructure(); a >> s.session >> s.mute >> s.deaf >> s.suppressed >> s.selfMute >> s.selfDeaf >> s.channel >> s.id >> s.name >> s.onlinesecs >> s.bytespersec; a.endStructure(); return a; } QDBusArgument &operator<<(QDBusArgument &a, const ChannelInfo &s) { a.beginStructure(); a << s.id << s.name << s.parent << s.links; a.endStructure(); return a; } const QDBusArgument & operator >>(const QDBusArgument &a, ChannelInfo &s) { a.beginStructure(); a >> s.id >> s.name >> s.parent >> s.links; a.endStructure(); return a; } QDBusArgument &operator<<(QDBusArgument &a, const GroupInfo &s) { a.beginStructure(); a << s.name << s.inherited << s.inherit << s.inheritable; a << s.add << s.remove << s.members; a.endStructure(); return a; } const QDBusArgument & operator >>(const QDBusArgument &a, GroupInfo &s) { a.beginStructure(); a >> s.name >> s.inherited >> s.inherit >> s.inheritable; a >> s.add >> s.remove >> s.members; a.endStructure(); return a; } QDBusArgument &operator<<(QDBusArgument &a, const ACLInfo &s) { a.beginStructure(); a << s.applyHere << s.applySubs << s.inherited; a << s.playerid << s.group; a << s.allow << s.deny; a.endStructure(); return a; } const QDBusArgument & operator >>(const QDBusArgument &a, ACLInfo &s) { a.beginStructure(); a >> s.applyHere >> s.applySubs >> s.inherited; a >> s.playerid >> s.group; a >> s.allow >> s.deny; a.endStructure(); return a; } QDBusArgument &operator<<(QDBusArgument &a, const BanInfo &s) { a.beginStructure(); a << s.address << s.bits; a.endStructure(); return a; } const QDBusArgument & operator >>(const QDBusArgument &a, BanInfo &s) { a.beginStructure(); a >> s.address >> s.bits; a.endStructure(); return a; } QDBusArgument &operator<<(QDBusArgument &a, const RegisteredPlayer &s) { a.beginStructure(); a << s.id << s.name << s.email << s.pw; a.endStructure(); return a; } const QDBusArgument & operator >>(const QDBusArgument &a, RegisteredPlayer &s) { a.beginStructure(); a >> s.id >> s.name >> s.email >> s.pw; a.endStructure(); return a; } QDBusArgument &operator<<(QDBusArgument &a, const LogEntry &s) { a.beginStructure(); a << s.timestamp << s.txt; a.endStructure(); return a; } const QDBusArgument & operator >>(const QDBusArgument &a, LogEntry &s) { a.beginStructure(); a >> s.timestamp >> s.txt; a.endStructure(); return a; } void MurmurDBus::registerTypes() { qDBusRegisterMetaType(); qDBusRegisterMetaType(); qDBusRegisterMetaType >(); qDBusRegisterMetaType(); qDBusRegisterMetaType >(); qDBusRegisterMetaType(); qDBusRegisterMetaType >(); qDBusRegisterMetaType(); qDBusRegisterMetaType >(); qDBusRegisterMetaType(); qDBusRegisterMetaType >(); qDBusRegisterMetaType(); qDBusRegisterMetaType >(); qDBusRegisterMetaType(); qDBusRegisterMetaType(); qDBusRegisterMetaType >(); } QDBusConnection *MurmurDBus::qdbc = NULL; MurmurDBus::MurmurDBus(Server *srv) : QDBusAbstractAdaptor(srv) { server = srv; srv->connectListener(this); } void MurmurDBus::removeAuthenticator() { server->disconnectAuthenticator(this); qsAuthPath = QString(); qsAuthService = QString(); } void MurmurDBus::idToNameSlot(QString &name, int id) { QDBusInterface remoteApp(qsAuthService,qsAuthPath,QString(),*qdbc); QDBusReply reply = remoteApp.call(bReentrant ? QDBus::BlockWithGui : QDBus::Block, "getUserName",id); if (reply.isValid()) name = reply.value(); else { server->log(QString("DBus Authenticator failed getUserName for %1: %2").arg(QString::number(id), QString(reply.error().message()))); removeAuthenticator(); } } void MurmurDBus::idToTextureSlot(QByteArray &qba, int id) { QDBusInterface remoteApp(qsAuthService,qsAuthPath,QString(),*qdbc); QDBusReply reply = remoteApp.call(bReentrant ? QDBus::BlockWithGui : QDBus::Block, "getUserTexture",id); if (reply.isValid()) { qba = reply.value(); } } void MurmurDBus::nameToIdSlot(int &id, const QString &name) { QDBusInterface remoteApp(qsAuthService,qsAuthPath,QString(),*qdbc); QDBusReply reply = remoteApp.call(bReentrant ? QDBus::BlockWithGui : QDBus::Block, "getUserId",name); if (reply.isValid()) id = reply.value(); else { server->log(QString("DBus Authenticator failed getUserId for %1: %2").arg(name).arg(reply.error().message())); removeAuthenticator(); } } void MurmurDBus::registerUserSlot(int &res, const QMap &info) { QDBusInterface remoteApp(qsAuthService,qsAuthPath,QString(),*qdbc); QDBusReply reply = remoteApp.call(bReentrant ? QDBus::BlockWithGui : QDBus::Block, "registerPlayer", info.value(ServerDB::User_Name)); if (reply.isValid()) { res = reply.value(); if ((info.count() > 1) && (res > 0)) setInfoSlot(res, res, info); } } void MurmurDBus::unregisterUserSlot(int &res, int id) { QDBusInterface remoteApp(qsAuthService,qsAuthPath,QString(),*qdbc); QDBusReply reply = remoteApp.call(bReentrant ? QDBus::BlockWithGui : QDBus::Block, "unregisterPlayer", id); if (reply.isValid()) res = reply.value(); } void MurmurDBus::getRegistrationSlot(int &res, int id, QMap &info) { QDBusInterface remoteApp(qsAuthService,qsAuthPath,QString(),*qdbc); QDBusReply reply = remoteApp.call(bReentrant ? QDBus::BlockWithGui : QDBus::Block, "getRegistration", id); if (reply.isValid()) { const RegisteredPlayer &r = reply.value(); info.insert(ServerDB::User_Name, r.name); if (! r.email.isEmpty()) info.insert(ServerDB::User_Email, r.email); res = 1; } } void MurmurDBus::getRegisteredUsersSlot(const QString &filter, QMap &m) { QDBusInterface remoteApp(qsAuthService,qsAuthPath,QString(),*qdbc); QDBusReply > reply = remoteApp.call(bReentrant ? QDBus::BlockWithGui : QDBus::Block, "getRegisteredPlayers", filter); if (reply.isValid()) { const QList &r = reply.value(); foreach(const RegisteredPlayer &p, r) { m.insert(p.id, p.name); } } } void MurmurDBus::setInfoSlot(int &res, int id, const QMap &info) { if (info.contains(ServerDB::User_Name)) { QDBusInterface remoteApp(qsAuthService,qsAuthPath,QString(),*qdbc); QDBusReply reply = remoteApp.call(bReentrant ? QDBus::BlockWithGui : QDBus::Block, "setName",id, info.value(ServerDB::User_Name)); if (reply.isValid()) res = reply.value(); } if (info.contains(ServerDB::User_Password)) { QDBusInterface remoteApp(qsAuthService,qsAuthPath,QString(),*qdbc); QDBusReply reply = remoteApp.call(bReentrant ? QDBus::BlockWithGui : QDBus::Block, "setPW",id, info.value(ServerDB::User_Password)); if (reply.isValid()) res = reply.value(); } if (info.contains(ServerDB::User_Email)) { QDBusInterface remoteApp(qsAuthService,qsAuthPath,QString(),*qdbc); QDBusReply reply = remoteApp.call(bReentrant ? QDBus::BlockWithGui : QDBus::Block, "setEmail",id, info.value(ServerDB::User_Email)); if (reply.isValid()) res = reply.value(); } } void MurmurDBus::setTextureSlot(int &res, int id, const QByteArray &texture) { QDBusInterface remoteApp(qsAuthService,qsAuthPath,QString(),*qdbc); QDBusReply reply = remoteApp.call(bReentrant ? QDBus::BlockWithGui : QDBus::Block, "setTexture",id, texture); if (reply.isValid()) res = reply.value(); } void MurmurDBus::authenticateSlot(int &res, QString &uname, int sessionId, const QList &, const QString &, bool, const QString &pw) { QDBusInterface remoteApp(qsAuthService,qsAuthPath,QString(),*qdbc); QDBusMessage msg = remoteApp.call(bReentrant ? QDBus::BlockWithGui : QDBus::Block, "authenticate",uname,pw); QDBusError err = msg; if (! err.isValid()) { QString newname; int uid = -2; bool ok = true; if (msg.arguments().count() >= 1) { uid = msg.arguments().at(0).toInt(&ok); } if (ok && (msg.arguments().count() >= 2)) { newname = msg.arguments().at(1).toString(); if (! newname.isEmpty()) { uname = newname; } } if (ok && (msg.arguments().count() >= 3)) { server->setTempGroups(uid, sessionId, NULL, msg.arguments().at(2).toStringList()); } if (ok) { server->log(QString("DBus Authenticate success for %1: %2").arg(uname).arg(uid)); res = uid; } else { server->log(QString("DBus Autenticator failed authenticate for %1: Invalid return type").arg(uname)); } } else { server->log(QString("DBus Authenticator failed authenticate for %1: %2").arg(uname).arg(err.message())); removeAuthenticator(); } } #define PLAYER_SETUP_VAR(var) \ ServerUser *pUser = server->qhUsers.value(var); \ if (! pUser) { \ qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.session", "Invalid session id")); \ return; \ } #define PLAYER_SETUP PLAYER_SETUP_VAR(session) #define CHANNEL_SETUP_VAR2(dst,var) \ Channel *dst = server->qhChannels.value(var); \ if (! dst) { \ qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.channel", "Invalid channel id")); \ return; \ } #define CHANNEL_SETUP_VAR(var) CHANNEL_SETUP_VAR2(cChannel,var) void MurmurDBus::getPlayers(QList &a) { a.clear(); foreach(ServerUser *p, server->qhUsers) { if (static_cast(p)->sState == ServerUser::Authenticated) a << PlayerInfoExtended(p); } } void MurmurDBus::getChannels(QList &a) { a.clear(); QQueue q; q << server->qhChannels.value(0); while (! q.isEmpty()) { Channel *c = q.dequeue(); a << ChannelInfo(c); foreach(c, c->qlChannels) q.enqueue(c); } } void MurmurDBus::kickPlayer(unsigned int session, const QString &reason, const QDBusMessage &msg) { PLAYER_SETUP; Connection *c = server->qhUsers.value(session); if (!c) return; MumbleProto::UserRemove mpur; mpur.set_session(session); mpur.set_reason(u8(reason)); server->sendAll(mpur); c->disconnectSocket(); } void MurmurDBus::getPlayerState(unsigned int session, const QDBusMessage &msg, PlayerInfo &pi) { PLAYER_SETUP; pi = PlayerInfo(pUser); } void MurmurDBus::setPlayerState(const PlayerInfo &npi, const QDBusMessage &msg) { PLAYER_SETUP_VAR(npi.session); CHANNEL_SETUP_VAR(npi.channel); PlayerInfo pi(pUser); server->setUserState(pUser, cChannel, npi.mute, npi.deaf, pUser->bPrioritySpeaker, npi.suppressed); } void MurmurDBus::sendMessage(unsigned int session, const QString &text, const QDBusMessage &msg) { PLAYER_SETUP; server->sendTextMessage(NULL, pUser, false, text); } void MurmurDBus::sendMessageChannel(int id, bool tree, const QString &text, const QDBusMessage &msg) { CHANNEL_SETUP_VAR(id); server->sendTextMessage(cChannel, NULL, tree, text); } void MurmurDBus::addChannel(const QString &name, int chanparent, const QDBusMessage &msg, int &newid) { CHANNEL_SETUP_VAR(chanparent); Channel *nc; { QWriteLocker wl(&server->qrwlVoiceThread); nc = server->addChannel(cChannel, name); } server->updateChannel(nc); newid = nc->iId; MumbleProto::ChannelState mpcs; mpcs.set_channel_id(nc->iId); mpcs.set_parent(cChannel->iId); mpcs.set_name(u8(name)); server->sendAll(mpcs); } void MurmurDBus::removeChannel(int id, const QDBusMessage &msg) { CHANNEL_SETUP_VAR(id); if (!cChannel->cParent) { qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.channel", "Invalid channel id")); return; } QWriteLocker wl(&server->qrwlVoiceThread); server->removeChannel(cChannel); } void MurmurDBus::getChannelState(int id, const QDBusMessage &msg, ChannelInfo &state) { CHANNEL_SETUP_VAR(id); state = ChannelInfo(cChannel); } void MurmurDBus::setChannelState(const ChannelInfo &nci, const QDBusMessage &msg) { CHANNEL_SETUP_VAR(nci.id); CHANNEL_SETUP_VAR2(cParent, nci.parent); QSet newset; foreach(int id, nci.links) { CHANNEL_SETUP_VAR2(cLink, id); newset << cLink; } if (! server->setChannelState(cChannel, cParent, nci.name, newset)) { qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.channel", "Moving channel to subchannel")); return; } } void MurmurDBus::getACL(int id, const QDBusMessage &msg, QList &acls, QList &groups, bool &inherit) { CHANNEL_SETUP_VAR(id); QStack chans; Channel *p; ChanACL *acl; p = cChannel; while (p) { chans.push(p); if ((p == cChannel) || (p->bInheritACL)) p = p->cParent; else p =NULL; } inherit = cChannel->bInheritACL; while (! chans.isEmpty()) { p = chans.pop(); foreach(acl, p->qlACL) { if ((p==cChannel) || (acl->bApplySubs)) { ACLInfo ai(acl); if (p != cChannel) ai.inherited = true; acls << ai; } } } p = cChannel->cParent; QSet allnames = Group::groupNames(cChannel); QString name; foreach(name, allnames) { Group *g = cChannel->qhGroups.value(name); Group *pg = p ? Group::getGroup(p, name) : NULL; if (!g && ! pg) continue; GroupInfo gi(g ? g : pg); QSet members; if (pg) members = pg->members(); if (g) { gi.add = g->qsAdd.values(); gi.remove = g->qsRemove.values(); gi.inherited = false; members+=g->qsAdd; members-=g->qsRemove; } else { gi.inherited = true; } gi.members = members.values(); groups << gi; } } void MurmurDBus::setACL(int id, const QList &acls, const QList &groups, bool inherit, const QDBusMessage &msg) { CHANNEL_SETUP_VAR(id); Group *g; ChanACL *a; ACLInfo ai; GroupInfo gi; QHash > hOldTemp; foreach(g, cChannel->qhGroups) { hOldTemp.insert(g->qsName, g->qsTemporary); delete g; } foreach(a, cChannel->qlACL) delete a; cChannel->qhGroups.clear(); cChannel->qlACL.clear(); cChannel->bInheritACL = inherit; foreach(gi, groups) { g = new Group(cChannel, gi.name); g->bInherit=gi.inherit; g->bInheritable=gi.inheritable; #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) g->qsAdd = QSet(gi.add.begin(), gi.add.end()); g->qsRemove = QSet(gi.remove.begin(), gi.remove.end()); #else // In Qt 5.14 QList::toSet() has been deprecated as there exists a dedicated constructor of QSet for this now g->qsAdd = gi.add.toSet(); g->qsRemove = gi.remove.toSet(); #endif g->qsTemporary = hOldTemp.value(gi.name); } foreach(ai, acls) { a = new ChanACL(cChannel); a->bApplyHere = ai.applyHere; a->bApplySubs = ai.applySubs; a->iUserId = ai.playerid; a->qsGroup = ai.group; a->pDeny = static_cast(ai.deny) & ChanACL::All; a->pAllow = static_cast(ai.allow) & ChanACL::All; } server->clearACLCache(); server->updateChannel(cChannel); } void MurmurDBus::getBans(QList &bi) { bi.clear(); foreach(const Ban &b, server->qlBans) { if (! b.haAddress.isV6()) bi << BanInfo(b); } } void MurmurDBus::setBans(const QList &, const QDBusMessage &) { } void MurmurDBus::getPlayerNames(const QList &ids, const QDBusMessage &, QStringList &names) { names.clear(); foreach(int id, ids) { names << server->getUserName(id); } } void MurmurDBus::getPlayerIds(const QStringList &names, const QDBusMessage &, QList &ids) { ids.clear(); foreach(QString name, names) { ids << server->getUserID(name); } } void MurmurDBus::registerPlayer(const QString &name, const QDBusMessage &msg, int &id) { QMap info; info.insert(ServerDB::User_Name, name); id = server->registerUser(info); if (id < 0) { qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.playername", "Illegal player name")); return; } } void MurmurDBus::unregisterPlayer(int id, const QDBusMessage &msg) { if (! server->unregisterUser(id)) { qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.playerid", "Invalid player id")); return; } } void MurmurDBus::getRegistration(int id, const QDBusMessage &msg, RegisteredPlayer &user) { QMap info = server->getRegistration(id); if (info.isEmpty()) { qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.playerid", "Invalid player id")); return; } user.id = id; user.name = info.value(ServerDB::User_Name); user.email = info.value(ServerDB::User_Email); } void MurmurDBus::setRegistration(int id, const QString &name, const QString &email, const QString &pw, const QDBusMessage &msg) { RegisteredPlayer user; user.id = id; user.name = name; user.email = email; user.pw = pw; updateRegistration(user, msg); } void MurmurDBus::updateRegistration(const RegisteredPlayer &user, const QDBusMessage &msg) { QMap info; if (! user.name.isEmpty()) info.insert(ServerDB::User_Name, user.name); if (! user.email.isEmpty()) info.insert(ServerDB::User_Email, user.email); if (! user.pw.isEmpty()) info.insert(ServerDB::User_Password, user.pw); if (info.isEmpty() || !server->setInfo(user.id, info)) { qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.playerid", "Invalid player id")); return; } } void MurmurDBus::getTexture(int id, const QDBusMessage &msg, QByteArray &texture) { if (! server->isUserId(id)) { qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.playerid", "Invalid player id")); return; } texture = server->getUserTexture(id); } void MurmurDBus::setTexture(int id, const QByteArray &texture, const QDBusMessage &msg) { if (! server->isUserId(id)) { qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.playerid", "Invalid player id")); return; } if (! server->setTexture(id, texture)) { qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.texture", "Invalid texture")); return; } } void MurmurDBus::getRegisteredPlayers(const QString &filter, QList &users) { users.clear(); QMap l = server->getRegisteredUsers(filter); QMap::const_iterator i; for (i = l.constBegin(); i != l.constEnd(); ++i) { RegisteredPlayer r; r.id = i.key(); r.name = i.value(); users << r; } } void MurmurDBus::verifyPassword(int id, const QString &pw, const QDBusMessage &msg, bool &ok) { QList ids; ids << id; QStringList names; getPlayerNames(ids, msg, names); if ((names.count() != 1) || (names.at(0).isEmpty())) { qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.playerid", "Invalid player id")); return; } QString name = names.at(0); int nid = server->authenticate(name, pw); if (nid == id) ok = true; else ok = false; } #ifdef Q_OS_WIN #undef interface #endif void MurmurDBus::setAuthenticator(const QDBusObjectPath &path, bool reentrant, const QDBusMessage &msg) { if (! qsAuthPath.isNull() || ! qsAuthService.isNull()) removeAuthenticator(); server->connectAuthenticator(this); qsAuthPath = path.path(); qsAuthService = msg.service(); QDBusConnectionInterface *interface = qdbc->interface(); QDBusReply names = interface->registeredServiceNames(); if (names.isValid()) { foreach(const QString &name, names.value()) { QDBusReply owner = interface->serviceOwner(name); if (owner.isValid() && (owner.value() != name) && (owner.value() == qsAuthService)) { qsAuthService = name; break; } } } bReentrant = reentrant; server->log(QString("DBus Authenticator set to %1 %2 (%3)").arg(qsAuthService, qsAuthPath, QString::number(reentrant))); } void MurmurDBus::setTemporaryGroups(int channel, int userid, const QStringList &groups, const QDBusMessage &msg) { CHANNEL_SETUP_VAR(channel); server->setTempGroups(userid, 0, cChannel, groups); } PlayerInfo::PlayerInfo(const User *p) { session = p->uiSession; mute = p->bMute; deaf = p->bDeaf; suppressed = p->bSuppress; selfMute = p->bSelfMute; selfDeaf = p->bSelfDeaf; channel = p->cChannel->iId; } PlayerInfoExtended::PlayerInfoExtended(const User *p) : PlayerInfo(p) { id = p->iId; name = p->qsName; const ServerUser *u = static_cast(p); onlinesecs = u->bwr.onlineSeconds(); bytespersec = u->bwr.bandwidth(); } ChannelInfo::ChannelInfo(const Channel *c) { id = c->iId; name = c->qsName; parent = c->cParent ? c->cParent->iId : -1; foreach(Channel *chn, c->qsPermLinks) links << chn->iId; } ACLInfo::ACLInfo(const ChanACL *acl) { applyHere = acl->bApplyHere; applySubs = acl->bApplySubs; inherited = false; playerid = acl->iUserId; group = acl->qsGroup; allow = acl->pAllow; deny = acl->pDeny; } GroupInfo::GroupInfo(const Group *g) : inherited(false) { name = g->qsName; inherit = g->bInherit; inheritable = g->bInheritable; members.clear(); } BanInfo::BanInfo(const Ban &b) { address = ntohl(b.haAddress.hash[3]); bits = b.iMask; } RegisteredPlayer::RegisteredPlayer() { id = -1; } LogEntry::LogEntry() { timestamp = 0; } LogEntry::LogEntry(const ServerDB::LogRecord &r) { timestamp = r.first; txt = r.second; } void MurmurDBus::userStateChanged(const User *p) { emit playerStateChanged(PlayerInfo(p)); } void MurmurDBus::userTextMessage(const User *, const TextMessage &) { // Not implemented for DBus. } void MurmurDBus::userConnected(const User *p) { emit playerConnected(PlayerInfo(p)); } void MurmurDBus::userDisconnected(const User *p) { emit playerDisconnected(PlayerInfo(p)); } void MurmurDBus::channelStateChanged(const Channel *c) { emit channelStateChanged(ChannelInfo(c)); } void MurmurDBus::channelCreated(const Channel *c) { emit channelCreated(ChannelInfo(c)); } void MurmurDBus::channelRemoved(const Channel *c) { emit channelRemoved(ChannelInfo(c)); } MetaDBus::MetaDBus(Meta *m) : QDBusAbstractAdaptor(m) { meta = m; m->connectListener(this); } void MetaDBus::started(Server *s) { new MurmurDBus(s); if (MurmurDBus::qdbc->isConnected()) MurmurDBus::qdbc->registerObject(QString::fromLatin1("/%1").arg(s->iServerNum), s); emit started(s->iServerNum); } void MetaDBus::stopped(Server *s) { emit stopped(s->iServerNum); } void MetaDBus::start(int server_id, const QDBusMessage &msg) { if (meta->qhServers.contains(server_id)) { MurmurDBus::qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.booted", "Server already booted")); } else if (! ServerDB::serverExists(server_id)) { MurmurDBus::qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.server", "Invalid server id")); } else if (! meta->boot(server_id)) { MurmurDBus::qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.bootfail", "Booting server failed")); } } void MetaDBus::stop(int server_id, const QDBusMessage &msg) { if (! meta->qhServers.contains(server_id)) { MurmurDBus::qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.booted", "Server not booted")); } else { meta->kill(server_id); } } void MetaDBus::newServer(int &server_id) { server_id = ServerDB::addServer(); } void MetaDBus::deleteServer(int server_id, const QDBusMessage &msg) { if (meta->qhServers.contains(server_id)) { MurmurDBus::qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.booted", "Server is running")); } else if (! ServerDB::serverExists(server_id)) { MurmurDBus::qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.server", "Invalid server id")); } else { ServerDB::deleteServer(server_id); } } void MetaDBus::getBootedServers(QList &server_list) { server_list = meta->qhServers.keys(); } void MetaDBus::getAllServers(QList &server_list) { server_list = ServerDB::getAllServers(); } void MetaDBus::isBooted(int server_id, bool &booted) { booted = meta->qhServers.contains(server_id); } void MetaDBus::getConf(int server_id, const QString &key, const QDBusMessage &msg, QString &value) { if (! ServerDB::serverExists(server_id)) { MurmurDBus::qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.server", "Invalid server id")); } else { if (key == "key" || key == "passphrase") MurmurDBus::qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.writeonly", "Requested read of write-only field.")); else value = ServerDB::getConf(server_id, key).toString(); } } void MetaDBus::setConf(int server_id, const QString &key, const QString &value, const QDBusMessage &msg) { if (! ServerDB::serverExists(server_id)) { MurmurDBus::qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.server", "Invalid server id")); } else { ServerDB::setConf(server_id, key, value); Server *s = meta->qhServers.value(server_id); if (s) s->setLiveConf(key, value); } } void MetaDBus::getAllConf(int server_id, const QDBusMessage &msg, ConfigMap &values) { if (! ServerDB::serverExists(server_id)) { MurmurDBus::qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.server", "Invalid server id")); } else { values = ServerDB::getAllConf(server_id); values.remove("key"); values.remove("passphrase"); } } void MetaDBus::getLog(int server_id, int min_offset, int max_offset, const QDBusMessage &msg, QList &entries) { if (! ServerDB::serverExists(server_id)) { MurmurDBus::qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.server", "Invalid server id")); } else { entries.clear(); QList dblog = ServerDB::getLog(server_id, min_offset, max_offset); foreach(const ServerDB::LogRecord &e, dblog) { entries << LogEntry(e); } } } void MetaDBus::getDefaultConf(ConfigMap &values) { values = Meta::mp.qmConfig; values.remove("key"); values.remove("passphrase"); } void MetaDBus::setSuperUserPassword(int server_id, const QString &pw, const QDBusMessage &msg) { if (! ServerDB::serverExists(server_id)) { MurmurDBus::qdbc->send(msg.createErrorReply("net.sourceforge.mumble.Error.server", "Invalid server id")); } else { ServerDB::setSUPW(server_id, pw); } } void MetaDBus::quit() { qCritical("Quit requested from D-Bus"); QCoreApplication::instance()->quit(); } void MetaDBus::getVersion(int &major, int &minor, int &patch, QString &text) { Meta::getVersion(major, minor, patch, text); }