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()); } }
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); }
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 }
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); } } }
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); }
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"); } } }
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()); } }
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"); } } }
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); } }
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)); }
void Client::sendDirectMessage(protocol::MessagePtr msg) { if(!d->isAwaitingReset || msg->isControl()) d->msgqueue->send(msg); }