/***************************************************************************
* Copyright (C) 2004 - 2005 by Raphael Langerhorst *
* raphael-langerhorst@gmx.at *
* *
* Permission is hereby granted, free of charge, to any person obtaining *
* a copy of this software and associated documentation files (the *
* "Software"), to deal in the Software without restriction, including *
* without limitation the rights to use, copy, modify, merge, publish, *
* distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to *
* the following conditions: *
* *
* The above copyright notice and this permission notice shall be *
* included in all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
* OTHER DEALINGS IN THE SOFTWARE. *
***************************************************************************/
#include "GXmppNetwork.h"
#include <qapplication.h>
#include <qptrlist.h>
#include <qevent.h>
#include <qtimer.h>
#include <exception>
//TODO implement all methods
namespace GWE
{
class QNetworkSendEvent : public QCustomEvent
{
private:
QString Message;
public:
QNetworkSendEvent(QString message) : QCustomEvent(65001),Message(message) {}
virtual ~QNetworkSendEvent() {}
QString message() { return Message; }
};
class GXmppMessageQueue
{
private:
QMap<QString,QStringList > Queues;
public:
void add(QString server, QString message);
/**
* The order is from front to back (start at begin()).
* Queue is automatically removed from Queues.
*/
QStringList takeMessagesForServer(QString server);
bool hasMessages(QString server);
};
void GXmppMessageQueue::add(QString server, QString message)
{
QStringList queue;
if (Queues.contains(server))
{
queue = Queues[server];
}
queue.append(message);
Queues.insert(server,queue);
}
QStringList GXmppMessageQueue::takeMessagesForServer(QString server)
{
QStringList msgs;
if (Queues.contains(server))
{
msgs = Queues[server];
Queues.remove(server);
}
return msgs;
}
bool GXmppMessageQueue::hasMessages(QString server)
{
return Queues.contains(server);
}
GXmppNetwork::GXmppNetwork(QString full_jid, QObject *parent, const char *name)
: GXmlNetwork(parent,name),
Active(FALSE),
Connected(FALSE),
Connecting(FALSE),
XmppLayerCreated(FALSE),
XmppConnector(NULL),
Tls(NULL),
TlsHandler(NULL),
Stream(NULL),
NetworkId(full_jid),
MessageQueue(new GXmppMessageQueue()),
StayConnected(FALSE)
{
connect(qApp,SIGNAL(aboutToQuit()),this,SLOT(closeNetwork()));
// QTimer* heartbeat_timer = new QTimer(this,"heartbeat timer");
// connect(heartbeat_timer,SIGNAL(timeout()),this,SLOT(sendHeartbeat()));
// heartbeat_timer->start(55000);
// see XMPP::ClientStream::setNoopTime() which is now used
}
GXmppNetwork::~GXmppNetwork()
{
deleteXmppLayer(true);
if (MessageQueue)
{
delete MessageQueue;
MessageQueue=NULL;
}
}
bool GXmppNetwork::createXmppLayer()
{
if (XmppLayerCreated)
{
qWarning("XMPP Layer already created! Destroying it first...");
this->deleteXmppLayer(true);
qWarning("XMPP Layer now destroyed");
}
//XMPP related setup
try
{
qDebug("Creating XMPP layer");
XmppConnector = new XMPP::AdvancedConnector();
Q_CHECK_PTR(XmppConnector);
//@todo something causes a segfault if the jabber server is not found.
if (XmppConnector==NULL)
{
throw std::exception();
}
connect(XmppConnector,SIGNAL(srvLookup(const QString &)),this,SLOT(connectorServerLookup(const QString&)));
connect(XmppConnector,SIGNAL(srvResult(bool)),this,SLOT(connectorServerResult(bool)));
connect(XmppConnector,SIGNAL(httpSyncStarted()),this,SLOT(connectorHttpSyncStarted()));
connect(XmppConnector,SIGNAL(httpSyncFinished()),this,SLOT(connectorHttpSyncFinished()));
if (QCA::isSupported(QCA::CAP_TLS))
{
qDebug("CAP TLS supported");
Tls = new QCA::TLS();
Q_CHECK_PTR(Tls);
if (Tls==NULL)
{
throw std::exception();
}
TlsHandler = new XMPP::QCATLSHandler(Tls);
Q_CHECK_PTR(TlsHandler);
if (TlsHandler == NULL)
{
throw std::exception();
}
connect(TlsHandler,SIGNAL(tlsHandshaken()),this,SLOT(tlsHandshaken()));
}
this->Stream = new XMPP::ClientStream(this->XmppConnector,this->TlsHandler);
Q_CHECK_PTR(Stream);
if (Stream == NULL)
{
throw std::exception();
}
connect(Stream,SIGNAL(connected()),SLOT(clientStreamConnected()));
connect(Stream,SIGNAL(securityLayerActivated(int)),SLOT(clientStreamSecurityLayerActivated(int)));
connect(Stream,SIGNAL(needAuthParams(bool,bool,bool)),SLOT(clientStreamNeedAuthenticationParameters(bool,bool,bool)));
connect(Stream,SIGNAL(authenticated()),SLOT(clientStreamAuthenticated()));
connect(Stream,SIGNAL(connectionClosed()),SLOT(clientStreamConnectionClosed()));
connect(Stream,SIGNAL(delayedCloseFinished()),SLOT(clientStreamDelayedCloseFinished()));
connect(Stream,SIGNAL(readyRead()),SLOT(clientStreamReadyRead()));
connect(Stream,SIGNAL(stanzaWritten()),SLOT(clientStreamStanzaWritten()));
connect(Stream,SIGNAL(warning(int)),SLOT(clientStreamWarning(int)));
connect(Stream,SIGNAL(error(int)),SLOT(clientStreamError(int)));
this->XmppLayerCreated = true;
qDebug("XMPP Layer now created");
return true;
}
catch (std::exception e)
{
deleteXmppLayer(true);
return false;
}
//active == false && connected == false, they are set in initNetwork()
}
bool GXmppNetwork::deleteXmppLayer(bool force)
{
if (force==FALSE)
{
if (!XmppLayerCreated)
{
qWarning("XMPP layer not even created! Nothing to delete.");
return true;
}
if (Active)
{
qWarning("XMPP network is active! Not deleting objects!");
return false;
}
if (Connected)
{
qWarning("XMPP network is still connected! Not deleting objects!");
return false;
}
}
if (Stream)
{
delete Stream;
Stream = NULL;
}
if (TlsHandler)
{
delete TlsHandler;
TlsHandler = NULL;
}
if (Tls)
{
delete Tls;
Tls = NULL;
}
if (XmppConnector)
{
delete XmppConnector;
XmppConnector=NULL;
}
this->Connected = false;
this->Connecting = false;
this->Active = false;
this->XmppLayerCreated = false;
return true;
}
void GXmppNetwork::customEvent(QCustomEvent* event)
{
if (event->type()==65001)
{
if (!this->isConnected())
{
qWarning("Can't send data because network is not connected!");
}
else
{
// qDebug("sending message:");
// qDebug(((QNetworkSendEvent*)event)->message());
Stream->writeDirect(((QNetworkSendEvent*)event)->message());
}
}
else
qWarning(QString("Received unknown custom event type %1").arg(QString::number(event->type())));
}
bool GXmppNetwork::isSubscribed(QString destination)
{
if (this->SubscriptionStates.contains(destination))
{
if (this->SubscriptionStates[destination]=="subscribed")
return true;
else
return false;
}
else
return false;
}
void GXmppNetwork::sendQueuedMessages(QString destination)
{
QStringList msgs = MessageQueue->takeMessagesForServer(destination);
QStringList::iterator it;
for (it = msgs.begin(); it != msgs.end(); ++it)
{
this->send(*it);
}
}
void GXmppNetwork::sendHeartbeat()
{
if (this->isConnected())
this->send("<presence/>");
}
// GXmlNetwork implementation BEGIN //
bool GXmppNetwork::initNetwork()
{
if (this->Connecting)
{
qWarning("Already in the process of connecting the network");
return false;
}
this->Connecting = true;
QMutexLocker lock(this);
if (!this->createXmppLayer())
{
qWarning("Failed to initialize XMPP layer");
return false;
}
if (Active)
{
qWarning("XMPP layer already active");
return true;
}
Active = true;
// HACK don't use XMPP 1.0 even if advertised (jabberd 1.4.4 is bugged)
this->Stream->setOldOnly(true);
//XMPP initialization - without SSL
this->XmppConnector->setOptHostPort(NetworkId.domain(),5222);
//@todo get option from a parameter!
this->XmppConnector->setOptSSL(false);
this->Stream->setAllowPlain(true);
this->Stream->setResourceBinding(true);
//for use with SSL
// this->XmppConnector->setOptHostPort(NetworkId.domain(),5223);
// this->XmppConnector->setOptSSL(true);
if (this->Tls)
{
QPtrList<QCA::Cert> certStore;
Tls->setCertificateStore(certStore);
}
Stream->setNoopTime(55000); // every 55 seconds
qDebug("Connecting XMPP network with JID " + this->getNetworkId());
qDebug("Warning: if you get a segmentation fault next, this probably means");
qDebug(" that the server you want to connect to (the domain part");
qDebug(" of the JID) does not have an XMPP/Jabber server running.");
qDebug(" In this case make sure the JID is correct and/or contact");
qDebug(" the G System Team.");
this->Stream->connectToServer(this->NetworkId);
return true;
}
void GXmppNetwork::reconnectNetwork()
{
QTimer::singleShot(100,this,SLOT(initNetwork()));
}
bool GXmppNetwork::closeNetwork()
{
QMutexLocker lock(this);
this->StayConnected = false;
if (this->Connected)
{
qDebug("Disconnecting XMPP Stream...");
this->Stream->close();
this->Connected = false;
this->Active = false; // correct place?
this->Connecting = false;
return true;
}
else
{
qWarning("Not closing network: not connected");
return true; //it's fine, not connected after all
}
}
QString GXmppNetwork::getNetworkId() const
{
return this->NetworkId.full();
}
void GXmppNetwork::setPassword(const QString& password)
{
this->Password = password;
}
bool GXmppNetwork::send(QDomElement data, const QString& destination)
{
if (destination.isEmpty())
{
qWarning("Destination is empty, not sending message!");
return false;
}
//@todo this doesn't seem to be functional(??)
XMPP::Jid destjid(destination);
if (!destjid.isValid())
{
qWarning(QString("Destination %1 not a valid JID, not sending message!").arg(destination));
return false;
}
// qDebug(QString("type range for user events: %1 to %2").arg(QString::number(QEvent::User)).arg(QString::number(QEvent::MaxUser)));
QDomDocument d;
QDomElement e = d.createElement("message");
d.appendChild(e);
e.setAttribute("to",destination);
e.appendChild(d.importNode(data,"true"));
if (!this->isSubscribed(destination) || !this->isConnected())
{
if (!this->isConnected() && this->StayConnected)
{
qWarning("Network is not connected! Reconnecting...");
this->reconnectNetwork();
}
else
{
qWarning(QString("Delaying sending of message, destination %1 is not yet available").arg(destination));
this->makeDestinationAvailable(destination);
}
this->MessageQueue->add(destination,d.toString());
}
else
{
this->send(d.toString());
// QApplication::postEvent(this,new QNetworkSendEvent(d.toString()));
}
return true;
}
bool GXmppNetwork::send(const QString& data)
{
QApplication::postEvent(this,new QNetworkSendEvent(data));
return true;
}
bool GXmppNetwork::flushOutput()
{
//assume everything is fine (I don't know about a method to flush output)
//@todo implement
return true;
}
void GXmppNetwork::makeDestinationAvailable(const QString& destination)
{
if (this->SubscriptionStates.contains(destination))
{
if (this->SubscriptionStates[destination] == "subscribed")
{
// XMPP::Stanza s = this->Stream->createStanza(XMPP::Stanza::Presence, destination, "probe");
// QString msg = s.toString();
QString msg = QString("<presence type=\"probe\" to=\"%1\"></presence>").arg(destination);
this->send(msg);
}
else
{
// XMPP::Stanza s = this->Stream->createStanza(XMPP::Stanza::Presence, destination, "subscribe");
// QString msg = s.toString();
QString msg = QString("<presence type=\"subscribe\" to=\"%1\"></presence>").arg(destination);
this->send(msg);
}
}
else
{
// XMPP::Stanza s = this->Stream->createStanza(XMPP::Stanza::Presence, destination, "subscribe");
// QString msg = s.toString();
this->SubscriptionStates.insert(destination,"unsubscribed");
// use this for XMPP 1.0
QString msg = QString("<presence type=\"subscribe\" to=\"%1\"></presence>").arg(destination);
this->send(msg);
// use this HACK for pre XMPP 1.0
msg = QString("<presence to=\"%1\"></presence>").arg(destination);
this->send(msg);
}
}
bool GXmppNetwork::isConnected()
{
if (this->Active && this->Connected && Stream->isAuthenticated() && Stream->isActive())
return true;
else
return false;
}
//END GXmlNetwork implementation //
//BEGIN XMPP slots and signals for network management //
// CONNECTOR SLOTS //
void GXmppNetwork::connectorServerLookup(const QString& server)
{
qDebug("XMPP Server Lookup: " + server);
}
void GXmppNetwork::connectorServerResult(bool success)
{
if (success)
{
qDebug("XMPP Server Result OK");
}
else
{
qDebug("XMPP Server Result FAILURE");
}
}
void GXmppNetwork::connectorHttpSyncStarted()
{
qDebug("XMPP Connector HTTP sync started");
}
void GXmppNetwork::connectorHttpSyncFinished()
{
qDebug("XMPP Connector HTTP sync finished");
}
// TLS SLOTS //
void GXmppNetwork::tlsHandshaken()
{
qDebug("XMPP TLS handshake complete");
}
// STREAM SLOTS //
void GXmppNetwork::clientStreamConnected()
{
this->Connecting = false;
this->Connected = true;
this->StayConnected = true;
qDebug("XMPP Stream connected");
}
void GXmppNetwork::clientStreamSecurityLayerActivated(int l)
{
qDebug("XMPP Stream Security Layer " + QString::number(l) + " activated");
}
void GXmppNetwork::clientStreamNeedAuthenticationParameters(bool a,bool b,bool c)
{
qDebug("XMPP needs authentication " + QString::number(a) + " " + QString::number(b) + " " + QString::number(c));
qDebug("Continuing to authenticate");
if (this->Stream)
{
if (a)
{
qDebug("username: " + this->NetworkId.full());
this->Stream->setUsername(this->NetworkId.full());
}
if (b)
{
// qDebug("password: (not shown)");
this->Stream->setPassword(this->Password);
}
if (c)
{
qDebug("domain: " + this->NetworkId.domain());
this->Stream->setRealm(this->NetworkId.domain());
}
this->Stream->continueAfterParams();
}
}
void GXmppNetwork::clientStreamAuthenticated()
{
qDebug("XMPP Stream authenticated");
//well, just let everyone know we are online
this->Stream->writeDirect("<presence><show></show></presence>");
emit this->networkConnected();
//@todo: send an apropriate message to the master (define a server-server-protocol!!)
}
void GXmppNetwork::clientStreamConnectionClosed()
{
qDebug("XMPP Stream connection closed.");
if (this->StayConnected)
{
qDebug("Using timer for delayed recreation of the XMPP layer...");
this->reconnectNetwork();
}
}
void GXmppNetwork::clientStreamDelayedCloseFinished()
{
qDebug("XMPP Stream delayed close finished");
}
void GXmppNetwork::clientStreamReadyRead()
{
qDebug("XMPP Stream ready read");
bool stanza_printed = false;
while(Stream->stanzaAvailable())
{
this->lock();
XMPP::Stanza s = Stream->read();
this->unlock();
// qDebug(s.toString());
// stanza_printed=true;
QDomElement data = s.element();
QString from = s.from().full();
QString type = s.type();
// qDebug(QString("XMPP message received, data tag name: %1").arg(data.tagName()));
if (data.tagName() == "message") //extract all child elements
{
//make sure presence is subscribed
if (this->SubscriptionStates.contains(from))
{
if (this->SubscriptionStates[from] != "subscribed")
this->makeDestinationAvailable(from);
}
else
this->makeDestinationAvailable(from);
//@todo improve detection of unneccessary offline messages,
// more clearly state which offline messages should go through (body does for now)
bool discard = false;
bool isbody = false;
if (data.elementsByTagName("error").count()>0 || type == "error")
discard=true;
else if (data.elementsByTagName("body").count()>0) //do not emit body tags when error tags are included - thus else if
isbody=true;
else //filter out all other delayed messages
{
QDomNodeList dom_list = data.elementsByTagName("x");
for (unsigned int i=0; i<dom_list.count(); i++)
{
// if (dom_list.item(i).toElement().attribute("xmlns","none") == "jabber:x:delay")
if (dom_list.item(i).toElement().text() == "Offline Storage")
{
// qWarning("Discarding offline message");
discard = true;
break;
}
}
}
if (!discard || isbody)
{
QDomNode node = data.firstChild();
while(!node.isNull())
{
if (node.isElement())
{
if (node.toElement().tagName() != "x") //do not forward x tags
{
qDebug(QString("emitting data available, message: %1").arg(node.toElement().tagName()));
emit this->dataAvailable(node.toElement(),from);
}
else
{
qDebug("x tag received, ignoring!");
if (!stanza_printed)
{
qDebug("Stanza data:");
qDebug(s.toString());
stanza_printed=true;
}
}
}
node = node.nextSibling();
}
}
else
{
qWarning("Discarding offline message");
}
}
else if (data.tagName() == "presence")
{
// qDebug(QString("Received presence stanza from %1").arg(from));
if (!data.hasAttribute("type"))
{
//this is a HACK to work with pre XMPP 1.0 (old) servers
if (!this->isSubscribed(from))
{
QString msg = QString("<presence to=\"%1\"></presence>").arg(from);
this->send(msg);
this->SubscriptionStates.insert(from,"subscribed");
qDebug(QString("%1 is now subscribed and available.").arg(from));
}
this->sendQueuedMessages(from);
emit this->presenceChanged(from,true);
}
else if (type == "error")
{
//@todo errors should be communicated to the data controller, somehow
qWarning("Presence error:");
if (!stanza_printed)
{
qDebug("Stanza data:");
qDebug(s.toString());
stanza_printed=true;
}
}
else
{
if (type == "unavailable")
{
qDebug(QString("%1 is unavailable.").arg(from));
//this is a HACK to work with pre XMPP 1.0 (old) servers
this->SubscriptionStates.remove(from);
emit this->presenceChanged(from,false);
}
else if (type == "subscribe")
{
qDebug(QString("%1 wants to subscribe.").arg(from));
QString msg = QString("<presence to=\"%1\" type=\"subscribed\"></presence>").arg(from);
this->send(msg);
if (!this->SubscriptionStates.contains(from))
{
this->SubscriptionStates.insert(from,"unsubscribed");
}
if (this->SubscriptionStates[from] == "unsubscribed")
{
msg = QString("<presence to=\"%1\" type=\"subscribe\"></presence>").arg(this->getNetworkId()).arg(from);
this->send(msg);
}
}
else if (type == "subscribed")
{
qDebug(QString("Subscribed to %1.").arg(from));
this->SubscriptionStates.insert(from,"subscribed");
this->makeDestinationAvailable(from);
}
else if (type == "unsubscribe")
{
qDebug(QString("Unsubscribing presence to %1").arg(from));
QString msg = QString("<presence to=\"%1\" type=\"subscribed\"></presence>").arg(from);
this->send(msg);
if (this->SubscriptionStates.contains(from))
{
if (this->SubscriptionStates[from] != "unsubscribed")
{
msg = QString("<presence to=\"%1\" type=\"unsubscribe\"></presence>").arg(from);
this->send(msg);
}
}
}
else if (type == "unsubscribed")
{
qDebug(QString("Unsubscribed from %1.").arg(from));
this->SubscriptionStates.insert(from,"unsubscribed");
// qDebug(QString("Unsubscribed presence from %1").arg(from));
emit this->presenceChanged(from,false);
}
}
}
else
{
qDebug(QString("%1 stanza received, ignoring!").arg(data.tagName()));
if (!stanza_printed)
{
qDebug("Stanza data:");
qDebug(s.toString());
stanza_printed=true;
}
// emit this->dataAvailable(data,from); //if it's not a "message", pass everything on
}
}
}
void GXmppNetwork::clientStreamStanzaWritten()
{
qDebug("XMPP Stream Stanza written");
}
void GXmppNetwork::clientStreamWarning(int w)
{
qDebug("XMPP Stream warning " + QString::number(w));
qDebug("continuing after warning");
if (this->Stream)
this->Stream->continueAfterWarning();
}
void GXmppNetwork::clientStreamError(int err)
{
// copied with small adaptions from the IRIS conntest example
// LGPL license, (c) Justin Karneges
// http://delta.affinix.com/iris/
QString s;
if(err == XMPP::ClientStream::ErrParse)
{
s = "XML parsing error";
}
else if(err == XMPP::ClientStream::ErrProtocol)
{
s = "XMPP protocol error";
}
else if(err == XMPP::ClientStream::ErrStream)
{
int x = Stream->errorCondition();
if(x == XMPP::Stream::GenericStreamError)
s = "generic stream error";
else if(x == XMPP::ClientStream::Conflict)
s = "conflict (remote login replacing this one)";
else if(x == XMPP::ClientStream::ConnectionTimeout)
s = "timed out from inactivity";
else if(x == XMPP::ClientStream::InternalServerError)
s = "internal server error";
else if(x == XMPP::ClientStream::InvalidXml)
s = "invalid XML";
else if(x == XMPP::ClientStream::PolicyViolation)
s = "policy violation. go to jail!";
else if(x == XMPP::ClientStream::ResourceConstraint)
s = "server out of resources";
else if(x == XMPP::ClientStream::SystemShutdown)
s = "system is shutting down NOW";
s = QString("XMPP stream error: ") + s;
}
else if(err == XMPP::ClientStream::ErrConnection)
{
int x = XmppConnector->errorCode();
QString s;
if(x == XMPP::AdvancedConnector::ErrConnectionRefused)
s = "unable to connect to server";
else if(x == XMPP::AdvancedConnector::ErrHostNotFound)
s = "host not found";
else if(x == XMPP::AdvancedConnector::ErrProxyConnect)
s = "proxy connect";
else if(x == XMPP::AdvancedConnector::ErrProxyNeg)
s = "proxy negotiating";
else if(x == XMPP::AdvancedConnector::ErrProxyAuth)
s = "proxy authorization";
else if(x == XMPP::AdvancedConnector::ErrStream)
s = "stream error";
s = QString("Connection error: ") + s;
}
else if(err == XMPP::ClientStream::ErrNeg)
{
int x = Stream->errorCondition();
QString s;
if(x == XMPP::ClientStream::HostGone)
s = "host no longer hosted";
else if(x == XMPP::ClientStream::HostUnknown)
s = "host unknown";
else if(x == XMPP::ClientStream::RemoteConnectionFailed)
s = "a required remote connection failed";
else if(x == XMPP::ClientStream::SeeOtherHost)
s = QString("see other host: [%1]").arg(Stream->errorText());
else if(x == XMPP::ClientStream::UnsupportedVersion)
s = "server does not support proper xmpp version";
s = QString("Stream negotiation error: ") + s;
}
else if(err == XMPP::ClientStream::ErrTLS)
{
int x = Stream->errorCondition();
QString s;
if(x == XMPP::ClientStream::TLSStart)
s = "server rejected STARTTLS";
else if(x == XMPP::ClientStream::TLSFail)
{
int t = TlsHandler->tlsError();
if(t == QCA::TLS::ErrHandshake)
s = "TLS handshake error";
else
s = "broken security layer (TLS)";
}
//nothing to add
}
else if(err == XMPP::ClientStream::ErrAuth)
{
int x = Stream->errorCondition();
if(x == XMPP::ClientStream::GenericAuthError)
s = "unable to login";
else if(x == XMPP::ClientStream::NoMech)
s = "no appropriate auth mechanism available for given security settings";
else if(x == XMPP::ClientStream::BadProto)
s = "bad server response";
else if(x == XMPP::ClientStream::BadServ)
s = "server failed mutual authentication";
else if(x == XMPP::ClientStream::EncryptionRequired)
s = "encryption required for chosen SASL mechanism";
else if(x == XMPP::ClientStream::InvalidAuthzid)
s = "invalid authzid";
else if(x == XMPP::ClientStream::InvalidMech)
s = "invalid SASL mechanism";
else if(x == XMPP::ClientStream::InvalidRealm)
s = "invalid realm";
else if(x == XMPP::ClientStream::MechTooWeak)
s = "SASL mechanism too weak for authzid";
else if(x == XMPP::ClientStream::NotAuthorized)
s = "not authorized";
else if(x == XMPP::ClientStream::TemporaryAuthFailure)
s = "temporary auth failure";
s = QString("Authentication error: ") + s;
}
else if(err == XMPP::ClientStream::ErrSecurityLayer)
s = "broken security layer (SASL)";
qWarning(s);
if (!this->isConnected() && this->StayConnected)
{
qWarning("XMPP Stream got disconnected, reconnecting...");
QTimer::singleShot(100,this,SLOT(initNetwork()));
}
}
//END XMPP slots and signals for network management //
}
syntax highlighted by Code2HTML, v. 0.9.1