1 /*
2  * Copyright (C) 2017  Sergey Ilinykh
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301  USA
18  *
19  */
20 
21 #include "irisnetplugin.h"
22 
23 #include <QNetworkInterface>
24 
25 namespace XMPP {
26 
27 class IrisQtName : public NameProvider
28 {
29 	Q_OBJECT
30 	Q_INTERFACES(XMPP::NameProvider)
31 
32 	int currentId;
33 	QHash<int,QDnsLookup*> lookups;
34 
35 public:
IrisQtName(QObject * parent=0)36 	IrisQtName(QObject *parent = 0) :
37 	    NameProvider(parent),
38 	    currentId(0)
39 	{
40 
41 	}
42 
~IrisQtName()43 	~IrisQtName()
44 	{
45 		qDeleteAll(lookups);
46 	}
47 
supportsSingle() const48 	bool supportsSingle() const
49 	{
50 		return true;
51 	}
52 
supportsRecordType(int type) const53 	bool supportsRecordType(int type) const
54 	{
55 		// yes the types matched to ones from jdns, so it's fine.
56 		static QVector<int> types = {
57 		    QDnsLookup::A, QDnsLookup::AAAA, QDnsLookup::ANY,
58 		    QDnsLookup::CNAME, QDnsLookup::MX, QDnsLookup::NS,
59 		    QDnsLookup::PTR, QDnsLookup::SRV, QDnsLookup::TXT};
60 		return types.contains(type);
61 	}
62 
resolve_start(const QByteArray & name,int qType,bool longLived)63 	int resolve_start(const QByteArray &name, int qType, bool longLived)
64 	{
65 		Q_UNUSED(longLived); // FIXME handle local like in jdns name provider
66         int id = currentId++;
67 
68         // check if it's A/AAAA. QDnsLookup fails to handle this in some cases.
69         QHostAddress addr(QString::fromLatin1(name));
70         if (!addr.isNull()) {
71             QList<XMPP::NameRecord> results;
72             XMPP::NameRecord r;
73             r.setAddress(addr);
74             results.append(r);
75             QMetaObject::invokeMethod(this, "resolve_resultsReady", Qt::QueuedConnection,
76                                       Q_ARG(int, id), Q_ARG(QList<XMPP::NameRecord>, results));
77         } else {
78             QDnsLookup *lookup = new QDnsLookup((QDnsLookup::Type)qType, QString::fromLatin1(name), this);
79             connect(lookup, SIGNAL(finished()), this, SLOT(handleLookup()));
80             lookup->setProperty("iid", id);
81             lookups.insert(id, lookup);
82             QMetaObject::invokeMethod(lookup, "lookup", Qt::QueuedConnection);
83         }
84 		return id;
85 	}
86 
resolve_stop(int id)87 	void resolve_stop(int id)
88 	{
89 		QDnsLookup *lookup = lookups.value(id);
90 		if (lookup) {
91 			lookup->abort(); // handleLookup will catch it and delete
92 		}
93 	}
94 
95 private slots:
handleLookup()96 	void handleLookup()
97 	{
98 		QDnsLookup *lookup = static_cast<QDnsLookup *>(sender());
99 		int id = lookup->property("iid").toInt();
100 		lookups.remove(id);
101 		if (lookup->error() != QDnsLookup::NoError) {
102 			XMPP::NameResolver::Error e;
103 			switch (lookup->error()) {
104 				case QDnsLookup::InvalidReplyError:
105 					e = XMPP::NameResolver::ErrorTimeout;
106 					break;
107 				case QDnsLookup::NotFoundError:
108 					e = XMPP::NameResolver::ErrorNoName;
109 					break;
110 				case QDnsLookup::ResolverError:
111 				case QDnsLookup::OperationCancelledError:
112 				case QDnsLookup::InvalidRequestError:
113 				case QDnsLookup::ServerFailureError:
114 				case QDnsLookup::ServerRefusedError:
115 				default:
116 					e = XMPP::NameResolver::ErrorGeneric;
117 					break;
118 			}
119 			if (lookup->error() != QDnsLookup::OperationCancelledError) { // don't report after resolve_stop()
120 				emit resolve_error(id, e);
121 			}
122 			lookup->deleteLater();
123 			return;
124 		}
125 
126 		QList<XMPP::NameRecord> results;
127 		for (auto &qtr: lookup->hostAddressRecords()) {
128 			XMPP::NameRecord ir(qtr.name().toLatin1(), qtr.timeToLive());
129 			ir.setAddress(qtr.value());
130 			results += ir;
131 		}
132 		for (auto &qtr: lookup->mailExchangeRecords()) {
133 			XMPP::NameRecord ir(qtr.name().toLatin1(), qtr.timeToLive());
134 			ir.setMx(qtr.exchange().toLatin1(), qtr.preference());
135 			results += ir;
136 		}
137 		for (auto &qtr: lookup->nameServerRecords()) {
138 			XMPP::NameRecord ir(qtr.name().toLatin1(), qtr.timeToLive());
139 			ir.setNs(qtr.value().toLatin1());
140 			results += ir;
141 		}
142 		for (auto &qtr: lookup->pointerRecords()) {
143 			XMPP::NameRecord ir(qtr.name().toLatin1(), qtr.timeToLive());
144 			ir.setPtr(qtr.value().toLatin1());
145 			results += ir;
146 		}
147 		for (auto &qtr: lookup->canonicalNameRecords()) {
148 			XMPP::NameRecord ir(qtr.name().toLatin1(), qtr.timeToLive());
149 			ir.setCname(qtr.value().toLatin1());
150 			results += ir;
151 		}
152 		for (auto &qtr: lookup->serviceRecords()) {
153 			XMPP::NameRecord ir(qtr.name().toLatin1(), qtr.timeToLive());
154 			ir.setSrv(qtr.target().toLatin1(),qtr.port(),qtr.priority(),qtr.weight());
155 			results += ir;
156 		}
157 		for (auto &qtr: lookup->textRecords()) {
158 			XMPP::NameRecord ir(qtr.name().toLatin1(), qtr.timeToLive());
159 			ir.setTxt(qtr.values());
160 			results += ir;
161 		}
162 		lookup->deleteLater();
163 		emit resolve_resultsReady(id, results);
164 	}
165 };
166 
167 class IrisQtNameProvider : public IrisNetProvider
168 {
169 	Q_OBJECT
170 	Q_INTERFACES(XMPP::IrisNetProvider)
171 public:
172 
createNameProviderInternet()173 	NameProvider *createNameProviderInternet()
174 	{
175 		return new IrisQtName;
176 	}
177 };
178 
irisnet_createQtNameProvider()179 IrisNetProvider *irisnet_createQtNameProvider()
180 {
181 	return new IrisQtNameProvider;
182 }
183 
184 }
185 
186 #include "netinterface_qtname.moc"
187