diff --git a/core/account.cpp b/core/account.cpp index 22b8e2e..54df50d 100644 --- a/core/account.cpp +++ b/core/account.cpp @@ -16,7 +16,9 @@ Account::Account(const QString& p_login, const QString& p_server, const QString& groups(), cm(new QXmppCarbonManager()), am(new QXmppMamManager()), - contacts() + contacts(), + maxReconnectTimes(0), + reconnectTimes(0) { config.setUser(p_login); config.setDomain(p_server); @@ -63,8 +65,9 @@ Shared::ConnectionState Core::Account::getState() const void Core::Account::connect() { if (state == Shared::disconnected) { - client.connectToServer(config, presence); + reconnectTimes = maxReconnectTimes; state = Shared::connecting; + client.connectToServer(config, presence); emit connectionStateChanged(state); } else { qDebug("An attempt to connect an account which is already connected, skipping"); @@ -73,6 +76,7 @@ void Core::Account::connect() void Core::Account::disconnect() { + reconnectTimes = 0; if (state != Shared::disconnected) { client.disconnectFromServer(); state = Shared::disconnected; @@ -83,24 +87,43 @@ void Core::Account::disconnect() void Core::Account::onClientConnected() { if (state == Shared::connecting) { + reconnectTimes = maxReconnectTimes; state = Shared::connected; cm->setCarbonsEnabled(true); emit connectionStateChanged(state); } else { - qDebug("Something weird had happened - xmpp client reported about successful connection but account wasn't in connecting state"); + qDebug() << "Something weird had happened - xmpp client reported about successful connection but account wasn't in" << state << "state"; } } void Core::Account::onClientDisconnected() { if (state != Shared::disconnected) { - state = Shared::disconnected; - emit connectionStateChanged(state); + if (reconnectTimes > 0) { + --reconnectTimes; + qDebug() << "Reconnecting..."; + state = Shared::connecting; + client.connectToServer(config, presence); + emit connectionStateChanged(state); + } else { + state = Shared::disconnected; + emit connectionStateChanged(state); + } } else { //qDebug("Something weird had happened - xmpp client reported about being disconnection but account was already in disconnected state"); } } +void Core::Account::reconnect() +{ + if (state == Shared::connected) { + ++reconnectTimes; + client.disconnectFromServer(); + } else { + qDebug() << "An attempt to reconnect account" << getName() << "which was not connected"; + } +} + QString Core::Account::getName() const { return name; @@ -131,6 +154,14 @@ void Core::Account::onRosterReceived() } } +void Core::Account::setReconnectTimes(unsigned int times) +{ + maxReconnectTimes = times; + if (state == Shared::connected) { + reconnectTimes = times; + } +} + void Core::Account::onRosterItemAdded(const QString& bareJid) { addedAccount(bareJid); @@ -616,18 +647,95 @@ void Core::Account::onContactHistoryResponse(const std::list& l void Core::Account::onClientError(QXmppClient::Error err) { + QString errorText; + QString errorType; switch (err) { case QXmppClient::SocketError: - qDebug() << "Client socket error" << client.socketErrorString(); + errorText = client.socketErrorString(); + errorType = "Client socket error"; break; - case QXmppClient::XmppStreamError: - qDebug() << "Client stream error" << client.socketErrorString(); + case QXmppClient::XmppStreamError: { + QXmppStanza::Error::Condition cnd = client.xmppStreamError(); + + switch (cnd) { + case QXmppStanza::Error::BadRequest: + errorText = "Bad request"; + break; + case QXmppStanza::Error::Conflict: + errorText = "Conflict"; + break; + case QXmppStanza::Error::FeatureNotImplemented: + errorText = "Feature is not implemented"; + break; + case QXmppStanza::Error::Forbidden: + errorText = "Forbidden"; + break; + case QXmppStanza::Error::Gone: + errorText = "Gone"; + break; + case QXmppStanza::Error::InternalServerError: + errorText = "Internal server error"; + break; + case QXmppStanza::Error::ItemNotFound: + errorText = "Item was not found"; + break; + case QXmppStanza::Error::JidMalformed: + errorText = "Malformed JID"; + break; + case QXmppStanza::Error::NotAcceptable: + errorText = "Not acceptable"; + break; + case QXmppStanza::Error::NotAllowed: + errorText = "Not allowed"; + break; + case QXmppStanza::Error::NotAuthorized: + errorText = "Authentication error"; + break; + case QXmppStanza::Error::PaymentRequired: + errorText = "Payment is required"; + break; + case QXmppStanza::Error::RecipientUnavailable: + errorText = "Recipient is unavailable"; + break; + case QXmppStanza::Error::Redirect: + errorText = "Redirected"; + break; + case QXmppStanza::Error::RegistrationRequired: + errorText = "Registration is required"; + break; + case QXmppStanza::Error::RemoteServerNotFound: + errorText = "Remote server was not found"; + break; + case QXmppStanza::Error::RemoteServerTimeout: + errorText = "Remote server timeout"; + break; + case QXmppStanza::Error::ResourceConstraint: + errorText = "Resource constraint"; + break; + case QXmppStanza::Error::ServiceUnavailable: + errorText = "Redirected"; + break; + case QXmppStanza::Error::SubscriptionRequired: + errorText = "Subscription is required"; + break; + case QXmppStanza::Error::UndefinedCondition: + errorText = "Undefined condition"; + break; + case QXmppStanza::Error::UnexpectedRequest: + errorText = "Unexpected request"; + break; + } + + errorType = "Client stream error"; + } + break; case QXmppClient::KeepAliveError: - qDebug() << "Client keep alive error"; + errorText = "Client keep alive error"; break; } - //onClientDisconnected(); + qDebug() << errorType << errorText; + emit error(errorText); } diff --git a/core/account.h b/core/account.h index 04f14b6..d66b519 100644 --- a/core/account.h +++ b/core/account.h @@ -24,6 +24,7 @@ public: void connect(); void disconnect(); + void reconnect(); Shared::ConnectionState getState() const; QString getName() const; @@ -42,6 +43,7 @@ public: QString getFullJid() const; void sendMessage(const Shared::Message& data); void requestArchive(const QString& jid, int count, const QString& before); + void setReconnectTimes(unsigned int times); signals: void connectionStateChanged(int); @@ -56,6 +58,7 @@ signals: void removePresence(const QString& jid, const QString& name); void message(const Shared::Message& data); void responseArchive(const QString& jid, const std::list& list); + void error(const QString& text); private: QString name; @@ -67,7 +70,9 @@ private: std::map> groups; QXmppCarbonManager* cm; QXmppMamManager* am; - std::map contacts; + std::map contacts; + unsigned int maxReconnectTimes; + unsigned int reconnectTimes; private slots: void onClientConnected(); diff --git a/core/squawk.cpp b/core/squawk.cpp index 1059c9a..eed4512 100644 --- a/core/squawk.cpp +++ b/core/squawk.cpp @@ -83,6 +83,7 @@ void Core::Squawk::addAccount(const QString& login, const QString& server, const amap.insert(std::make_pair(name, acc)); connect(acc, SIGNAL(connectionStateChanged(int)), this, SLOT(onAccountConnectionStateChanged(int))); + connect(acc, SIGNAL(error(const QString&)), this, SLOT(onAccountError(const QString&))); connect(acc, SIGNAL(availabilityChanged(int)), this, SLOT(onAccountAvailabilityChanged(int))); connect(acc, SIGNAL(addContact(const QString&, const QString&, const QMap&)), this, SLOT(onAccountAddContact(const QString&, const QString&, const QMap&))); @@ -106,7 +107,8 @@ void Core::Squawk::addAccount(const QString& login, const QString& server, const {"password", password}, {"resource", resource}, {"state", Shared::disconnected}, - {"offline", Shared::offline} + {"offline", Shared::offline}, + {"error", ""} }; emit newAccount(map); } @@ -149,7 +151,7 @@ void Core::Squawk::disconnectAccount(const QString& account) void Core::Squawk::onAccountConnectionStateChanged(int state) { Account* acc = static_cast(sender()); - emit accountConnectionStateChanged(acc->getName(), state); + emit changeAccount(acc->getName(), {{"state", state}}); if (state == Shared::disconnected) { bool equals = true; @@ -216,7 +218,7 @@ void Core::Squawk::onAccountRemovePresence(const QString& jid, const QString& na void Core::Squawk::onAccountAvailabilityChanged(int state) { Account* acc = static_cast(sender()); - emit accountAvailabilityChanged(acc->getName(), state); + emit changeAccount(acc->getName(), {{"availability", state}}); } void Core::Squawk::onAccountMessage(const Shared::Message& data) @@ -252,3 +254,47 @@ void Core::Squawk::onAccountResponseArchive(const QString& jid, const std::list< emit responseArchive(acc->getName(), jid, list); } +void Core::Squawk::modifyAccountRequest(const QString& name, const QMap& map) +{ + AccountsMap::const_iterator itr = amap.find(name); + if (itr == amap.end()) { + qDebug("An attempt to modify non existing account, skipping"); + return; + } + + Core::Account* acc = itr->second; + Shared::ConnectionState st = acc->getState(); + + if (st != Shared::disconnected) { + acc->reconnect(); + } + + QMap::const_iterator mItr; + mItr = map.find("login"); + if (mItr != map.end()) { + acc->setLogin(mItr->toString()); + } + + mItr = map.find("password"); + if (mItr != map.end()) { + acc->setPassword(mItr->toString()); + } + + mItr = map.find("resource"); + if (mItr != map.end()) { + acc->setResource(mItr->toString()); + } + + mItr = map.find("server"); + if (mItr != map.end()) { + acc->setServer(mItr->toString()); + } + + emit changeAccount(name, map); +} + +void Core::Squawk::onAccountError(const QString& text) +{ + Account* acc = static_cast(sender()); + emit changeAccount(acc->getName(), {{"error", text}}); +} diff --git a/core/squawk.h b/core/squawk.h index 3daf26f..c9cd2ea 100644 --- a/core/squawk.h +++ b/core/squawk.h @@ -24,8 +24,7 @@ public: signals: void quit(); void newAccount(const QMap&); - void accountConnectionStateChanged(const QString&, int); - void accountAvailabilityChanged(const QString&, int); + void changeAccount(const QString& account, const QMap& data); void addGroup(const QString& account, const QString& name); void removeGroup(const QString& account, const QString& name); void addContact(const QString& account, const QString& jid, const QString& group, const QMap& data); @@ -42,6 +41,7 @@ public slots: void start(); void stop(); void newAccountRequest(const QMap& map); + void modifyAccountRequest(const QString& name, const QMap& map); void connectAccount(const QString& account); void disconnectAccount(const QString& account); void changeState(int state); @@ -63,6 +63,7 @@ private slots: void onAccountConnectionStateChanged(int state); void onAccountAvailabilityChanged(int state); void onAccountAddGroup(const QString& name); + void onAccountError(const QString& text); void onAccountRemoveGroup(const QString& name); void onAccountAddContact(const QString& jid, const QString& group, const QMap& data); void onAccountRemoveContact(const QString& jid); diff --git a/main.cpp b/main.cpp index 87ee2b5..8fc1404 100644 --- a/main.cpp +++ b/main.cpp @@ -32,17 +32,20 @@ int main(int argc, char *argv[]) QObject::connect(coreThread, SIGNAL(finished()), squawk, SLOT(deleteLater())); QObject::connect(&w, SIGNAL(newAccountRequest(const QMap&)), squawk, SLOT(newAccountRequest(const QMap&))); + QObject::connect(&w, SIGNAL(modifyAccountRequest(const QString&, const QMap&)), + squawk, SLOT(modifyAccountRequest(const QString&, const QMap&))); QObject::connect(&w, SIGNAL(connectAccount(const QString&)), squawk, SLOT(connectAccount(const QString&))); QObject::connect(&w, SIGNAL(disconnectAccount(const QString&)), squawk, SLOT(disconnectAccount(const QString&))); QObject::connect(&w, SIGNAL(changeState(int)), squawk, SLOT(changeState(int))); QObject::connect(&w, SIGNAL(sendMessage(const QString&, const Shared::Message&)), squawk, SLOT(sendMessage(const QString&, const Shared::Message&))); - QObject::connect(&w, SIGNAL(requestArchive(const QString&, const QString&, int, const QString&)), squawk, SLOT(requestArchive(const QString&, const QString&, int, const QString&))); + QObject::connect(&w, SIGNAL(requestArchive(const QString&, const QString&, int, const QString&)), + squawk, SLOT(requestArchive(const QString&, const QString&, int, const QString&))); QObject::connect(squawk, SIGNAL(newAccount(const QMap&)), &w, SLOT(newAccount(const QMap&))); - QObject::connect(squawk, SIGNAL(accountAvailabilityChanged(const QString&, int)), &w, SLOT(accountAvailabilityChanged(const QString&, int))); - QObject::connect(squawk, SIGNAL(accountConnectionStateChanged(const QString&, int)), &w, SLOT(accountConnectionStateChanged(const QString&, int))); QObject::connect(squawk, SIGNAL(addContact(const QString&, const QString&, const QString&, const QMap&)), &w, SLOT(addContact(const QString&, const QString&, const QString&, const QMap&))); + QObject::connect(squawk, SIGNAL(changeAccount(const QString&, const QMap&)), + &w, SLOT(changeAccount(const QString&, const QMap&))); QObject::connect(squawk, SIGNAL(addGroup(const QString&, const QString&)), &w, SLOT(addGroup(const QString&, const QString&))); QObject::connect(squawk, SIGNAL(removeGroup(const QString&, const QString&)), &w, SLOT(removeGroup(const QString&, const QString&))); QObject::connect(squawk, SIGNAL(removeContact(const QString&, const QString&)), &w, SLOT(removeContact(const QString&, const QString&))); diff --git a/ui/accounts.cpp b/ui/accounts.cpp index d5743f6..2822825 100644 --- a/ui/accounts.cpp +++ b/ui/accounts.cpp @@ -31,8 +31,9 @@ void Accounts::onAccountAccepted() { Account* acc = static_cast(sender()); QMap map = acc->value(); + const Models::Account* mAcc = model->getAccount(m_ui->tableView->selectionModel()->selectedRows().at(0).row()); if (editing) { - emit changeAccount(map); + emit changeAccount(mAcc->getName(), map); } else { emit newAccount(map); } diff --git a/ui/accounts.h b/ui/accounts.h index 95b8fd6..c290693 100644 --- a/ui/accounts.h +++ b/ui/accounts.h @@ -22,7 +22,7 @@ public: signals: void newAccount(const QMap&); - void changeAccount(const QMap&); + void changeAccount(const QString&, const QMap&); private slots: void onAddButton(bool clicked = 0); diff --git a/ui/models/account.cpp b/ui/models/account.cpp index 4c64bdf..f41d85d 100644 --- a/ui/models/account.cpp +++ b/ui/models/account.cpp @@ -7,6 +7,7 @@ Models::Account::Account(const QMap& data, Models::Item* pare password(data.value("password").toString()), server(data.value("server").toString()), resource(data.value("resource").toString()), + error(data.value("error").toString()), state(Shared::disconnected), availability(Shared::offline) { @@ -61,7 +62,7 @@ void Models::Account::setAvailability(Shared::Availability p_avail) { if (availability != p_avail) { availability = p_avail; - changed(5); + changed(6); } } @@ -101,7 +102,7 @@ void Models::Account::setLogin(const QString& p_login) { if (login != p_login) { login = p_login; - changed(3); + changed(4); } } @@ -109,7 +110,7 @@ void Models::Account::setPassword(const QString& p_password) { if (password != p_password) { password = p_password; - changed(4); + changed(5); } } @@ -131,12 +132,14 @@ QVariant Models::Account::data(int column) const case 2: return Shared::connectionStateNames[state]; case 3: - return login; + return error; case 4: - return password; + return login; case 5: - return Shared::availabilityNames[availability]; + return password; case 6: + return Shared::availabilityNames[availability]; + case 7: return resource; default: return QVariant(); @@ -145,7 +148,7 @@ QVariant Models::Account::data(int column) const int Models::Account::columnCount() const { - return 7; + return 8; } void Models::Account::update(const QString& field, const QVariant& value) @@ -164,6 +167,8 @@ void Models::Account::update(const QString& field, const QVariant& value) setAvailability(value.toUInt()); } else if (field == "resource") { setResource(value.toString()); + } else if (field == "error") { + setError(value.toString()); } } @@ -176,7 +181,20 @@ void Models::Account::setResource(const QString& p_resource) { if (resource != p_resource) { resource = p_resource; - changed(6); + changed(7); + } +} + +QString Models::Account::getError() const +{ + return error; +} + +void Models::Account::setError(const QString& p_resource) +{ + if (error != p_resource) { + error = p_resource; + changed(3); } } diff --git a/ui/models/account.h b/ui/models/account.h index 0d5e70d..e09863f 100644 --- a/ui/models/account.h +++ b/ui/models/account.h @@ -28,6 +28,9 @@ namespace Models { void setResource(const QString& p_resource); QString getResource() const; + void setError(const QString& p_resource); + QString getError() const; + void setAvailability(Shared::Availability p_avail); void setAvailability(unsigned int p_avail); Shared::Availability getAvailability() const; @@ -44,6 +47,7 @@ namespace Models { QString password; QString server; QString resource; + QString error; Shared::ConnectionState state; Shared::Availability availability; }; diff --git a/ui/models/accounts.cpp b/ui/models/accounts.cpp index f617c84..8c47529 100644 --- a/ui/models/accounts.cpp +++ b/ui/models/accounts.cpp @@ -6,7 +6,8 @@ std::deque Models::Accounts::columns = { "name", "server", - "state" + "state", + "error" }; Models::Accounts::Accounts(QObject* parent): diff --git a/ui/squawk.cpp b/ui/squawk.cpp index 6dcd78d..51a5be1 100644 --- a/ui/squawk.cpp +++ b/ui/squawk.cpp @@ -35,6 +35,7 @@ void Squawk::onAccounts() accounts->setAttribute(Qt::WA_DeleteOnClose); connect(accounts, SIGNAL(destroyed(QObject*)), this, SLOT(onAccountsClosed(QObject*))); connect(accounts, SIGNAL(newAccount(const QMap&)), this, SIGNAL(newAccountRequest(const QMap&))); + connect(accounts, SIGNAL(changeAccount(const QString&, const QMap&)), this, SIGNAL(modifyAccountRequest(const QString&, const QMap&))); accounts->show(); } else { @@ -96,14 +97,12 @@ void Squawk::onComboboxActivated(int index) } } -void Squawk::accountConnectionStateChanged(const QString& account, int state) +void Squawk::changeAccount(const QString& account, const QMap& data) { - rosterModel.updateAccount(account, "state", state); -} - -void Squawk::accountAvailabilityChanged(const QString& account, int state) -{ - rosterModel.updateAccount(account, "availability", state); + for (QMap::const_iterator itr = data.begin(), end = data.end(); itr != end; ++itr) { + QString attr = itr.key(); + rosterModel.updateAccount(account, attr, *itr); + } } void Squawk::addContact(const QString& account, const QString& jid, const QString& group, const QMap& data) diff --git a/ui/squawk.h b/ui/squawk.h index 573e1ac..23de897 100644 --- a/ui/squawk.h +++ b/ui/squawk.h @@ -28,6 +28,7 @@ public: signals: void newAccountRequest(const QMap&); + void modifyAccountRequest(const QString&, const QMap&); void connectAccount(const QString&); void disconnectAccount(const QString&); void changeState(int state); @@ -36,8 +37,7 @@ signals: public slots: void newAccount(const QMap& account); - void accountConnectionStateChanged(const QString& account, int state); - void accountAvailabilityChanged(const QString& account, int state); + void changeAccount(const QString& account, const QMap& data); void addGroup(const QString& account, const QString& name); void removeGroup(const QString& account, const QString& name); void addContact(const QString& account, const QString& jid, const QString& group, const QMap& data);