bool StartTLSFeature::xmppStanzaIn(IXmppStream *AXmppStream, Stanza &AStanza, int AOrder) { if (AXmppStream==FXmppStream && AOrder==XSHO_XMPP_FEATURE) { FXmppStream->removeXmppStanzaHandler(XSHO_XMPP_FEATURE,this); if (AStanza.tagName() == "proceed") { if (FXmppStream->connection()->startEncryption()) { LOG_STRM_INFO(FXmppStream->streamJid(),"Starting StartTLS encryption"); connect(FXmppStream->connection()->instance(),SIGNAL(encrypted()),SLOT(onConnectionEncrypted())); } else { LOG_STRM_ERROR(FXmppStream->streamJid(),"Failed to negotiate StartTLS encryption: Handshake not started"); emit error(XmppError(IERR_STARTTLS_NOT_STARTED)); } } else if (AStanza.tagName() == "failure") { LOG_STRM_WARNING(FXmppStream->streamJid(),"Failed to negotiate StartTLS encryption: Negotiation failed"); emit error(XmppError(IERR_STARTTLS_NEGOTIATION_FAILED)); } else { LOG_STRM_WARNING(FXmppStream->streamJid(),"Failed to negotiate StartTLS encryption: Invalid responce"); emit error(XmppError(IERR_STARTTLS_INVALID_RESPONCE)); } return true; } return false; }
void CompressFeature::processData(QByteArray &AData, bool ADataOut) { if (AData.size() > 0) { int ret; int dataPosOut = 0; z_streamp zstream = ADataOut ? &FDefStruc : &FInfStruc; zstream->avail_in = AData.size(); zstream->next_in = (Bytef *)(AData.constData()); do { zstream->avail_out = FOutBuffer.capacity() - dataPosOut; zstream->next_out = (Bytef *)(FOutBuffer.data() + dataPosOut); ret = ADataOut ? deflate(zstream,Z_SYNC_FLUSH) : inflate(zstream,Z_SYNC_FLUSH); if (ret != Z_OK) REPORT_ERROR(QString("Failed to deflate/inflate data, ZLib=%1: %2").arg(ZLIB_VERSION).arg(ret)); switch (ret) { case Z_OK: dataPosOut = FOutBuffer.capacity() - zstream->avail_out; if (zstream->avail_out == 0) FOutBuffer.reserve(FOutBuffer.capacity() + CHUNK); break; case Z_STREAM_ERROR: emit error(XmppError(IERR_COMPRESS_INVALID_COMPRESSION_LEVEL)); break; case Z_DATA_ERROR: emit error(XmppError(IERR_COMPRESS_INVALID_DEFLATE_DATA)); break; case Z_MEM_ERROR: emit error(XmppError(IERR_COMPRESS_OUT_OF_MEMORY)); break; case Z_VERSION_ERROR: emit error(XmppError(IERR_COMPRESS_VERSION_MISMATCH)); break; default: emit error(XmppError(IERR_COMPRESS_UNKNOWN_ERROR,tr("Error code: %1").arg(ret))); } } while (ret == Z_OK && zstream->avail_out == 0); AData.resize(dataPosOut); memcpy(AData.data(),FOutBuffer.constData(),dataPosOut); } }
bool InBandStream::sendNextPaket(bool AFlush) { bool sent = false; if (isOpen() && FDataIqRequestId.isEmpty() && (bytesToWrite()>=FBlockSize || AFlush)) { FThreadLock.lockForWrite(); QByteArray data = FWriteBuffer.read(FBlockSize); FThreadLock.unlock(); if (!data.isEmpty()) { if (FStanzaProcessor) { Stanza paket(FStanzaType==StanzaMessage ? STANZA_KIND_MESSAGE : STANZA_KIND_IQ); paket.setTo(FContactJid.full()).setUniqueId(); QDomElement dataElem = paket.addElement("data",NS_INBAND_BYTESTREAMS); dataElem.setAttribute("sid",FStreamId); dataElem.setAttribute("seq",FSeqOut); dataElem.appendChild(paket.createTextNode(QString::fromUtf8(data.toBase64()))); if (FStanzaType == StanzaMessage) { QDomElement ampElem = paket.addElement("amp","http://jabber.org/protocol/amp"); QDomElement ruleElem = ampElem.appendChild(paket.createElement("rule")).toElement(); ruleElem.setAttribute("condition","deliver"); ruleElem.setAttribute("value","stored"); ruleElem.setAttribute("action","error"); ruleElem = ampElem.appendChild(paket.createElement("rule")).toElement(); ruleElem.setAttribute("condition","match-resource"); ruleElem.setAttribute("value","exact"); ruleElem.setAttribute("action","error"); DataEvent *dataEvent = new DataEvent(AFlush); QCoreApplication::postEvent(this, dataEvent); sent = FStanzaProcessor->sendStanzaOut(FStreamJid,paket); } else { paket.setType(STANZA_TYPE_SET); FDataIqRequestId = paket.id(); sent = FStanzaProcessor->sendStanzaRequest(this,FStreamJid,paket,DATA_TIMEOUT); } } if (sent) { FSeqOut = FSeqOut<USHRT_MAX ? FSeqOut+1 : 0; emit bytesWritten(data.size()); FBytesWrittenCondition.wakeAll(); } else { abort(XmppError(IERR_INBAND_STREAM_DATA_NOT_SENT)); } } } return sent; }
void RegisterStream::onRegisterDialogRejected() { LOG_STRM_INFO(FXmppStream->streamJid(),"Account registration terminated by user"); FXmppStream->setKeepAliveTimerActive(true); emit error(XmppError(IERR_REGISTER_REJECTED_BY_USER)); FDialog = NULL; }
void DataMediaWidget::onUrlLoaded(const QUrl &AUrl, const QByteArray &AData) { if (FUriIndex<FMedia.uris.count() && FMedia.uris.at(FUriIndex).url == AUrl) { const IDataMediaURI &uri = FMedia.uris.at(FUriIndex); if (!updateWidget(uri, AData)) { FUriIndex++; FLastError = XmppError(IERR_DATAFORMS_MEDIA_INVALID_FORMAT); loadUri(); } } }
void Roster::stanzaRequestResult(const Jid &AStreamJid, const Stanza &AStanza) { if (AStanza.id() == FDelimRequestId) { FDelimRequestId.clear(); QString groupDelim = ROSTER_GROUP_DELIMITER; if (AStanza.type() == "result") { groupDelim = AStanza.firstElement("query",NS_JABBER_PRIVATE).firstChildElement("roster").text(); if (groupDelim.isEmpty()) { groupDelim = ROSTER_GROUP_DELIMITER; LOG_STRM_INFO(streamJid(),QString("Saving default roster group delimiter on server, delimiter='%1'").arg(groupDelim)); Stanza delim("iq"); delim.setType("set").setId(FStanzaProcessor->newId()); QDomElement elem = delim.addElement("query",NS_JABBER_PRIVATE); elem.appendChild(delim.createElement("roster",NS_STORAGE_GROUP_DELIMITER)).appendChild(delim.createTextNode(groupDelim)); FStanzaProcessor->sendStanzaOut(AStreamJid,delim); } else { LOG_STRM_INFO(streamJid(),QString("Roster group delimiter loaded, delimiter='%1'").arg(groupDelim)); } } else { LOG_STRM_WARNING(streamJid(),QString("Failed to load roster group delimiter: %1").arg(XmppStanzaError(AStanza).condition())); } setGroupDelimiter(groupDelim); requestRosterItems(); } else if (AStanza.id() == FOpenRequestId) { FOpenRequestId.clear(); if (AStanza.type() == "result") { LOG_STRM_INFO(streamJid(),"Roster items loaded"); processItemsElement(AStanza.firstElement("query",NS_JABBER_ROSTER),true); FOpened = true; emit opened(); } else { LOG_STRM_WARNING(streamJid(),QString("Failed to load roster items: %1").arg(XmppStanzaError(AStanza).condition())); FXmppStream->abort(XmppError(IERR_ROSTER_REQUEST_FAILED)); } } }
DataMediaWidget::DataMediaWidget(IDataForms *ADataForms, const IDataMedia &AMedia, QWidget *AParent) : QLabel(AParent) { FMedia = AMedia; FDataForms = ADataForms; setTextFormat(Qt::PlainText); setFrameShape(QLabel::Panel); setFrameShadow(QLabel::Sunken); connect(FDataForms->instance(),SIGNAL(urlLoaded(const QUrl &, const QByteArray &)),SLOT(onUrlLoaded(const QUrl &, const QByteArray &))); connect(FDataForms->instance(),SIGNAL(urlLoadFailed(const QUrl &, const XmppError &)),SLOT(onUrlLoadFailed(const QUrl &, const XmppError &))); FUriIndex = 0; FLastError = XmppError(IERR_DATAFORMS_MEDIA_INVALID_TYPE); QTimer::singleShot(0,this,SLOT(loadUri())); }
void RegisterStream::onRegisterDialogAccepred() { FXmppStream->setKeepAliveTimerActive(true); if (FDialog) { Stanza submit("iq"); submit.setType("set").setId("setReg"); QDomElement query = submit.addElement("query",NS_JABBER_REGISTER); FDataForms->xmlForm(FDataForms->dataSubmit(FDialog->formWidget()->userDataForm()),query); FXmppStream->sendStanza(submit); LOG_STRM_INFO(FXmppStream->streamJid(),"Account registration submit request sent"); } else { LOG_STRM_WARNING(FXmppStream->streamJid(),"Account registration form dialog destroyed"); emit error(XmppError(IERR_REGISTER_INVALID_DIALOG)); } FDialog = NULL; }
void InBandStream::stanzaRequestResult(const Jid &AStreamJid, const Stanza &AStanza) { Q_UNUSED(AStreamJid); if (AStanza.id() == FDataIqRequestId) { if (AStanza.isResult()) { FDataIqRequestId.clear(); sendNextPaket(); } else { abort(XmppStanzaError(AStanza)); } } else if (AStanza.id() == FOpenRequestId) { if (AStanza.isResult()) { FSHIData = insertStanzaHandle(FStanzaType==StanzaMessage ? SHC_INBAND_DATA_MESSAGE : SHC_INBAND_DATA_IQ); FSHIClose = insertStanzaHandle(SHC_INBAND_CLOSE); if (FSHIData>0 && FSHIClose>0) setStreamState(IDataStreamSocket::Opened); else abort(XmppError(IERR_INBAND_STREAM_NOT_OPENED)); } else { abort(XmppStanzaError(AStanza)); } } else if (AStanza.id() == FCloseRequestId) { setStreamState(IDataStreamSocket::Closed); } }
bool InBandStream::stanzaReadWrite(int AHandleId, const Jid &AStreamJid, Stanza &AStanza, bool &AAccept) { QDomElement elem = AStanza.firstElement(QString::null,NS_INBAND_BYTESTREAMS); if (AHandleId==FSHIData && elem.attribute("sid")==FStreamId) { AAccept = true; if (AStanza.firstElement("error").isNull()) { QByteArray data = QByteArray::fromBase64(elem.text().toLatin1()); if (FSeqIn==elem.attribute("seq").toInt() && data.size()>0 && data.size()<=FBlockSize) { if (AStanza.kind() == STANZA_KIND_IQ) { Stanza result = FStanzaProcessor->makeReplyResult(AStanza); FStanzaProcessor->sendStanzaOut(AStreamJid,result); } FThreadLock.lockForWrite(); FReadBuffer.write(data); FThreadLock.unlock(); FSeqIn = FSeqIn<USHRT_MAX ? FSeqIn+1 : 0; emit readyRead(); FReadyReadCondition.wakeAll(); } else { abort(XmppError(IERR_INBAND_STREAM_INVALID_DATA)); } } else { abort(XmppStanzaError(AStanza)); } } else if (AHandleId==FSHIOpen && elem.attribute("sid")==FStreamId) { AAccept = true; removeStanzaHandle(FSHIOpen); if (FStreamState == IDataStreamSocket::Opening) { QDomElement openElem = AStanza.firstElement("open"); FBlockSize = openElem.attribute("block-size").toInt(); if (FBlockSize>MINIMUM_BLOCK_SIZE && FBlockSize<=FMaxBlockSize) { FStanzaType = openElem.attribute("stanza")==STANZA_KIND_MESSAGE ? StanzaMessage : StanzaIq; FSHIData = insertStanzaHandle(FStanzaType==StanzaMessage ? SHC_INBAND_DATA_MESSAGE : SHC_INBAND_DATA_IQ); FSHIClose = insertStanzaHandle(SHC_INBAND_CLOSE); if (FSHIData>0 && FSHIClose>0) { Stanza result = FStanzaProcessor->makeReplyResult(AStanza); if (FStanzaProcessor->sendStanzaOut(AStreamJid,result)) setStreamState(IDataStreamSocket::Opened); else abort(XmppError(IERR_INBAND_STREAM_NOT_OPENED)); } else { Stanza error = FStanzaProcessor->makeReplyError(AStanza,XmppStanzaError::EC_INTERNAL_SERVER_ERROR); FStanzaProcessor->sendStanzaOut(AStreamJid,error); abort(XmppError(IERR_INBAND_STREAM_NOT_OPENED)); } } else { Stanza error = FStanzaProcessor->makeReplyError(AStanza,XmppStanzaError::EC_RESOURCE_CONSTRAINT); FStanzaProcessor->sendStanzaOut(AStreamJid,error); abort(XmppError(IERR_INBAND_STREAM_INVALID_BLOCK_SIZE)); } } else { LOG_STRM_WARNING(AStreamJid,QString("Unexpected open request from=%1, sid=%2: Invalid state").arg(AStanza.from(),FStreamId)); Stanza error = FStanzaProcessor->makeReplyError(AStanza,XmppStanzaError::EC_UNEXPECTED_REQUEST); FStanzaProcessor->sendStanzaOut(AStreamJid,error); } } else if (AHandleId==FSHIClose && elem.attribute("sid")==FStreamId) { AAccept = true; Stanza result = FStanzaProcessor->makeReplyResult(AStanza); FStanzaProcessor->sendStanzaOut(AStreamJid,result); setStreamState(IDataStreamSocket::Closed); } return false; }
InBandStream::~InBandStream() { abort(XmppError(IERR_INBAND_STREAM_DESTROYED)); LOG_STRM_INFO(FStreamJid,QString("In-band stream destroyed, sid=%1, kind=%2").arg(FStreamId).arg(FStreamKind)); }
bool RegisterStream::xmppStanzaIn(IXmppStream *AXmppStream, Stanza &AStanza, int AOrder) { if (AXmppStream==FXmppStream && AOrder==XSHO_XMPP_FEATURE) { if (AStanza.id() == "getReg") { if (AStanza.type() == "result") { LOG_STRM_INFO(AXmppStream->streamJid(),"Account registration fileds loaded"); QDomElement queryElem = AStanza.firstElement("query",NS_JABBER_REGISTER); QDomElement formElem = Stanza::findElement(queryElem,"x",NS_JABBER_DATA); if (FDataForms && !formElem.isNull()) { IDataForm form = FDataForms->dataForm(formElem); if (FDataForms->isFormValid(form)) { int userFiled = FDataForms->fieldIndex("username",form.fields); if (userFiled >= 0) { form.fields[userFiled].value = FXmppStream->streamJid().node(); form.fields[userFiled].type = DATAFIELD_TYPE_HIDDEN; } int passFiled = FDataForms->fieldIndex("password",form.fields); if (passFiled >= 0) { form.fields[passFiled].value = FXmppStream->getSessionPassword(); form.fields[passFiled].type = DATAFIELD_TYPE_HIDDEN; } FDialog = FDataForms->dialogWidget(form,NULL); FDialog->setAllowInvalid(false); FDialog->instance()->setWindowTitle(tr("Registration on %1").arg(FXmppStream->streamJid().domain())); connect(FDialog->instance(),SIGNAL(accepted()),SLOT(onRegisterDialogAccepred())); connect(FDialog->instance(),SIGNAL(rejected()),SLOT(onRegisterDialogRejected())); WidgetManager::showActivateRaiseWindow(FDialog->instance()); FXmppStream->setKeepAliveTimerActive(false); LOG_STRM_INFO(AXmppStream->streamJid(),"Account registration form dialog shown"); } else { LOG_STRM_WARNING(AXmppStream->streamJid(),"Failed to register new account on server: Invalid registration form received"); emit error(XmppError(IERR_REGISTER_INVALID_FORM)); } } else { Stanza submit("iq"); submit.setType("set").setId("setReg"); QDomElement querySubmit = submit.addElement("query",NS_JABBER_REGISTER); if (!queryElem.firstChildElement("username").isNull()) querySubmit.appendChild(submit.createElement("username")).appendChild(submit.createTextNode(FXmppStream->streamJid().node())); if (!queryElem.firstChildElement("password").isNull()) querySubmit.appendChild(submit.createElement("password")).appendChild(submit.createTextNode(FXmppStream->getSessionPassword())); if (!queryElem.firstChildElement("key").isNull()) querySubmit.appendChild(submit.createElement("key")).appendChild(submit.createTextNode(AStanza.firstElement("query").attribute("key"))); FXmppStream->sendStanza(submit); LOG_STRM_INFO(AXmppStream->streamJid(),"Account registration submit request sent"); } } else { XmppStanzaError err(AStanza); LOG_STRM_WARNING(AXmppStream->streamJid(),QString("Failed to load account registration fields: %1").arg(err.condition())); emit error(err); } return true; } else if (AStanza.id() == "setReg") { FXmppStream->removeXmppStanzaHandler(XSHO_XMPP_FEATURE,this); if (AStanza.type() == "result") { REPORT_EVENT(SEVP_REGISTRATION_STREAM_SUCCESS,1); LOG_STRM_INFO(AXmppStream->streamJid(),"Account registration submit accepted"); deleteLater(); emit finished(false); } else { XmppStanzaError err(AStanza); LOG_STRM_WARNING(AXmppStream->streamJid(),QString("Account registration submit rejected: %1").arg(err.condition())); emit error(err); } return true; } } return false; }
bool IqAuthFeature::xmppStanzaIn(IXmppStream *AXmppStream, Stanza &AStanza, int AOrder) { if (AXmppStream==FXmppStream && AOrder==XSHO_XMPP_FEATURE) { if (AStanza.id() == "getIqAuth") { if (AStanza.type() == "result") { Stanza auth("iq"); auth.setType("set").setTo(FXmppStream->streamJid().domain()).setId("setIqAuth"); QDomElement query = auth.addElement("query",NS_JABBER_IQ_AUTH); query.appendChild(auth.createElement("username")).appendChild(auth.createTextNode(FXmppStream->streamJid().pNode())); query.appendChild(auth.createElement("resource")).appendChild(auth.createTextNode(FXmppStream->streamJid().resource())); QDomElement reqElem = AStanza.firstElement("query",NS_JABBER_IQ_AUTH); if (!reqElem.firstChildElement("digest").isNull()) { QByteArray shaData = FXmppStream->streamId().toUtf8()+FXmppStream->password().toUtf8(); QByteArray shaDigest = QCryptographicHash::hash(shaData,QCryptographicHash::Sha1).toHex(); query.appendChild(auth.createElement("digest")).appendChild(auth.createTextNode(shaDigest.toLower().trimmed())); FXmppStream->sendStanza(auth); LOG_STRM_INFO(AXmppStream->streamJid(),"Username and encrypted password sent"); } else if (!reqElem.firstChildElement("password").isNull()) { if (FXmppStream->connection()->isEncrypted()) { query.appendChild(auth.createElement("password")).appendChild(auth.createTextNode(FXmppStream->password())); FXmppStream->sendStanza(auth); LOG_STRM_INFO(AXmppStream->streamJid(),"Username and plain text password sent"); } else { LOG_STRM_ERROR(AXmppStream->streamJid(),"Failed to send username and plain text password: Connection not encrypted"); emit error(XmppError(IERR_XMPPSTREAM_NOT_SECURE)); } } } else { XmppStanzaError err(AStanza); LOG_STRM_ERROR(AXmppStream->streamJid(),QString("Failed to receive authentication initialization: %1").arg(err.condition())); emit error(err); } return true; } else if (AStanza.id() == "setIqAuth") { FXmppStream->removeXmppStanzaHandler(XSHO_XMPP_FEATURE,this); if (AStanza.type() == "result") { LOG_STRM_INFO(AXmppStream->streamJid(),"Username and password accepted"); deleteLater(); emit finished(false); } else { XmppStanzaError err(AStanza); LOG_STRM_WARNING(AXmppStream->streamJid(),QString("Username and password rejected: %1").arg(err.condition())); emit error(XmppStanzaError(AStanza)); } return true; } } return false; }