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 Sat Nov 27 13:41:18 2004 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003