Example #1
0
void AnnotationState::handleAnnotationCommand(protocol::MessagePtr msg)
{
	switch(msg->type()) {
	case protocol::MSG_ANNOTATION_CREATE: {
		const auto &cmd = msg.cast<const protocol::AnnotationCreate>();
		addAnnotation(Annotation { cmd.id(), QString(), QRect(cmd.x(), cmd.y(), cmd.w(), cmd.h()), QColor(Qt::transparent) });
		break;
	}
	case protocol::MSG_ANNOTATION_RESHAPE: {
			const auto &cmd = msg.cast<const protocol::AnnotationReshape>();
			reshapeAnnotation(cmd.id(), QRect(cmd.x(), cmd.y(), cmd.w(), cmd.h()));
			break;
	}
	case protocol::MSG_ANNOTATION_EDIT: {
			const auto &cmd = msg.cast<const protocol::AnnotationEdit>();
			changeAnnotation(cmd.id(), cmd.text(), QColor::fromRgba(cmd.bg()));
			break;
	}
	case protocol::MSG_ANNOTATION_DELETE: {
			const auto &cmd = msg.cast<const protocol::AnnotationDelete>();
			deleteAnnotation(cmd.id());
			break;
	}
	default: qFatal("unhandled annotation command: %d", msg->type());
	}
}
Example #2
0
void Client::sendMessage(protocol::MessagePtr msg)
{
	msg->setContextId(m_myId);

	// Command type messages go to the local fork too
	if(msg->isCommand())
		emit drawingCommandLocal(msg);

	_server->sendMessage(msg);
}
Example #3
0
void LoopbackServer::sendMessage(protocol::MessagePtr msg)
{
	// Keep track of layer and annotation IDs.
	switch(msg->type()) {
		using namespace protocol;
		case MSG_LAYER_CREATE: {
			LayerCreate &lc = msg.cast<LayerCreate>();
			if(lc.id() == 0)
				lc.setId(_layer_ids.takeNext());
			else
				_layer_ids.reserve(lc.id());
			break;
		}
		case MSG_ANNOTATION_CREATE: {
			AnnotationCreate &ac = msg.cast<AnnotationCreate>();
			if(ac.id() == 0)
				ac.setId(_annotation_ids.takeNext());
			else
				_annotation_ids.reserve(ac.id());
			break;
		}
		default: /* no special handling needed */ break;
	}
#ifdef LAG_SIMULATOR
	_msgqueue.append(msg);
	if(!_lagtimer->isActive()) {
		_lagtimer->start(qrand() % LAG_SIMULATOR);
	}
#else
	emit messageReceived(msg);
#endif
}
Example #4
0
void Client::sendAvailableCommands()
{
	if(_state != IN_SESSION)
		return;

	if(_substreampointer>=0) {
		// Are we downloading a substream?
		const protocol::MessagePtr sptr = _session->mainstream().at(_streampointer);
		Q_ASSERT(sptr->type() == protocol::MSG_SNAPSHOTPOINT);
		const protocol::SnapshotPoint &sp = sptr.cast<const protocol::SnapshotPoint>();

		if(_substreampointer == 0) {
			// User is in the beginning of a stream, send stream position message
			uint streamlen = 0;
			for(int i=0;i<sp.substream().length();++i)
				streamlen += sp.substream().at(i)->length();
			for(int i=_streampointer+1;i<_session->mainstream().end();++i)
				streamlen += _session->mainstream().at(i)->length();

			_msgqueue->send(MessagePtr(new protocol::StreamPos(streamlen)));
		}
		// Enqueue substream
		while(_substreampointer < sp.substream().length())
			_msgqueue->send(sp.substream().at(_substreampointer++));

		if(sp.isComplete()) {
			_substreampointer = -1;
			++_streampointer;
			sendAvailableCommands();
		}
	} else {
		// No substream in progress, enqueue normal commands
		// Snapshot points (substreams) are skipped.
		while(_streampointer < _session->mainstream().end()) {
			MessagePtr msg = _session->mainstream().at(_streampointer++);
			if(msg->type() != protocol::MSG_SNAPSHOTPOINT)
				_msgqueue->send(msg);
		}
	}
}
Example #5
0
void Client::handleMessage(protocol::MessagePtr msg)
{
	// Handle control messages here
	// (these are sent only by the server and are not stored in the session)
	if(msg->isControl()) {
		switch(msg->type()) {
		using namespace protocol;
		case MSG_COMMAND:
			handleServerCommand(msg.cast<Command>());
			break;
		case MSG_DISCONNECT:
			handleDisconnectMessage(msg.cast<Disconnect>());
			break;
		default:
			qWarning("Received unhandled control message %d", msg->type());
		}
		return;
	}

	// Rest of the messages are part of the session
	emit messageReceived(msg);
}
Example #6
0
void LoginHandler::handleLoginMessage(protocol::MessagePtr msg)
{
	if(msg->type() != protocol::MSG_LOGIN) {
		logger::error() << "login handler was passed a non-login message!";
		return;
	}

	QString message = msg.cast<protocol::Login>().message();

	if(_state == WAIT_FOR_SECURE) {
		// Secure mode: wait for STARTTLS before doing anything
		if(message == "STARTTLS") {
			handleStarttls();
		} else {
			send("ERROR MUSTSECURE");
			logger::notice() << _client << "Didn't secure connection!";
			_client->disconnectError("must secure connection first");
		}

	} else if(_state == WAIT_FOR_IDENT) {
		// Wait for user identification before moving on to session listing
		if(message == "STARTTLS") {
			handleStarttls();
		} else if(message.startsWith("IDENT ")) {
			handleIdentMessage(message);
		} else {
			logger::notice() << _client << "Invalid login message";
			_client->disconnectError("invalid message");
		}

	} else if(_state == WAIT_FOR_IDENTITYMANAGER_REPLY) {
		// Client shouldn't shouldn't send anything in this state
		logger::notice() << _client << "Got login message while waiting for identity manager reply";
		_client->disconnectError("unexpected message");

	} else {
		if(message.startsWith("HOST ")) {
			handleHostMessage(message);
		} else if(message.startsWith("JOIN ")) {
			handleJoinMessage(message);
		} else {
			logger::notice() << _client << "Got invalid login message";
			_client->disconnectError("invalid message");
		}
	}
}
Example #7
0
void CanvasModel::handleCommand(protocol::MessagePtr cmd)
{
	using namespace protocol;

	// Apply ACL filter
	if(!m_aclfilter->filterMessage(*cmd)) {
		qDebug("Filtered message %d from %d", cmd->type(), cmd->contextId());
		return;
	}

	if(cmd->isMeta()) {
		// Handle meta commands here
		switch(cmd->type()) {
		case MSG_CHAT:
			metaChat(cmd.cast<Chat>());
			break;
		case MSG_USER_JOIN:
			metaUserJoin(cmd.cast<UserJoin>());
			break;
		case MSG_USER_LEAVE:
			metaUserLeave(cmd.cast<UserLeave>());
			break;
		case MSG_SESSION_OWNER:
		case MSG_USER_ACL:
		case MSG_SESSION_ACL:
		case MSG_LAYER_ACL:
			// Handled by the ACL filter
			break;
		case MSG_INTERVAL:
			/* intervals are used only when playing back recordings */
			break;
		case MSG_LASERTRAIL:
			metaLaserTrail(cmd.cast<protocol::LaserTrail>());
			break;
		case MSG_MOVEPOINTER:
			metaMovePointer(cmd.cast<MovePointer>());
			break;
		case MSG_MARKER:
			metaMarkerMessage(cmd.cast<Marker>());
			break;
		default:
			qWarning("Unhandled meta message type %d", cmd->type());
		}

	} else if(cmd->isCommand()) {
		// The state tracker handles all drawing commands
		m_statetracker->receiveQueuedCommand(cmd);
		emit canvasModified();

	} else {
		qWarning("CanvasModel::handleDrawingCommand: command %d is neither Meta nor Command type!", cmd->type());
	}
}
Example #8
0
void LoginHandler::handleLoginMessage(protocol::MessagePtr msg)
{
	if(msg->type() != protocol::MSG_COMMAND) {
		logger::error() << "login handler was passed a non-login message!";
		return;
	}

	protocol::ServerCommand cmd = msg.cast<protocol::Command>().cmd();

	if(m_state == WAIT_FOR_SECURE) {
		// Secure mode: wait for STARTTLS before doing anything
		if(cmd.cmd == "startTls") {
			handleStarttls();
		} else {
			logger::notice() << m_client << "Didn't secure connection!";
			sendError("tlsRequired", "TLS required");
		}

	} else if(m_state == WAIT_FOR_IDENT) {
		// Wait for user identification before moving on to session listing
		if(cmd.cmd == "startTls") {
			handleStarttls();
		} else if(cmd.cmd == "ident") {
			handleIdentMessage(cmd);
		} else {
			logger::notice() << m_client << "Invalid login message";
			m_client->disconnectError("invalid message");
		}

	} else if(m_state == WAIT_FOR_IDENTITYMANAGER_REPLY) {
		// Client shouldn't shouldn't send anything in this state
		logger::notice() << m_client << "Got login message while waiting for identity manager reply";
		m_client->disconnectError("unexpected message");

	} else {
		if(cmd.cmd == "host") {
			handleHostMessage(cmd);
		} else if(cmd.cmd == "join") {
			handleJoinMessage(cmd);
		} else {
			logger::notice() << m_client << "Got invalid login message";
			m_client->disconnectError("invalid message");
		}
	}
}
Example #9
0
void Writer::recordMessage(const protocol::MessagePtr &msg)
{
	if(msg->isRecordable()) {
		const qint64 now = QDateTime::currentMSecsSinceEpoch();

		if(m_minInterval>0) {
			const qint64 interval = now - m_interval;
			if(interval >= m_minInterval) {
				writeMessage(protocol::Interval(0, qMin(qint64(0xffff), interval)));
			}
			m_interval = now;
		}

		if(m_timestampInterval > 0) {
			const qint64 interval = now - m_lastTimestamp;
			if(interval >= m_timestampInterval) {
				writeMessage(protocol::Marker(0, QDateTime::currentDateTime().toString()));
				m_lastTimestamp = now;
			}
		}

		writeMessage(*msg);
	}
}
Example #10
0
void IndexBuilder::addToIndex(const protocol::MessagePtr msg)
{
	IndexType type = IDX_NULL;
	QString title;
	quint32 color = _colors[msg->contextId()];

	switch(msg->type()) {
	using namespace protocol;
	case MSG_CANVAS_RESIZE: type = IDX_RESIZE; break;

	case MSG_LAYER_CREATE: type = IDX_CREATELAYER; break;

	case MSG_LAYER_DELETE: type = IDX_DELETELAYER; break;
	case MSG_PUTIMAGE: type = IDX_PUTIMAGE; break;

	case MSG_PEN_MOVE:
	case MSG_PEN_UP: type = IDX_STROKE; break;

	case MSG_TOOLCHANGE:
		_colors[msg->contextId()] = msg.cast<const protocol::ToolChange>().color();
		break;

	case MSG_ANNOTATION_CREATE:
	case MSG_ANNOTATION_DELETE:
	case MSG_ANNOTATION_EDIT:
	case MSG_ANNOTATION_RESHAPE: type = IDX_ANNOTATE; break;

	case MSG_UNDO:
		if(msg.cast<const protocol::Undo>().points() > 0)
			type = IDX_UNDO;
		else
			type = IDX_REDO;
		break;

	case MSG_FILLRECT:
		type = IDX_FILL;
		color = msg.cast<const protocol::FillRect>().color();
		break;

	case MSG_CHAT:
		type = IDX_CHAT;
		title = msg.cast<const protocol::Chat>().message().left(32);
		break;

	case MSG_INTERVAL: type = IDX_PAUSE; break;

	case MSG_MOVEPOINTER: type = IDX_LASER; break;

	case MSG_MARKER:
		type = IDX_MARKER;
		title = msg.cast<const protocol::Marker>().text();
		break;

	case MSG_USER_JOIN:
		m_index.m_ctxnames[msg->contextId()] = msg.cast<const protocol::UserJoin>().name();
		return;

	default: break;
	}

	if(type==IDX_NULL) {
		return;

	} else if(type==IDX_PUTIMAGE || type==IDX_ANNOTATE) {
		// Combine consecutive messages from the same user
		for(int i=m_index.m_index.size()-1;i>=0;--i) {
			IndexEntry &e = m_index.m_index[i];
			if(e.context_id == msg->contextId()) {
				if(e.type == type) {
					e.end = _pos;
					return;
				}
				break;
			}
		}

	} else if(type==IDX_LASER) {
		// Combine laser pointer strokes
		for(int i=m_index.m_index.size()-1;i>=0;--i) {
			IndexEntry &e = m_index.m_index[i];
			if(e.context_id == msg->contextId()) {
				if(!(e.flags & IndexEntry::FLAG_FINISHED)) {
					e.end = _pos;
					if(msg->type() == protocol::MSG_LASERTRAIL)
						e.flags |= IndexEntry::FLAG_FINISHED;
					return;
				}
				break;
			}
		}

	} else if(type==IDX_STROKE) {
		// Combine all strokes up to last pen-up from the same user
		for(int i=m_index.m_index.size()-1;i>=0;--i) {
			IndexEntry &e = m_index.m_index[i];
			if(e.context_id == msg->contextId() && e.type == IDX_STROKE) {
				if(!(e.flags & IndexEntry::FLAG_FINISHED)) {
					e.end = _pos;
					if(msg->type() == protocol::MSG_PEN_UP)
						e.flags |= IndexEntry::FLAG_FINISHED;
					return;
				}
				break;
			}
		}
	}

	// New index entry
	m_index.m_index.append(IndexEntry(type, msg->contextId(), _offset, _pos, _pos, color, title));
}
Example #11
0
void Client::sendDirectMessage(protocol::MessagePtr msg)
{
	if(!d->isAwaitingReset || msg->isControl())
		d->msgqueue->send(msg);
}