FileTransferHandler::FileTransferHandler(PsiAccount *pa, FileTransfer *ft) { d = new Private; d->pa = pa; d->c = 0; if(ft) { d->sending = false; d->peer = ft->peer(); d->fileName = clean_filename(ft->fileName()); d->fileSize = ft->fileSize(); d->desc = ft->description(); d->shift = calcShift(d->fileSize); d->complement = calcComplement(d->fileSize, d->shift); d->ft = ft; Jid proxy = d->pa->userAccount().dtProxy; if(proxy.isValid()) d->ft->setProxy(proxy); mapSignals(); } else { d->sending = true; d->ft = 0; } }
bool SASLBind::xmppStanzaIn(IXmppStream *AXmppStream, Stanza &AStanza, int AOrder) { if (AXmppStream==FXmppStream && AOrder==XSHO_XMPP_FEATURE && AStanza.id()=="bind") { FXmppStream->removeXmppStanzaHandler(this, XSHO_XMPP_FEATURE); if (AStanza.type() == "result") { Jid streamJid = AStanza.firstElement().firstChild().toElement().text(); if (streamJid.isValid()) { LogDetaile(QString("[SASLBind][%1] XMPP session binded with resource='%2'").arg(FXmppStream->streamJid().bare()).arg(streamJid.resource())); deleteLater(); FXmppStream->setStreamJid(streamJid); emit finished(false); } else { LogError(QString("[SASLBind][%1] Invalid XMPP stream JID in response").arg(FXmppStream->streamJid().bare())); emit error(tr("Invalid XMPP stream JID in SASL bind response")); } } else { ErrorHandler err(AStanza.element()); LogError(QString("[SASLBind] Failed to bind XMPP session: %1").arg(err.message())); emit error(err.message()); } return true; } return false; }
void MUCJoinDlg::doJoin() { if(!d->pa || !d->pa->checkConnected(this)) return; QString host = le_host->text(); QString room = le_room->text(); QString nick = le_nick->text(); QString pass = le_pass->text(); if(host.isEmpty() || room.isEmpty() || nick.isEmpty()) { QMessageBox::information(this, tr("Error"), tr("You must fill out the fields in order to join.")); return; } Jid j = room + '@' + host + '/' + nick; if(!j.isValid()) { QMessageBox::information(this, tr("Error"), tr("You entered an invalid room name.")); return; } if(!d->pa->groupChatJoin(host, room, nick, pass, !ck_history->isChecked())) { QMessageBox::information(this, tr("Error"), tr("You are in or joining this room already!")); return; } d->psi->dialogUnregister(this); d->jid = room + '@' + host + '/' + nick; d->pa->dialogRegister(this, d->jid); disableWidgets(); d->busy->start(); }
bool ClientInfo::requestLastActivity(const Jid &AStreamJid, const Jid &AContactJid) { bool sent = FActivityId.values().contains(AContactJid); if (!sent && AStreamJid.isValid() && AContactJid.isValid()) { Stanza iq(STANZA_KIND_IQ); iq.setType(STANZA_TYPE_GET).setTo(AContactJid.full()).setUniqueId(); iq.addElement("query",NS_JABBER_LAST); sent = FStanzaProcessor->sendStanzaRequest(this,AStreamJid,iq,LAST_ACTIVITY_TIMEOUT); if (sent) { FActivityId.insert(iq.id(),AContactJid); LOG_STRM_INFO(AStreamJid,QString("Last activity request sent to=%1").arg(AContactJid.full())); } else { LOG_STRM_WARNING(AStreamJid,QString("Failed to send last activity request to=%1").arg(AContactJid.full())); } } return sent; }
bool ClientInfo::requestSoftwareInfo(const Jid &AStreamJid, const Jid &AContactJid) { bool sent = FSoftwareId.values().contains(AContactJid); if (!sent && AStreamJid.isValid() && AContactJid.isValid()) { Stanza iq(STANZA_KIND_IQ); iq.setType(STANZA_TYPE_GET).setTo(AContactJid.full()).setUniqueId(); iq.addElement("query",NS_JABBER_VERSION); sent = FStanzaProcessor->sendStanzaRequest(this,AStreamJid,iq,SOFTWARE_INFO_TIMEOUT); if (sent) { FSoftwareId.insert(iq.id(),AContactJid); FSoftwareItems[AContactJid].status = SoftwareLoading; LOG_STRM_INFO(AStreamJid,QString("Software version request sent to=%1").arg(AContactJid.full())); } else { LOG_STRM_WARNING(AStreamJid,QString("Failed to sent software request to=%1").arg(AContactJid.full())); } } return sent; }
void NewPoi::initStreamList(const QString &ABareJid, bool AEditable) { if (FAccounts) { Jid streamJid; if (!ABareJid.isEmpty()) streamJid=FPoi->findStreamJid(ABareJid); for (QList<IAccount *>::const_iterator it=FAccounts->constBegin(); it!=FAccounts->constEnd(); it++) ui->boxAccount->addItem((*it)->name(), QVariant((*it)->streamJid().full())); ui->boxAccount->setCurrentIndex(streamJid.isValid()?ui->boxAccount->findData(QVariant(streamJid.full())):0); } ui->boxAccount->setEnabled(AEditable); }
bool ClientInfo::requestEntityTime(const Jid &AStreamJid, const Jid &AContactJid) { bool sent = FTimeId.values().contains(AContactJid); if (!sent && AStreamJid.isValid() && AContactJid.isValid()) { Stanza iq(STANZA_KIND_IQ); iq.setType(STANZA_TYPE_GET).setTo(AContactJid.full()).setUniqueId(); iq.addElement("time",NS_XMPP_TIME); sent = FStanzaProcessor->sendStanzaRequest(this,AStreamJid,iq,ENTITY_TIME_TIMEOUT); if (sent) { TimeItem &tItem = FTimeItems[AContactJid]; tItem.ping = QTime::currentTime().msecsTo(QTime(0,0,0,0)); FTimeId.insert(iq.id(),AContactJid); LOG_STRM_INFO(AStreamJid,QString("Current time request sent to=%1").arg(AContactJid.full())); emit entityTimeChanged(AContactJid); } else { LOG_STRM_WARNING(AStreamJid,QString("Failed to send current time request to=%1").arg(AContactJid.full())); } } return sent; }
void ClientInfo::showClientInfo(const Jid &AStreamJid, const Jid &AContactJid, int AInfoTypes) { if (AStreamJid.isValid() && AContactJid.isValid() && AInfoTypes>0) { ClientInfoDialog *dialog = FClientInfoDialogs.value(AContactJid,NULL); if (!dialog) { QString contactName = AContactJid.uNode(); if (FDiscovery!=NULL && FDiscovery->discoInfo(AStreamJid,AContactJid.bare()).identity.value(0).category=="conference") contactName = AContactJid.resource(); if (contactName.isEmpty()) contactName = FDiscovery!=NULL ? FDiscovery->discoInfo(AStreamJid,AContactJid).identity.value(0).name : AContactJid.domain(); if (FRosterManager) { IRoster *roster = FRosterManager->findRoster(AStreamJid); if (roster) { IRosterItem ritem = roster->findItem(AContactJid); if (!ritem.name.isEmpty()) contactName = ritem.name; } } dialog = new ClientInfoDialog(this,AStreamJid,AContactJid,!contactName.isEmpty() ? contactName : AContactJid.uFull(),AInfoTypes); connect(dialog,SIGNAL(clientInfoDialogClosed(const Jid &)),SLOT(onClientInfoDialogClosed(const Jid &))); FClientInfoDialogs.insert(AContactJid,dialog); dialog->show(); } else { dialog->setInfoTypes(dialog->infoTypes() | AInfoTypes); WidgetManager::showActivateRaiseWindow(dialog); } } }
QString XmppUriQueries::makeXmppUri(const Jid &AContactJid, const QString &AAction, const QMultiMap<QString, QString> &AParams) const { if (AContactJid.isValid() && !AAction.isEmpty()) { QUrl url; url.setQueryDelimiters('=',';'); url.setScheme(XMPP_URI_SCHEME); url.setPath(AContactJid.full()); QList< QPair<QString, QString> > query; query.append(qMakePair<QString,QString>(AAction,QString::null)); for(QMultiMap<QString, QString>::const_iterator it=AParams.constBegin(); it!=AParams.end(); ++it) query.append(qMakePair<QString,QString>(it.key(),it.value())); url.setQueryItems(query); return url.toString().replace(QString("?%1=;").arg(AAction),QString("?%1;").arg(AAction)); } return QString::null; }
Stanza::Stanza(Stream *s, Kind k, const Jid &to, const QString &type, const QString &id) { Q_ASSERT(s); d = new Private; Kind kind; if(k == Message || k == Presence || k == IQ) kind = k; else kind = Message; d->s = s; if(d->s) d->e = d->s->doc().createElementNS(s->baseNS(), Private::kindToString(kind)); if(to.isValid()) setTo(to); if(!type.isEmpty()) setType(type); if(!id.isEmpty()) setId(id); }
bool XmppUriQueries::parseXmppUri(const QUrl &AUrl, Jid &AContactJid, QString &AAction, QMultiMap<QString, QString> &AParams) const { if (AUrl.isValid() && AUrl.scheme()==XMPP_URI_SCHEME) { QUrl url = QUrl::fromEncoded(AUrl.toEncoded().replace(';','&'), QUrl::StrictMode); QList< QPair<QString, QString> > keyValues = url.queryItems(); if (!keyValues.isEmpty()) { AContactJid = url.path(); AAction = keyValues.takeAt(0).first; if (AContactJid.isValid() && !AAction.isEmpty()) { for (int i=0; i<keyValues.count(); i++) AParams.insertMulti(keyValues.at(i).first, keyValues.at(i).second); return true; } } } return false; }
bool XmppUriQueries::openXmppUri(const Jid &AStreamJid, const QUrl &AUrl) const { if (AUrl.isValid() && AUrl.scheme()=="xmpp") { QUrl url = QUrl::fromEncoded(AUrl.toEncoded().replace(';','&'), QUrl::StrictMode); Jid contactJid = url.path(); QList< QPair<QString, QString> > keyValues = url.queryItems(); if (keyValues.count() > 0) { QString action = keyValues.takeAt(0).first; if (contactJid.isValid() && !action.isEmpty()) { QMultiMap<QString, QString> params; for (int i=0; i<keyValues.count(); i++) params.insertMulti(keyValues.at(i).first, keyValues.at(i).second); LOG_STRM_INFO(AStreamJid,QString("Opening XMPP URI, url=%1").arg(AUrl.toString())); foreach (IXmppUriHandler *handler, FHandlers) { if (handler->xmppUriOpen(AStreamJid, contactJid, action, params)) return true; } }
void FileTransferHandler::send(const XMPP::Jid &to, const QString &fname, const QString &desc) { if(!d->sending) return; d->peer = to; QFileInfo fi(fname); d->filePath = fname; d->fileName = fi.fileName(); d->fileSize = fi.size(); // TODO: large file support d->desc = desc; d->shift = calcShift(d->fileSize); d->complement = calcComplement(d->fileSize, d->shift); d->ft = d->pa->client()->fileTransferManager()->createTransfer(); Jid proxy = d->pa->userAccount().dtProxy; if(proxy.isValid()) d->ft->setProxy(proxy); mapSignals(); d->f.setFileName(fname); d->ft->sendFile(d->peer, d->fileName, d->fileSize, desc); }
void FileTransferHandler::send(const XMPP::Jid &to, const QString &fname, const QString &desc) { if(!d->sending) return; d->peer = to; QFileInfo fi(fname); d->filePath = fname; d->fileName = fi.fileName(); d->fileSize = fi.size(); // TODO: large file support d->desc = desc; d->shift = calcShift(d->fileSize); d->complement = calcComplement(d->fileSize, d->shift); d->ft = d->pa->client()->fileTransferManager()->createTransfer(); Jid proxy = d->pa->userAccount().dtProxy; if(proxy.isValid()) d->ft->setProxy(proxy); mapSignals(); d->f.setFileName(fname); // try to make thumbnail QImage img(fname); XMPP::FTThumbnail thumb; if (!img.isNull()) { QByteArray ba; QBuffer buffer(&ba); buffer.open(QIODevice::WriteOnly); img = img.scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation); img.save(&buffer, "PNG"); thumb = XMPP::FTThumbnail(ba, "image/png", img.width(), img.height()); } d->ft->sendFile(d->peer, d->fileName, d->fileSize, desc, thumb); }
bool CoreProtocol::normalStep(const QDomElement &e) { if(step == Start) { if(isIncoming()) { need = NSASLMechs; step = SendFeatures; return false; } else { if(old) { if(doAuth) step = HandleAuthGet; else return loginComplete(); } else step = GetFeatures; return processStep(); } } else if(step == HandleFeatures) { // deal with TLS? if(doTLS && !tls_started && !sasl_authed && features.tls_supported) { QDomElement e = doc.createElementNS(NS_TLS, "starttls"); send(e, true); event = ESend; step = GetTLSProceed; return true; } // Should we go further ? if (!doAuth) return loginComplete(); // Deal with compression if (doCompress && !compress_started && features.compress_supported && features.compression_mechs.contains("zlib")) { QDomElement e = doc.createElementNS(NS_COMPRESS_PROTOCOL, "compress"); QDomElement m = doc.createElementNS(NS_COMPRESS_PROTOCOL, "method"); m.appendChild(doc.createTextNode("zlib")); e.appendChild(m); send(e,true); event = ESend; step = GetCompressProceed; return true; } // deal with SASL? if(!sasl_authed) { if(!features.sasl_supported) { // SASL MUST be supported //event = EError; //errorCode = ErrProtocol; //return true; // Fall back on auth for non-compliant servers step = HandleAuthGet; old = true; return true; } #ifdef XMPP_TEST TD::msg("starting SASL authentication..."); #endif need = NSASLFirst; step = GetSASLFirst; return false; } if(server) { return loginComplete(); } else { if(!doBinding) return loginComplete(); } // deal with bind if(!features.bind_supported) { // bind MUST be supported event = EError; errorCode = ErrProtocol; return true; } QDomElement e = doc.createElement("iq"); e.setAttribute("type", "set"); e.setAttribute("id", "bind_1"); QDomElement b = doc.createElementNS(NS_BIND, "bind"); // request specific resource? QString resource = jid_.resource(); if(!resource.isEmpty()) { QDomElement r = doc.createElement("resource"); r.appendChild(doc.createTextNode(jid_.resource())); b.appendChild(r); } e.appendChild(b); send(e); event = ESend; step = GetBindResponse; return true; } else if(step == GetSASLFirst) { QDomElement e = doc.createElementNS(NS_SASL, "auth"); e.setAttribute("mechanism", sasl_mech); if(!sasl_step.isEmpty()) { #ifdef XMPP_TEST TD::msg(QString("SASL OUT: [%1]").arg(printArray(sasl_step))); #endif e.appendChild(doc.createTextNode(QCA::Base64().arrayToString(sasl_step))); } send(e, true); event = ESend; step = GetSASLChallenge; return true; } else if(step == GetSASLNext) { if(isIncoming()) { if(sasl_authed) { QDomElement e = doc.createElementNS(NS_SASL, "success"); writeElement(e, TypeElement, false, true); event = ESend; step = IncHandleSASLSuccess; return true; } else { QByteArray stepData = sasl_step; QDomElement e = doc.createElementNS(NS_SASL, "challenge"); if(!stepData.isEmpty()) e.appendChild(doc.createTextNode(QCA::Base64().arrayToString(stepData))); writeElement(e, TypeElement, false, true); event = ESend; step = GetSASLResponse; return true; } } else { // already authed? then ignore last client step // (this happens if "additional data with success" // is used) if(sasl_authed) { event = ESASLSuccess; step = HandleSASLSuccess; return true; } QByteArray stepData = sasl_step; #ifdef XMPP_TEST TD::msg(QString("SASL OUT: [%1]").arg(printArray(sasl_step))); #endif QDomElement e = doc.createElementNS(NS_SASL, "response"); if(!stepData.isEmpty()) e.appendChild(doc.createTextNode(QCA::Base64().arrayToString(stepData))); send(e, true); event = ESend; step = GetSASLChallenge; return true; } } else if(step == HandleSASLSuccess) { need = NSASLLayer; spare = resetStream(); step = Start; return false; } else if(step == HandleAuthGet) { QDomElement e = doc.createElement("iq"); e.setAttribute("to", to); e.setAttribute("type", "get"); e.setAttribute("id", "auth_1"); QDomElement q = doc.createElementNS("jabber:iq:auth", "query"); QDomElement u = doc.createElement("username"); u.appendChild(doc.createTextNode(jid_.node())); q.appendChild(u); e.appendChild(q); send(e); event = ESend; step = GetAuthGetResponse; return true; } else if(step == HandleAuthSet) { QDomElement e = doc.createElement("iq"); e.setAttribute("to", to); e.setAttribute("type", "set"); e.setAttribute("id", "auth_2"); QDomElement q = doc.createElementNS("jabber:iq:auth", "query"); QDomElement u = doc.createElement("username"); u.appendChild(doc.createTextNode(jid_.node())); q.appendChild(u); QDomElement p; if(digest) { // need SHA1 here //if(!QCA::isSupported(QCA::CAP_SHA1)) // QCA::insertProvider(createProviderHash()); p = doc.createElement("digest"); Q3CString cs = id.utf8() + password.utf8(); p.appendChild(doc.createTextNode(QCA::Hash("sha1").hashToString(cs))); } else { p = doc.createElement("password"); p.appendChild(doc.createTextNode(password)); } q.appendChild(p); QDomElement r = doc.createElement("resource"); r.appendChild(doc.createTextNode(jid_.resource())); q.appendChild(r); e.appendChild(q); send(e, true); event = ESend; step = GetAuthSetResponse; return true; } // server else if(step == SendFeatures) { QDomElement f = doc.createElementNS(NS_ETHERX, "stream:features"); if(!tls_started && !sasl_authed) { // don't offer tls if we are already sasl'd QDomElement tls = doc.createElementNS(NS_TLS, "starttls"); f.appendChild(tls); } if(sasl_authed) { if(!server) { QDomElement bind = doc.createElementNS(NS_BIND, "bind"); f.appendChild(bind); } } else { QDomElement mechs = doc.createElementNS(NS_SASL, "mechanisms"); for(QStringList::ConstIterator it = sasl_mechlist.begin(); it != sasl_mechlist.end(); ++it) { QDomElement m = doc.createElement("mechanism"); m.appendChild(doc.createTextNode(*it)); mechs.appendChild(m); } f.appendChild(mechs); } writeElement(f, TypeElement, false); event = ESend; step = GetRequest; return true; } // server else if(step == HandleTLS) { tls_started = true; need = NStartTLS; spare = resetStream(); step = Start; return false; } // server else if(step == IncHandleSASLSuccess) { event = ESASLSuccess; spare = resetStream(); step = Start; printf("sasl success\n"); return true; } else if(step == GetFeatures) { // we are waiting for stream features if(e.namespaceURI() == NS_ETHERX && e.tagName() == "features") { // extract features StreamFeatures f; QDomElement s = e.elementsByTagNameNS(NS_TLS, "starttls").item(0).toElement(); if(!s.isNull()) { f.tls_supported = true; f.tls_required = s.elementsByTagNameNS(NS_TLS, "required").count() > 0; } QDomElement m = e.elementsByTagNameNS(NS_SASL, "mechanisms").item(0).toElement(); if(!m.isNull()) { f.sasl_supported = true; QDomNodeList l = m.elementsByTagNameNS(NS_SASL, "mechanism"); for(int n = 0; n < l.count(); ++n) f.sasl_mechs += l.item(n).toElement().text(); } QDomElement c = e.elementsByTagNameNS(NS_COMPRESS_FEATURE, "compression").item(0).toElement(); if(!c.isNull()) { f.compress_supported = true; QDomNodeList l = c.elementsByTagNameNS(NS_COMPRESS_FEATURE, "method"); for(int n = 0; n < l.count(); ++n) f.compression_mechs += l.item(n).toElement().text(); } QDomElement b = e.elementsByTagNameNS(NS_BIND, "bind").item(0).toElement(); if(!b.isNull()) f.bind_supported = true; if(f.tls_supported) { #ifdef XMPP_TEST QString s = "STARTTLS is available"; if(f.tls_required) s += " (required)"; TD::msg(s); #endif } if(f.sasl_supported) { #ifdef XMPP_TEST QString s = "SASL mechs:"; for(QStringList::ConstIterator it = f.sasl_mechs.begin(); it != f.sasl_mechs.end(); ++it) s += QString(" [%1]").arg((*it)); TD::msg(s); #endif } if(f.compress_supported) { #ifdef XMPP_TEST QString s = "Compression mechs:"; for(QStringList::ConstIterator it = f.compression_mechs.begin(); it != f.compression_mechs.end(); ++it) s += QString(" [%1]").arg((*it)); TD::msg(s); #endif } event = EFeatures; features = f; step = HandleFeatures; return true; } else { // ignore } } else if(step == GetTLSProceed) { // waiting for proceed to starttls if(e.namespaceURI() == NS_TLS) { if(e.tagName() == "proceed") { #ifdef XMPP_TEST TD::msg("Server wants us to proceed with ssl handshake"); #endif tls_started = true; need = NStartTLS; spare = resetStream(); step = Start; return false; } else if(e.tagName() == "failure") { event = EError; errorCode = ErrStartTLS; return true; } else { event = EError; errorCode = ErrProtocol; return true; } } else { // ignore } } else if(step == GetCompressProceed) { // waiting for proceed to compression if(e.namespaceURI() == NS_COMPRESS_PROTOCOL) { if(e.tagName() == "compressed") { #ifdef XMPP_TEST TD::msg("Server wants us to proceed with compression"); #endif compress_started = true; need = NCompress; spare = resetStream(); step = Start; return false; } else if(e.tagName() == "failure") { event = EError; errorCode = ErrCompress; return true; } else { event = EError; errorCode = ErrProtocol; return true; } } else { // ignore } } else if(step == GetSASLChallenge) { // waiting for sasl challenge/success/fail if(e.namespaceURI() == NS_SASL) { if(e.tagName() == "challenge") { QByteArray a = QCA::Base64().stringToArray(e.text()).toByteArray(); #ifdef XMPP_TEST TD::msg(QString("SASL IN: [%1]").arg(printArray(a))); #endif sasl_step = a; need = NSASLNext; step = GetSASLNext; return false; } else if(e.tagName() == "success") { QString str = e.text(); // "additional data with success" ? if(!str.isEmpty()) { QByteArray a = QCA::Base64().stringToArray(str).toByteArray(); sasl_step = a; sasl_authed = true; need = NSASLNext; step = GetSASLNext; return false; } sasl_authed = true; event = ESASLSuccess; step = HandleSASLSuccess; return true; } else if(e.tagName() == "failure") { QDomElement t = firstChildElement(e); if(t.isNull() || t.namespaceURI() != NS_SASL) errCond = -1; else errCond = stringToSASLCond(t.tagName()); event = EError; errorCode = ErrAuth; return true; } else { event = EError; errorCode = ErrProtocol; return true; } } } else if(step == GetBindResponse) { if(e.namespaceURI() == NS_CLIENT && e.tagName() == "iq") { QString type(e.attribute("type")); QString id(e.attribute("id")); if(id == "bind_1" && (type == "result" || type == "error")) { if(type == "result") { QDomElement b = e.elementsByTagNameNS(NS_BIND, "bind").item(0).toElement(); Jid j; if(!b.isNull()) { QDomElement je = e.elementsByTagName("jid").item(0).toElement(); j = je.text(); } if(!j.isValid()) { event = EError; errorCode = ErrProtocol; return true; } jid_ = j; return loginComplete(); } else { errCond = -1; QDomElement err = e.elementsByTagNameNS(NS_CLIENT, "error").item(0).toElement(); if(!err.isNull()) { // get error condition QDomNodeList nl = err.childNodes(); QDomElement t; for(int n = 0; n < nl.count(); ++n) { QDomNode i = nl.item(n); if(i.isElement()) { t = i.toElement(); break; } } if(!t.isNull() && t.namespaceURI() == NS_STANZAS) { QString cond = t.tagName(); if(cond == "not-allowed") errCond = BindNotAllowed; else if(cond == "conflict") errCond = BindConflict; } } event = EError; errorCode = ErrBind; return true; } } else { // ignore } } else { // ignore } } else if(step == GetAuthGetResponse) { // waiting for an iq if(e.namespaceURI() == NS_CLIENT && e.tagName() == "iq") { Jid from(e.attribute("from")); QString type(e.attribute("type")); QString id(e.attribute("id")); bool okfrom = (from.isEmpty() || from.compare(Jid(to))); if(okfrom && id == "auth_1" && (type == "result" || type == "error")) { if(type == "result") { QDomElement q = e.elementsByTagNameNS("jabber:iq:auth", "query").item(0).toElement(); if(q.isNull() || q.elementsByTagName("username").item(0).isNull() || q.elementsByTagName("resource").item(0).isNull()) { event = EError; errorCode = ErrProtocol; return true; } bool plain_supported = !q.elementsByTagName("password").item(0).isNull(); bool digest_supported = !q.elementsByTagName("digest").item(0).isNull(); if(!digest_supported && !plain_supported) { event = EError; errorCode = ErrProtocol; return true; } // plain text not allowed? if(!digest_supported && !allowPlain) { event = EError; errorCode = ErrPlain; return true; } digest = digest_supported; need = NPassword; step = HandleAuthSet; return false; } else { errCond = getOldErrorCode(e); event = EError; errorCode = ErrAuth; return true; } } else { // ignore } } else { // ignore } } else if(step == GetAuthSetResponse) { // waiting for an iq if(e.namespaceURI() == NS_CLIENT && e.tagName() == "iq") { Jid from(e.attribute("from")); QString type(e.attribute("type")); QString id(e.attribute("id")); bool okfrom = (from.isEmpty() || from.compare(Jid(to))); if(okfrom && id == "auth_2" && (type == "result" || type == "error")) { if(type == "result") { return loginComplete(); } else { errCond = getOldErrorCode(e); event = EError; errorCode = ErrAuth; return true; } } else { // ignore } } else { // ignore } } // server else if(step == GetRequest) { printf("get request: [%s], %s\n", e.namespaceURI().latin1(), e.tagName().latin1()); if(e.namespaceURI() == NS_TLS && e.localName() == "starttls") { // TODO: don't let this be done twice QDomElement e = doc.createElementNS(NS_TLS, "proceed"); writeElement(e, TypeElement, false, true); event = ESend; step = HandleTLS; return true; } if(e.namespaceURI() == NS_SASL) { if(e.localName() == "auth") { if(sasl_started) { // TODO printf("error\n"); return false; } sasl_started = true; sasl_mech = e.attribute("mechanism"); // TODO: if child text missing, don't pass it sasl_step = QCA::Base64().stringToArray(e.text()).toByteArray(); need = NSASLFirst; step = GetSASLNext; return false; } else { // TODO printf("unknown sasl tag\n"); return false; } } if(e.namespaceURI() == NS_CLIENT && e.tagName() == "iq") { QDomElement b = e.elementsByTagNameNS(NS_BIND, "bind").item(0).toElement(); if(!b.isNull()) { QDomElement res = b.elementsByTagName("resource").item(0).toElement(); QString resource = res.text(); QDomElement r = doc.createElement("iq"); r.setAttribute("type", "result"); r.setAttribute("id", e.attribute("id")); QDomElement bind = doc.createElementNS(NS_BIND, "bind"); QDomElement jid = doc.createElement("jid"); Jid j = user + '@' + host + '/' + resource; jid.appendChild(doc.createTextNode(j.full())); bind.appendChild(jid); r.appendChild(bind); writeElement(r, TypeElement, false); event = ESend; // TODO return true; } else { // TODO } } } else if(step == GetSASLResponse) { if(e.namespaceURI() == NS_SASL && e.localName() == "response") { sasl_step = QCA::Base64().stringToArray(e.text()).toByteArray(); need = NSASLNext; step = GetSASLNext; return false; } } if(isReady()) { if(!e.isNull() && isValidStanza(e)) { stanzaToRecv = e; event = EStanzaReady; setIncomingAsExternal(); return true; } } need = NNotify; notify |= NRecv; return false; }