Commit eee98ff0 authored by Pali Rohár's avatar Pali Rohár

Update libiris from https://github.com/psi-im/iris.git commit...

Update libiris from https://github.com/psi-im/iris.git commit f8f13444c87048b18cc374a493424f36f5e5d489
parent 5d236087
#include "../../src/xmpp/xmpp-im/xmpp_caps.h"
......@@ -3,8 +3,9 @@ DEPENDPATH += $$PWD/../..
HEADERS += \
$$PWD/randomnumbergenerator.h \
$$PWD/randrandomnumbergenerator.h
$$PWD/randrandomnumbergenerator.h \
$$PWD/timezone.h
SOURCES += \
$$PWD/randomnumbergenerator.cpp
$$PWD/randomnumbergenerator.cpp \
$$PWD/timezone.cpp
/*
* Copyright (C) Psi Development Team
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <QtGlobal>
#if QT_VERSION < QT_VERSION_CHECK(5, 2, 0)
#include <QByteArray>
#include <QTime>
#ifdef Q_OS_UNIX
#include <time.h>
#endif
#ifdef Q_OS_WIN
#include <windows.h>
#endif
#else
#include <QTimeZone>
#endif
#include "timezone.h"
#if QT_VERSION < QT_VERSION_CHECK(5,2,0)
static bool inited = false;
static int timezone_offset_;
static QString timezone_str_;
static void init()
{
#if defined(Q_OS_UNIX)
time_t x;
time(&x);
char str[256];
char fmt[32];
int size;
strcpy(fmt, "%z");
size = strftime(str, 256, fmt, localtime(&x));
if(size && strncmp(fmt, str, size)) {
timezone_offset_ = QByteArray::fromRawData(str + 1, 2).toInt() * 60 + QByteArray::fromRawData(str + 3, 2).toInt();
if(str[0] == '-')
timezone_offset_ = -timezone_offset_;
}
strcpy(fmt, "%Z");
strftime(str, 256, fmt, localtime(&x));
if(strcmp(fmt, str))
timezone_str_ = str;
#elif defined(Q_OS_WIN)
TIME_ZONE_INFORMATION i;
memset(&i, 0, sizeof(i));
bool inDST = (GetTimeZoneInformation(&i) == TIME_ZONE_ID_DAYLIGHT);
int bias = i.Bias;
if(inDST)
bias += i.DaylightBias;
timezone_offset_ = -bias;
timezone_str_ = "";
for(int n = 0; n < 32; ++n) {
int w = inDST ? i.DaylightName[n] : i.StandardName[n];
if(w == 0)
break;
timezone_str_ += QChar(w);
}
#else
qWarning("Failed to properly init timezone data. Use UTC offset instead");
inited = true;
timezone_offset_ = 0;
timezone_str_ = QLatin1String("N/A");
#endif
}
#endif
int TimeZone::offsetFromUtc()
{
#if QT_VERSION < QT_VERSION_CHECK(5,2,0)
if (!inited) {
init();
}
return timezone_offset_;
#else
return QTimeZone::systemTimeZone().offsetFromUtc(QDateTime::currentDateTime());
#endif
}
QString TimeZone::abbreviation()
{
#if QT_VERSION < QT_VERSION_CHECK(5,2,0)
return timezone_str_;
#else
return QTimeZone::systemTimeZone().abbreviation(QDateTime::currentDateTime());
#endif
}
int TimeZone::tzdToInt(const QString &tzd)
{
int tzoSign = 1;
if (tzd.startsWith('Z')) {
return 0;
} else if (tzd.startsWith('+') || tzd.startsWith('-')) {
QTime time = QTime::fromString(tzd.mid(1), "hh:mm");
if (time.isValid()) {
if (tzd[0] == '-') {
tzoSign = -1;
}
return tzoSign * (time.hour() * 60 + time.second());
}
}
return -1; /* we don't have -1 sec offset. and usually the value is common for errors */
}
/**
* \fn int TimeZone::timezoneOffset()
* \brief Local timezone offset in minutes.
*/
/**
* \fn QString TimeZone::timezoneString()
* \brief Local timezone name.
*/
/*
* Copyright (C) Psi Development Team
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef IRIS_TIMEZONE_H
#define IRIS_TIMEZONE_H
#include <QObject>
class TimeZone
{
public:
static int offsetFromUtc();
static QString abbreviation();
static int tzdToInt(const QString &tzd);
};
#endif // IRIS_TIMEZONE_H
......@@ -724,6 +724,11 @@ public:
in->pause(true);
reader->parse(in, true);
in->pause(false);
} else {
reader = 0;
handler = 0;
in = 0;
doc = 0;
}
}
......
......@@ -34,7 +34,7 @@
#include "td.h"
#endif
//#define SM_DEBUG
//#define IRIS_SM_DEBUG
using namespace XMPP;
......@@ -661,12 +661,12 @@ void CoreProtocol::sendStanza(const QDomElement &e, bool notify) {
if (notify) qDebug() << "Want notification for stanza";
#endif
sm_send_queue.push_back(qMakePair(e, notify));
#ifdef SM_DEBUG
#ifdef IRIS_SM_DEBUG
qDebug() << "sm_send_queue: ";
#endif
for (QList<QPair<QDomElement, bool> >::iterator i = sm_send_queue.begin(); i != sm_send_queue.end(); ++i) {
QPair<QDomElement, bool> entry = *i;
#ifdef SM_DEBUG
#ifdef IRIS_SM_DEBUG
qDebug() << "\t" << entry.first.tagName() << " : " << entry.second;
#endif
}
......@@ -951,14 +951,14 @@ bool CoreProtocol::streamManagementHandleStanza(const QDomElement &e)
qulonglong last_handled_id = getSMLastHandledId();
QDomElement e = doc.createElementNS(NS_STREAM_MANAGEMENT, "a");
e.setAttribute("h", last_handled_id);
#ifdef SM_DEBUG
#ifdef IRIS_SM_DEBUG
qWarning() << "Stream Management: Sending acknowledgment with h=" << last_handled_id;
#endif
send(e);
event = ESend;
return true;
} else if (s == "a") {
#ifdef SM_DEBUG
#ifdef IRIS_SM_DEBUG
qWarning() << "Received ack response from server";
#endif
processSMAcknowlegement(e.attribute("h").toULong());
......@@ -976,7 +976,7 @@ unsigned long CoreProtocol::getNewSMId() {
sm_receive_queue.push_back(qMakePair(sm_id, false));
sm_receive_count++;
if (sm_receive_count == (unsigned long)-1) sm_receive_count = 0; /* why do we skip -1? */
#ifdef SM_DEBUG
#ifdef IRIS_SM_DEBUG
qWarning() << "Current SM id: " << sm_id;
#endif
return sm_id;
......@@ -1006,19 +1006,19 @@ void CoreProtocol::markStanzaHandled(unsigned long id) {
return;
}
}
#ifdef SM_DEBUG
#ifdef IRIS_SM_DEBUG
qWarning() << "Stream Management: Higher level client marked unknown stanza handled!";
#endif
}
void CoreProtocol::markLastMessageStanzaAcked() {
if (sm_receive_queue.isEmpty()) {
#ifdef SM_DEBUG
#ifdef IRIS_SM_DEBUG
qWarning() << "Stream Management: Higher level client marked unexistant stanza as acked.";
#endif
return;
}
#ifdef SM_DEBUG
#ifdef IRIS_SM_DEBUG
qWarning() << "Previous list: " << sm_receive_queue;
#endif
for(QList<QPair<unsigned long, bool> >::Iterator it = sm_receive_queue.begin(); it != sm_receive_queue.end(); ++it ) {
......@@ -1034,7 +1034,7 @@ bool CoreProtocol::isStreamManagementActive() const {
}
void CoreProtocol::requestSMAcknowlegement() {
#ifdef SM_DEBUG
#ifdef IRIS_SM_DEBUG
qDebug() << "Now I'd request acknowledgement from the server.";
#endif
sendDirect(QString("<r xmlns='" NS_STREAM_MANAGEMENT "'/>"));
......@@ -1046,7 +1046,7 @@ int CoreProtocol::getNotableStanzasAcked() {
}
ClientStream::SMState CoreProtocol::getSMState() const {
#ifdef SM_DEBUG
#ifdef IRIS_SM_DEBUG
qDebug("\tCoreProtocol::getSMState()");
#endif
ClientStream::SMState state;
......@@ -1539,6 +1539,12 @@ bool CoreProtocol::normalStep(const QDomElement &e)
f.hosts += l.item(n).toElement().text();
hosts += f.hosts;
}
QDomElement caps = e.elementsByTagNameNS(NS_CAPS, "c").item(0).toElement();
if(!caps.isNull()) {
f.capsNode = caps.attribute("node");
f.capsVersion = caps.attribute("ver");
f.capsAlgo = caps.attribute("hash");
}
// check for XEP-0198 support if we are already authed
if (sasl_authed) {
......@@ -1894,17 +1900,17 @@ bool CoreProtocol::normalStep(const QDomElement &e)
}
}
else if(step == GetSMResponse) {
#ifdef SM_DEBUG
#ifdef IRIS_SM_DEBUG
qWarning() << "HandleSM: step";
#endif
if (e.namespaceURI() == NS_STREAM_MANAGEMENT) {
if (e.localName() == "enabled") {
#ifdef SM_DEBUG
#ifdef IRIS_SM_DEBUG
qWarning() << "Stream Management enabled";
#endif
sm_started = true;
if (e.attribute("resume", "false") == "true" || e.attribute("resume", "false") == "1") {
#ifdef SM_DEBUG
#ifdef IRIS_SM_DEBUG
qDebug("\tResumption Supported");
#endif
sm_resumption_supported = true;
......
......@@ -22,7 +22,6 @@
#define PROTOCOL_H
#include <QObject>
//Added by qt3to4:
#include <QList>
#include <QPair>
#include <QTimer>
......@@ -40,6 +39,7 @@
#define NS_SESSION "urn:ietf:params:xml:ns:xmpp-session"
#define NS_STANZAS "urn:ietf:params:xml:ns:xmpp-stanzas"
#define NS_BIND "urn:ietf:params:xml:ns:xmpp-bind"
#define NS_CAPS "http://jabber.org/protocol/caps"
#define NS_COMPRESS_FEATURE "http://jabber.org/features/compress"
#define NS_COMPRESS_PROTOCOL "http://jabber.org/protocol/compress"
#define NS_HOSTS "http://barracuda.com/xmppextensions/hosts"
......@@ -66,6 +66,9 @@ namespace XMPP
QStringList sasl_mechs;
QStringList compression_mechs;
QStringList hosts;
QString capsVersion;
QString capsNode;
QString capsAlgo;
};
class BasicProtocol : public XmlProtocol
......
......@@ -200,6 +200,7 @@ public:
QString connectHost;
int minimumSSF, maximumSSF;
QString sasl_mech;
QMap<QString,QString> mechProviders; // mech to provider map
bool doBinding;
bool in_rrsig;
......@@ -437,6 +438,24 @@ void ClientStream::continueAfterParams()
}
}
void ClientStream::setSaslMechanismProvider(const QString &m, const QString &p)
{
d->mechProviders.insert(m, p);
}
QString ClientStream::saslMechanismProvider(const QString &m) const
{
return d->mechProviders.value(m);
}
QCA::Provider::Context *ClientStream::currentSASLContext() const
{
if (d->sasl) {
return d->sasl->context();
}
return 0;
}
void ClientStream::setSCRAMStoredSaltedHash(const QString &s) {
QCA::SASLContext *context = (QCA::SASLContext *)(d->sasl->context());
if (context) {
......@@ -925,7 +944,8 @@ void ClientStream::srvProcessNext()
void ClientStream::doReadyRead()
{
//QGuardedPtr<QObject> self = this;
readyRead();
if (isActive())
emit readyRead();
//if(!self)
// return;
//d->in_rrsig = false;
......@@ -1162,7 +1182,21 @@ bool ClientStream::handleNeed()
QCA::setProviderPriority("simplesasl", 10);
}
d->sasl = new QCA::SASL();
QStringList ml;
if(!d->sasl_mech.isEmpty())
ml += d->sasl_mech;
else
ml = d->client.features.sasl_mechs;
QString saslProvider;
foreach (const QString &mech, d->mechProviders.keys()) {
if (ml.contains(mech)) {
saslProvider = d->mechProviders[mech];
break;
}
}
d->sasl = new QCA::SASL(0, saslProvider);
connect(d->sasl, SIGNAL(clientStarted(bool,QByteArray)), SLOT(sasl_clientFirstStep(bool,QByteArray)));
connect(d->sasl, SIGNAL(nextStep(QByteArray)), SLOT(sasl_nextStep(QByteArray)));
connect(d->sasl, SIGNAL(needParams(QCA::SASL::Params)), SLOT(sasl_needParams(QCA::SASL::Params)));
......@@ -1187,12 +1221,6 @@ bool ClientStream::handleNeed()
auth_flags = (QCA::SASL::AuthFlags) (auth_flags | QCA::SASL::RequireMutualAuth);
d->sasl->setConstraints(auth_flags,d->minimumSSF,d->maximumSSF);
QStringList ml;
if(!d->sasl_mech.isEmpty())
ml += d->sasl_mech;
else
ml = d->client.features.sasl_mechs;
#ifdef IRIS_SASLCONNECTHOST
d->sasl->startClient("xmpp", QUrl::toAce(d->connectHost), ml, QCA::SASL::AllowClientSendFirst);
#else
......@@ -1427,6 +1455,11 @@ QStringList ClientStream::hosts() const
return d->client.hosts;
}
const StreamFeatures &ClientStream::streamFeatures() const
{
return d->client.features;
}
//----------------------------------------------------------------------------
// Debug
......
......@@ -36,6 +36,7 @@ namespace XMPP
{
class TLSHandler;
class Connector;
class StreamFeatures;
class ClientStream : public Stream
{
......@@ -119,6 +120,9 @@ namespace XMPP
void setRealm(const QString &s);
void setAuthzid(const QString &s);
void continueAfterParams();
void setSaslMechanismProvider(const QString &m, const QString &p);
QString saslMechanismProvider(const QString &m) const;
QCA::Provider::Context *currentSASLContext() const;
void setSCRAMStoredSaltedHash(const QString &s);
const QString getSCRAMStoredSaltedHash();
......@@ -172,6 +176,8 @@ namespace XMPP
// barracuda extension
QStringList hosts() const;
const StreamFeatures &streamFeatures() const;
signals:
void connected();
void securityLayerActivated(int);
......
......@@ -18,9 +18,6 @@
*
*/
#include "im.h"
#include "safedelete.h"
//! \class XMPP::Client client.h
//! \brief Communicates with the XMPP network. Start here.
//!
......@@ -69,34 +66,22 @@
//! }
//! \endcode
#include <stdarg.h>
#include <qobject.h>
#include <QObject>
#include <QMap>
#include <qtimer.h>
#include <qpointer.h>
//Added by qt3to4:
#include <QTimer>
#include <QPointer>
#include <QList>
#include "im.h"
#include "safedelete.h"
#include "xmpp_tasks.h"
#include "xmpp_xmlcommon.h"
#include "s5b.h"
#include "xmpp_ibb.h"
#include "xmpp_bitsofbinary.h"
#include "filetransfer.h"
/*#include <stdio.h>
#include <stdarg.h>
#include <qstring.h>
#include <qdom.h>
#include <qobjectlist.h>
#include <qtimer.h>
#include "xmpp_stream.h"
#include "xmpp_tasks.h"
#include "xmpp_xmlcommon.h"
#include "xmpp_dtcp.h"
#include "xmpp_ibb.h"
#include "xmpp_jidlink.h"
using namespace Jabber;*/
#include "xmpp_caps.h"
#include "protocol.h"
#ifdef Q_OS_WIN
#define vsnprintf _vsnprintf
......@@ -129,7 +114,8 @@ public:
int id_seed;
Task *root;
QString host, user, pass, resource;
QString osname, tzname, clientName, clientVersion, capsNode, capsVersion, capsExt;
QString osName, osVersion, tzname, clientName, clientVersion;
CapsSpec caps;
DiscoItem::Identity identity;
Features features;
QMap<QString,Features> extension_features;
......@@ -139,6 +125,7 @@ public:
LiveRoster roster;
ResourceList resourceList;
CapsManager *capsman;
S5BManager *s5bman;
IBBManager *ibbman;
BoBManager *bobman;
......@@ -155,12 +142,9 @@ Client::Client(QObject *par)
d->tzoffset = 0;
d->useTzoffset = false;
d->active = false;
d->osname = "N/A";
d->osName = "N/A";
d->clientName = "N/A";
d->clientVersion = "0.0";
d->capsNode = "";
d->capsVersion = "";
d->capsExt = "";
d->id_seed = 0xaaaa;
d->root = new Task(this, true);
......@@ -174,6 +158,8 @@ Client::Client(QObject *par)
d->bobman = new BoBManager(this);
d->ftman = 0;
d->capsman = new CapsManager(this);
}
Client::~Client()
......@@ -265,6 +251,11 @@ BoBManager *Client::bobManager() const
return d->bobman;
}
CapsManager *Client::capsManager() const
{
return d->capsman;
}
bool Client::isActive() const
{
return d->active;
......@@ -1007,6 +998,12 @@ void Client::sendSubscription(const Jid &jid, const QString &type, const QString
void Client::setPresence(const Status &s)
{
if (d->capsman->isEnabled()) {
if (d->caps.version().isEmpty() && !d->caps.node().isEmpty()) {
d->caps = CapsSpec(makeDiscoResult(d->caps.node())); /* recompute caps hash */
}
}
JT_Presence *j = new JT_Presence(rootTask());
j->pres(s);
j->go(true);
......@@ -1020,7 +1017,12 @@ void Client::setPresence(const Status &s)
QString Client::OSName() const
{
return d->osname;
return d->osName;
}
QString Client::OSVersion() const
{
return d->osVersion;
}
QString Client::timeZone() const
......@@ -1058,24 +1060,30 @@ QString Client::clientVersion() const
return d->clientVersion;
}
QString Client::capsNode() const
CapsSpec Client::caps() const
{
return d->capsNode;
return d->caps;
}
QString Client::capsVersion() const
CapsSpec Client::serverCaps() const
{
return d->capsVersion;
const StreamFeatures &f = d->stream->streamFeatures();
if (!(f.capsAlgo.isEmpty() || f.capsNode.isEmpty() || f.capsVersion.isEmpty())) {
if (CapsSpec::cryptoMap().contains(f.capsAlgo)) {
return CapsSpec(f.capsNode, CapsSpec::cryptoMap().value(f.capsAlgo), f.capsVersion);
}
}
return CapsSpec();
}
QString Client::capsExt() const
void Client::setOSName(const QString &name)
{
return d->capsExt;
d->osName = name;
}
void Client::setOSName(const QString &name)
void Client::setOSVersion(const QString &version)
{
d->osname = name;
d->osVersion = version