1 // Copyright 2005-2019 The Mumble Developers. All rights reserved.
2 // Use of this source code is governed by a BSD-style license
3 // that can be found in the LICENSE file at the root of the
4 // Mumble source tree or at <https://www.mumble.info/LICENSE>.
5 
6 #ifndef Q_MOC_RUN
7 # include <boost/function.hpp>
8 #endif
9 
10 #include "murmur_pch.h"
11 
12 #include "Mumble.pb.h"
13 
14 #include "../Message.h"
15 #include "../Group.h"
16 #include "MurmurGRPCImpl.h"
17 #include "ServerDB.h"
18 #include "ServerUser.h"
19 #include "Server.h"
20 #include "Channel.h"
21 #include "Utils.h"
22 
23 #include <chrono>
24 
25 #include <QtCore/QStack>
26 
27 #include "MurmurRPC.proto.Wrapper.cpp"
28 
29 // GRPC system overview
30 // ====================
31 //
32 // Definitions:
33 //
34 //  - Completion queue: a mechanism used for handling asynchronous grpc
35 //    requests. Whenever you want to do something with grpc (e.g. accept a
36 //    remote call, read/write a message), the completion queue manages that
37 //    request for you.
38 //
39 //    When you wish to perform an asynchronous action, you provide the
40 //    completion queue with a unique "tag". This tag used to identify the
41 //    request after it has finished.
42 //
43 //    To check the status of asynchronous actions that have been added to the
44 //    completion queue, you call its "Next" method. Next returns when there is
45 //    a finished action in the completion queue. Next provides two output
46 //    variables: the completed action's tag, and a boolean, which indicates if
47 //    the action was successful. All tags in this project are are
48 //    heap-allocated pointers to "boost::function"s that accept a boolean.
49 //    After Next returns, the tag pointer is dereferenced, executed with the
50 //    success variable, and then freed.
51 //
52 //  - Wrapper class: each RPC method that is defined in the .proto has had a
53 //    class generated for it (the generator program is located in scripts/).
54 //    Each class provides storage for the incoming and outgoing protocol buffer
55 //    message, as well as helper methods for registering events with the
56 //    completion queue. Each wrapper class also has an "impl(bool)" method;
57 //    each one is implemented in this file. This impl method gets executed when
58 //    the particular RPC method gets invoked by an RPC client.
59 //
60 //    Each wrapper class extends RPCCall. Among other things, RPCCall provides
61 //    reference counting for the object. This is needed for memory management,
62 //    as the wrapper objects can be used and stored in several locations (this
63 //    is only really true for streaming grpc calls).
64 //
65 // The flow of the grpc system is as follows:
66 //
67 //  - GRPCStart() is called from murmur's main().
68 //  - If an address for the grpc has been set in murmur.ini, the grpc service
69 //    begins listening on that address for grpc client connections.
70 //  - A new thread is created which handles the grpc completion queue (defined
71 //    above). This thread continuously calls the completion queue's Next method
72 //    to process the next completed event.
73 //  - The wrapper classes' "create" methods are executed, which makes them
74 //    invokable by grpc clients.
75 //  - With the completion queue now running in the background, murmur
76 //    continues starting up.
77 //
78 //  - When a grpc client invokes an RPC method, the previously mentioned thread
79 //    is notified of this and executes the "tag" (recall, tags are pointers to
80 //    functions). The wrapper method "impl(bool)" for the corresponding RPC
81 //    method ends up being called. It is important to note that this impl
82 //    method gets executed in the main thread. This prevents data corruption
83 //    of murmur's data structures without the need of locks.
84 //
85 //    Additionally, the execution of tags are wrapped with a try-catch. This
86 //    try-catch catches any grpc::Status that is thrown. If one is caught, the
87 //    status is automatically sent to the grpc client and the invocation of the
88 //    current method is stopped.
89 
90 static MurmurRPCImpl *service;
91 
GRPCStart()92 void GRPCStart() {
93 	const auto &address = meta->mp.qsGRPCAddress;
94 	if (address.isEmpty()) {
95 		return;
96 	}
97 	const auto &cert = meta->mp.qsGRPCCert;
98 	const auto &key = meta->mp.qsGRPCKey;
99 	std::shared_ptr<::grpc::ServerCredentials> credentials;
100 	if (cert.isEmpty() || key.isEmpty()) {
101 		credentials = ::grpc::InsecureServerCredentials();
102 	} else {
103 		::grpc::SslServerCredentialsOptions options;
104 		::grpc::SslServerCredentialsOptions::PemKeyCertPair pair;
105 		{
106 			QFile file(cert);
107 			if (!file.open(QIODevice::ReadOnly)) {
108 				qFatal("could not open gRPC certificate file: %s", cert.toStdString().c_str());
109 				return;
110 			}
111 			QTextStream stream(&file);
112 			auto contents = stream.readAll();
113 			pair.cert_chain = contents.toStdString();
114 		}
115 		{
116 			QFile file(key);
117 			if (!file.open(QIODevice::ReadOnly)) {
118 				qFatal("could not open gRPC key file: %s", key.toStdString().c_str());
119 				return;
120 			}
121 			QTextStream stream(&file);
122 			auto contents = stream.readAll();
123 			pair.private_key = contents.toStdString();
124 		}
125 		options.pem_key_cert_pairs.push_back(pair);
126 		credentials = ::grpc::SslServerCredentials(options);
127 	}
128 
129 	service = new MurmurRPCImpl(address, credentials);
130 
131 	qWarning("GRPC: listening on '%s'", qPrintable(address));
132 }
133 
GRPCStop()134 void GRPCStop() {
135 	if (service) {
136 		delete service;
137 	}
138 }
139 
MurmurRPCImpl(const QString & address,std::shared_ptr<::grpc::ServerCredentials> credentials)140 MurmurRPCImpl::MurmurRPCImpl(const QString &address, std::shared_ptr<::grpc::ServerCredentials> credentials) {
141 	::grpc::ServerBuilder builder;
142 	builder.AddListeningPort(u8(address), credentials);
143 	builder.RegisterService(&m_V1Service);
144 	m_completionQueue = builder.AddCompletionQueue();
145 	m_server = builder.BuildAndStart();
146 	meta->connectListener(this);
147 	m_isRunning = true;
148 	start();
149 }
150 
~MurmurRPCImpl()151 MurmurRPCImpl::~MurmurRPCImpl() {
152 	void *ignored_tag;
153 	bool ignored_ok;
154 	m_isRunning = false;
155 	m_server->Shutdown(std::chrono::system_clock::now());
156 	m_completionQueue->Shutdown();
157 	while (m_completionQueue->Next(&ignored_tag, &ignored_ok)) {
158 		if (ignored_tag) {
159 			auto op = static_cast<boost::function<void(bool)> *>(ignored_tag);
160 			delete op;
161 		}
162 	}
163 }
164 
165 // ToRPC/FromRPC methods convert data to/from grpc protocol buffer messages.
ToRPC(const::Server * srv,const::Channel * c,::MurmurRPC::Channel * rc)166 void ToRPC(const ::Server *srv, const ::Channel *c, ::MurmurRPC::Channel *rc) {
167 	rc->mutable_server()->set_id(srv->iServerNum);
168 
169 	rc->set_id(c->iId);
170 	rc->set_name(u8(c->qsName));
171 	if (c->cParent) {
172 		rc->mutable_parent()->mutable_server()->set_id(srv->iServerNum);
173 		rc->mutable_parent()->set_id(c->cParent->iId);
174 	}
175 	rc->set_description(u8(c->qsDesc));
176 	rc->set_position(c->iPosition);
177 	foreach(::Channel *chn, c->qsPermLinks) {
178 		::MurmurRPC::Channel *linked = rc->add_links();
179 		linked->mutable_server()->set_id(srv->iServerNum);
180 		linked->set_id(chn->iId);
181 	}
182 	rc->set_temporary(c->bTemporary);
183 }
184 
ToRPC(const::Server * srv,const::User * u,::MurmurRPC::User * ru)185 void ToRPC(const ::Server *srv, const ::User *u, ::MurmurRPC::User *ru) {
186 	ru->mutable_server()->set_id(srv->iServerNum);
187 
188 	ru->set_session(u->uiSession);
189 	if (u->iId >= 0) {
190 		ru->set_id(u->iId);
191 	}
192 	ru->set_name(u8(u->qsName));
193 	ru->set_mute(u->bMute);
194 	ru->set_deaf(u->bDeaf);
195 	ru->set_suppress(u->bSuppress);
196 	ru->set_recording(u->bRecording);
197 	ru->set_priority_speaker(u->bPrioritySpeaker);
198 	ru->set_self_mute(u->bSelfMute);
199 	ru->set_self_deaf(u->bSelfDeaf);
200 	ru->mutable_channel()->mutable_server()->set_id(srv->iServerNum);
201 	ru->mutable_channel()->set_id(u->cChannel->iId);
202 	ru->set_comment(u8(u->qsComment));
203 
204 	const auto su = static_cast<const ServerUser *>(u);
205 	ru->set_online_secs(su->bwr.onlineSeconds());
206 	ru->set_bytes_per_sec(su->bwr.bandwidth());
207 	ru->mutable_version()->set_version(su->uiVersion);
208 	ru->mutable_version()->set_release(u8(su->qsRelease));
209 	ru->mutable_version()->set_os(u8(su->qsOS));
210 	ru->mutable_version()->set_os_version(u8(su->qsOSVersion));
211 	ru->set_plugin_identity(u8(su->qsIdentity));
212 	ru->set_plugin_context(su->ssContext);
213 	ru->set_idle_secs(su->bwr.idleSeconds());
214 	ru->set_udp_ping_msecs(su->dUDPPingAvg);
215 	ru->set_tcp_ping_msecs(su->dTCPPingAvg);
216 
217 	ru->set_tcp_only(QAtomicIntLoad(su->aiUdpFlag) == 0);
218 
219 	ru->set_address(su->haAddress.toStdString());
220 }
221 
ToRPC(const::Server * srv,const QMap<int,QString> & info,const QByteArray & texture,::MurmurRPC::DatabaseUser * du)222 void ToRPC(const ::Server *srv, const QMap<int, QString> &info, const QByteArray &texture, ::MurmurRPC::DatabaseUser *du) {
223 	du->mutable_server()->set_id(srv->iServerNum);
224 
225 	if (info.contains(::ServerDB::User_Name)) {
226 		du->set_name(u8(info[::ServerDB::User_Name]));
227 	}
228 	if (info.contains(::ServerDB::User_Email)) {
229 		du->set_email(u8(info[::ServerDB::User_Email]));
230 	}
231 	if (info.contains(::ServerDB::User_Comment)) {
232 		du->set_comment(u8(info[::ServerDB::User_Comment]));
233 	}
234 	if (info.contains(::ServerDB::User_Hash)) {
235 		du->set_hash(u8(info[::ServerDB::User_Hash]));
236 	}
237 	if (info.contains(::ServerDB::User_Password)) {
238 		du->set_password(u8(info[::ServerDB::User_Password]));
239 	}
240 	if (info.contains(::ServerDB::User_LastActive)) {
241 		du->set_last_active(u8(info[::ServerDB::User_LastActive]));
242 	}
243 	if (!texture.isNull()) {
244 		du->set_texture(texture.constData(), texture.size());
245 	}
246 }
247 
FromRPC(const::MurmurRPC::DatabaseUser & du,QMap<int,QString> & info)248 void FromRPC(const ::MurmurRPC::DatabaseUser &du, QMap<int, QString> &info) {
249 	if (du.has_name()) {
250 		info.insert(::ServerDB::User_Name, u8(du.name()));
251 	}
252 	if (du.has_email()) {
253 		info.insert(::ServerDB::User_Email, u8(du.email()));
254 	}
255 	if (du.has_comment()) {
256 		info.insert(::ServerDB::User_Comment, u8(du.comment()));
257 	}
258 	if (du.has_hash()) {
259 		info.insert(::ServerDB::User_Hash, u8(du.hash()));
260 	}
261 	if (du.has_password()) {
262 		info.insert(::ServerDB::User_Password, u8(du.password()));
263 	}
264 	if (du.has_last_active()) {
265 		info.insert(::ServerDB::User_LastActive, u8(du.last_active()));
266 	}
267 }
268 
ToRPC(const::Server * srv,const::ChanACL * acl,::MurmurRPC::ACL * ra)269 void ToRPC(const ::Server *srv, const ::ChanACL *acl, ::MurmurRPC::ACL *ra) {
270 	ra->set_apply_here(acl->bApplyHere);
271 	ra->set_apply_subs(acl->bApplySubs);
272 	ra->set_inherited(false);
273 
274 	if (acl->iUserId >= 0) {
275 		ra->mutable_user()->mutable_server()->set_id(srv->iServerNum);
276 		ra->mutable_user()->set_id(acl->iUserId);
277 	}
278 	if (!acl->qsGroup.isEmpty()) {
279 		ra->mutable_group()->set_name(u8(acl->qsGroup));
280 	}
281 
282 	ra->set_allow(MurmurRPC::ACL_Permission(int(acl->pAllow)));
283 	ra->set_deny(MurmurRPC::ACL_Permission(int(acl->pDeny)));
284 }
285 
ToRPC(const::Server *,const::Group * g,::MurmurRPC::ACL_Group * rg)286 void ToRPC(const ::Server *, const ::Group *g, ::MurmurRPC::ACL_Group *rg) {
287 	rg->set_name(u8(g->qsName));
288 	rg->set_inherit(g->bInherit);
289 	rg->set_inheritable(g->bInheritable);
290 }
291 
ToRPC(const::Server * srv,const::Ban & ban,::MurmurRPC::Ban * rb)292 void ToRPC(const ::Server *srv, const ::Ban &ban, ::MurmurRPC::Ban *rb) {
293 	rb->mutable_server()->set_id(srv->iServerNum);
294 
295 	rb->set_address(ban.haAddress.toStdString());
296 	rb->set_bits(ban.iMask);
297 	rb->set_name(u8(ban.qsUsername));
298 	rb->set_hash(u8(ban.qsHash));
299 	rb->set_reason(u8(ban.qsReason));
300 	rb->set_start(ban.qdtStart.toLocalTime().toTime_t());
301 	rb->set_duration_secs(ban.iDuration);
302 }
303 
FromRPC(const::Server *,const::MurmurRPC::Ban & rb,::Ban & ban)304 void FromRPC(const ::Server *, const ::MurmurRPC::Ban &rb, ::Ban &ban) {
305 	ban.haAddress = HostAddress(rb.address());
306 	ban.iMask = rb.bits();
307 	ban.qsUsername = u8(rb.name());
308 	ban.qsHash = u8(rb.hash());
309 	ban.qsReason = u8(rb.reason());
310 	ban.qdtStart = QDateTime::fromTime_t(static_cast<quint32>(rb.start())).toUTC();
311 	ban.iDuration = rb.duration_secs();
312 }
313 
ToRPC(int serverID,const::ServerDB::LogRecord & log,::MurmurRPC::Log * rl)314 void ToRPC(int serverID, const ::ServerDB::LogRecord &log, ::MurmurRPC::Log *rl) {
315 	rl->mutable_server()->set_id(serverID);
316 
317 	rl->set_timestamp(log.first);
318 	rl->set_text(u8(log.second));
319 }
320 
ToRPC(const::Server * srv,const::User * user,const::TextMessage & message,::MurmurRPC::TextMessage * rtm)321 void ToRPC(const ::Server *srv, const ::User *user, const ::TextMessage &message, ::MurmurRPC::TextMessage *rtm) {
322 	rtm->mutable_server()->set_id(srv->iServerNum);
323 
324 	rtm->mutable_actor()->mutable_server()->set_id(srv->iServerNum);
325 	rtm->mutable_actor()->set_session(user->uiSession);
326 
327 	foreach(auto session, message.qlSessions) {
328 		auto target = rtm->add_users();
329 		target->mutable_server()->set_id(srv->iServerNum);
330 		target->set_session(session);
331 	}
332 
333 	foreach(auto id, message.qlChannels) {
334 		auto target = rtm->add_channels();
335 		target->mutable_server()->set_id(srv->iServerNum);
336 		target->set_id(id);
337 	}
338 
339 	foreach(auto id, message.qlTrees) {
340 		auto target = rtm->add_trees();
341 		target->mutable_server()->set_id(srv->iServerNum);
342 		target->set_id(id);
343 	}
344 
345 	rtm->set_text(u8(message.qsText));
346 }
347 
348 // Sends a meta event to any subscribed listeners.
sendMetaEvent(const::MurmurRPC::Event & e)349 void MurmurRPCImpl::sendMetaEvent(const ::MurmurRPC::Event &e) {
350 	auto listeners = m_metaServiceListeners;
351 
352 	for (auto i = listeners.constBegin(); i != listeners.constEnd(); ++i) {
353 		auto listener = *i;
354 		listener->ref();
355 		auto cb = [this, listener] (::MurmurRPC::Wrapper::V1_Events *, bool ok) {
356 			if (!ok && m_metaServiceListeners.remove(listener)) {
357 				listener->deref();
358 			}
359 			listener->deref();
360 		};
361 		listener->write(e, listener->callback(cb));
362 	}
363 }
364 
365 // Called when a server starts.
started(::Server * server)366 void MurmurRPCImpl::started(::Server *server) {
367 	server->connectListener(this);
368 	server->connectAuthenticator(this);
369 	connect(server, SIGNAL(contextAction(const User *, const QString &, unsigned int, int)), this, SLOT(contextAction(const User *, const QString &, unsigned int, int)));
370 	connect(server, SIGNAL(textMessageFilterSig(int &, const User *, MumbleProto::TextMessage &)), this, SLOT(textMessageFilter(int &, const User *, MumbleProto::TextMessage &)));
371 
372 	::MurmurRPC::Event rpcEvent;
373 	rpcEvent.set_type(::MurmurRPC::Event_Type_ServerStarted);
374 	rpcEvent.mutable_server()->set_id(server->iServerNum);
375 	sendMetaEvent(rpcEvent);
376 }
377 
378 // Called when a server stops.
stopped(::Server * server)379 void MurmurRPCImpl::stopped(::Server *server) {
380 	removeActiveContextActions(server);
381 
382 	::MurmurRPC::Event rpcEvent;
383 	rpcEvent.set_type(::MurmurRPC::Event_Type_ServerStopped);
384 	rpcEvent.mutable_server()->set_id(server->iServerNum);
385 	sendMetaEvent(rpcEvent);
386 }
387 
388 // Removes a connected text message filter.
removeTextMessageFilter(const::Server * s)389 void MurmurRPCImpl::removeTextMessageFilter(const ::Server *s) {
390 	auto filter = m_textMessageFilters.value(s->iServerNum);
391 	if (!filter) {
392 		return;
393 	}
394 	filter->error(::grpc::Status(::grpc::CANCELLED, "filter detached"));
395 	m_textMessageFilters.remove(s->iServerNum);
396 }
397 
398 // Removes a connected authenticator.
removeAuthenticator(const::Server * s)399 void MurmurRPCImpl::removeAuthenticator(const ::Server *s) {
400 	auto authenticator = m_authenticators.value(s->iServerNum);
401 	if (!authenticator) {
402 		return;
403 	}
404 	authenticator->error(::grpc::Status(::grpc::CANCELLED, "authenticator detached"));
405 	m_authenticators.remove(s->iServerNum);
406 }
407 
408 // Called when a connecting user needs to be authenticated.
authenticateSlot(int & res,QString & uname,int sessionId,const QList<QSslCertificate> & certlist,const QString & certhash,bool certstrong,const QString & pw)409 void MurmurRPCImpl::authenticateSlot(int &res, QString &uname, int sessionId, const QList<QSslCertificate> &certlist, const QString &certhash, bool certstrong, const QString &pw) {
410 	::Server *s = qobject_cast< ::Server *> (sender());
411 	auto authenticator = RPCCall::Ref<::MurmurRPC::Wrapper::V1_AuthenticatorStream>(m_authenticators.value(s->iServerNum));
412 	if (!authenticator) {
413 		return;
414 	}
415 
416 	auto &request = authenticator->response;
417 	request.Clear();
418 	request.mutable_authenticate()->set_name(u8(uname));
419 	if (!pw.isEmpty()) {
420 		request.mutable_authenticate()->set_password(u8(pw));
421 	}
422 	foreach(const auto &cert, certlist) {
423 		auto data = cert.toDer();
424 		request.mutable_authenticate()->add_certificates(data.constData(), data.size());
425 	}
426 	if (!certhash.isEmpty()) {
427 		request.mutable_authenticate()->set_certificate_hash(u8(certhash));
428 		request.mutable_authenticate()->set_strong_certificate(certstrong);
429 	}
430 
431 	{
432 		QMutexLocker l(&qmAuthenticatorsLock);
433 		if (!authenticator->writeRead()) {
434 			removeAuthenticator(s);
435 			res = -1;
436 			return;
437 		}
438 	}
439 
440 	auto &response = authenticator->request;
441 	switch (response.authenticate().status()) {
442 	case ::MurmurRPC::Authenticator_Response_Status_Success:
443 		if (!response.authenticate().has_id()) {
444 			res = -3;
445 			break;
446 		}
447 		res = response.authenticate().id();
448 		if (response.authenticate().has_name()) {
449 			uname = u8(response.authenticate().name());
450 		}
451 		{
452 			QStringList qsl;
453 			for (int i = 0; i < response.authenticate().groups_size(); i++) {
454 				auto &group = response.authenticate().groups(i);
455 				if (group.has_name()) {
456 					qsl << u8(group.name());
457 				}
458 			}
459 			if (!qsl.isEmpty()) {
460 				s->setTempGroups(res, sessionId, NULL, qsl);
461 			}
462 		}
463 		break;
464 	case ::MurmurRPC::Authenticator_Response_Status_TemporaryFailure:
465 		res = -3;
466 		break;
467 	case ::MurmurRPC::Authenticator_Response_Status_Failure:
468 		res = -1;
469 		break;
470 	default:
471 		break;
472 	}
473 }
474 
475 // Called when a user is being registered on the server.
registerUserSlot(int & res,const QMap<int,QString> & info)476 void MurmurRPCImpl::registerUserSlot(int &res, const QMap<int, QString> &info) {
477 	::Server *s = qobject_cast< ::Server *> (sender());
478 	auto authenticator = RPCCall::Ref<::MurmurRPC::Wrapper::V1_AuthenticatorStream>(m_authenticators.value(s->iServerNum));
479 	if (!authenticator) {
480 		return;
481 	}
482 
483 	auto &request = authenticator->response;
484 	request.Clear();
485 	ToRPC(s, info, QByteArray(), request.mutable_register_()->mutable_user());
486 
487 	{
488 		QMutexLocker l(&qmAuthenticatorsLock);
489 		if (!authenticator->writeRead()) {
490 			removeAuthenticator(s);
491 			return;
492 		}
493 	}
494 
495 	auto &response = authenticator->request;
496 	switch (response.register_().status()) {
497 	case ::MurmurRPC::Authenticator_Response_Status_Success:
498 		if (!response.register_().has_user() || !response.register_().user().has_id()) {
499 			res = -1;
500 			break;
501 		}
502 		res = response.register_().user().id();
503 		break;
504 	case ::MurmurRPC::Authenticator_Response_Status_Fallthrough:
505 		break;
506 	default:
507 		res = -1;
508 		break;
509 	}
510 }
511 
512 // Called when a user is being deregistered on the server.
unregisterUserSlot(int & res,int id)513 void MurmurRPCImpl::unregisterUserSlot(int &res, int id) {
514 	::Server *s = qobject_cast< ::Server *> (sender());
515 	auto authenticator = RPCCall::Ref<::MurmurRPC::Wrapper::V1_AuthenticatorStream>(m_authenticators.value(s->iServerNum));
516 	if (!authenticator) {
517 		return;
518 	}
519 
520 	auto &request = authenticator->response;
521 	request.Clear();
522 	request.mutable_deregister()->mutable_user()->mutable_server()->set_id(s->iServerNum);
523 	request.mutable_deregister()->mutable_user()->set_id(id);
524 
525 	{
526 		QMutexLocker l(&qmAuthenticatorsLock);
527 		if (!authenticator->writeRead()) {
528 			removeAuthenticator(s);
529 			return;
530 		}
531 	}
532 
533 	auto &response = authenticator->request;
534 
535 	if (response.deregister().status() != ::MurmurRPC::Authenticator_Response_Status_Fallthrough) {
536 		res = 0;
537 	}
538 }
539 
540 // Called when a list of registered users is requested.
getRegisteredUsersSlot(const QString & filter,QMap<int,QString> & res)541 void MurmurRPCImpl::getRegisteredUsersSlot(const QString &filter, QMap<int, QString> &res) {
542 	::Server *s = qobject_cast< ::Server *> (sender());
543 	auto authenticator = RPCCall::Ref<::MurmurRPC::Wrapper::V1_AuthenticatorStream>(m_authenticators.value(s->iServerNum));
544 	if (!authenticator) {
545 		return;
546 	}
547 
548 	auto &request = authenticator->response;
549 	request.Clear();
550 	if (!filter.isEmpty()) {
551 		request.mutable_query()->set_filter(u8(filter));
552 	}
553 
554 	{
555 		QMutexLocker l(&qmAuthenticatorsLock);
556 		if (!authenticator->writeRead()) {
557 			removeAuthenticator(s);
558 			return;
559 		}
560 	}
561 
562 	auto &response = authenticator->request;
563 
564 	for (int i = 0; i < response.query().users_size(); i++) {
565 		const auto &user = response.query().users(i);
566 		if (!user.has_id() || !user.has_name()) {
567 			continue;
568 		}
569 		res.insert(user.id(), u8(user.name()));
570 	}
571 }
572 
573 // Called when information about a registered user is requested.
getRegistrationSlot(int & res,int id,QMap<int,QString> & info)574 void MurmurRPCImpl::getRegistrationSlot(int &res, int id, QMap<int, QString> &info) {
575 	::Server *s = qobject_cast< ::Server *> (sender());
576 	auto authenticator = RPCCall::Ref<::MurmurRPC::Wrapper::V1_AuthenticatorStream>(m_authenticators.value(s->iServerNum));
577 	if (!authenticator) {
578 		return;
579 	}
580 
581 	auto &request = authenticator->response;
582 	request.Clear();
583 	request.mutable_find()->set_id(id);
584 
585 	res = -1;
586 
587 	{
588 		QMutexLocker l(&qmAuthenticatorsLock);
589 		if (!authenticator->writeRead()) {
590 			removeAuthenticator(s);
591 			return;
592 		}
593 	}
594 
595 	auto &response = authenticator->request;
596 	if (response.find().has_user()) {
597 		FromRPC(response.find().user(), info);
598 		res = 1;
599 	}
600 }
601 
602 // Called when information about a registered user is being updated.
setInfoSlot(int & res,int id,const QMap<int,QString> & info)603 void MurmurRPCImpl::setInfoSlot(int &res, int id, const QMap<int, QString> &info) {
604 	::Server *s = qobject_cast< ::Server *> (sender());
605 	auto authenticator = RPCCall::Ref<::MurmurRPC::Wrapper::V1_AuthenticatorStream>(m_authenticators.value(s->iServerNum));
606 	if (!authenticator) {
607 		return;
608 	}
609 
610 	auto &request = authenticator->response;
611 	request.Clear();
612 	request.mutable_update()->mutable_user()->set_id(id);
613 	ToRPC(s, info, QByteArray(), request.mutable_update()->mutable_user());
614 
615 	res = 0;
616 
617 	{
618 		QMutexLocker l(&qmAuthenticatorsLock);
619 		if (!authenticator->writeRead()) {
620 			removeAuthenticator(s);
621 			return;
622 		}
623 	}
624 
625 	auto &response = authenticator->request;
626 	switch (response.update().status()) {
627 	case ::MurmurRPC::Authenticator_Response_Status_Success:
628 		res = 1;
629 		break;
630 	case ::MurmurRPC::Authenticator_Response_Status_Fallthrough:
631 		res = -1;
632 		break;
633 	default:
634 		break;
635 	}
636 }
637 
638 // Called when a texture for a registered user is being updated.
setTextureSlot(int & res,int id,const QByteArray & texture)639 void MurmurRPCImpl::setTextureSlot(int &res, int id, const QByteArray &texture) {
640 	::Server *s = qobject_cast< ::Server *> (sender());
641 	auto authenticator = RPCCall::Ref<::MurmurRPC::Wrapper::V1_AuthenticatorStream>(m_authenticators.value(s->iServerNum));
642 	if (!authenticator) {
643 		return;
644 	}
645 
646 	auto &request = authenticator->response;
647 	request.Clear();
648 	request.mutable_update()->mutable_user()->set_id(id);
649 	request.mutable_update()->mutable_user()->set_texture(texture.constData(), texture.size());
650 
651 	{
652 		QMutexLocker l(&qmAuthenticatorsLock);
653 		if (!authenticator->writeRead()) {
654 			removeAuthenticator(s);
655 			return;
656 		}
657 	}
658 
659 	auto &response = authenticator->request;
660 	if (response.update().status() == ::MurmurRPC::Authenticator_Response_Status_Success) {
661 		res = 1;
662 	}
663 }
664 
665 // Called when a user name needs to be converted to a user ID.
nameToIdSlot(int & res,const QString & name)666 void MurmurRPCImpl::nameToIdSlot(int &res, const QString &name) {
667 	::Server *s = qobject_cast< ::Server *> (sender());
668 	auto authenticator = RPCCall::Ref<::MurmurRPC::Wrapper::V1_AuthenticatorStream>(m_authenticators.value(s->iServerNum));
669 	if (!authenticator) {
670 		return;
671 	}
672 
673 	auto &request = authenticator->response;
674 	request.Clear();
675 	request.mutable_find()->set_name(u8(name));
676 
677 	{
678 		QMutexLocker l(&qmAuthenticatorsLock);
679 		if (!authenticator->writeRead()) {
680 			removeAuthenticator(s);
681 			return;
682 		}
683 	}
684 
685 	auto &response = authenticator->request;
686 	if (response.find().has_user() && response.find().user().has_id()) {
687 		res = response.find().user().id();
688 	}
689 }
690 
691 // Called when a user ID needs to be converted to a user name.
idToNameSlot(QString & res,int id)692 void MurmurRPCImpl::idToNameSlot(QString &res, int id) {
693 	::Server *s = qobject_cast< ::Server *> (sender());
694 	auto authenticator = RPCCall::Ref<::MurmurRPC::Wrapper::V1_AuthenticatorStream>(m_authenticators.value(s->iServerNum));
695 	if (!authenticator) {
696 		return;
697 	}
698 
699 	auto &request = authenticator->response;
700 	request.Clear();
701 	request.mutable_find()->set_id(id);
702 
703 	{
704 		QMutexLocker l(&qmAuthenticatorsLock);
705 		if (!authenticator->writeRead()) {
706 			removeAuthenticator(s);
707 			return;
708 		}
709 	}
710 
711 	auto &response = authenticator->request;
712 	if (response.find().has_user() && response.find().user().has_name()) {
713 		res = u8(response.find().user().name());
714 	}
715 }
716 
717 // Called when a texture for a given registered user is requested.
idToTextureSlot(QByteArray & res,int id)718 void MurmurRPCImpl::idToTextureSlot(QByteArray &res, int id) {
719 	::Server *s = qobject_cast< ::Server *> (sender());
720 	auto authenticator = RPCCall::Ref<::MurmurRPC::Wrapper::V1_AuthenticatorStream>(m_authenticators.value(s->iServerNum));
721 	if (!authenticator) {
722 		return;
723 	}
724 
725 	auto &request = authenticator->response;
726 	request.Clear();
727 	request.mutable_find()->set_id(id);
728 
729 	{
730 		QMutexLocker l(&qmAuthenticatorsLock);
731 		if (!authenticator->writeRead()) {
732 			removeAuthenticator(s);
733 			return;
734 		}
735 	}
736 
737 	auto &response = authenticator->request;
738 	if (response.find().has_user() && response.find().user().has_texture()) {
739 		const auto &texture = response.find().user().texture();
740 		res = QByteArray(texture.data(), texture.size());
741 	}
742 }
743 
744 // Sends a server event to subscribed listeners.
sendServerEvent(const::Server * s,const::MurmurRPC::Server_Event & e)745 void MurmurRPCImpl::sendServerEvent(const ::Server *s, const ::MurmurRPC::Server_Event &e) {
746 	auto listeners = m_serverServiceListeners;
747 	auto serverID = s->iServerNum;
748 	auto i = listeners.find(serverID);
749 
750 	for ( ; i != listeners.end() && i.key() == serverID; ++i) {
751 		auto listener = i.value();
752 		listener->ref();
753 		auto cb = [this, listener, serverID] (::MurmurRPC::Wrapper::V1_ServerEvents *, bool ok) {
754 			if (!ok && m_serverServiceListeners.remove(serverID, listener) > 0) {
755 				listener->deref();
756 			}
757 			listener->deref();
758 		};
759 		listener->write(e, listener->callback(cb));
760 	}
761 }
762 
763 // Called when a user's state changes.
userStateChanged(const::User * user)764 void MurmurRPCImpl::userStateChanged(const ::User *user) {
765 	::Server *s = qobject_cast< ::Server *> (sender());
766 
767 	::MurmurRPC::Server_Event event;
768 	event.mutable_server()->set_id(s->iServerNum);
769 	event.set_type(::MurmurRPC::Server_Event_Type_UserStateChanged);
770 	ToRPC(s, user, event.mutable_user());
771 	sendServerEvent(s, event);
772 }
773 
774 // Called when a user sends a text message.
userTextMessage(const::User * user,const::TextMessage & message)775 void MurmurRPCImpl::userTextMessage(const ::User *user, const ::TextMessage &message) {
776 	::Server *s = qobject_cast< ::Server *> (sender());
777 
778 	::MurmurRPC::Server_Event event;
779 	event.mutable_server()->set_id(s->iServerNum);
780 	event.set_type(::MurmurRPC::Server_Event_Type_UserTextMessage);
781 	ToRPC(s, user, event.mutable_user());
782 	ToRPC(s, user, message, event.mutable_message());
783 	sendServerEvent(s, event);
784 }
785 
786 // Called when a user successfully connects to a server.
userConnected(const::User * user)787 void MurmurRPCImpl::userConnected(const ::User *user) {
788 	::Server *s = qobject_cast< ::Server *> (sender());
789 
790 	::MurmurRPC::Server_Event event;
791 	event.mutable_server()->set_id(s->iServerNum);
792 	event.set_type(::MurmurRPC::Server_Event_Type_UserConnected);
793 	ToRPC(s, user, event.mutable_user());
794 	sendServerEvent(s, event);
795 }
796 
797 // Called when a user disconnects from a server.
userDisconnected(const::User * user)798 void MurmurRPCImpl::userDisconnected(const ::User *user) {
799 	::Server *s = qobject_cast< ::Server *> (sender());
800 
801 	removeUserActiveContextActions(s, user);
802 
803 	::MurmurRPC::Server_Event event;
804 	event.mutable_server()->set_id(s->iServerNum);
805 	event.set_type(::MurmurRPC::Server_Event_Type_UserDisconnected);
806 	ToRPC(s, user, event.mutable_user());
807 	sendServerEvent(s, event);
808 }
809 
810 // Called when a channel's state changes.
channelStateChanged(const::Channel * channel)811 void MurmurRPCImpl::channelStateChanged(const ::Channel *channel) {
812 	::Server *s = qobject_cast< ::Server *> (sender());
813 
814 	::MurmurRPC::Server_Event event;
815 	event.mutable_server()->set_id(s->iServerNum);
816 	event.set_type(::MurmurRPC::Server_Event_Type_ChannelStateChanged);
817 	ToRPC(s, channel, event.mutable_channel());
818 	sendServerEvent(s, event);
819 }
820 
821 // Called when a channel is created.
channelCreated(const::Channel * channel)822 void MurmurRPCImpl::channelCreated(const ::Channel *channel) {
823 	::Server *s = qobject_cast< ::Server *> (sender());
824 
825 	::MurmurRPC::Server_Event event;
826 	event.mutable_server()->set_id(s->iServerNum);
827 	event.set_type(::MurmurRPC::Server_Event_Type_ChannelCreated);
828 	ToRPC(s, channel, event.mutable_channel());
829 	sendServerEvent(s, event);
830 }
831 
832 // Called when a channel is removed.
channelRemoved(const::Channel * channel)833 void MurmurRPCImpl::channelRemoved(const ::Channel *channel) {
834 	::Server *s = qobject_cast< ::Server *> (sender());
835 
836 	::MurmurRPC::Server_Event event;
837 	event.mutable_server()->set_id(s->iServerNum);
838 	event.set_type(::MurmurRPC::Server_Event_Type_ChannelRemoved);
839 	ToRPC(s, channel, event.mutable_channel());
840 	sendServerEvent(s, event);
841 }
842 
843 // Called when a user sends a text message.
textMessageFilter(int & res,const User * user,MumbleProto::TextMessage & message)844 void MurmurRPCImpl::textMessageFilter(int &res, const User *user, MumbleProto::TextMessage &message) {
845 	::Server *s = qobject_cast< ::Server *> (sender());
846 	auto filter = RPCCall::Ref<::MurmurRPC::Wrapper::V1_TextMessageFilter>(m_textMessageFilters.value(s->iServerNum));
847 	if (!filter) {
848 		return;
849 	}
850 
851 	auto &request = filter->response;
852 	request.Clear();
853 	request.mutable_server()->set_id(s->iServerNum);
854 	auto m = request.mutable_message();
855 	m->mutable_server()->set_id(s->iServerNum);
856 	m->mutable_actor()->mutable_server()->set_id(s->iServerNum);
857 	m->mutable_actor()->set_session(user->uiSession);
858 	for (int i = 0; i < message.session_size(); i++) {
859 		auto u = m->add_users();
860 		u->mutable_server()->set_id(s->iServerNum);
861 		u->set_session(message.session(i));
862 	}
863 	for (int i = 0; i < message.channel_id_size(); i++) {
864 		auto c = m->add_channels();
865 		c->mutable_server()->set_id(s->iServerNum);
866 		c->set_id(message.channel_id(i));
867 	}
868 	for (int i = 0; i < message.tree_id_size(); i++) {
869 		auto c = m->add_trees();
870 		c->mutable_server()->set_id(s->iServerNum);
871 		c->set_id(message.tree_id(i));
872 	}
873 	m->set_text(message.message());
874 
875 	{
876 		QMutexLocker l(&qmTextMessageFilterLock);
877 		if (!filter->writeRead()) {
878 			removeTextMessageFilter(s);
879 			return;
880 		}
881 	}
882 
883 	auto &response = filter->request;
884 	res = response.action();
885 	switch (response.action()) {
886 	case ::MurmurRPC::TextMessage_Filter_Action_Accept:
887 		if (response.has_message() && response.message().has_text()) {
888 			message.set_message(response.message().text());
889 		}
890 		break;
891 	default:
892 		break;
893 	}
894 }
895 
896 // Has the user been sent the given context action?
hasActiveContextAction(const::Server * s,const::User * u,const QString & action)897 bool MurmurRPCImpl::hasActiveContextAction(const ::Server *s, const ::User *u, const QString &action) {
898 	const auto &m = m_activeContextActions;
899 	if (!m.contains(s->iServerNum)) {
900 		return false;
901 	}
902 	const auto &n = m.value(s->iServerNum);
903 	if (!n.contains(u->uiSession)) {
904 		return false;
905 	}
906 	const auto &o = n.value(u->uiSession);
907 	if (!o.contains(action)) {
908 		return false;
909 	}
910 	return true;
911 }
912 
913 // Add the context action to the user's active context actions.
addActiveContextAction(const::Server * s,const::User * u,const QString & action)914 void MurmurRPCImpl::addActiveContextAction(const ::Server *s, const ::User *u, const QString &action) {
915 	m_activeContextActions[s->iServerNum][u->uiSession].insert(action);
916 }
917 
918 // Remove the context action to the user's active context actions.
removeActiveContextAction(const::Server * s,const::User * u,const QString & action)919 void MurmurRPCImpl::removeActiveContextAction(const ::Server *s, const ::User *u, const QString &action) {
920 	auto &m = m_activeContextActions;
921 	if (!m.contains(s->iServerNum)) {
922 		return;
923 	}
924 	auto &n = m[s->iServerNum];
925 	if (!n.contains(u->uiSession)) {
926 		return;
927 	}
928 	auto &o = n[u->uiSession];
929 	o.remove(action);
930 }
931 
932 // Remove all of the user's active context actions.
removeUserActiveContextActions(const::Server * s,const::User * u)933 void MurmurRPCImpl::removeUserActiveContextActions(const ::Server *s, const ::User *u) {
934 	auto &m = m_activeContextActions;
935 	if (m.contains(s->iServerNum)) {
936 		m[s->iServerNum].remove(u->uiSession);
937 	}
938 }
939 
940 // Remove all of the server's active context actions.
removeActiveContextActions(const::Server * s)941 void MurmurRPCImpl::removeActiveContextActions(const ::Server *s) {
942 	auto &m = m_activeContextActions;
943 	if (m.contains(s->iServerNum)) {
944 		m.remove(s->iServerNum);
945 	}
946 }
947 
948 // Called when a context action event is triggered.
contextAction(const::User * user,const QString & action,unsigned int session,int channel)949 void MurmurRPCImpl::contextAction(const ::User *user, const QString &action, unsigned int session, int channel) {
950 	::Server *s = qobject_cast< ::Server *> (sender());
951 
952 	if (!hasActiveContextAction(s, user, action)) {
953 		return;
954 	}
955 
956 	::MurmurRPC::ContextAction ca;
957 	ca.mutable_server()->set_id(s->iServerNum);
958 	ca.mutable_actor()->mutable_server()->set_id(s->iServerNum);
959 	ca.mutable_actor()->set_session(user->uiSession);
960 	ca.set_action(u8(action));
961 	if (session > 0) {
962 		ca.mutable_user()->mutable_server()->set_id(s->iServerNum);
963 		ca.mutable_user()->set_session(session);
964 	}
965 	if (channel >= 0) {
966 		ca.mutable_channel()->mutable_server()->set_id(s->iServerNum);
967 		ca.mutable_channel()->set_id(channel);
968 	}
969 
970 	auto serverID = s->iServerNum;
971 	auto listeners = this->m_contextActionListeners.value(serverID);
972 	auto i = listeners.find(action);
973 	for ( ; i != listeners.end() && i.key() == action; ++i) {
974 		auto listener = i.value();
975 		listener->ref();
976 		auto cb = [this, listener, serverID, action] (::MurmurRPC::Wrapper::V1_ContextActionEvents *, bool ok) {
977 			if (!ok && m_contextActionListeners[serverID].remove(action, listener) > 0) {
978 				listener->deref();
979 			}
980 			listener->deref();
981 		};
982 		listener->write(ca, listener->callback(cb));
983 	}
984 }
985 
986 // *Must* functions return the requested value, or throw a ::grpc::Status
987 // exception.
MustUser(const Server * server,unsigned int session)988 ::ServerUser *MustUser(const Server *server, unsigned int session) {
989 	auto user = server->qhUsers.value(session);
990 	if (!user || user->sState != ServerUser::Authenticated) {
991 		throw ::grpc::Status(::grpc::NOT_FOUND, "invalid user");
992 	}
993 	return user;
994 }
995 
996 template <class T>
MustUser(const::Server * server,const T & msg)997 ::ServerUser *MustUser(const ::Server *server, const T &msg) {
998 	if (!msg.has_user()) {
999 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing user");
1000 	}
1001 	return MustUser(server, msg.user().session());
1002 }
1003 
1004 template <>
MustUser(const Server * server,const::MurmurRPC::User & msg)1005 ::ServerUser *MustUser(const Server *server, const ::MurmurRPC::User &msg) {
1006 	if (!msg.has_session()) {
1007 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing user session");
1008 	}
1009 	return MustUser(server, msg.session());
1010 }
1011 
MustServer(unsigned int id)1012 ::Server *MustServer(unsigned int id) {
1013 	auto server = meta->qhServers.value(id);
1014 	if (!server) {
1015 		throw ::grpc::Status(::grpc::NOT_FOUND, "invalid server");
1016 	}
1017 	return server;
1018 }
1019 
MustServer(int id)1020 ::Server *MustServer(int id) {
1021 	auto server = meta->qhServers.value(id);
1022 	if (!server) {
1023 		throw ::grpc::Status(::grpc::NOT_FOUND, "invalid server");
1024 	}
1025 	return server;
1026 }
1027 
1028 template <class T>
MustServer(const T & msg)1029 ::Server *MustServer(const T &msg) {
1030 	if (!msg.has_server()) {
1031 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing server");
1032 	}
1033 	if (!msg.server().has_id()) {
1034 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing server id");
1035 	}
1036 	return MustServer(msg.server().id());
1037 }
1038 
1039 template <>
MustServer(const::MurmurRPC::Server & msg)1040 ::Server *MustServer(const ::MurmurRPC::Server &msg) {
1041 	if (!msg.has_id()) {
1042 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing server id");
1043 	}
1044 	return MustServer(msg.id());
1045 }
1046 
1047 template <class T>
MustServerID(const T & msg)1048 int MustServerID(const T &msg) {
1049 	if (!msg.has_server()) {
1050 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing server");
1051 	}
1052 	if (!msg.server().has_id()) {
1053 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing server id");
1054 	}
1055 	auto id = msg.server().id();
1056 	if (!ServerDB::serverExists(id)) {
1057 		throw ::grpc::Status(::grpc::NOT_FOUND, "invalid server id");
1058 	}
1059 	return id;
1060 }
1061 
MustServerID(const::MurmurRPC::Server & msg)1062 int MustServerID(const ::MurmurRPC::Server &msg) {
1063 	if (!msg.has_id()) {
1064 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing server id");
1065 	}
1066 	auto id = msg.id();
1067 	if (!ServerDB::serverExists(id)) {
1068 		throw ::grpc::Status(::grpc::NOT_FOUND, "invalid server id");
1069 	}
1070 	return id;
1071 }
1072 
MustChannel(const Server * server,int channel_id)1073 ::Channel *MustChannel(const Server *server, int channel_id) {
1074 	auto channel = server->qhChannels.value(channel_id);
1075 	if (!channel) {
1076 		throw ::grpc::Status(::grpc::NOT_FOUND, "invalid channel");
1077 	}
1078 	return channel;
1079 }
1080 
MustChannel(const Server * server,unsigned int channel_id)1081 ::Channel *MustChannel(const Server *server, unsigned int channel_id) {
1082 	auto channel = server->qhChannels.value(channel_id);
1083 	if (!channel) {
1084 		throw ::grpc::Status(::grpc::NOT_FOUND, "invalid channel");
1085 	}
1086 	return channel;
1087 }
1088 
1089 template <class T>
MustChannel(const Server * server,const T & msg)1090 ::Channel *MustChannel(const Server *server, const T &msg) {
1091 	if (!msg.has_channel()) {
1092 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing channel");
1093 	}
1094 	return MustChannel(server, msg.channel());
1095 }
1096 
1097 template <>
MustChannel(const Server * server,const::MurmurRPC::Channel & msg)1098 ::Channel *MustChannel(const Server *server, const ::MurmurRPC::Channel &msg) {
1099 	if (!msg.has_id()) {
1100 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing channel id");
1101 	}
1102 	return MustChannel(server, msg.id());
1103 }
1104 
1105 // Qt event listener for RPCExecEvents.
customEvent(QEvent * evt)1106 void MurmurRPCImpl::customEvent(QEvent *evt) {
1107 	if (evt->type() == EXEC_QEVENT) {
1108 		auto event = static_cast<RPCExecEvent *>(evt);
1109 		try {
1110 			event->execute();
1111 		} catch (::grpc::Status &ex) {
1112 			event->call->error(ex);
1113 		}
1114 	}
1115 }
1116 
1117 // QThread::run() implementation that runs the grpc event loop and executes
1118 // tags as callback functions.
run()1119 void MurmurRPCImpl::run() {
1120 	MurmurRPC::Wrapper::V1_Init(this, &m_V1Service);
1121 
1122 	while (m_isRunning) {
1123 		void *tag;
1124 		bool ok;
1125 		if (!m_completionQueue->Next(&tag, &ok)) {
1126 			break;
1127 		}
1128 		if (tag != nullptr) {
1129 			auto op = static_cast<boost::function<void(bool)> *>(tag);
1130 			(*op)(ok);
1131 			delete op;
1132 		}
1133 	}
1134 	// TODO(grpc): cleanup allocated memory? not super important, because murmur
1135 	// should be exiting now.
1136 }
1137 
1138 // The Wrapper implementation methods are below. Implementation methods are
1139 // executed in the main thread when its corresponding grpc method is invoked.
1140 //
1141 // Since the grpc asynchronous API is used, the implementation methods below
1142 // do not have to complete the call during the lifetime of the method (although
1143 // this is only used for streaming calls).
1144 
1145 namespace MurmurRPC {
1146 namespace Wrapper {
1147 
impl(bool)1148 void V1_ServerCreate::impl(bool) {
1149 	auto id = ServerDB::addServer();
1150 
1151 	::MurmurRPC::Server rpcServer;
1152 	rpcServer.set_id(id);
1153 	end(rpcServer);
1154 }
1155 
impl(bool)1156 void V1_ServerQuery::impl(bool) {
1157 	::MurmurRPC::Server_List list;
1158 
1159 	foreach(int id, ServerDB::getAllServers()) {
1160 		auto rpcServer = list.add_servers();
1161 		rpcServer->set_id(id);
1162 		try {
1163 			auto server = MustServer(id);
1164 			rpcServer->set_running(true);
1165 			rpcServer->mutable_uptime()->set_secs(server->tUptime.elapsed()/1000000LL);
1166 		} catch (::grpc::Status &ex) {
1167 		}
1168 	}
1169 
1170 	end(list);
1171 }
1172 
impl(bool)1173 void V1_ServerGet::impl(bool) {
1174 	auto serverID = MustServerID(request);
1175 
1176 	::MurmurRPC::Server rpcServer;
1177 	rpcServer.set_id(serverID);
1178 	rpcServer.set_running(false);
1179 	try {
1180 		auto server = MustServer(serverID);
1181 		rpcServer.set_running(true);
1182 		rpcServer.mutable_uptime()->set_secs(server->tUptime.elapsed()/1000000LL);
1183 	} catch (::grpc::Status &ex) {
1184 	}
1185 	end(rpcServer);
1186 }
1187 
impl(bool)1188 void V1_ServerStart::impl(bool) {
1189 	auto serverID = MustServerID(request);
1190 
1191 	if (!meta->boot(serverID)) {
1192 		throw ::grpc::Status(::grpc::UNKNOWN, "server could not be started, or is already started");
1193 	}
1194 
1195 	end();
1196 }
1197 
impl(bool)1198 void V1_ServerStop::impl(bool) {
1199 	auto server = MustServer(request);
1200 	meta->kill(server->iServerNum);
1201 	end();
1202 }
1203 
impl(bool)1204 void V1_ServerRemove::impl(bool) {
1205 	auto serverID = MustServerID(request);
1206 
1207 	if (meta->qhServers.value(serverID)) {
1208 		throw ::grpc::Status(::grpc::FAILED_PRECONDITION, "cannot remove started server");
1209 	}
1210 
1211 	ServerDB::deleteServer(serverID);
1212 	end();
1213 }
1214 
impl(bool)1215 void V1_ServerEvents::impl(bool) {
1216 	auto server = MustServer(request);
1217 	rpc->m_serverServiceListeners.insert(server->iServerNum, this);
1218 }
1219 
done(bool)1220 void V1_ServerEvents::done(bool) {
1221 	auto &ssls = rpc->m_serverServiceListeners;
1222 	auto i = std::find(ssls.begin(), ssls.end(), this);
1223 	if (i != ssls.end()) {
1224 		ssls.erase(i);
1225 	}
1226 	deref();
1227 }
1228 
impl(bool)1229 void V1_GetUptime::impl(bool) {
1230 	::MurmurRPC::Uptime uptime;
1231 	uptime.set_secs(meta->tUptime.elapsed()/1000000LL);
1232 	end(uptime);
1233 }
1234 
impl(bool)1235 void V1_GetVersion::impl(bool) {
1236 	::MurmurRPC::Version version;
1237 	int major, minor, patch;
1238 	QString release;
1239 	Meta::getVersion(major, minor, patch, release);
1240 	version.set_version(major << 16 | minor << 8 | patch);
1241 	version.set_release(u8(release));
1242 	end(version);
1243 }
1244 
impl(bool)1245 void V1_Events::impl(bool) {
1246 	rpc->m_metaServiceListeners.insert(this);
1247 }
1248 
done(bool)1249 void V1_Events::done(bool) {
1250 	auto &msls = rpc->m_metaServiceListeners;
1251 	auto i = std::find(msls.begin(), msls.end(), this);
1252 	if (i != msls.end()) {
1253 		msls.erase(i);
1254 	}
1255 	deref();
1256 }
1257 
impl(bool)1258 void V1_ContextActionAdd::impl(bool) {
1259 	auto server = MustServer(request);
1260 	auto user = MustUser(server, request);
1261 
1262 	if (!request.has_action()) {
1263 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing action");
1264 	}
1265 	if (!request.has_text()) {
1266 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing text");
1267 	}
1268 	if (!request.has_context()) {
1269 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing context");
1270 	}
1271 
1272 	rpc->addActiveContextAction(server, user, u8(request.action()));
1273 
1274 	::MumbleProto::ContextActionModify mpcam;
1275 	mpcam.set_action(request.action());
1276 	mpcam.set_text(request.text());
1277 	mpcam.set_context(request.context());
1278 	mpcam.set_operation(::MumbleProto::ContextActionModify_Operation_Add);
1279 	server->sendMessage(user, mpcam);
1280 
1281 	end();
1282 }
1283 
impl(bool)1284 void V1_ContextActionRemove::impl(bool) {
1285 	auto server = MustServer(request);
1286 
1287 	if (!request.has_action()) {
1288 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing action");
1289 	}
1290 
1291 	auto action = u8(request.action());
1292 
1293 	::MumbleProto::ContextActionModify mpcam;
1294 	mpcam.set_action(request.action());
1295 	mpcam.set_operation(::MumbleProto::ContextActionModify_Operation_Remove);
1296 
1297 	if (request.has_user()) {
1298 		// Remove context action from specific user
1299 		auto user = MustUser(server, request);
1300 		rpc->removeActiveContextAction(server, user, action);
1301 		server->sendMessage(user, mpcam);
1302 	} else {
1303 		// Remove context action from all users
1304 		foreach(::ServerUser *user, server->qhUsers) {
1305 			if (user->sState != ServerUser::Authenticated) {
1306 				continue;
1307 			}
1308 			rpc->removeActiveContextAction(server, user, action);
1309 			server->sendMessage(user, mpcam);
1310 		}
1311 	}
1312 
1313 	end();
1314 }
1315 
impl(bool)1316 void V1_ContextActionEvents::impl(bool) {
1317 	auto server = MustServer(request);
1318 
1319 	if (!request.has_action()) {
1320 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing action");
1321 	}
1322 
1323 	rpc->m_contextActionListeners[server->iServerNum].insert(u8(request.action()), this);
1324 }
1325 
done(bool)1326 void V1_ContextActionEvents::done(bool) {
1327 	auto server = MustServer(request);
1328 	auto &cals = rpc->m_contextActionListeners;
1329 	auto &scals = cals[server->iServerNum];
1330 
1331 	auto i = std::find(scals.begin(), scals.end(), this);
1332 	if (i != scals.end()) {
1333 		scals.erase(i);
1334 	}
1335 	deref();
1336 	if (scals.isEmpty()) {
1337 		auto i = std::find(cals.begin(), cals.end(), scals);
1338 		if (i != cals.end()) {
1339 			cals.erase(i);
1340 		}
1341 	}
1342 }
1343 
impl(bool)1344 void V1_TextMessageSend::impl(bool) {
1345 	auto server = MustServer(request);
1346 
1347 	::MumbleProto::TextMessage tm;
1348 	tm.set_message(request.text());
1349 	if (request.has_actor() && request.actor().has_session()) {
1350 		tm.set_actor(request.actor().session());
1351 	}
1352 	for (int i = 0; i < request.users_size(); i++) {
1353 		if (request.users(i).has_session()) {
1354 			tm.add_session(request.users(i).session());
1355 		}
1356 	}
1357 	for (int i = 0; i < request.channels_size(); i++) {
1358 		if (request.channels(i).has_id()) {
1359 			tm.add_channel_id(request.channels(i).id());
1360 		}
1361 	}
1362 	for (int i = 0; i < request.trees_size(); i++) {
1363 		if (request.trees(i).has_id()) {
1364 			tm.add_tree_id(request.trees(i).id());
1365 		}
1366 	}
1367 
1368 	server->sendTextMessageGRPC(tm);
1369 
1370 	end();
1371 }
1372 
impl(bool)1373 void V1_TextMessageFilter::impl(bool) {
1374 	auto onInitialize = [this] (V1_TextMessageFilter *, bool ok) {
1375 		if (!ok) {
1376 			finish(ok);
1377 			return;
1378 		}
1379 		auto server = MustServer(request);
1380 		QMutexLocker l(&rpc->qmTextMessageFilterLock);
1381 		rpc->removeTextMessageFilter(server);
1382 		rpc->m_textMessageFilters.insert(server->iServerNum, this);
1383 	};
1384 	stream.Read(&request, callback(onInitialize));
1385 }
1386 
done(bool)1387 void V1_TextMessageFilter::done(bool) {
1388 	auto server = MustServer(request);
1389 	auto filter = rpc->m_textMessageFilters.value(server->iServerNum);
1390 	if (filter == this) {
1391 		rpc->m_textMessageFilters.remove(server->iServerNum);
1392 	}
1393 	deref();
1394 }
1395 
impl(bool)1396 void V1_LogQuery::impl(bool) {
1397 	auto serverID = MustServerID(request);
1398 
1399 	int total = ::ServerDB::getLogLen(serverID);
1400 	if (total < 0) {
1401 		throw ::grpc::Status(::grpc::StatusCode::UNAVAILABLE, "could not access database");
1402 	}
1403 
1404 	::MurmurRPC::Log_List list;
1405 	list.mutable_server()->set_id(serverID);
1406 	list.set_total(total);
1407 
1408 	if (!request.has_min() || !request.has_max()) {
1409 		end(list);
1410 		return;
1411 	}
1412 	list.set_min(request.min());
1413 	list.set_max(request.max());
1414 
1415 	auto dblog = ::ServerDB::getLog(serverID, request.min(), request.max());
1416 	foreach(const ::ServerDB::LogRecord &record, dblog) {
1417 		auto rpcLog = list.add_entries();
1418 		ToRPC(serverID, record, rpcLog);
1419 	}
1420 
1421 	end(list);
1422 }
1423 
impl(bool)1424 void V1_ConfigGet::impl(bool) {
1425 	auto serverID = MustServerID(request);
1426 	auto config = ServerDB::getAllConf(serverID);
1427 
1428 	::MurmurRPC::Config rpcConfig;
1429 	rpcConfig.mutable_server()->set_id(serverID);
1430 	auto &fields = *rpcConfig.mutable_fields();
1431 	for (auto i = config.constBegin(); i != config.constEnd(); ++i) {
1432 		fields[u8(i.key())] = u8(i.value());
1433 	}
1434 
1435 	end(rpcConfig);
1436 }
1437 
impl(bool)1438 void V1_ConfigGetField::impl(bool) {
1439 	auto serverID = MustServerID(request);
1440 	if (!request.has_key()) {
1441 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing key");
1442 	}
1443 	::MurmurRPC::Config_Field rpcField;
1444 	rpcField.mutable_server()->set_id(serverID);
1445 	rpcField.set_key(request.key());
1446 	rpcField.set_value(u8(ServerDB::getConf(serverID, u8(request.key()), QVariant()).toString()));
1447 	end(rpcField);
1448 }
1449 
impl(bool)1450 void V1_ConfigSetField::impl(bool) {
1451 	auto serverID = MustServerID(request);
1452 	if (!request.has_key()) {
1453 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing key");
1454 	}
1455 	QString key = u8(request.key());
1456 	QString value;
1457 	if (request.has_value()) {
1458 		value = u8(request.value());
1459 	}
1460 	ServerDB::setConf(serverID, key, value);
1461 	try {
1462 		auto server = MustServer(serverID);
1463 		server->setLiveConf(key, value);
1464 	} catch (::grpc::Status &ex) {
1465 	}
1466 
1467 	end();
1468 }
1469 
impl(bool)1470 void V1_ConfigGetDefault::impl(bool) {
1471 	::MurmurRPC::Config rpcConfig;
1472 	auto &fields = *rpcConfig.mutable_fields();
1473 	for (auto i = meta->mp.qmConfig.constBegin(); i != meta->mp.qmConfig.constEnd(); ++i) {
1474 		fields[u8(i.key())] = u8(i.value());
1475 	}
1476 
1477 	end(rpcConfig);
1478 }
1479 
impl(bool)1480 void V1_ChannelQuery::impl(bool) {
1481 	auto server = MustServer(request);
1482 
1483 	::MurmurRPC::Channel_List list;
1484 	list.mutable_server()->set_id(server->iServerNum);
1485 
1486 	foreach(const ::Channel *channel, server->qhChannels) {
1487 		auto rpcChannel = list.add_channels();
1488 		ToRPC(server, channel, rpcChannel);
1489 	}
1490 
1491 	end(list);
1492 }
1493 
impl(bool)1494 void V1_ChannelGet::impl(bool) {
1495 	auto server = MustServer(request);
1496 	auto channel = MustChannel(server, request);
1497 
1498 	::MurmurRPC::Channel rpcChannel;
1499 	ToRPC(server, channel, &rpcChannel);
1500 	end(rpcChannel);
1501 }
1502 
impl(bool)1503 void V1_ChannelAdd::impl(bool) {
1504 	auto server = MustServer(request);
1505 
1506 	if (!request.has_parent() || !request.has_name()) {
1507 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "parent channel and name required");
1508 	}
1509 	::Channel *parent;
1510 	try {
1511 		parent = MustChannel(server, request.parent());
1512 	} catch (::grpc::Status &ex) {
1513 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "invalid parent channel");
1514 	}
1515 
1516 	if (!server->canNest(parent)) {
1517 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "cannot nest channel in given parent");
1518 	}
1519 
1520 	QString qsName = u8(request.name());
1521 
1522 	::Channel *nc;
1523 
1524 	{
1525 		QWriteLocker wl(&server->qrwlVoiceThread);
1526 		nc = server->addChannel(parent, qsName, request.temporary(), request.position());
1527 	}
1528 
1529 	nc->qsDesc = u8(request.description());
1530 
1531 	server->updateChannel(nc);
1532 	int newid = nc->iId;
1533 
1534 	::MumbleProto::ChannelState mpcs;
1535 	mpcs.set_channel_id(newid);
1536 	mpcs.set_parent(parent->iId);
1537 	mpcs.set_name(request.name());
1538 	mpcs.set_temporary(request.temporary());
1539 	mpcs.set_position(request.position());
1540 	mpcs.set_description(request.description());
1541 	server->sendAll(mpcs);
1542 
1543 	::MurmurRPC::Channel resChannel;
1544 	ToRPC(server, nc, &resChannel);
1545 	end(resChannel);
1546 }
1547 
impl(bool)1548 void V1_ChannelRemove::impl(bool) {
1549 	auto server = MustServer(request);
1550 	auto channel = MustChannel(server, request);
1551 
1552 	if (!channel->cParent) {
1553 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "cannot remove the root channel");
1554 	}
1555 
1556 	server->removeChannel(channel);
1557 
1558 	end();
1559 }
1560 
impl(bool)1561 void V1_ChannelUpdate::impl(bool) {
1562 	auto server = MustServer(request);
1563 	auto channel = MustChannel(server, request);
1564 
1565 	::MumbleProto::ChannelState mpcs;
1566 	mpcs.set_channel_id(channel->iId);
1567 	for (int i = 0; i < request.links_size(); i++) {
1568 		if (!request.links(i).has_id()) {
1569 			throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "invalid channel link");
1570 		}
1571 		mpcs.add_links(request.links(i).id());
1572 	}
1573 	if (request.has_parent()) {
1574 		if (!request.parent().has_id()) {
1575 			throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "invalid channel parent");
1576 		}
1577 		mpcs.set_parent(request.parent().id());
1578 	}
1579 	if (request.has_name()) {
1580 		mpcs.set_name(request.name());
1581 	}
1582 	if (request.has_position()) {
1583 		mpcs.set_position(request.position());
1584 	}
1585 	if (request.has_description()) {
1586 		mpcs.set_description(request.description());
1587 	}
1588 
1589 	QString err;
1590 	if (!server->setChannelStateGRPC(mpcs, err)) {
1591 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, u8(err));
1592 	}
1593 
1594 	::MurmurRPC::Channel rpcChannel;
1595 	ToRPC(server, channel, &rpcChannel);
1596 	end(rpcChannel);
1597 }
1598 
impl(bool)1599 void V1_UserQuery::impl(bool) {
1600 	auto server = MustServer(request);
1601 
1602 	::MurmurRPC::User_List list;
1603 	list.mutable_server()->set_id(server->iServerNum);
1604 
1605 	foreach(const ::ServerUser *user, server->qhUsers) {
1606 		if (user->sState != ServerUser::Authenticated) {
1607 			continue;
1608 		}
1609 		auto rpcUser = list.add_users();
1610 		ToRPC(server, user, rpcUser);
1611 	}
1612 
1613 	end(list);
1614 }
1615 
impl(bool)1616 void V1_UserGet::impl(bool) {
1617 	auto server = MustServer(request);
1618 
1619 	::MurmurRPC::User rpcUser;
1620 
1621 	if (request.has_session()) {
1622 		// Lookup user by session
1623 		auto user = MustUser(server, request);
1624 		ToRPC(server, user, &rpcUser);
1625 		end(rpcUser);
1626 		return;
1627 	} else if (request.has_name()) {
1628 		// Lookup user by name
1629 		QString qsName = u8(request.name());
1630 		foreach(const ::ServerUser *user, server->qhUsers) {
1631 			if (user->sState != ServerUser::Authenticated) {
1632 				continue;
1633 			}
1634 			if (user->qsName == qsName) {
1635 				ToRPC(server, user, &rpcUser);
1636 				end(rpcUser);
1637 				return;
1638 			}
1639 		}
1640 		throw ::grpc::Status(::grpc::NOT_FOUND, "invalid user");
1641 	}
1642 
1643 	throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "session or name required");
1644 }
1645 
impl(bool)1646 void V1_UserUpdate::impl(bool) {
1647 	auto server = MustServer(request);
1648 	auto user = MustUser(server, request);
1649 
1650 	auto channel = user->cChannel;
1651 	if (request.has_channel()) {
1652 		channel = MustChannel(server, request.channel());
1653 	}
1654 	auto mute = user->bMute;
1655 	if (request.has_mute()) {
1656 		mute = request.mute();
1657 	}
1658 	auto deaf = user->bDeaf;
1659 	if (request.has_deaf()) {
1660 		deaf = request.deaf();
1661 	}
1662 	auto suppress = user->bSuppress;
1663 	if (request.has_suppress()) {
1664 		suppress = request.suppress();
1665 	}
1666 	auto prioritySpeaker = user->bPrioritySpeaker;
1667 	if (request.has_priority_speaker()) {
1668 		prioritySpeaker = request.priority_speaker();
1669 	}
1670 	auto name = user->qsName;
1671 	if (request.has_name()) {
1672 		name = u8(request.name());
1673 	}
1674 	auto comment = user->qsComment;
1675 	if (request.has_comment()) {
1676 		comment = u8(request.comment());
1677 	}
1678 
1679 	server->setUserState(user, channel, mute, deaf, suppress, prioritySpeaker, name, comment);
1680 
1681 	::MurmurRPC::User rpcUser;
1682 	ToRPC(server, user, &rpcUser);
1683 	end(rpcUser);
1684 }
1685 
impl(bool)1686 void V1_UserKick::impl(bool) {
1687 	auto server = MustServer(request);
1688 	auto user = MustUser(server, request);
1689 
1690 	::MumbleProto::UserRemove mpur;
1691 	mpur.set_session(user->uiSession);
1692 	if (request.has_reason()) {
1693 		mpur.set_reason(request.reason());
1694 	}
1695 	if (request.has_actor() && request.actor().has_session()) {
1696 		mpur.set_actor(request.actor().session());
1697 	}
1698 	server->sendAll(mpur);
1699 	user->disconnectSocket();
1700 
1701 	end();
1702 }
1703 
impl(bool)1704 void V1_TreeQuery::impl(bool) {
1705 	auto server = MustServer(request);
1706 
1707 	auto channel = MustChannel(server, 0);
1708 	::MurmurRPC::Tree root;
1709 
1710 	QQueue< QPair<const ::Channel *, ::MurmurRPC::Tree *> > qQueue;
1711 	qQueue.enqueue(qMakePair(channel, &root));
1712 
1713 	while (!qQueue.isEmpty()) {
1714 		auto current = qQueue.dequeue();
1715 		auto currentChannel = current.first;
1716 		auto currentTree = current.second;
1717 
1718 		ToRPC(server, currentChannel, currentTree->mutable_channel());
1719 
1720 		QList< ::User *> users = currentChannel->qlUsers;
1721 		qSort(users.begin(), users.end(), [] (const ::User *a, const ::User *b) -> bool {
1722 			return ::User::lessThan(a, b);
1723 		});
1724 		foreach(const ::User *u, users) {
1725 			auto rpcUser = currentTree->add_users();
1726 			ToRPC(server, u, rpcUser);
1727 		}
1728 
1729 		QList< ::Channel *> channels = currentChannel->qlChannels;
1730 		qSort(channels.begin(), channels.end(), [] (const ::Channel *a, const ::Channel *b) -> bool {
1731 			return ::Channel::lessThan(a, b);
1732 		});
1733 		foreach(const ::Channel *subChannel, channels) {
1734 			auto subTree = currentTree->add_children();
1735 			qQueue.enqueue(qMakePair(subChannel, subTree));
1736 		}
1737 	}
1738 
1739 	end(root);
1740 }
1741 
impl(bool)1742 void V1_BansGet::impl(bool) {
1743 	auto server = MustServer(request);
1744 
1745 	::MurmurRPC::Ban_List list;
1746 	list.mutable_server()->set_id(server->iServerNum);
1747 	foreach(const ::Ban &ban, server->qlBans) {
1748 		auto rpcBan = list.add_bans();
1749 		ToRPC(server, ban, rpcBan);
1750 	}
1751 
1752 	end(list);
1753 }
1754 
impl(bool)1755 void V1_BansSet::impl(bool) {
1756 	auto server = MustServer(request);
1757 	server->qlBans.clear();
1758 
1759 	for (int i = 0; i < request.bans_size(); i++) {
1760 		const auto &rpcBan = request.bans(i);
1761 		::Ban ban;
1762 		FromRPC(server, rpcBan, ban);
1763 		server->qlBans << ban;
1764 	}
1765 	server->saveBans();
1766 
1767 	end();
1768 }
1769 
impl(bool)1770 void V1_ACLGet::impl(bool) {
1771 	auto server = MustServer(request);
1772 	auto channel = MustChannel(server, request);
1773 
1774 	::MurmurRPC::ACL_List list;
1775 	list.set_inherit(channel->bInheritACL);
1776 
1777 	QStack< ::Channel *> chans;
1778 	ChanACL *acl;
1779 	::Channel *p = channel;
1780 	while (p) {
1781 		chans.push(p);
1782 		if ((p == channel) || p->bInheritACL) {
1783 			p = p->cParent;
1784 		} else {
1785 			p = NULL;
1786 		}
1787 	}
1788 
1789 	while (!chans.isEmpty()) {
1790 		p = chans.pop();
1791 		foreach(acl, p->qlACL) {
1792 			if (p == channel || acl->bApplySubs) {
1793 				auto rpcACL = list.add_acls();
1794 				ToRPC(server, acl, rpcACL);
1795 				if (p != channel) {
1796 					rpcACL->set_inherited(true);
1797 				}
1798 			}
1799 		}
1800 	}
1801 
1802 	p = channel->cParent;
1803 	const QSet<QString> allnames = ::Group::groupNames(channel);
1804 	foreach(const QString &name, allnames) {
1805 		::Group *g = channel->qhGroups.value(name);
1806 		::Group *pg = p ? ::Group::getGroup(p, name) : NULL;
1807 		if (!g && ! pg) {
1808 			continue;
1809 		}
1810 		auto aclGroup = list.add_groups();
1811 		ToRPC(server, g ? g : pg, aclGroup);
1812 		QSet<int> members;
1813 		if (pg) {
1814 			members = pg->members();
1815 		}
1816 		if (g) {
1817 			foreach(auto id, g->qsAdd) {
1818 				auto rpcUser = aclGroup->add_users_add();
1819 				rpcUser->mutable_server()->set_id(server->iServerNum);
1820 				rpcUser->set_id(id);
1821 			}
1822 			foreach(auto id, g->qsRemove) {
1823 				auto rpcUser = aclGroup->add_users_remove();
1824 				rpcUser->mutable_server()->set_id(server->iServerNum);
1825 				rpcUser->set_id(id);
1826 			}
1827 			aclGroup->set_inherited(false);
1828 			members += g->qsAdd;
1829 			members -= g->qsRemove;
1830 		} else {
1831 			aclGroup->set_inherited(true);
1832 		}
1833 		foreach(auto id, members) {
1834 			auto rpcUser = aclGroup->add_users();
1835 			rpcUser->mutable_server()->set_id(server->iServerNum);
1836 			rpcUser->set_id(id);
1837 		}
1838 	}
1839 
1840 	end(list);
1841 }
1842 
impl(bool)1843 void V1_ACLSet::impl(bool) {
1844 	auto server = MustServer(request);
1845 	auto channel = MustChannel(server, request);
1846 
1847 	::Group *g;
1848 	::ChanACL *acl;
1849 
1850 	{
1851 		QWriteLocker wl(&server->qrwlVoiceThread);
1852 
1853 		QHash<QString, QSet<int> > hOldTemp;
1854 		foreach(g, channel->qhGroups) {
1855 			hOldTemp.insert(g->qsName, g->qsTemporary);
1856 			delete g;
1857 		}
1858 		foreach(acl, channel->qlACL) {
1859 			delete acl;
1860 		}
1861 
1862 		channel->qhGroups.clear();
1863 		channel->qlACL.clear();
1864 
1865 		channel->bInheritACL = request.inherit();
1866 
1867 		for (int i = 0; i < request.groups_size(); i++) {
1868 			auto &rpcGroup = request.groups(i);
1869 			auto name = u8(rpcGroup.name());
1870 			g = new ::Group(channel, name);
1871 			g->bInherit = rpcGroup.inherit();
1872 			g->bInheritable = rpcGroup.inheritable();
1873 			for (int j = 0; j < rpcGroup.users_add_size(); j++) {
1874 				g->qsAdd.insert(rpcGroup.users_add(j).id());
1875 			}
1876 			for (int j = 0; j < rpcGroup.users_remove_size(); j++) {
1877 				g->qsRemove.insert(rpcGroup.users_remove(j).id());
1878 			}
1879 			g->qsTemporary = hOldTemp.value(name);
1880 		}
1881 		for (int i = 0; i < request.acls_size(); i++) {
1882 			auto &rpcACL = request.acls(i);
1883 			acl = new ChanACL(channel);
1884 			acl->bApplyHere = rpcACL.apply_here();
1885 			acl->bApplySubs = rpcACL.apply_subs();
1886 			if (rpcACL.has_user()) {
1887 				acl->iUserId = rpcACL.user().id();
1888 			}
1889 			if (rpcACL.has_group() && rpcACL.group().has_name()) {
1890 				acl->qsGroup = u8(rpcACL.group().name());
1891 			}
1892 			acl->pDeny = static_cast<ChanACL::Permissions>(rpcACL.deny()) & ChanACL::All;
1893 			acl->pAllow = static_cast<ChanACL::Permissions>(rpcACL.allow()) & ChanACL::All;
1894 		}
1895 	}
1896 
1897 	server->clearACLCache();
1898 	server->updateChannel(channel);
1899 
1900 	end();
1901 }
1902 
impl(bool)1903 void V1_ACLGetEffectivePermissions::impl(bool) {
1904 	auto server = MustServer(request);
1905 	auto user = MustUser(server, request);
1906 	auto channel = MustChannel(server, request);
1907 
1908 	auto flags = int(server->effectivePermissions(user, channel));
1909 
1910 	::MurmurRPC::ACL rpcACL;
1911 	rpcACL.set_allow(::MurmurRPC::ACL_Permission(flags));
1912 	end(rpcACL);
1913 }
1914 
impl(bool)1915 void V1_ACLAddTemporaryGroup::impl(bool) {
1916 	auto server = MustServer(request);
1917 	auto user = MustUser(server, request);
1918 	auto channel = MustChannel(server, request);
1919 
1920 	if (!request.has_name()) {
1921 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing name");
1922 	}
1923 
1924 	QString qsgroup = u8(request.name());
1925 	if (qsgroup.isEmpty()) {
1926 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "empty name");
1927 	}
1928 
1929 	{
1930 		QWriteLocker wl(&server->qrwlVoiceThread);
1931 
1932 		::Group *g = channel->qhGroups.value(qsgroup);
1933 		if (!g) {
1934 			g = new ::Group(channel, qsgroup);
1935 		}
1936 
1937 		g->qsTemporary.insert(-user->uiSession);
1938 	}
1939 
1940 	server->clearACLCache(user);
1941 
1942 	end();
1943 }
1944 
impl(bool)1945 void V1_ACLRemoveTemporaryGroup::impl(bool) {
1946 	auto server = MustServer(request);
1947 	auto user = MustUser(server, request);
1948 	auto channel = MustChannel(server, request);
1949 
1950 	if (!request.has_name()) {
1951 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing name");
1952 	}
1953 
1954 	QString qsgroup = u8(request.name());
1955 	if (qsgroup.isEmpty()) {
1956 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "empty name");
1957 	}
1958 
1959 	{
1960 		QWriteLocker wl(&server->qrwlVoiceThread);
1961 
1962 		::Group *g = channel->qhGroups.value(qsgroup);
1963 		if (!g) {
1964 			g = new ::Group(channel, qsgroup);
1965 		}
1966 
1967 		g->qsTemporary.remove(-user->uiSession);
1968 	}
1969 
1970 	server->clearACLCache(user);
1971 
1972 	end();
1973 }
1974 
impl(bool)1975 void V1_AuthenticatorStream::impl(bool) {
1976 	auto onInitialize = [this] (V1_AuthenticatorStream *, bool ok) {
1977 		if (!ok) {
1978 			finish(ok);
1979 			return;
1980 		}
1981 		if (!request.has_initialize()) {
1982 			throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing initialize");
1983 		}
1984 		auto server = MustServer(request.initialize());
1985 		QMutexLocker l(&rpc->qmAuthenticatorsLock);
1986 		rpc->removeAuthenticator(server);
1987 		rpc->m_authenticators.insert(server->iServerNum, this);
1988 	};
1989 	stream.Read(&request, callback(onInitialize));
1990 }
1991 
done(bool)1992 void V1_AuthenticatorStream::done(bool) {
1993 	auto i = std::find(rpc->m_authenticators.begin(), rpc->m_authenticators.end(), this);
1994 	if (i != rpc->m_authenticators.end()) {
1995 		rpc->m_authenticators.erase(i);
1996 	}
1997 	deref();
1998 }
1999 
impl(bool)2000 void V1_DatabaseUserQuery::impl(bool) {
2001 	auto server = MustServer(request);
2002 
2003 	QString filter;
2004 	if (request.has_filter()) {
2005 		filter = u8(request.filter());
2006 	}
2007 	auto users = server->getRegisteredUsers(filter);
2008 
2009 	::MurmurRPC::DatabaseUser_List list;
2010 	list.mutable_server()->set_id(server->iServerNum);
2011 
2012 	for (auto itr = users.constBegin(); itr != users.constEnd(); ++itr) {
2013 		auto user = list.add_users();
2014 		user->mutable_server()->set_id(server->iServerNum);
2015 		user->set_id(itr.key());
2016 		user->set_name(u8(itr.value()));
2017 	}
2018 
2019 	end(list);
2020 }
2021 
impl(bool)2022 void V1_DatabaseUserGet::impl(bool) {
2023 	auto server = MustServer(request);
2024 
2025 	if (!request.has_id()) {
2026 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing id");
2027 	}
2028 	auto info = server->getRegistration(request.id());
2029 	if (info.isEmpty()) {
2030 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "invalid user");
2031 	}
2032 	auto texture = server->getUserTexture(request.id());
2033 
2034 	::MurmurRPC::DatabaseUser rpcDatabaseUser;
2035 	ToRPC(server, info, texture, &rpcDatabaseUser);
2036 	end(rpcDatabaseUser);
2037 }
2038 
impl(bool)2039 void V1_DatabaseUserUpdate::impl(bool) {
2040 	auto server = MustServer(request);
2041 
2042 	if (!request.has_id()) {
2043 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing id");
2044 	}
2045 	if (!server->isUserId(request.id())) {
2046 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "invalid user");
2047 	}
2048 
2049 	QMap<int, QString> info;
2050 	FromRPC(request, info);
2051 
2052 	if (!server->setInfo(request.id(), info)) {
2053 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "invalid user");
2054 	}
2055 	if (request.has_texture()) {
2056 		server->setTexture(request.id(), QByteArray(request.texture().c_str(), request.texture().size()));
2057 	}
2058 
2059 	if (info.contains(ServerDB::User_Name) || info.contains(ServerDB::User_Comment)) {
2060 		foreach(::ServerUser *u, server->qhUsers) {
2061 			if (static_cast<unsigned int>(u->iId) == request.id()) {
2062 				QString name = u->qsName;
2063 				QString comment = u->qsComment;
2064 				if (info.contains(ServerDB::User_Name)) {
2065 					name = info.value(ServerDB::User_Name);
2066 				}
2067 				if (info.contains(ServerDB::User_Comment)) {
2068 					comment = info.value(ServerDB::User_Comment);
2069 				}
2070 				server->setUserState(u, u->cChannel, u->bMute, u->bDeaf, u->bSuppress, u->bPrioritySpeaker, name, comment);
2071 				break;
2072 			}
2073 		}
2074 	}
2075 
2076 	end();
2077 }
2078 
impl(bool)2079 void V1_DatabaseUserRegister::impl(bool) {
2080 	auto server = MustServer(request);
2081 
2082 	QMap<int, QString> info;
2083 	FromRPC(request, info);
2084 
2085 	auto userid = server->registerUser(info);
2086 	if (userid < 0) {
2087 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "invalid user");
2088 	}
2089 	QByteArray texture;
2090 	if (request.has_texture()) {
2091 		texture = QByteArray(request.texture().c_str(), request.texture().size());
2092 		server->setTexture(request.id(), texture);
2093 	}
2094 
2095 	::MurmurRPC::DatabaseUser rpcDatabaseUser;
2096 	rpcDatabaseUser.set_id(userid);
2097 	ToRPC(server, info, texture, &rpcDatabaseUser);
2098 	end(rpcDatabaseUser);
2099 }
2100 
impl(bool)2101 void V1_DatabaseUserDeregister::impl(bool) {
2102 	auto server = MustServer(request);
2103 
2104 	if (!request.has_id()) {
2105 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing id");
2106 	}
2107 	if (!server->unregisterUser(request.id())) {
2108 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "invalid user");
2109 	}
2110 
2111 	end();
2112 }
2113 
impl(bool)2114 void V1_DatabaseUserVerify::impl(bool) {
2115 	auto server = MustServer(request);
2116 
2117 	if (!request.has_name()) {
2118 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing name");
2119 	}
2120 	if (!request.has_password()) {
2121 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing password");
2122 	}
2123 
2124 	auto name = u8(request.name());
2125 	auto password = u8(request.password());
2126 
2127 	auto ret = server->authenticate(name, password);
2128 	switch (ret) {
2129 	case -1:
2130 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "invalid username and/or password");
2131 	case -2:
2132 		throw ::grpc::Status(::grpc::NOT_FOUND, "unknown user");
2133 	case -3:
2134 		throw ::grpc::Status(::grpc::UNAVAILABLE, "authenticator temporarily unavailable");
2135 	}
2136 
2137 	::MurmurRPC::DatabaseUser rpcDatabaseUser;
2138 	rpcDatabaseUser.mutable_server()->set_id(server->iServerNum);
2139 	rpcDatabaseUser.set_id(ret);
2140 	end(rpcDatabaseUser);
2141 }
2142 
impl(bool)2143 void V1_RedirectWhisperGroupAdd::impl(bool) {
2144 	auto server = MustServer(request);
2145 	auto user = MustUser(server, request);
2146 
2147 	if (!request.source().has_name()) {
2148 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing source name");
2149 	}
2150 	if (!request.target().has_name()) {
2151 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing target name");
2152 	}
2153 
2154 	QString qssource = u8(request.source().name());
2155 	QString qstarget = u8(request.target().name());
2156 
2157 	{
2158 		QWriteLocker wl(&server->qrwlVoiceThread);
2159 		user->qmWhisperRedirect.insert(qssource, qstarget);
2160 	}
2161 
2162 	server->clearACLCache(user);
2163 
2164 	end();
2165 }
2166 
impl(bool)2167 void V1_RedirectWhisperGroupRemove::impl(bool) {
2168 	auto server = MustServer(request);
2169 	auto user = MustUser(server, request);
2170 
2171 	if (!request.source().has_name()) {
2172 		throw ::grpc::Status(::grpc::INVALID_ARGUMENT, "missing source name");
2173 	}
2174 
2175 	QString qssource = u8(request.source().name());
2176 
2177 	{
2178 		QWriteLocker wl(&server->qrwlVoiceThread);
2179 		user->qmWhisperRedirect.remove(qssource);
2180 	}
2181 
2182 	server->clearACLCache(user);
2183 
2184 	end();
2185 }
2186 
2187 }
2188 }
2189