kdecore Library API Documentation

kresolver.cpp

00001 /* -*- C++ -*- 00002 * Copyright (C) 2003 Thiago Macieira <thiago.macieira@kdemail.net> 00003 * 00004 * 00005 * Permission is hereby granted, free of charge, to any person obtaining 00006 * a copy of this software and associated documentation files (the 00007 * "Software"), to deal in the Software without restriction, including 00008 * without limitation the rights to use, copy, modify, merge, publish, 00009 * distribute, sublicense, and/or sell copies of the Software, and to 00010 * permit persons to whom the Software is furnished to do so, subject to 00011 * the following conditions: 00012 * 00013 * The above copyright notice and this permission notice shall be included 00014 * in all copies or substantial portions of the Software. 00015 * 00016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 00017 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00018 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00019 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 00020 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 00021 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 00022 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00023 */ 00024 00025 #include "config.h" 00026 00027 // System includes 00028 #include <sys/types.h> 00029 #include <sys/socket.h> 00030 #include <errno.h> 00031 #include <netdb.h> 00032 #include <time.h> 00033 #include <arpa/inet.h> 00034 #include <netinet/in.h> 00035 00036 // Qt includes 00037 #include <qapplication.h> 00038 #include <qstring.h> 00039 #include <qcstring.h> 00040 #include <qstrlist.h> 00041 #include <qstringlist.h> 00042 #include <qshared.h> 00043 #include <qdatetime.h> 00044 #include <qtimer.h> 00045 #include <qmutex.h> 00046 #include <qguardedptr.h> 00047 00048 // IDN 00049 #ifdef HAVE_IDNA_H 00050 # include <idna.h> 00051 #endif 00052 00053 // KDE 00054 #include <klocale.h> 00055 00056 // Us 00057 #include "kresolver.h" 00058 #include "kresolver_p.h" 00059 #include "ksocketaddress.h" 00060 00061 using namespace KNetwork; 00062 using namespace KNetwork::Internal; 00063 00065 // class KResolverEntry 00066 00067 class KNetwork::KResolverEntryPrivate: public QShared 00068 { 00069 public: 00070 KSocketAddress addr; 00071 int socktype; 00072 int protocol; 00073 QString canonName; 00074 QCString encodedName; 00075 00076 inline KResolverEntryPrivate() : 00077 socktype(0), protocol(0) 00078 { } 00079 }; 00080 00081 // default constructor 00082 KResolverEntry::KResolverEntry() : 00083 d(0L) 00084 { 00085 } 00086 00087 // constructor with stuff 00088 KResolverEntry::KResolverEntry(const KSocketAddress& addr, int socktype, int protocol, 00089 const QString& canonName, const QCString& encodedName) : 00090 d(new KResolverEntryPrivate) 00091 { 00092 d->addr = addr; 00093 d->socktype = socktype; 00094 d->protocol = protocol; 00095 d->canonName = canonName; 00096 d->encodedName = encodedName; 00097 } 00098 00099 // constructor with even more stuff 00100 KResolverEntry::KResolverEntry(const struct sockaddr* sa, Q_UINT16 salen, int socktype, 00101 int protocol, const QString& canonName, 00102 const QCString& encodedName) : 00103 d(new KResolverEntryPrivate) 00104 { 00105 d->addr = KSocketAddress(sa, salen); 00106 d->socktype = socktype; 00107 d->protocol = protocol; 00108 d->canonName = canonName; 00109 d->encodedName = encodedName; 00110 } 00111 00112 // copy constructor 00113 KResolverEntry::KResolverEntry(const KResolverEntry& that) : 00114 d(0L) 00115 { 00116 *this = that; 00117 } 00118 00119 // destructor 00120 KResolverEntry::~KResolverEntry() 00121 { 00122 if (d == 0L) 00123 return; 00124 00125 if (d->deref()) 00126 delete d; 00127 } 00128 00129 // returns the socket address 00130 KSocketAddress KResolverEntry::address() const 00131 { 00132 return d ? d->addr : KSocketAddress(); 00133 } 00134 00135 // returns the length 00136 Q_UINT16 KResolverEntry::length() const 00137 { 00138 return d ? d->addr.length() : 0; 00139 } 00140 00141 // returns the family 00142 int KResolverEntry::family() const 00143 { 00144 return d ? d->addr.family() : AF_UNSPEC; 00145 } 00146 00147 // returns the canonical name 00148 QString KResolverEntry::canonicalName() const 00149 { 00150 return d ? d->canonName : QString::null; 00151 } 00152 00153 // returns the encoded name 00154 QCString KResolverEntry::encodedName() const 00155 { 00156 return d ? d->encodedName : QCString(); 00157 } 00158 00159 // returns the socket type 00160 int KResolverEntry::socketType() const 00161 { 00162 return d ? d->socktype : 0; 00163 } 00164 00165 // returns the protocol 00166 int KResolverEntry::protocol() const 00167 { 00168 return d ? d->protocol : 0; 00169 } 00170 00171 // assignment operator 00172 KResolverEntry& KResolverEntry::operator= (const KResolverEntry& that) 00173 { 00174 // copy the data 00175 if (that.d) 00176 that.d->ref(); 00177 00178 if (d && d->deref()) 00179 delete d; 00180 00181 d = that.d; 00182 return *this; 00183 } 00184 00186 // class KResolverResults 00187 00188 class KNetwork::KResolverResultsPrivate: public QShared 00189 { 00190 public: 00191 QString node, service; 00192 int errorcode, syserror; 00193 00194 KResolverResultsPrivate() : 00195 errorcode(0), syserror(0) 00196 { } 00197 00198 // duplicate the data if necessary, while decreasing the reference count 00199 // on the original data 00200 inline void dup(KResolverResultsPrivate*& d) 00201 { 00202 if (!d->count > 1) 00203 { 00204 d->deref(); 00205 KResolverResultsPrivate *e = new KResolverResultsPrivate(*d); 00206 e->count = 1; 00207 d = e; // set the pointer 00208 } 00209 } 00210 }; 00211 00212 // default constructor 00213 KResolverResults::KResolverResults() 00214 : d(new KResolverResultsPrivate) 00215 { 00216 } 00217 00218 // copy constructor 00219 KResolverResults::KResolverResults(const KResolverResults& other) 00220 : QValueList<KResolverEntry>(other), d(other.d) 00221 { 00222 d->ref(); 00223 } 00224 00225 // destructor 00226 KResolverResults::~KResolverResults() 00227 { 00228 if (d->deref()) 00229 delete d; 00230 } 00231 00232 // assignment operator 00233 KResolverResults& 00234 KResolverResults::operator= (const KResolverResults& other) 00235 { 00236 other.d->ref(); 00237 00238 // release our data 00239 if (d->deref()) 00240 delete d; 00241 00242 // copy over the other data 00243 d = other.d; 00244 00245 // now let QValueList do the rest of the work 00246 QValueList<KResolverEntry>::operator =(other); 00247 00248 return *this; 00249 } 00250 00251 // gets the error code 00252 int KResolverResults::error() const 00253 { 00254 return d->errorcode; 00255 } 00256 00257 // gets the system errno 00258 int KResolverResults::systemError() const 00259 { 00260 return d->syserror; 00261 } 00262 00263 // sets the error codes 00264 void KResolverResults::setError(int errorcode, int systemerror) 00265 { 00266 d->dup(d); 00267 00268 d->errorcode = errorcode; 00269 d->syserror = systemerror; 00270 } 00271 00272 // gets the hostname 00273 QString KResolverResults::nodeName() const 00274 { 00275 return d->node; 00276 } 00277 00278 // gets the service name 00279 QString KResolverResults::serviceName() const 00280 { 00281 return d->service; 00282 } 00283 00284 // sets the address 00285 void KResolverResults::setAddress(const QString& node, 00286 const QString& service) 00287 { 00288 d->dup(d); 00289 00290 d->node = node; 00291 d->service = service; 00292 } 00293 00294 void KResolverResults::virtual_hook( int, void* ) 00295 { /*BASE::virtual_hook( id, data );*/ } 00296 00297 00299 // class KResolver 00300 00301 // default constructor 00302 KResolver::KResolver(QObject *parent, const char *name) 00303 : QObject(parent, name), d(new KResolverPrivate(this)) 00304 { 00305 } 00306 00307 // constructor with host and service 00308 KResolver::KResolver(const QString& nodename, const QString& servicename, 00309 QObject *parent, const char *name) 00310 : QObject(parent, name), d(new KResolverPrivate(this, nodename, servicename)) 00311 { 00312 } 00313 00314 // destructor 00315 KResolver::~KResolver() 00316 { 00317 // this deletes our d pointer (if necessary) 00318 // and cancels the lookup as well 00319 KResolverManager::manager()->aboutToBeDeleted(this); 00320 d = 0L; 00321 } 00322 00323 // get the status 00324 int KResolver::status() const 00325 { 00326 return d->status; 00327 } 00328 00329 // get the error code 00330 int KResolver::error() const 00331 { 00332 return d->errorcode; 00333 } 00334 00335 // get the errno 00336 int KResolver::systemError() const 00337 { 00338 return d->syserror; 00339 } 00340 00341 // are we running? 00342 bool KResolver::isRunning() const 00343 { 00344 return d->status > 0 && d->status < Success; 00345 } 00346 00347 // get the hostname 00348 QString KResolver::nodeName() const 00349 { 00350 return d->input.node; 00351 } 00352 00353 // get the service 00354 QString KResolver::serviceName() const 00355 { 00356 return d->input.service; 00357 } 00358 00359 // sets the hostname 00360 void KResolver::setNodeName(const QString& nodename) 00361 { 00362 // don't touch those values if we're working! 00363 if (!isRunning()) 00364 { 00365 d->input.node = nodename; 00366 d->status = Idle; 00367 d->results.setAddress(nodename, d->input.service); 00368 } 00369 } 00370 00371 // sets the service 00372 void KResolver::setServiceName(const QString& service) 00373 { 00374 // don't change if running 00375 if (!isRunning()) 00376 { 00377 d->input.service = service; 00378 d->status = Idle; 00379 d->results.setAddress(d->input.node, service); 00380 } 00381 } 00382 00383 // sets the address 00384 void KResolver::setAddress(const QString& nodename, const QString& service) 00385 { 00386 setNodeName(nodename); 00387 setServiceName(service); 00388 } 00389 00390 // get the flags 00391 int KResolver::flags() const 00392 { 00393 return d->input.flags; 00394 } 00395 00396 // sets the flags 00397 int KResolver::setFlags(int flags) 00398 { 00399 int oldflags = d->input.flags; 00400 if (!isRunning()) 00401 { 00402 d->input.flags = flags; 00403 d->status = Idle; 00404 } 00405 return oldflags; 00406 } 00407 00408 // sets the family mask 00409 void KResolver::setFamily(int families) 00410 { 00411 if (!isRunning()) 00412 { 00413 d->input.familyMask = families; 00414 d->status = Idle; 00415 } 00416 } 00417 00418 // sets the socket type 00419 void KResolver::setSocketType(int type) 00420 { 00421 if (!isRunning()) 00422 { 00423 d->input.socktype = type; 00424 d->status = Idle; 00425 } 00426 } 00427 00428 // sets the protocol 00429 void KResolver::setProtocol(int protonum, const char *name) 00430 { 00431 if (isRunning()) 00432 return; // can't change now 00433 00434 // we copy the given protocol name. If it isn't an empty string 00435 // and the protocol number was 0, we will look it up in /etc/protocols 00436 // we also leave the error reporting to the actual lookup routines, in 00437 // case the given protocol name doesn't exist 00438 00439 d->input.protocolName = name; 00440 if (protonum == 0 && name != 0L && *name != '\0') 00441 { 00442 // must look up the protocol number 00443 d->input.protocol = KResolver::protocolNumber(name); 00444 } 00445 else 00446 d->input.protocol = protonum; 00447 d->status = Idle; 00448 } 00449 00450 bool KResolver::start() 00451 { 00452 if (!isRunning()) 00453 { 00454 d->results.empty(); 00455 d->emitSignal = true; // reset the variable 00456 00457 // is there anything to be queued? 00458 if (d->input.node.isEmpty() && d->input.service.isEmpty()) 00459 { 00460 d->status = KResolver::Success; 00461 emitFinished(); 00462 } 00463 else 00464 KResolverManager::manager()->enqueue(this, 0L); 00465 } 00466 00467 return true; 00468 } 00469 00470 bool KResolver::wait(int msec) 00471 { 00472 if (!isRunning()) 00473 { 00474 emitFinished(); 00475 return true; 00476 } 00477 00478 QMutexLocker locker(&d->mutex); 00479 00480 if (!isRunning()) 00481 return true; 00482 else 00483 { 00484 QTime t; 00485 t.start(); 00486 00487 while (!msec || t.elapsed() < msec) 00488 { 00489 // wait on the manager to broadcast completion 00490 d->waiting = true; 00491 if (msec) 00492 KResolverManager::manager()->notifyWaiters.wait(&d->mutex, msec - t.elapsed()); 00493 else 00494 KResolverManager::manager()->notifyWaiters.wait(&d->mutex); 00495 00496 // the manager has processed 00497 // see if this object is done 00498 if (!isRunning()) 00499 { 00500 // it's done 00501 d->waiting = false; 00502 emitFinished(); 00503 return true; 00504 } 00505 } 00506 00507 // if we've got here, we've timed out 00508 d->waiting = false; 00509 return false; 00510 } 00511 } 00512 00513 void KResolver::cancel(bool emitSignal) 00514 { 00515 d->emitSignal = emitSignal; 00516 KResolverManager::manager()->dequeue(this); 00517 } 00518 00519 KResolverResults 00520 KResolver::results() const 00521 { 00522 if (!isRunning()) 00523 return d->results; 00524 00525 // return a dummy, empty result 00526 KResolverResults r; 00527 r.setAddress(d->input.node, d->input.service); 00528 r.setError(d->errorcode, d->syserror); 00529 return r; 00530 } 00531 00532 bool KResolver::event(QEvent* e) 00533 { 00534 if (static_cast<int>(e->type()) == KResolverManager::ResolutionCompleted) 00535 { 00536 emitFinished(); 00537 return true; 00538 } 00539 00540 return false; 00541 } 00542 00543 void KResolver::emitFinished() 00544 { 00545 if (isRunning()) 00546 d->status = KResolver::Success; 00547 00548 QGuardedPtr<QObject> p = this; // guard against deletion 00549 00550 if (d->emitSignal) 00551 emit finished(d->results); 00552 00553 if (p && d->deleteWhenDone) 00554 deleteLater(); // in QObject 00555 } 00556 00557 QString KResolver::errorString(int errorcode, int syserror) 00558 { 00559 // no i18n now... 00560 static const char * const messages[] = 00561 { 00562 I18N_NOOP("no error"), // NoError 00563 I18N_NOOP("requested family not supported for this host name"), // AddrFamily 00564 I18N_NOOP("temporary failure in name resolution"), // TryAgain 00565 I18N_NOOP("non-recoverable failure in name resolution"), // NonRecoverable 00566 I18N_NOOP("invalid flags"), // BadFlags 00567 I18N_NOOP("memory allocation failure"), // Memory 00568 I18N_NOOP("name or service not known"), // NoName 00569 I18N_NOOP("requested family not supported"), // UnsupportedFamily 00570 I18N_NOOP("requested service not supported for this socket type"), // UnsupportedService 00571 I18N_NOOP("requested socket type not supported"), // UnsupportedSocketType 00572 I18N_NOOP("unknown error"), // UnknownError 00573 I18N_NOOP2("1: the i18n'ed system error code, from errno", 00574 "system error: %1") // SystemError 00575 }; 00576 00577 // handle the special value 00578 if (errorcode == Canceled) 00579 return i18n("request was canceled"); 00580 00581 if (errorcode > 0 || errorcode < SystemError) 00582 return QString::null; 00583 00584 QString msg = i18n(messages[-errorcode]); 00585 if (errorcode == SystemError) 00586 msg.arg(QString::fromLocal8Bit(strerror(syserror))); 00587 00588 return msg; 00589 } 00590 00591 KResolverResults 00592 KResolver::resolve(const QString& host, const QString& service, int flags, 00593 int families) 00594 { 00595 KResolver qres(host, service, qApp, "synchronous KResolver"); 00596 qres.setFlags(flags); 00597 qres.setFamily(families); 00598 qres.start(); 00599 qres.wait(); 00600 return qres.results(); 00601 } 00602 00603 bool KResolver::resolveAsync(QObject* userObj, const char *userSlot, 00604 const QString& host, const QString& service, 00605 int flags, int families) 00606 { 00607 KResolver* qres = new KResolver(host, service, qApp, "asynchronous KResolver"); 00608 QObject::connect(qres, SIGNAL(finished(KResolverResults)), userObj, userSlot); 00609 qres->setFlags(flags); 00610 qres->setFamily(families); 00611 qres->d->deleteWhenDone = true; // this is the only difference from the example code 00612 return qres->start(); 00613 } 00614 00615 #ifdef NEED_MUTEX 00616 QMutex getXXbyYYmutex; 00617 #endif 00618 00619 QStrList KResolver::protocolName(int protonum) 00620 { 00621 struct protoent *pe; 00622 #ifndef HAVE_GETPROTOBYNAME_R 00623 QMutexLocker locker(&getXXbyYYmutex); 00624 00625 pe = getprotobynumber(protonum); 00626 00627 #else 00628 size_t buflen = 1024; 00629 struct protoent protobuf; 00630 char *buf; 00631 do 00632 { 00633 buf = new char[buflen]; 00634 if (getprotobynumber_r(protonum, &protobuf, buf, buflen, &pe) == ERANGE) 00635 { 00636 buflen += 1024; 00637 delete [] buf; 00638 } 00639 else 00640 break; 00641 } 00642 while (pe == 0L); 00643 #endif 00644 00645 // Do common processing 00646 QStrList lst(true); // use deep copies 00647 if (pe != NULL) 00648 { 00649 lst.append(pe->p_name); 00650 for (char **p = pe->p_aliases; *p; p++) 00651 lst.append(*p); 00652 } 00653 00654 #ifdef HAVE_GETPROTOBYNAME_R 00655 delete [] buf; 00656 #endif 00657 00658 return lst; 00659 } 00660 00661 QStrList KResolver::protocolName(const char *protoname) 00662 { 00663 struct protoent *pe; 00664 #ifndef HAVE_GETPROTOBYNAME_R 00665 QMutexLocker locker(&getXXbyYYmutex); 00666 00667 pe = getprotobyname(protoname); 00668 00669 #else 00670 size_t buflen = 1024; 00671 struct protoent protobuf; 00672 char *buf; 00673 do 00674 { 00675 buf = new char[buflen]; 00676 if (getprotobyname_r(protoname, &protobuf, buf, buflen, &pe) == ERANGE) 00677 { 00678 buflen += 1024; 00679 delete [] buf; 00680 } 00681 else 00682 break; 00683 } 00684 while (pe == 0L); 00685 #endif 00686 00687 // Do common processing 00688 QStrList lst(true); // use deep copies 00689 if (pe != NULL) 00690 { 00691 lst.append(pe->p_name); 00692 for (char **p = pe->p_aliases; *p; p++) 00693 lst.append(*p); 00694 } 00695 00696 #ifdef HAVE_GETPROTOBYNAME_R 00697 delete [] buf; 00698 #endif 00699 00700 return lst; 00701 } 00702 00703 int KResolver::protocolNumber(const char *protoname) 00704 { 00705 struct protoent *pe; 00706 #ifndef HAVE_GETPROTOBYNAME_R 00707 QMutexLocker locker(&getXXbyYYmutex); 00708 00709 pe = getprotobyname(protoname); 00710 00711 #else 00712 size_t buflen = 1024; 00713 struct protoent protobuf; 00714 char *buf; 00715 do 00716 { 00717 buf = new char[buflen]; 00718 if (getprotobyname_r(protoname, &protobuf, buf, buflen, &pe) == ERANGE) 00719 { 00720 buflen += 1024; 00721 delete [] buf; 00722 } 00723 else 00724 break; 00725 } 00726 while (pe == 0L); 00727 #endif 00728 00729 // Do common processing 00730 int protonum = -1; 00731 if (pe != NULL) 00732 protonum = pe->p_proto; 00733 00734 #ifdef HAVE_GETPROTOBYNAME_R 00735 delete [] buf; 00736 #endif 00737 00738 return protonum; 00739 } 00740 00741 int KResolver::servicePort(const char *servname, const char *protoname) 00742 { 00743 struct servent *se; 00744 #ifndef HAVE_GETSERVBYNAME_R 00745 QMutexLocker locker(&getXXbyYYmutex); 00746 00747 se = getservbyname(servname, protoname); 00748 00749 #else 00750 size_t buflen = 1024; 00751 struct servent servbuf; 00752 char *buf; 00753 do 00754 { 00755 buf = new char[buflen]; 00756 if (getservbyname_r(servname, protoname, &servbuf, buf, buflen, &se) == ERANGE) 00757 { 00758 buflen += 1024; 00759 delete [] buf; 00760 } 00761 else 00762 break; 00763 } 00764 while (se == 0L); 00765 #endif 00766 00767 // Do common processing 00768 int servport = -1; 00769 if (se != NULL) 00770 servport = ntohs(se->s_port); 00771 00772 #ifdef HAVE_GETSERVBYNAME_R 00773 delete [] buf; 00774 #endif 00775 00776 return servport; 00777 } 00778 00779 QStrList KResolver::serviceName(const char* servname, const char *protoname) 00780 { 00781 struct servent *se; 00782 #ifndef HAVE_GETSERVBYNAME_R 00783 QMutexLocker locker(&getXXbyYYmutex); 00784 00785 se = getservbyname(servname, protoname); 00786 00787 #else 00788 size_t buflen = 1024; 00789 struct servent servbuf; 00790 char *buf; 00791 do 00792 { 00793 buf = new char[buflen]; 00794 if (getservbyname_r(servname, protoname, &servbuf, buf, buflen, &se) == ERANGE) 00795 { 00796 buflen += 1024; 00797 delete [] buf; 00798 } 00799 else 00800 break; 00801 } 00802 while (se == 0L); 00803 #endif 00804 00805 // Do common processing 00806 QStrList lst(true); // use deep copies 00807 if (se != NULL) 00808 { 00809 lst.append(se->s_name); 00810 for (char **p = se->s_aliases; *p; p++) 00811 lst.append(*p); 00812 } 00813 00814 #ifdef HAVE_GETSERVBYNAME_R 00815 delete [] buf; 00816 #endif 00817 00818 return lst; 00819 } 00820 00821 QStrList KResolver::serviceName(int port, const char *protoname) 00822 { 00823 struct servent *se; 00824 #ifndef HAVE_GETSERVBYNAME_R 00825 QMutexLocker locker(&getXXbyYYmutex); 00826 00827 se = getservbyport(port, protoname); 00828 00829 #else 00830 size_t buflen = 1024; 00831 struct servent servbuf; 00832 char *buf; 00833 do 00834 { 00835 buf = new char[buflen]; 00836 if (getservbyport_r(port, protoname, &servbuf, buf, buflen, &se) == ERANGE) 00837 { 00838 buflen += 1024; 00839 delete [] buf; 00840 } 00841 else 00842 break; 00843 } 00844 while (se == 0L); 00845 #endif 00846 00847 // Do common processing 00848 QStrList lst(true); // use deep copies 00849 if (se != NULL) 00850 { 00851 lst.append(se->s_name); 00852 for (char **p = se->s_aliases; *p; p++) 00853 lst.append(*p); 00854 } 00855 00856 #ifdef HAVE_GETSERVBYNAME_R 00857 delete [] buf; 00858 #endif 00859 00860 return lst; 00861 } 00862 00863 // forward declaration 00864 static QStringList splitLabels(const QString& unicodeDomain); 00865 static QCString ToASCII(const QString& label); 00866 static QString ToUnicode(const QString& label); 00867 00868 // implement the ToAscii function, as described by IDN documents 00869 QCString KResolver::domainToAscii(const QString& unicodeDomain) 00870 { 00871 QCString retval; 00872 // RFC 3490, section 4 describes the operation: 00873 // 1) this is a query, so don't allow unassigned 00874 00875 // 2) split the domain into individual labels, without 00876 // separators. 00877 QStringList input = splitLabels(unicodeDomain); 00878 00879 // 3) decide whether to enforce the STD3 rules for chars < 0x7F 00880 // we don't enforce 00881 00882 // 4) for each label, apply ToASCII 00883 QStringList::Iterator it = input.begin(); 00884 for ( ; it != input.end(); it++) 00885 { 00886 QCString cs = ToASCII(*it); 00887 if (cs.isNull()) 00888 return QCString(); // error! 00889 00890 // no, all is Ok. 00891 if (!retval.isEmpty()) 00892 retval += '.'; 00893 retval += cs; 00894 } 00895 00896 return retval; 00897 } 00898 00899 QString KResolver::domainToUnicode(const QCString& asciiDomain) 00900 { 00901 return domainToUnicode(QString::fromLatin1(asciiDomain)); 00902 } 00903 00904 // implement the ToUnicode function, as described by IDN documents 00905 QString KResolver::domainToUnicode(const QString& asciiDomain) 00906 { 00907 if (asciiDomain.isEmpty()) 00908 return asciiDomain; 00909 00910 QString retval; 00911 00912 // draft-idn-idna-14.txt, section 4 describes the operation: 00913 // 1) this is a query, so don't allow unassigned 00914 // besides, input is ASCII 00915 00916 // 2) split the domain into individual labels, without 00917 // separators. 00918 QStringList input = splitLabels(asciiDomain); 00919 00920 // 3) decide whether to enforce the STD3 rules for chars < 0x7F 00921 // we don't enforce 00922 00923 // 4) for each label, apply ToUnicode 00924 QStringList::Iterator it; 00925 for (it = input.begin(); it != input.end(); it++) 00926 { 00927 QString label = ToUnicode(*it).lower(); 00928 00929 // ToUnicode can't fail 00930 if (!retval.isEmpty()) 00931 retval += '.'; 00932 retval += label; 00933 } 00934 00935 return retval; 00936 } 00937 00938 QString KResolver::normalizeDomain(const QString& domain) 00939 { 00940 return domainToUnicode(domainToAscii(domain)); 00941 } 00942 00943 void KResolver::virtual_hook( int, void* ) 00944 { /*BASE::virtual_hook( id, data );*/ } 00945 00946 // here follows IDN functions 00947 // all IDN functions conform to the following documents: 00948 // RFC 3454 - Preparation of Internationalized Strings 00949 // RFC 3490 - Internationalizing Domain Names in Applications (IDNA) 00950 // RFC 3491 - Nameprep: A Stringprep Profile for 00951 // Internationalized Domain Names (IDN 00952 // RFC 3492 - Punycode: A Bootstring encoding of Unicode 00953 // for Internationalized Domain Names in Applications (IDNA) 00954 00955 static QStringList splitLabels(const QString& unicodeDomain) 00956 { 00957 // From RFC 3490 section 3.1: 00958 // "Whenever dots are used as label separators, the following characters 00959 // MUST be recognized as dots: U+002E (full stop), U+3002 (ideographic full 00960 // stop), U+FF0E (fullwidth full stop), U+FF61 (halfwidth ideographic full 00961 // stop)." 00962 static const unsigned int separators[] = { 0x002E, 0x3002, 0xFF0E, 0xFF61 }; 00963 00964 QStringList lst; 00965 int start = 0; 00966 uint i; 00967 for (i = 0; i < unicodeDomain.length(); i++) 00968 { 00969 unsigned int c = unicodeDomain[i].unicode(); 00970 00971 if (c == separators[0] || 00972 c == separators[1] || 00973 c == separators[2] || 00974 c == separators[3]) 00975 { 00976 // found a separator! 00977 lst << unicodeDomain.mid(start, i - start); 00978 start = i + 1; 00979 } 00980 } 00981 if ((long)i > start) 00982 // there is still one left 00983 lst << unicodeDomain.mid(start, i - start); 00984 00985 return lst; 00986 } 00987 00988 static QCString ToASCII(const QString& label) 00989 { 00990 #ifdef HAVE_IDNA_H 00991 // We have idna.h, so we can use the idna_to_ascii 00992 // function :) 00993 00994 if (label.length() > 64) 00995 return (char*)0L; // invalid label 00996 00997 QCString retval; 00998 char buf[65]; 00999 01000 Q_UINT32* ucs4 = new Q_UINT32[label.length() + 1]; 01001 01002 uint i; 01003 for (i = 0; i < label.length(); i++) 01004 ucs4[i] = (unsigned long)label[i].unicode(); 01005 ucs4[i] = 0; // terminate with NUL, just to be on the safe side 01006 01007 if (idna_to_ascii_4i(ucs4, label.length(), buf, 0) == IDNA_SUCCESS) 01008 // success! 01009 retval = buf; 01010 01011 delete [] ucs4; 01012 return retval; 01013 #else 01014 return label.latin1(); 01015 #endif 01016 } 01017 01018 static QString ToUnicode(const QString& label) 01019 { 01020 #ifdef HAVE_IDNA_H 01021 // We have idna.h, so we can use the idna_to_unicode 01022 // function :) 01023 01024 Q_UINT32 *ucs4_input, *ucs4_output; 01025 size_t outlen; 01026 01027 ucs4_input = new Q_UINT32[label.length() + 1]; 01028 for (uint i = 0; i < label.length(); i++) 01029 ucs4_input[i] = (unsigned long)label[i].unicode(); 01030 01031 // try the same length for output 01032 ucs4_output = new Q_UINT32[outlen = label.length()]; 01033 01034 idna_to_unicode_44i(ucs4_input, label.length(), 01035 ucs4_output, &outlen, 01036 0); 01037 01038 if (outlen > label.length()) 01039 { 01040 // it must have failed 01041 delete [] ucs4_output; 01042 ucs4_output = new Q_UINT32[outlen]; 01043 01044 idna_to_unicode_44i(ucs4_input, label.length(), 01045 ucs4_output, &outlen, 01046 0); 01047 } 01048 01049 // now set the answer 01050 QString result; 01051 result.setLength(outlen); 01052 for (uint i = 0; i < outlen; i++) 01053 result[i] = (unsigned int)ucs4_output[i]; 01054 01055 delete [] ucs4_input; 01056 delete [] ucs4_output; 01057 01058 return result; 01059 #else 01060 return label; 01061 #endif 01062 } 01063 01064 #include "kresolver.moc"
KDE Logo
This file is part of the documentation for kdecore Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Sep 29 09:43:10 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003