void Synchronizer::_registerWndClass() // Win32-only { if (sm_iClass) { UT_DEBUGMSG(("Skipping window class registration\n")); return; } AbiCollabSessionManager * pSessionManager = AbiCollabSessionManager::getManager(); UT_return_if_fail(pSessionManager); HINSTANCE hInstance = pSessionManager->getInstance(); UT_return_if_fail(hInstance); WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = Synchronizer::s_wndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = NULL; wc.hCursor = NULL; wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.lpszClassName = SYNC_CLASSNAME; sm_iClass = RegisterClass(&wc); UT_return_if_fail(sm_iClass); sm_iMessageWindows = 0; }
void AP_UnixDialog_CollaborationAddBuddy::_populateWindowData() { // populate the account combobox GtkListStore* store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_POINTER); GtkTreeIter iter; AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); for (UT_uint32 i = 0; i < pManager->getAccounts().size(); i++) { AccountHandler* pHandler = pManager->getAccounts()[i]; if (pHandler && pHandler->allowsManualBuddies()) { gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, DESC_COLUMN, pHandler->getDescription().utf8_str(), HANDLER_COLUMN, pHandler, -1); } } m_model = GTK_TREE_MODEL (store); gtk_combo_box_set_model(GTK_COMBO_BOX(m_wAccount), m_model); // if we have at least one account, then make sure the first one is selected if (pManager->getAccounts().size() > 0) { gtk_combo_box_set_active(GTK_COMBO_BOX(m_wAccount), 0); } else { // nope, we don't have any account :'-( gtk_combo_box_set_active(GTK_COMBO_BOX(m_wAccount), -1); } }
bool TelepathyAccountHandler::disconnect() { UT_DEBUGMSG(("TelepathyAccountHandler::disconnect()\n")); UT_return_val_if_fail(m_pTpClient, false); AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); UT_return_val_if_fail(pManager, false); // unregister as a telepathy client tp_base_client_unregister(m_pTpClient); m_pTpClient = NULL; // tear down all active rooms for (std::vector<TelepathyChatroomPtr>::iterator it = m_chatrooms.begin(); it != m_chatrooms.end(); it++) (*it)->stop(); // we are disconnected now, no need to receive events anymore pManager->unregisterEventListener(this); // signal all listeners we are logged out AccountOfflineEvent event; AbiCollabSessionManager::getManager()->signal(event); return true; }
void TCPAccountHandler::addBuddy(BuddyPtr pBuddy) { UT_DEBUGMSG(("TCPAccountHandler::addBuddy()\n")); UT_return_if_fail(pBuddy); AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); UT_return_if_fail(pManager); if (getProperty("allow-all") == "true") { const UT_GenericVector<AbiCollab *> pSessions = pManager->getSessions(); for (UT_sint32 i = 0; i < pSessions.size(); i++) { AbiCollab* pSession = pSessions.getNthItem(i); UT_continue_if_fail(pSession); if (pSession->getAclAccount() != this) continue; pSession->appendAcl(pBuddy->getDescriptor(false).utf8_str()); } } AccountHandler::addBuddy(pBuddy); }
GtkListStore* AP_UnixDialog_CollaborationAccounts::_constructModel() { GtkTreeIter iter; GtkListStore* model = gtk_list_store_new (4, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); for (UT_uint32 i = 0; i < pManager->getAccounts().size(); i++) { AccountHandler* pHandler = pManager->getAccounts()[i]; if (pHandler) { UT_DEBUGMSG(("Got account: %s of type %s\n", pHandler->getDescription().utf8_str(), pHandler->getDisplayType().utf8_str() )); gtk_list_store_append (model, &iter); gtk_list_store_set (model, &iter, ONLINE_COLUMN, pHandler->isOnline(), DESC_COLUMN, pHandler->getDescription().utf8_str(), TYPE_COLUMN, pHandler->getDisplayType().utf8_str(), HANDLER_COLUMN, pHandler, -1); } } return model; }
void TelepathyAccountHandler::handleMessage(DTubeBuddyPtr pBuddy, const std::string& packet_str) { UT_DEBUGMSG(("TelepathyAccountHandler::handleMessage()\n")); UT_return_if_fail(pBuddy); AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); UT_return_if_fail(pManager); TelepathyChatroomPtr pChatroom = pBuddy->getChatRoom(); UT_return_if_fail(pChatroom); // construct the packet Packet* pPacket = _createPacket(packet_str, pBuddy); UT_return_if_fail(pPacket); switch (pPacket->getClassType()) { case PCT_GetSessionsEvent: { if (pChatroom->isLocallyControlled()) { // return only the session that belongs to the chatroom that the buddy is in GetSessionsResponseEvent gsre; gsre.m_Sessions[pChatroom->getSessionId()] = pChatroom->getDocName(); send(&gsre, pBuddy); } else UT_DEBUGMSG(("Ignoring GetSessionsEvent, we are not controlling session '%s'\n", pChatroom->getSessionId().utf8_str())); break; } case PCT_GetSessionsResponseEvent: { // check if we received 1 (and only 1) session, and join it // immediately if that is the case GetSessionsResponseEvent* gsre = static_cast<GetSessionsResponseEvent*>( pPacket ); UT_return_if_fail(gsre->m_Sessions.size() == 1); std::map<UT_UTF8String,UT_UTF8String>::iterator it=gsre->m_Sessions.begin(); DocHandle* pDocHandle = new DocHandle((*it).first, (*it).second); // store the session id pChatroom->setSessionId(pDocHandle->getSessionId()); // join the session UT_DEBUGMSG(("Got a running session (%s - %s), let's join it immediately\n", pDocHandle->getSessionId().utf8_str(), pDocHandle->getName().utf8_str())); pManager->joinSessionInitiate(pBuddy, pDocHandle); DELETEP(pDocHandle); break; } default: // let the default handler handle it AccountHandler::handleMessage(pPacket, pBuddy); break; } }
/*! * This virtual method is called if the attached document is deleted with an attached * AbiCollab_Export connected to the document. */ void ABI_Collab_Export::removeDocument(void) { UT_DEBUGMSG(("ABI_Collab_Export::removeDocument()\n")); // inform the session manager that this session is being (forcefully) closed AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); UT_return_if_fail(pManager); // WARNING: Don't do anything after this line, as the disconnectSession() call will // have destroyed ourselves (yes, that is ugly). pManager->disconnectSession(m_pAbiCollab); }
void AbiCollab::initiateSessionTakeover(BuddyPtr pNewMaster) { UT_return_if_fail(pNewMaster); UT_DEBUGMSG(("AbiCollab::initiateSessionTakeover() - pNewMaster: %s\n", pNewMaster->getDescriptor(true).utf8_str())); AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); UT_return_if_fail(pManager); // this could lead to us never exiting; add a timeout or something somewhere :) pManager->beginAsyncOperation(this); // NOTE: we only allow slaves in the session takeover process // that are on the same account as the proposed master is. The // others are dropped from the session. At least for now. // TODO: implement me // reset any old session takeover state m_bProposedController = false; m_pProposedController = pNewMaster; m_vApprovedReconnectBuddies.clear(); m_mAckedSessionTakeoverBuddies.clear(); m_bSessionFlushed = false; if (m_vOutgoingQueue.size() > 0) UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN); m_vOutgoingQueue.clear(); // send a SessionTakeoverRequest packet to the new master std::vector<std::string> buddyIdentifiers; for (std::map<BuddyPtr, std::string>::iterator it = m_vCollaborators.begin(); it != m_vCollaborators.end(); it++) { BuddyPtr pBuddy = (*it).first; UT_continue_if_fail(pBuddy); if (pNewMaster != pBuddy) buddyIdentifiers.push_back(pBuddy->getDescriptor(true).utf8_str()); } SessionTakeoverRequestPacket strp_promote(m_sId, m_pDoc->getDocUUIDString(), true, buddyIdentifiers); pNewMaster->getHandler()->send(&strp_promote, pNewMaster); // send a SessionTakeoverRequest packet to the other slaves (if any) buddyIdentifiers.clear(); buddyIdentifiers.push_back(pNewMaster->getDescriptor(true).utf8_str()); SessionTakeoverRequestPacket strp_normal(m_sId, m_pDoc->getDocUUIDString(), false, buddyIdentifiers); for (std::map<BuddyPtr, std::string>::iterator it = m_vCollaborators.begin(); it != m_vCollaborators.end(); it++) { BuddyPtr pBuddy = (*it).first; UT_continue_if_fail(pBuddy); if (pNewMaster != pBuddy) pBuddy->getHandler()->send(&strp_normal, pBuddy); } m_eTakeoveState = STS_SENT_TAKEOVER_REQUEST; }
void AP_Dialog_CollaborationShare::share(AccountHandler* pAccount, const std::vector<std::string>& vAcl) { UT_DEBUGMSG(("AP_Dialog_CollaborationShare::_share()\n")); AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); UT_return_if_fail(pManager); // determine which document to share XAP_Frame* pFrame = XAP_App::getApp()->getLastFocussedFrame(); UT_return_if_fail(pFrame); PD_Document* pDoc = static_cast<PD_Document *>(pFrame->getCurrentDoc()); UT_return_if_fail(pDoc); AbiCollab* pSession = NULL; if (!pManager->isInSession(pDoc)) { UT_DEBUGMSG(("Sharing document...\n")); // FIXME: this can cause a race condition: the other side can already be // offered the session before we actually started it! // Tell the account handler that we start a new session, so // it set up things if needed. This call may just setup some stuff // for a new session, or it might actually start a new session. bool b = pAccount->startSession(pDoc, m_vAcl, &pSession); if (!b) { XAP_App::getApp()->getLastFocussedFrame()->showMessageBox( "There was an error sharing this document!", XAP_Dialog_MessageBox::b_O, XAP_Dialog_MessageBox::a_OK); return; } // start the session ourselves when the account handler did not... if (!pSession) { // ... and start the session! UT_UTF8String sSessionId(""); // TODO: we could use/generate a proper descriptor when there is only // 1 account where we share this document over pSession = pManager->startSession(pDoc, sSessionId, pAccount, true, NULL, ""); } } else { pSession = pManager->getSession(pDoc); } UT_return_if_fail(pSession); pManager->updateAcl(pSession, pAccount, vAcl); }
void AP_UnixDialog_CollaborationShare::_populateWindowData() { AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); UT_return_if_fail(pManager); // populate the account combobox GtkListStore* store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_POINTER); GtkTreeIter iter; AccountHandler* pShareeableAcount = _getShareableAccountHandler(); if (pShareeableAcount) { gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, 0, pShareeableAcount->getDescription().utf8_str(), 1, pShareeableAcount, -1); gtk_widget_set_sensitive(m_wAccount, false); } else { for (std::vector<AccountHandler*>::const_iterator cit = pManager->getAccounts().begin(); cit != pManager->getAccounts().end(); cit++) { AccountHandler* pAccount = *cit; UT_continue_if_fail(pAccount); if (!pAccount->isOnline() || !pAccount->canManuallyStartSession()) continue; gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, 0, pAccount->getDescription().utf8_str(), 1, pAccount, -1); } gtk_widget_set_sensitive(m_wAccount, true); } m_pAccountModel = GTK_TREE_MODEL (store); gtk_combo_box_set_model(GTK_COMBO_BOX(m_wAccount), m_pAccountModel); // if we have at least one account handler, then make sure the first one is selected if (pManager->getRegisteredAccountHandlers().size() > 0) { gtk_combo_box_set_active(GTK_COMBO_BOX(m_wAccount), 0); } else { // nope, we don't have any account handler :'-( gtk_combo_box_set_active(GTK_COMBO_BOX(m_wAccount), -1); } }
void TCPAccountHandler::handleEvent(boost::shared_ptr<Session> session_ptr) { UT_DEBUGMSG(("TCPAccountHandler::handleEvent()\n")); UT_return_if_fail(session_ptr); AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); UT_return_if_fail(pManager); // make sure we have handled _all_ packets in the queue before checking // the disconnected status bool disconnected = !session_ptr->isConnected(); _handleMessages(session_ptr); // check the connection status if (disconnected) { UT_DEBUGMSG(("Socket is not connected anymore!\n")); // drop all buddies that were on this connection std::map<TCPBuddyPtr, boost::shared_ptr<Session> >::iterator next; for (std::map<TCPBuddyPtr, boost::shared_ptr<Session> >::iterator it = m_clients.begin(); it != m_clients.end(); it = next) { next = it; next++; UT_continue_if_fail((*it).first); UT_continue_if_fail((*it).second); TCPBuddyPtr pB = (*it).first; if ((*it).second == session_ptr) { UT_DEBUGMSG(("Lost connection to %s buddy %s:%s\n", getProperty("server") == "" ? "client" : "server", pB->getAddress().c_str(), pB->getPort().c_str())); // drop this buddy from all sessions pManager->removeBuddy(pB, false); // erase the buddy <-> session mapping m_clients.erase(it); deleteBuddy(pB); } } // if we were connected to a server, then we are basically disconnected now if (getProperty("server") != "") disconnect(); } // check other things here if needed... }
bool s_abicollab_join(AV_View* /*v*/, EV_EditMethodCallData* /*d*/) { AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); UT_return_val_if_fail(pManager, false); // Get the current view that the user is in. XAP_Frame *pFrame = XAP_App::getApp()->getLastFocussedFrame(); // Get an Accounts dialog instance XAP_DialogFactory* pFactory = static_cast<XAP_DialogFactory *>(XAP_App::getApp()->getDialogFactory()); UT_return_val_if_fail(pFactory, false); AP_Dialog_CollaborationJoin* pDialog = static_cast<AP_Dialog_CollaborationJoin*>( pFactory->requestDialog(AbiCollabSessionManager::getManager()->getDialogJoinId()) ); // Run the dialog pDialog->runModal(pFrame); // Handle the dialog outcome AP_Dialog_CollaborationJoin::tAnswer answer = pDialog->getAnswer(); BuddyPtr pBuddy = pDialog->getBuddy(); DocHandle* pDocHandle = pDialog->getDocHandle(); pFactory->releaseDialog(pDialog); switch (answer) { case AP_Dialog_CollaborationJoin::a_OPEN: { UT_return_val_if_fail(pBuddy && pDocHandle, false); // Check if we have already joined this session. If so, then just // ignore the request. Otherwise actually join the session. AbiCollab* pSession = pManager->getSessionFromSessionId(pDocHandle->getSessionId()); if (pSession) { UT_DEBUGMSG(("Already connected to session, just raising the associated frame\n")); // Just raise a frame that contains this session, instead of // opening the document again XAP_Frame* pFrameForSession = pManager->findFrameForSession(pSession); UT_return_val_if_fail(pFrameForSession, false); pFrameForSession->raise(); } else pManager->joinSessionInitiate(pBuddy, pDocHandle); } break; case AP_Dialog_CollaborationJoin::a_CANCEL: break; } return true; }
AbiCollab* AP_Dialog_CollaborationShare::_getActiveSession() { AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); UT_return_val_if_fail(pManager, NULL); XAP_Frame* pFrame = XAP_App::getApp()->getLastFocussedFrame(); UT_return_val_if_fail(pFrame, NULL); PD_Document* pDoc = static_cast<PD_Document *>(pFrame->getCurrentDoc()); UT_return_val_if_fail(pDoc, NULL); if (!pManager->isInSession(pDoc)) return NULL; return pManager->getSession(pDoc); }
/*! * This virtual method is called from the AbiWord main tree upon doing a replace document with an attached * AbiCollab_Export connected to the document. * * Note: this is a really weird signal, coming from a PD_Document * Note: If anything, a Frame should emit this signal to its listeners */ void ABI_Collab_Export::setNewDocument(PD_Document * /*pDoc*/) { UT_DEBUGMSG(("ABI_Collab_Export::setNewDocument()\n")); // inform the session manager to kill off this session, as that is the only // thing we can do if the document is replaced AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); UT_return_if_fail(pManager); // WARNING: Don't do anything after this line, as the disconnectSession() call will // have destroyed ourselves (yes, that is ugly). pManager->disconnectSession(m_pAbiCollab); // FIXME: The AbiCollab destructor will unregister this object as a PD_Document listener, // while the PD_Document will also unregister us as soon as this function returns. // Unregistering the same object twice works, but it is ugly as hell. Fix this someday. }
bool AP_Dialog_CollaborationShare::_populateShareState(BuddyPtr pBuddy) { AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); UT_return_val_if_fail(pManager, false); PD_Document *pDoc = static_cast<PD_Document*>(XAP_App::getApp()->getLastFocussedFrame()->getCurrentDoc()); UT_return_val_if_fail(pDoc, false); if (!pManager->isInSession(pDoc)) { AccountHandler* pHandler = pBuddy->getHandler(); UT_return_val_if_fail(pHandler, false); return pHandler->defaultShareState(pBuddy); } return _inAcl(m_vAcl, pBuddy); }
ConnectResult TelepathyAccountHandler::connect() { UT_DEBUGMSG(("TelepathyAccountHandler::connect()\n")); AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); UT_return_val_if_fail(pManager, CONNECT_FAILED); UT_return_val_if_fail(m_pTpClient == NULL, CONNECT_INTERNAL_ERROR); // inform telepathy that we can handle incoming AbiCollab tubes GError *error = NULL; TpDBusDaemon* dbus = tp_dbus_daemon_dup (&error); UT_return_val_if_fail(dbus, CONNECT_FAILED); m_pTpClient = tp_simple_handler_new(dbus, TRUE, FALSE, "AbiCollab", FALSE, handle_dbus_channel, this, NULL); tp_base_client_take_handler_filter(m_pTpClient, tp_asv_new ( TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_DBUS_TUBE, TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_ROOM, TP_PROP_CHANNEL_TYPE_DBUS_TUBE_SERVICE_NAME, G_TYPE_STRING, INTERFACE, NULL ) ); if (!tp_base_client_register(m_pTpClient, &error)) { UT_DEBUGMSG(("Error registering tube handler: %s", error->message)); UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN); } UT_DEBUGMSG(("Tube handler setup, listening for incoming tubes...\n")); // we are connected now, time to start sending out messages (such as events) pManager->registerEventListener(this); // signal all listeners we are logged in AccountOnlineEvent event; pManager->signal(event); return CONNECT_SUCCESS; }
TCPWin32AccountHandler::TCPWin32AccountHandler() : TCPAccountHandler(), m_pWin32Dialog(NULL), m_hInstance(NULL), m_hServerEntry(NULL), m_hPortEntry(NULL), m_hServerRadio(NULL), m_hJoinRadio(NULL), m_hServerLabel(NULL), m_hPortLabel(NULL), m_hAllowAllCheck(NULL), m_hAutoconnectCheck(NULL) { AbiCollabSessionManager * pSessionManager = AbiCollabSessionManager::getManager(); if (pSessionManager) { m_hInstance = pSessionManager->getInstance(); } }
void TelepathyAccountHandler::buddyDisconnected(TelepathyChatroomPtr pChatroom, TpHandle disconnected) { UT_DEBUGMSG(("TelepathyAccountHandler::buddyDisconnected() - handle: %d\n", disconnected)); UT_return_if_fail(pChatroom); AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); UT_return_if_fail(pManager); DTubeBuddyPtr pBuddy = pChatroom->getBuddy(disconnected); bool isController = pChatroom->isController(pBuddy); pManager->removeBuddy(pBuddy, false); pChatroom->removeBuddy(disconnected); if (isController) { UT_DEBUGMSG(("The master buddy left; stopping the chatroom!\n")); pChatroom->stop(); } }
bool XMPPAccountHandler::disconnect() { UT_DEBUGMSG(("XMPPAccountHandler::disconnect()\n")); AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); UT_return_val_if_fail(pManager, false); // we are disconnected now, no need to receive events anymore pManager->unregisterEventListener(this); tearDown(); // signal all listeners we are logged out AccountOfflineEvent event; // TODO: fill the event AbiCollabSessionManager::getManager()->signal(event); return true; }
Synchronizer::Synchronizer(boost::function<void ()> signalhandler) // Win32 Implementation : m_signalhandler(signalhandler), m_hWnd(0), m_bIsProcessing(false), m_iDeferredMessages(0), m_bIsDestroyed(NULL) { UT_DEBUGMSG(("Synchronizer()\n")); AbiCollabSessionManager * pSessionManager = AbiCollabSessionManager::getManager(); UT_return_if_fail(pSessionManager); HINSTANCE hInstance = pSessionManager->getInstance(); UT_return_if_fail(hInstance); _registerWndClass(); // HWND_MESSAGE as parent HWND is Win2k/xp/vista only - replaced with 0 // (also HWND_MESSAGE doesn't compile in MinGW, weird bug. --RP 8 August 2007) m_hWnd = CreateWindow(SYNC_CLASSNAME, "AbiCollab", 0, CW_USEDEFAULT, SW_HIDE, CW_USEDEFAULT, CW_USEDEFAULT, HWND_MESSAGE, NULL, hInstance, (void *) this ); UT_DEBUGMSG(("Created message window: HWND 0x%x\n", m_hWnd)); switch ((INT_PTR)m_hWnd) { case NULL: UT_DEBUGMSG(("Win32 error: %d.\n", GetLastError())); break; default: sm_iMessageWindows++; break; // ok! }; }
/*! * returns true if at least one account is online */ static bool s_any_accounts_online(bool bIncludeNonManualShareAccounts = true) { AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); UT_return_val_if_fail(pManager, false); const std::vector<AccountHandler *>& vecAccounts = pManager->getAccounts(); for (UT_uint32 i = 0; i < vecAccounts.size(); i++) { AccountHandler* pHandler = vecAccounts[i]; if (pHandler && pHandler->isOnline()) { if (bIncludeNonManualShareAccounts) return true; if (pHandler->canManuallyStartSession()) return true; } } return false; }
void Synchronizer::_unregisterWndClass() // Win32-only { UT_DEBUGMSG(("Synchronizer::_unregisterWndClass()\n")); UT_return_if_fail(sm_iClass); if (sm_iMessageWindows > 0) { UT_DEBUGMSG(("%d message windows still exist, skipping unregistering\n", sm_iMessageWindows)); return; } AbiCollabSessionManager * pManager = AbiCollabSessionManager::getManager(); UT_return_if_fail(pManager); HINSTANCE hInstance = pManager->getInstance(); UT_return_if_fail(hInstance); UT_DEBUGMSG(("Unregistrating message window class\n")); UT_return_if_fail(UnregisterClass(SYNC_CLASSNAME, hInstance)); sm_iClass = 0; }
bool TCPAccountHandler::disconnect() { UT_DEBUGMSG(("TCPAccountHandler::disconnect()\n")); if (!m_bConnected) return true; AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); UT_return_val_if_fail(pManager, false); _teardownAndDestroyHandler(); m_bConnected = false; // signal all listeners we are logged out AccountOfflineEvent event; // TODO: fill the event AbiCollabSessionManager::getManager()->signal(event); // we are disconnected now, no need to sent out messages (such as events) anymore pManager->unregisterEventListener(this); return true; }
void AbiCollab::_shutdownAsMaster() { UT_DEBUGMSG(("AbiCollab::_shutdownAsMaster()\n")); UT_return_if_fail(m_pController == BuddyPtr()); UT_return_if_fail(!m_bProposedController); AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); UT_return_if_fail(pManager); // the session takeover is complete; inform everyone that all session data // is flushed, and that everyone should talk to the new master from now on SessionFlushedPacket sfp(m_sId, m_pDoc->getDocUUIDString()); for (std::map<BuddyPtr, std::string>::iterator it = m_vCollaborators.begin(); it != m_vCollaborators.end(); it++) { BuddyPtr pBuddy = (*it).first; UT_continue_if_fail(pBuddy); pBuddy->getHandler()->send(&sfp, pBuddy); } // session takeover is done as far as the leaving session contoller is concerned pManager->endAsyncOperation(this); }
void AP_Win32Dialog_CollaborationAccounts::_populateWindowData() { AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); UT_return_if_fail(pManager); m_bPopulating = true; // clear out the old contents, if any ListView_DeleteAllItems(m_hAccountList); for (UT_uint32 i = 0; i < pManager->getAccounts().size(); i++) { AccountHandler* pAccount = pManager->getAccounts()[i]; UT_continue_if_fail(pAccount); UT_Win32LocaleString sAccountText = AP_Win32App::s_fromUTF8ToWinLocale(pAccount->getDescription().utf8_str()); UT_Win32LocaleString sAccountTypeText = AP_Win32App::s_fromUTF8ToWinLocale(pAccount->getDisplayType().utf8_str()); // insert a new account record LVITEMW lviAccount; lviAccount.mask = LVIF_STATE | LVIF_IMAGE | LVIF_PARAM; lviAccount.state = 1; lviAccount.iItem = i; lviAccount.iSubItem = 0; lviAccount.lParam = (LPARAM)pAccount; SendMessageW(m_hAccountList, LVM_INSERTITEMW, 0, (LPARAM) &lviAccount); ListView_SetCheckState(m_hAccountList, i, pAccount->isOnline()); lviAccount.iSubItem=1; lviAccount.pszText= const_cast<LPWSTR>(sAccountText.c_str()); SendMessageW(m_hAccountList, LVM_SETITEMTEXTW, i, (LPARAM) &lviAccount); lviAccount.iSubItem=2; lviAccount.pszText= const_cast<LPWSTR>(sAccountTypeText.c_str()); SendMessageW(m_hAccountList, LVM_SETITEMTEXTW, i, (LPARAM) &lviAccount); } _updateSelection(); m_bPopulating = false; }
void AccountHandler::handleMessage(Packet* pPacket, BuddyPtr pBuddy) { UT_return_if_fail(pPacket); UT_return_if_fail(pBuddy); AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); UT_return_if_fail(pManager); // // handle the incoming packet: first check for a protocol error, then ask the // session manager to handle it, then try to handle it ourselves // if (_handleProtocolError(pPacket, pBuddy) || pManager->processPacket(*this, pPacket, pBuddy)) { DELETEP(pPacket); return; } // it seems we need to handle the packet ourselves _handlePacket(pPacket, pBuddy); DELETEP(pPacket); }
bool s_abicollab_record(AV_View* /*v*/, EV_EditMethodCallData* /*d*/) { UT_DEBUGMSG(("s_abicollab_record\n")); // this option only works in debug mode AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); XAP_Frame *pFrame = XAP_App::getApp()->getLastFocussedFrame(); UT_return_val_if_fail(pFrame, false); PD_Document* pDoc = static_cast<PD_Document *>(pFrame->getCurrentDoc()); UT_return_val_if_fail(pDoc, false); // retrieve session AbiCollab* session = pManager->getSession( pDoc ); if (session) { if (session->isRecording()) { session->stopRecording(); UT_ASSERT(!session->isRecording()); } else { session->startRecording( new DiskSessionRecorder( session ) ); UT_ASSERT(session->isRecording()); } } return true; }
void AccountHandler::_handlePacket(Packet* packet, BuddyPtr buddy) { // packet and buddy must always be set UT_return_if_fail(packet); UT_return_if_fail(buddy); // as must the session manager AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); UT_return_if_fail(pManager); // manager didn't handle it, see what we can do switch (packet->getClassType()) { case PCT_JoinSessionRequestEvent: { JoinSessionRequestEvent* jse = static_cast<JoinSessionRequestEvent*>(packet); // lookup session AbiCollab* pSession = pManager->getSessionFromSessionId(jse->getSessionId()); UT_return_if_fail(pSession); // check if this buddy is allowed to access this document // TODO: this should be done for every session packet, not just join session packets if (!hasAccess(pSession->getAcl(), buddy)) { // we should only reach this point if someone is brute forcing trying // out session IDs while not being on the ACL. Ban this uses. UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN); return; } // lookup exporter ABI_Collab_Export* pExport = pSession->getExport(); UT_return_if_fail(pExport); // lookup adjusts const UT_GenericVector<ChangeAdjust *>* pExpAdjusts = pExport->getAdjusts(); UT_return_if_fail(pExpAdjusts); PD_Document* pDoc = pSession->getDocument(); // add this author to the document if we don't recognize him UT_sint32 iAuthorId = -1; UT_UTF8String buddyDescriptor = buddy->getDescriptor(); UT_GenericVector<pp_Author*> authors = pDoc->getAuthors(); UT_DEBUGMSG(("Scanning %d authors to see if we recognize this buddy\n", authors.getItemCount())); for (UT_sint32 i = 0; i < authors.getItemCount(); i++) { pp_Author* pAuthor = authors.getNthItem(i); UT_continue_if_fail(pAuthor); const gchar* szDescriptor = NULL; pAuthor->getProperty("abicollab-descriptor", szDescriptor); if (!szDescriptor) continue; if (buddyDescriptor != szDescriptor) continue; // yay, we know this author! iAuthorId = pAuthor->getAuthorInt(); UT_DEBUGMSG(("Found known author with descriptior %s, id %d!\n", buddyDescriptor.utf8_str(), iAuthorId)); break; } if (iAuthorId == -1) { // we don't know this author yet, create a new author object for him iAuthorId = pDoc->findFirstFreeAuthorInt(); pp_Author * pA = pDoc->addAuthor(iAuthorId); PP_AttrProp * pPA = pA->getAttrProp(); pPA->setProperty("abicollab-descriptor", buddyDescriptor.utf8_str()); pDoc->sendAddAuthorCR(pA); UT_DEBUGMSG(("Added a new author to the documument with descriptor %s, id %d\n", buddyDescriptor.utf8_str(), iAuthorId)); } // serialize entire document into string JoinSessionRequestResponseEvent jsre(jse->getSessionId(), iAuthorId); if (AbiCollabSessionManager::serializeDocument(pDoc, jsre.m_sZABW, false /* no base64 */) == UT_OK) { // set more document properties jsre.m_iRev = pDoc->getCRNumber(); jsre.m_sDocumentId = pDoc->getDocUUIDString(); if (pDoc->getFilename()) jsre.m_sDocumentName = UT_go_basename_from_uri(pDoc->getFilename()); // send to buddy! send(&jsre, buddy); // add this buddy to the collaboration session pSession->addCollaborator(buddy); } break; } case PCT_JoinSessionRequestResponseEvent: { JoinSessionRequestResponseEvent* jsre = static_cast<JoinSessionRequestResponseEvent*>( packet ); PD_Document* pDoc = 0; if (AbiCollabSessionManager::deserializeDocument(&pDoc, jsre->m_sZABW, false) == UT_OK) { if (pDoc) { // NOTE: we could adopt the same document name here, but i'd // rather not at the moment - MARCM pDoc->forceDirty(); if (jsre->m_sDocumentName.size() > 0) { gchar* fname = g_strdup(jsre->m_sDocumentName.utf8_str()); pDoc->setFilename(fname); } // The default ownership when joining is FALSE, as that seems // to make sense for the generic case. The person sharing the // document by default owns the document (and is thus allowed // to modify the ACL). pManager->joinSession(jsre->getSessionId(), pDoc, jsre->m_sDocumentId, jsre->m_iRev, jsre->getAuthorId(), buddy, this, false, NULL); } else { UT_DEBUGMSG(("AccountHandler::_handlePacket() - deserializing document failed!\n")); } } break; } case PCT_GetSessionsEvent: { GetSessionsResponseEvent gsre; const UT_GenericVector<AbiCollab *> sessions = pManager->getSessions(); for (UT_sint32 i = 0; i < sessions.getItemCount(); i++) { AbiCollab* pSession = sessions.getNthItem(i); if (pSession && pSession->isLocallyControlled()) { // check if the buddy has access to this session if (!hasAccess(pSession->getAcl(), buddy)) { UT_DEBUGMSG(("Buddy %s denied access to session %s by ALC\n", buddy->getDescriptor(true).utf8_str(), pSession->getSessionId().utf8_str())); continue; } const PD_Document * pDoc = pSession->getDocument(); UT_continue_if_fail(pDoc); // determine name UT_UTF8String documentBaseName; if (pDoc->getFilename()) documentBaseName = UT_go_basename_from_uri(pDoc->getFilename()); // set session info gsre.m_Sessions[ pSession->getSessionId() ] = documentBaseName; } } send(&gsre, buddy); break; } case PCT_GetSessionsResponseEvent: { GetSessionsResponseEvent* gsre = static_cast<GetSessionsResponseEvent*>( packet ); UT_GenericVector<DocHandle*> vDocHandles; for (std::map<UT_UTF8String,UT_UTF8String>::iterator it=gsre->m_Sessions.begin(); it!=gsre->m_Sessions.end(); ++it) { DocHandle* pDocHandle = new DocHandle((*it).first, (*it).second); vDocHandles.addItem(pDocHandle); } pManager->setDocumentHandles(buddy, vDocHandles); break; } default: { UT_DEBUGMSG(("Unhandled packet class: 0x%x\n", packet->getClassType())); UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN); break; } } }
ConnectResult TCPAccountHandler::connect() { UT_DEBUGMSG(("TCPAccountHandler::connect()\n")); AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); UT_return_val_if_fail(pManager, CONNECT_INTERNAL_ERROR); UT_return_val_if_fail(!m_pDelegator, CONNECT_INTERNAL_ERROR); UT_return_val_if_fail(!m_bConnected, CONNECT_ALREADY_CONNECTED); UT_return_val_if_fail(!m_thread, CONNECT_INTERNAL_ERROR); m_io_service.reset(); m_thread = new asio::thread(boost::bind(&asio::io_service::run, &m_io_service)); // set up the connection if (getProperty("server") == "") { UT_sint32 port = _getPort(getProperties()); UT_DEBUGMSG(("Start accepting connections on port %d...\n", port)); try { IOServerHandler* pDelegator = new IOServerHandler(port, boost::bind(&TCPAccountHandler::_handleAccept, this, _1, _2), boost::bind(&TCPAccountHandler::handleEvent, this, _1), m_io_service); m_pDelegator = pDelegator; m_bConnected = true; // todo: ask it to the acceptor pDelegator->run(); } catch (asio::system_error se) { UT_DEBUGMSG(("Failed to start accepting connections: %s\n", se.what())); _teardownAndDestroyHandler(); return CONNECT_FAILED; } catch (...) { UT_DEBUGMSG(("Caught unhandled server exception!\n")); _teardownAndDestroyHandler(); return CONNECT_FAILED; } } else { UT_DEBUGMSG(("Connecting to server %s on port %d...\n", getProperty("server").c_str(), _getPort(getProperties()))); try { asio::ip::tcp::resolver resolver(m_io_service); asio::ip::tcp::resolver::query query(getProperty("server"), getProperty("port")); asio::ip::tcp::resolver::iterator iterator(resolver.resolve(query)); bool connected = false; boost::shared_ptr<Session> session_ptr(new Session(m_io_service, boost::bind(&TCPAccountHandler::handleEvent, this, _1))); while (iterator != tcp::resolver::iterator()) { try { UT_DEBUGMSG(("Attempting to connect...\n")); session_ptr->connect(iterator); UT_DEBUGMSG(("Connected!\n")); connected = true; break; } catch (asio::system_error se) { UT_DEBUGMSG(("Connection attempt failed: %s\n", se.what())); // make sure we close the socket after a failed attempt, as it // may have been opened by the connect() call. try { session_ptr->getSocket().close(); } catch(...) {} } iterator++; } if (!connected) { UT_DEBUGMSG(("Giving up to connecting to server!\n")); _teardownAndDestroyHandler(); return CONNECT_FAILED; } session_ptr->asyncReadHeader(); m_bConnected = true; // todo: ask it to the socket // Add a buddy TCPBuddyPtr pBuddy = boost::shared_ptr<TCPBuddy>(new TCPBuddy(this, session_ptr->getRemoteAddress(), boost::lexical_cast<std::string>(session_ptr->getRemotePort()))); addBuddy(pBuddy); m_clients.insert(std::pair<TCPBuddyPtr, boost::shared_ptr<Session> >(pBuddy, session_ptr)); } catch (asio::system_error se) { UT_DEBUGMSG(("Failed to resolve %s:%d: %s\n", getProperty("server").c_str(), _getPort(getProperties()), se.what())); _teardownAndDestroyHandler(); return CONNECT_FAILED; } } if (!m_bConnected) return CONNECT_FAILED; // we are connected now, time to start sending out messages (such as events) pManager->registerEventListener(this); // signal all listeners we are logged in AccountOnlineEvent event; // TODO: fill the event AbiCollabSessionManager::getManager()->signal(event); return CONNECT_SUCCESS; }
bool AbiCollab::_handleSessionTakeover(AbstractSessionTakeoverPacket* pPacket, BuddyPtr collaborator) { UT_DEBUGMSG(("AbiCollab::_handleSessionTakeover()\n")); UT_return_val_if_fail(pPacket, false); UT_return_val_if_fail(collaborator, false); AbiCollabSessionManager* pManager = AbiCollabSessionManager::getManager(); UT_return_val_if_fail(pManager, false); switch (m_eTakeoveState) { case STS_NONE: { // we only accept a SessionTakeoverRequest or MasterChangeRequest packet UT_return_val_if_fail(pPacket->getClassType() == PCT_SessionTakeoverRequestPacket, false); // we can only allow such a packet from the controller UT_return_val_if_fail(m_pController == collaborator, false); // handle the SessionTakeoverRequestPacket packet m_pProposedController = BuddyPtr(); m_vApprovedReconnectBuddies.clear(); SessionTakeoverRequestPacket* strp = static_cast<SessionTakeoverRequestPacket*>(pPacket); m_bProposedController = strp->promote(); if (m_bProposedController) { for (std::vector<std::string>::const_iterator cit = strp->getBuddyIdentifiers().begin(); cit != strp->getBuddyIdentifiers().end(); cit++) m_vApprovedReconnectBuddies[*cit] = false; } else { UT_return_val_if_fail(strp->getBuddyIdentifiers().size() == 1, false); BuddyPtr pBuddy = pManager->constructBuddy(strp->getBuddyIdentifiers()[0], collaborator); UT_return_val_if_fail(pBuddy, false); m_pProposedController = pBuddy; } // inform the master that we received the takeover request SessionTakeoverAckPacket stap(m_sId, m_pDoc->getDocUUIDString()); collaborator->getHandler()->send(&stap, collaborator); m_eTakeoveState = STS_SENT_TAKEOVER_ACK; return true; } return false; case STS_SENT_TAKEOVER_REQUEST: { // we only accept SessionTakeoverAck packets UT_return_val_if_fail(pPacket->getClassType() == PCT_SessionTakeoverAckPacket, false); // we can only receive SessionTakeoverAck packets when we are the master UT_return_val_if_fail(!m_pController, false); // we should have a proposed master UT_return_val_if_fail(m_pProposedController, false); // a slave should only ack once UT_return_val_if_fail(!_hasAckedSessionTakeover(collaborator), false); // handle the SessionTakeoverAck packet m_mAckedSessionTakeoverBuddies[collaborator] = true; // check if every slave has acknowledged the session takeover // TODO: handle dropouts if (m_vCollaborators.size() == 1 || m_mAckedSessionTakeoverBuddies.size() == m_vCollaborators.size()) { // ... our tour of duty is done _shutdownAsMaster(); m_eTakeoveState = STS_NONE; return true; } } return true; case STS_SENT_TAKEOVER_ACK: // we only accept a SessionFlushed or SessionReconnectRequest packet UT_return_val_if_fail( pPacket->getClassType() == PCT_SessionFlushedPacket || pPacket->getClassType() == PCT_SessionReconnectRequestPacket, false ); if (pPacket->getClassType() == PCT_SessionReconnectRequestPacket) { // we only accept a SessionReconnectRequest when we are the proposed master UT_return_val_if_fail(m_bProposedController, false); // we only allow an incoming SessionReconnectRequest packet from a buddy // that is in the buddy list we received from the master, and we didn't receive // such a packet from him before bool allow = false; for (std::map<std::string, bool>::iterator it = m_vApprovedReconnectBuddies.begin(); it != m_vApprovedReconnectBuddies.end(); it++) { // TODO: is it a good idea to compare descriptors with full session information? if ((*it).first == collaborator->getDescriptor(true) && (*it).second == false) { (*it).second = true; allow = true; break; } } UT_return_val_if_fail(allow, false); // handle the SessionReconnectRequest packet addCollaborator(collaborator); _checkRestartAsMaster(); return true; } else if (pPacket->getClassType() == PCT_SessionFlushedPacket) { // we can only allow a SessionFlushed packet from the controller UT_return_val_if_fail(m_pController == collaborator, false); // handle the SessionFlushed packet m_bSessionFlushed = true; if (m_bProposedController) { // as far we we're concerned now, the old master is dead _becomeMaster(); _checkRestartAsMaster(); return true; } else { // as far we we're concerned now, the old master is dead _switchMaster(); // inform the new master that we want to rejoin the session SessionReconnectRequestPacket srrp(m_sId, m_pDoc->getDocUUIDString()); m_pProposedController->getHandler()->send(&srrp, m_pProposedController); m_eTakeoveState = STS_SENT_SESSION_RECONNECT_REQUEST; } return true; } return false; case STS_SENT_SESSION_RECONNECT_REQUEST: { // we only accept a SessionReconnectAck packet UT_return_val_if_fail(pPacket->getClassType() == PCT_SessionReconnectAckPacket, false); // we only accept said packet when we are a slave UT_return_val_if_fail(m_pController, false); // we only accept said packet when we are not the proposed master UT_return_val_if_fail(!m_bProposedController, false); // we only accept said packet from the proposed master UT_return_val_if_fail(m_pProposedController == collaborator, false); // handle the SessionReconnectAck packet SessionReconnectAckPacket* srap = static_cast<SessionReconnectAckPacket*>(pPacket); // Nuke the current collaboration state, and restart with the // given revision from the proposed master UT_return_val_if_fail(_restartAsSlave(srap->getDocUUID(), srap->getRev()), false); } return true; default: UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN); break; } return false; }