File indexing completed on 2024-06-23 04:03:33
0001 /* 0002 * jid.cpp - class for verifying and manipulating Jabber IDs 0003 * Copyright (C) 2003 Justin Karneges 0004 * 0005 * This library is free software; you can redistribute it and/or 0006 * modify it under the terms of the GNU Lesser General Public 0007 * License as published by the Free Software Foundation; either 0008 * either version 2 0009 of the License, or (at your option) any later version.1 of the License, or (at your option) any later version. 0010 * 0011 * This library is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0014 * Lesser General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU Lesser General Public 0017 * License along with this library; if not, write to the Free Software 0018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 0019 * 0020 */ 0021 0022 #undef IRIS_XMPP_JID_DEPRECATED 0023 #include "xmpp/jid/jid.h" 0024 0025 #include <QCoreApplication> 0026 #include <QByteArray> 0027 #include <QHash> 0028 #include <libidn/stringprep.h> 0029 0030 using namespace XMPP; 0031 0032 0033 //---------------------------------------------------------------------------- 0034 // StringPrepCache 0035 //---------------------------------------------------------------------------- 0036 class StringPrepCache : public QObject 0037 { 0038 public: 0039 static bool nameprep(const QString &in, int maxbytes, QString& out) 0040 { 0041 if (in.isEmpty()) { 0042 out = QString(); 0043 return true; 0044 } 0045 0046 StringPrepCache *that = get_instance(); 0047 0048 Result *r = that->nameprep_table[in]; 0049 if (r) { 0050 if(!r->norm) { 0051 return false; 0052 } 0053 out = *(r->norm); 0054 return true; 0055 } 0056 0057 QByteArray cs = in.toUtf8(); 0058 cs.resize(maxbytes); 0059 if(stringprep(cs.data(), maxbytes, (Stringprep_profile_flags)0, stringprep_nameprep) != 0) 0060 { 0061 that->nameprep_table.insert(in, new Result); 0062 return false; 0063 } 0064 0065 QString norm = QString::fromUtf8(cs); 0066 that->nameprep_table.insert(in, new Result(norm)); 0067 out = norm; 0068 return true; 0069 } 0070 0071 static bool nodeprep(const QString &in, int maxbytes, QString& out) 0072 { 0073 if(in.isEmpty()) { 0074 out = QString(); 0075 return true; 0076 } 0077 0078 StringPrepCache *that = get_instance(); 0079 0080 Result *r = that->nodeprep_table[in]; 0081 if(r) { 0082 if(!r->norm) { 0083 return false; 0084 } 0085 out = *(r->norm); 0086 return true; 0087 } 0088 0089 QByteArray cs = in.toUtf8(); 0090 cs.resize(maxbytes); 0091 if(stringprep(cs.data(), maxbytes, (Stringprep_profile_flags)0, stringprep_xmpp_nodeprep) != 0) { 0092 that->nodeprep_table.insert(in, new Result); 0093 return false; 0094 } 0095 0096 QString norm = QString::fromUtf8(cs); 0097 that->nodeprep_table.insert(in, new Result(norm)); 0098 out = norm; 0099 return true; 0100 } 0101 0102 static bool resourceprep(const QString &in, int maxbytes, QString& out) 0103 { 0104 if(in.isEmpty()) { 0105 out = QString(); 0106 return true; 0107 } 0108 0109 StringPrepCache *that = get_instance(); 0110 0111 Result *r = that->resourceprep_table[in]; 0112 if(r) { 0113 if(!r->norm) { 0114 return false; 0115 } 0116 out = *(r->norm); 0117 return true; 0118 } 0119 0120 QByteArray cs = in.toUtf8(); 0121 cs.resize(maxbytes); 0122 if(stringprep(cs.data(), maxbytes, (Stringprep_profile_flags)0, stringprep_xmpp_resourceprep) != 0) { 0123 that->resourceprep_table.insert(in, new Result); 0124 return false; 0125 } 0126 0127 QString norm = QString::fromUtf8(cs); 0128 that->resourceprep_table.insert(in, new Result(norm)); 0129 out = norm; 0130 return true; 0131 } 0132 0133 private: 0134 class Result 0135 { 0136 public: 0137 QString *norm; 0138 0139 Result() : norm(0) 0140 { 0141 } 0142 0143 Result(const QString &s) : norm(new QString(s)) 0144 { 0145 } 0146 0147 ~Result() 0148 { 0149 delete norm; 0150 } 0151 }; 0152 0153 QHash<QString,Result*> nameprep_table; 0154 QHash<QString,Result*> nodeprep_table; 0155 QHash<QString,Result*> resourceprep_table; 0156 0157 static StringPrepCache *instance; 0158 0159 static StringPrepCache *get_instance() 0160 { 0161 if(!instance) 0162 instance = new StringPrepCache; 0163 return instance; 0164 } 0165 0166 StringPrepCache() 0167 : QObject(QCoreApplication::instance()) 0168 { 0169 } 0170 0171 ~StringPrepCache() override 0172 { 0173 foreach(Result* r, nameprep_table) { 0174 delete r; 0175 } 0176 nameprep_table.clear(); 0177 foreach(Result* r, nodeprep_table) { 0178 delete r; 0179 } 0180 nodeprep_table.clear(); 0181 foreach(Result* r, resourceprep_table) { 0182 delete r; 0183 } 0184 resourceprep_table.clear(); 0185 } 0186 }; 0187 0188 StringPrepCache *StringPrepCache::instance = 0; 0189 0190 //---------------------------------------------------------------------------- 0191 // Jid 0192 //---------------------------------------------------------------------------- 0193 // 0194 static inline bool validDomain(const QString &s, QString& norm) 0195 { 0196 return StringPrepCache::nameprep(s, 1024, norm); 0197 } 0198 0199 static inline bool validNode(const QString &s, QString& norm) 0200 { 0201 return StringPrepCache::nodeprep(s, 1024, norm); 0202 } 0203 0204 static inline bool validResource(const QString &s, QString& norm) 0205 { 0206 return StringPrepCache::resourceprep(s, 1024, norm); 0207 } 0208 0209 Jid::Jid() 0210 { 0211 valid = false; 0212 null = true; 0213 } 0214 0215 Jid::~Jid() 0216 { 0217 } 0218 0219 Jid::Jid(const QString &s) 0220 { 0221 set(s); 0222 } 0223 0224 Jid::Jid(const QString &node, const QString& domain, const QString& resource) 0225 { 0226 set(domain, node, resource); 0227 } 0228 0229 Jid::Jid(const char *s) 0230 { 0231 set(QString(s)); 0232 } 0233 0234 Jid & Jid::operator=(const QString &s) 0235 { 0236 set(s); 0237 return *this; 0238 } 0239 0240 Jid & Jid::operator=(const char *s) 0241 { 0242 set(QString(s)); 0243 return *this; 0244 } 0245 0246 void Jid::reset() 0247 { 0248 f = QString(); 0249 b = QString(); 0250 d = QString(); 0251 n = QString(); 0252 r = QString(); 0253 valid = false; 0254 null = true; 0255 } 0256 0257 void Jid::update() 0258 { 0259 // build 'bare' and 'full' jids 0260 if(n.isEmpty()) 0261 b = d; 0262 else 0263 b = n + '@' + d; 0264 if(r.isEmpty()) 0265 f = b; 0266 else 0267 f = b + '/' + r; 0268 if(f.isEmpty()) 0269 valid = false; 0270 null = f.isEmpty() && r.isEmpty(); 0271 } 0272 0273 void Jid::set(const QString &s) 0274 { 0275 QString rest, domain, node, resource; 0276 QString norm_domain, norm_node, norm_resource; 0277 int x = s.indexOf('/'); 0278 if(x != -1) { 0279 rest = s.mid(0, x); 0280 resource = s.mid(x+1); 0281 } 0282 else { 0283 rest = s; 0284 resource = QString(); 0285 } 0286 if(!validResource(resource, norm_resource)) { 0287 reset(); 0288 return; 0289 } 0290 0291 x = rest.indexOf('@'); 0292 if(x != -1) { 0293 node = rest.mid(0, x); 0294 domain = rest.mid(x+1); 0295 } 0296 else { 0297 node = QString(); 0298 domain = rest; 0299 } 0300 if(!validDomain(domain, norm_domain) || !validNode(node, norm_node)) { 0301 reset(); 0302 return; 0303 } 0304 0305 valid = true; 0306 null = false; 0307 d = norm_domain; 0308 n = norm_node; 0309 r = norm_resource; 0310 update(); 0311 } 0312 0313 void Jid::set(const QString &domain, const QString &node, const QString &resource) 0314 { 0315 QString norm_domain, norm_node, norm_resource; 0316 if(!validDomain(domain, norm_domain) || !validNode(node, norm_node) || !validResource(resource, norm_resource)) { 0317 reset(); 0318 return; 0319 } 0320 valid = true; 0321 null = false; 0322 d = norm_domain; 0323 n = norm_node; 0324 r = norm_resource; 0325 update(); 0326 } 0327 0328 void Jid::setDomain(const QString &s) 0329 { 0330 if(!valid) 0331 return; 0332 QString norm; 0333 if(!validDomain(s, norm)) { 0334 reset(); 0335 return; 0336 } 0337 d = norm; 0338 update(); 0339 } 0340 0341 void Jid::setNode(const QString &s) 0342 { 0343 if(!valid) 0344 return; 0345 QString norm; 0346 if(!validNode(s, norm)) { 0347 reset(); 0348 return; 0349 } 0350 n = norm; 0351 update(); 0352 } 0353 0354 void Jid::setResource(const QString &s) 0355 { 0356 if(!valid) 0357 return; 0358 QString norm; 0359 if(!validResource(s, norm)) { 0360 reset(); 0361 return; 0362 } 0363 r = norm; 0364 update(); 0365 } 0366 0367 Jid Jid::withNode(const QString &s) const 0368 { 0369 Jid j = *this; 0370 j.setNode(s); 0371 return j; 0372 } 0373 0374 Jid Jid::withResource(const QString &s) const 0375 { 0376 Jid j = *this; 0377 j.setResource(s); 0378 return j; 0379 } 0380 0381 bool Jid::isValid() const 0382 { 0383 return valid; 0384 } 0385 0386 bool Jid::isEmpty() const 0387 { 0388 return f.isEmpty(); 0389 } 0390 0391 bool Jid::compare(const Jid &a, bool compareRes) const 0392 { 0393 if(null && a.null) 0394 return true; 0395 0396 // only compare valid jids 0397 if(!valid || !a.valid) 0398 return false; 0399 0400 if(compareRes ? (f != a.f) : (b != a.b)) 0401 return false; 0402 0403 return true; 0404 }