kdecore Library API Documentation

kurl.cpp

00001 /* 00002 Copyright (C) 1999 Torben Weis <weis@kde.org> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00017 Boston, MA 02111-1307, USA. 00018 */ 00019 00020 #include "kurl.h" 00021 00022 #ifndef KDE_QT_ONLY 00023 #include <kdebug.h> 00024 #include <kglobal.h> 00025 #include <kidna.h> 00026 #include <kprotocolinfo.h> 00027 #endif 00028 00029 #include <stdio.h> 00030 #include <assert.h> 00031 #include <ctype.h> 00032 #include <stdlib.h> 00033 #include <unistd.h> 00034 00035 #include <qurl.h> 00036 #include <qdir.h> 00037 #include <qstringlist.h> 00038 #include <qregexp.h> 00039 #include <qstylesheet.h> 00040 #include <qmap.h> 00041 #include <qtextcodec.h> 00042 #include <qmutex.h> 00043 00044 static const QString fileProt = "file"; 00045 00046 static QTextCodec * codecForHint( int encoding_hint /* not 0 ! */ ) 00047 { 00048 return QTextCodec::codecForMib( encoding_hint ); 00049 } 00050 00051 // encoding_offset: 00052 // 0 encode both @ and / 00053 // 1 encode @ but not / 00054 // 2 encode neither @ or / 00055 static QString encode( const QString& segment, int encoding_offset, int encoding_hint ) 00056 { 00057 const char *encode_string = "/@<>#\"&%?={}|^~[]\'`\\:+"; 00058 encode_string += encoding_offset; 00059 00060 QCString local; 00061 if (encoding_hint==0) 00062 local = segment.local8Bit(); 00063 else 00064 { 00065 QTextCodec * textCodec = codecForHint( encoding_hint ); 00066 if (!textCodec) 00067 local = segment.local8Bit(); 00068 else 00069 local = textCodec->fromUnicode( segment ); 00070 } 00071 00072 int old_length = local.length(); 00073 00074 if ( !old_length ) 00075 return segment.isNull() ? QString::null : QString(""); // differentiate null and empty 00076 00077 // a worst case approximation 00078 QChar *new_segment = new QChar[ old_length * 3 + 1 ]; 00079 int new_length = 0; 00080 00081 for ( int i = 0; i < old_length; i++ ) 00082 { 00083 // 'unsave' and 'reserved' characters 00084 // according to RFC 1738, 00085 // 2.2. URL Character Encoding Issues (pp. 3-4) 00086 // WABA: Added non-ascii 00087 unsigned char character = local[i]; 00088 if ( (character <= 32) || (character >= 127) || 00089 strchr(encode_string, character) ) 00090 { 00091 new_segment[ new_length++ ] = '%'; 00092 00093 unsigned int c = character / 16; 00094 c += (c > 9) ? ('A' - 10) : '0'; 00095 new_segment[ new_length++ ] = c; 00096 00097 c = character % 16; 00098 c += (c > 9) ? ('A' - 10) : '0'; 00099 new_segment[ new_length++ ] = c; 00100 00101 } 00102 else 00103 new_segment[ new_length++ ] = local[i]; 00104 } 00105 00106 QString result = QString(new_segment, new_length); 00107 delete [] new_segment; 00108 return result; 00109 } 00110 00111 static QString encodeHost( const QString& segment, bool encode_slash, int encoding_hint ) 00112 { 00113 // Hostnames are encoded differently 00114 // we use the IDNA transformation instead 00115 00116 // Note: when merging qt-addon, use QResolver::domainToAscii here 00117 #ifndef KDE_QT_ONLY 00118 Q_UNUSED( encode_slash ); 00119 Q_UNUSED( encoding_hint ); 00120 return KIDNA::toAscii(segment); 00121 #else 00122 return encode(segment, encode_slash ? 0 : 1, encoding_hint); 00123 #endif 00124 } 00125 00126 static int hex2int( unsigned int _char ) 00127 { 00128 if ( _char >= 'A' && _char <='F') 00129 return _char - 'A' + 10; 00130 if ( _char >= 'a' && _char <='f') 00131 return _char - 'a' + 10; 00132 if ( _char >= '0' && _char <='9') 00133 return _char - '0'; 00134 return -1; 00135 } 00136 00137 // WABA: The result of lazy_encode isn't usable for a URL which 00138 // needs to satisfies RFC requirements. However, the following 00139 // operation will make it usable again: 00140 // encode(decode(...)) 00141 // 00142 // As a result one can see that url.prettyURL() does not result in 00143 // a RFC compliant URL but that the following sequence does: 00144 // KURL(url.prettyURL()).url() 00145 00146 00147 static QString lazy_encode( const QString& segment, bool encodeAt=true ) 00148 { 00149 int old_length = segment.length(); 00150 00151 if ( !old_length ) 00152 return QString::null; 00153 00154 // a worst case approximation 00155 QChar *new_segment = new QChar[ old_length * 3 + 1 ]; 00156 int new_length = 0; 00157 00158 for ( int i = 0; i < old_length; i++ ) 00159 { 00160 unsigned int character = segment[i].unicode(); // Don't use latin1() 00161 // It returns 0 for non-latin1 values 00162 // Small set of really ambiguous chars 00163 if ((character < 32) || // Low ASCII 00164 ((character == '%') && // The escape character itself 00165 (i+2 < old_length) && // But only if part of a valid escape sequence! 00166 (hex2int(segment[i+1].unicode())!= -1) && 00167 (hex2int(segment[i+2].unicode())!= -1)) || 00168 (character == '?') || // Start of query delimiter 00169 ((character == '@') && encodeAt) || // Username delimiter 00170 (character == '#') || // Start of reference delimiter 00171 ((character == 32) && (i+1 == old_length))) // A trailing space 00172 { 00173 new_segment[ new_length++ ] = '%'; 00174 00175 unsigned int c = character / 16; 00176 c += (c > 9) ? ('A' - 10) : '0'; 00177 new_segment[ new_length++ ] = c; 00178 00179 c = character % 16; 00180 c += (c > 9) ? ('A' - 10) : '0'; 00181 new_segment[ new_length++ ] = c; 00182 } 00183 else 00184 new_segment[ new_length++ ] = segment[i]; 00185 } 00186 00187 QString result = QString(new_segment, new_length); 00188 delete [] new_segment; 00189 return result; 00190 } 00191 00192 static void decode( const QString& segment, QString &decoded, QString &encoded, int encoding_hint=0, bool updateDecoded = true ) 00193 { 00194 decoded = QString::null; 00195 encoded = segment; 00196 00197 int old_length = segment.length(); 00198 if ( !old_length ) 00199 return; 00200 00201 QTextCodec *textCodec = 0; 00202 if (encoding_hint) 00203 textCodec = codecForHint( encoding_hint ); 00204 00205 if (!textCodec) 00206 textCodec = QTextCodec::codecForLocale(); 00207 00208 QCString csegment = textCodec->fromUnicode(segment); 00209 // Check if everything went ok 00210 if (textCodec->toUnicode(csegment) != segment) 00211 { 00212 // Uh oh 00213 textCodec = codecForHint( 106 ); // Fall back to utf-8 00214 csegment = textCodec->fromUnicode(segment); 00215 } 00216 old_length = csegment.length(); 00217 00218 int new_length = 0; 00219 int new_length2 = 0; 00220 00221 // make a copy of the old one 00222 char *new_segment = new char[ old_length + 1 ]; 00223 QChar *new_usegment = new QChar[ old_length * 3 + 1 ]; 00224 00225 int i = 0; 00226 while( i < old_length ) 00227 { 00228 bool bReencode = false; 00229 unsigned char character = csegment[ i++ ]; 00230 if ((character <= ' ') || (character > 127)) 00231 bReencode = true; 00232 00233 new_usegment [ new_length2++ ] = character; 00234 if (character == '%' ) 00235 { 00236 int a = i+1 < old_length ? hex2int( csegment[i] ) : -1; 00237 int b = i+1 < old_length ? hex2int( csegment[i+1] ) : -1; 00238 if ((a == -1) || (b == -1)) // Only replace if sequence is valid 00239 { 00240 // Contains stray %, make sure to re-encode! 00241 bReencode = true; 00242 } 00243 else 00244 { 00245 // Valid %xx sequence 00246 character = a * 16 + b; // Replace with value of %dd 00247 if (!character && updateDecoded) 00248 break; // Stop at %00 00249 00250 new_usegment [ new_length2++ ] = (unsigned char) csegment[i++]; 00251 new_usegment [ new_length2++ ] = (unsigned char) csegment[i++]; 00252 } 00253 } 00254 if (bReencode) 00255 { 00256 new_length2--; 00257 new_usegment [ new_length2++ ] = '%'; 00258 00259 unsigned int c = character / 16; 00260 c += (c > 9) ? ('A' - 10) : '0'; 00261 new_usegment[ new_length2++ ] = c; 00262 00263 c = character % 16; 00264 c += (c > 9) ? ('A' - 10) : '0'; 00265 new_usegment[ new_length2++ ] = c; 00266 } 00267 00268 new_segment [ new_length++ ] = character; 00269 } 00270 new_segment [ new_length ] = 0; 00271 00272 encoded = QString( new_usegment, new_length2); 00273 00274 // Encoding specified 00275 if (updateDecoded) 00276 { 00277 QByteArray array; 00278 array.setRawData(new_segment, new_length); 00279 decoded = textCodec->toUnicode( array, new_length ); 00280 array.resetRawData(new_segment, new_length); 00281 QCString validate = textCodec->fromUnicode(decoded); 00282 00283 if (strcmp(validate.data(), new_segment) != 0) 00284 { 00285 decoded = QString::fromLocal8Bit(new_segment, new_length); 00286 } 00287 } 00288 00289 delete [] new_segment; 00290 delete [] new_usegment; 00291 } 00292 00293 static QString decode(const QString &segment, int encoding_hint = 0) 00294 { 00295 QString result; 00296 QString tmp; 00297 decode(segment, result, tmp, encoding_hint); 00298 return result; 00299 } 00300 00301 static QString cleanpath(const QString &_path, bool cleanDirSeparator, bool decodeDots) 00302 { 00303 if (_path.isEmpty()) return QString::null; 00304 00305 if (_path[0] != '/') 00306 return _path; // Don't mangle mailto-style URLs 00307 00308 QString path = _path; 00309 00310 int len = path.length(); 00311 00312 if (decodeDots) 00313 { 00314 #ifndef KDE_QT_ONLY 00315 static const QString &encodedDot = KGlobal::staticQString("%2e"); 00316 #else 00317 QString encodedDot("%2e"); 00318 #endif 00319 if (path.find(encodedDot, 0, false) != -1) 00320 { 00321 #ifndef KDE_QT_ONLY 00322 static const QString &encodedDOT = KGlobal::staticQString("%2E"); // Uppercase! 00323 #else 00324 QString encodedDOT("%2E"); 00325 #endif 00326 path.replace(encodedDot, "."); 00327 path.replace(encodedDOT, "."); 00328 len = path.length(); 00329 } 00330 } 00331 00332 bool slash = (len && path[len-1] == '/') || 00333 (len > 1 && path[len-2] == '/' && path[len-1] == '.'); 00334 00335 // The following code cleans up directory path much like 00336 // QDir::cleanDirPath() except it can be made to ignore multiple 00337 // directory separators by setting the flag to false. That fixes 00338 // bug# 15044, mail.altavista.com and other similar brain-dead server 00339 // implementations that do not follow what has been specified in 00340 // RFC 2396!! (dA) 00341 QString result; 00342 int cdUp, orig_pos, pos; 00343 00344 cdUp = 0; 00345 pos = orig_pos = len; 00346 while ( pos && (pos = path.findRev('/',--pos)) != -1 ) 00347 { 00348 len = orig_pos - pos - 1; 00349 if ( len == 2 && path[pos+1] == '.' && path[pos+2] == '.' ) 00350 cdUp++; 00351 else 00352 { 00353 // Ignore any occurrences of '.' 00354 // This includes entries that simply do not make sense like /..../ 00355 if ( (len || !cleanDirSeparator) && 00356 (len != 1 || path[pos+1] != '.' ) ) 00357 { 00358 if ( !cdUp ) 00359 result.prepend(path.mid(pos, len+1)); 00360 else 00361 cdUp--; 00362 } 00363 } 00364 orig_pos = pos; 00365 } 00366 00367 if ( result.isEmpty() ) 00368 result = "/"; 00369 else if ( slash && result[result.length()-1] != '/' ) 00370 result.append('/'); 00371 00372 return result; 00373 } 00374 00375 bool KURL::isRelativeURL(const QString &_url) 00376 { 00377 int len = _url.length(); 00378 if (!len) return true; // Very short relative URL. 00379 const QChar *str = _url.unicode(); 00380 00381 // Absolute URL must start with alpha-character 00382 if (!isalpha(str[0].latin1())) 00383 return true; // Relative URL 00384 00385 for(int i = 1; i < len; i++) 00386 { 00387 char c = str[i].latin1(); // Note: non-latin1 chars return 0! 00388 if (c == ':') 00389 return false; // Absolute URL 00390 00391 // Protocol part may only contain alpha, digit, + or - 00392 if (!isalpha(c) && !isdigit(c) && (c != '+') && (c != '-')) 00393 return true; // Relative URL 00394 } 00395 // URL did not contain ':' 00396 return true; // Relative URL 00397 } 00398 00399 KURL::List::List(const KURL &url) 00400 { 00401 append( url ); 00402 } 00403 00404 KURL::List::List(const QStringList &list) 00405 { 00406 for (QStringList::ConstIterator it = list.begin(); 00407 it != list.end(); 00408 it++) 00409 { 00410 append( KURL(*it) ); 00411 } 00412 } 00413 00414 QStringList KURL::List::toStringList() const 00415 { 00416 QStringList lst; 00417 for( KURL::List::ConstIterator it = begin(); 00418 it != end(); 00419 it++) 00420 { 00421 lst.append( (*it).url() ); 00422 } 00423 return lst; 00424 } 00425 00426 00427 KURL::KURL() 00428 { 00429 reset(); 00430 } 00431 00432 KURL::~KURL() 00433 { 00434 } 00435 00436 00437 KURL::KURL( const QString &url, int encoding_hint ) 00438 { 00439 reset(); 00440 parse( url, encoding_hint ); 00441 } 00442 00443 KURL::KURL( const char * url, int encoding_hint ) 00444 { 00445 reset(); 00446 parse( QString::fromLatin1(url), encoding_hint ); 00447 } 00448 00449 KURL::KURL( const QCString& url, int encoding_hint ) 00450 { 00451 reset(); 00452 parse( QString::fromLatin1(url), encoding_hint ); 00453 } 00454 00455 KURL::KURL( const KURL& _u ) 00456 { 00457 *this = _u; 00458 } 00459 00460 QDataStream & operator<< (QDataStream & s, const KURL & a) 00461 { 00462 QString QueryForWire=a.m_strQuery_encoded; 00463 if (!a.m_strQuery_encoded.isNull()) 00464 QueryForWire.prepend("?"); 00465 00466 s << a.m_strProtocol << a.m_strUser << a.m_strPass << a.m_strHost 00467 << a.m_strPath << a.m_strPath_encoded << QueryForWire << a.m_strRef_encoded 00468 << Q_INT8(a.m_bIsMalformed ? 1 : 0) << a.m_iPort; 00469 return s; 00470 } 00471 00472 QDataStream & operator>> (QDataStream & s, KURL & a) 00473 { 00474 Q_INT8 malf; 00475 QString QueryFromWire; 00476 s >> a.m_strProtocol >> a.m_strUser >> a.m_strPass >> a.m_strHost 00477 >> a.m_strPath >> a.m_strPath_encoded >> QueryFromWire >> a.m_strRef_encoded 00478 >> malf >> a.m_iPort; 00479 a.m_bIsMalformed = (malf != 0); 00480 00481 if ( QueryFromWire.isNull() ) 00482 a.m_strQuery_encoded = QString::null; 00483 else if ( QueryFromWire.length() == 1 ) // empty query 00484 a.m_strQuery_encoded = ""; 00485 else 00486 a.m_strQuery_encoded = QueryFromWire.mid(1); 00487 00488 a.m_iUriMode = KURL::uriModeForProtocol( a.m_strProtocol ); 00489 00490 return s; 00491 } 00492 00493 #ifndef QT_NO_NETWORKPROTOCOL 00494 KURL::KURL( const QUrl &u ) 00495 { 00496 *this = u; 00497 } 00498 #endif 00499 00500 KURL::KURL( const KURL& _u, const QString& _rel_url, int encoding_hint ) 00501 { 00502 if (_u.hasSubURL()) // Operate on the last suburl, not the first 00503 { 00504 KURL::List lst = split( _u ); 00505 KURL u(lst.last(), _rel_url, encoding_hint); 00506 lst.remove( lst.last() ); 00507 lst.append( u ); 00508 *this = join( lst ); 00509 return; 00510 } 00511 // WORKAROUND THE RFC 1606 LOOPHOLE THAT ALLOWS 00512 // http:/index.html AS A VALID SYNTAX FOR RELATIVE 00513 // URLS. ( RFC 2396 section 5.2 item # 3 ) 00514 QString rUrl = _rel_url; 00515 int len = _u.m_strProtocol.length(); 00516 if ( !_u.m_strHost.isEmpty() && !rUrl.isEmpty() && 00517 rUrl.find( _u.m_strProtocol, 0, false ) == 0 && 00518 rUrl[len] == ':' && (rUrl[len+1] != '/' || 00519 (rUrl[len+1] == '/' && rUrl[len+2] != '/')) ) 00520 { 00521 rUrl.remove( 0, rUrl.find( ':' ) + 1 ); 00522 } 00523 00524 if ( rUrl.isEmpty() ) 00525 { 00526 *this = _u; 00527 } 00528 else if ( rUrl[0] == '#' ) 00529 { 00530 *this = _u; 00531 QString ref = decode(rUrl.mid(1), encoding_hint); 00532 if ( ref.isNull() ) 00533 ref = ""; // we know there was an (empty) html ref, we saw the '#' 00534 setHTMLRef( ref ); 00535 } 00536 else if ( isRelativeURL( rUrl) ) 00537 { 00538 *this = _u; 00539 m_strQuery_encoded = QString::null; 00540 m_strRef_encoded = QString::null; 00541 if ( rUrl[0] == '/') 00542 { 00543 if ((rUrl.length() > 1) && (rUrl[1] == '/')) 00544 { 00545 m_strHost = QString::null; 00546 } 00547 m_strPath = QString::null; 00548 m_strPath_encoded = QString::null; 00549 } 00550 else if ( rUrl[0] != '?' ) 00551 { 00552 int pos = m_strPath.findRev( '/' ); 00553 if (pos >= 0) 00554 m_strPath.truncate(pos); 00555 m_strPath += '/'; 00556 if (!m_strPath_encoded.isEmpty()) 00557 { 00558 pos = m_strPath_encoded.findRev( '/' ); 00559 if (pos >= 0) 00560 m_strPath_encoded.truncate(pos); 00561 m_strPath_encoded += '/'; 00562 } 00563 } 00564 else 00565 { 00566 if ( m_strPath.isEmpty() ) 00567 m_strPath = '/'; 00568 } 00569 KURL tmp( url() + rUrl, encoding_hint); 00570 *this = tmp; 00571 cleanPath(false); 00572 } 00573 else 00574 { 00575 KURL tmp( rUrl, encoding_hint); 00576 *this = tmp; 00577 // Preserve userinfo if applicable. 00578 if (!_u.m_strUser.isEmpty() && m_strUser.isEmpty() && (_u.m_strHost == m_strHost) && (_u.m_strProtocol == m_strProtocol)) 00579 { 00580 m_strUser = _u.m_strUser; 00581 m_strPass = _u.m_strPass; 00582 } 00583 cleanPath(false); 00584 } 00585 } 00586 00587 void KURL::reset() 00588 { 00589 m_strProtocol = QString::null; 00590 m_strUser = QString::null; 00591 m_strPass = QString::null; 00592 m_strHost = QString::null; 00593 m_strPath = QString::null; 00594 m_strPath_encoded = QString::null; 00595 m_strQuery_encoded = QString::null; 00596 m_strRef_encoded = QString::null; 00597 m_bIsMalformed = true; 00598 m_iPort = 0; 00599 m_iUriMode = Auto; 00600 } 00601 00602 bool KURL::isEmpty() const 00603 { 00604 return (m_strPath.isEmpty() && m_strProtocol.isEmpty()); 00605 } 00606 00607 void KURL::parse( const QString& _url, int encoding_hint ) 00608 { 00609 if ( _url.isEmpty() || m_iUriMode == Invalid ) 00610 { 00611 m_strProtocol = _url; 00612 m_iUriMode = Invalid; 00613 return; 00614 } 00615 00616 const QChar* buf = _url.unicode(); 00617 const QChar* orig = buf; 00618 uint len = _url.length(); 00619 uint pos = 0; 00620 00621 // Node 1: Accept alpha or slash 00622 QChar x = buf[pos++]; 00623 if ( x == '/' ) 00624 { 00625 // A slash means we immediately proceed to parse it as a file URL. 00626 m_iUriMode = URL; 00627 m_strProtocol = fileProt; 00628 parseURL( _url, encoding_hint ); 00629 return; 00630 } 00631 if ( !isalpha( (int)x ) ) 00632 goto NodeErr; 00633 00634 // Node 2: Accept any amount of (alpha|digit|'+'|'-') 00635 // '.' is not currently accepted, because current KURL may be confused. 00636 // Proceed with :// :/ or : 00637 while( pos < len && (isalpha((int)buf[pos]) || isdigit((int)buf[pos]) || 00638 buf[pos] == '+' || buf[pos] == '-')) pos++; 00639 00640 if (pos < len && buf[pos] == ':' ) 00641 { 00642 m_strProtocol = QString( orig, pos ).lower(); 00643 if ( m_iUriMode == Auto ) 00644 m_iUriMode = uriModeForProtocol( m_strProtocol ); 00645 // Proceed to correct parse function. 00646 switch ( m_iUriMode ) 00647 { 00648 case RawURI: 00649 parseRawURI( _url ); 00650 return; 00651 case Mailto: 00652 parseMailto( _url ); 00653 return; 00654 case URL: 00655 parseURL( _url, encoding_hint ); 00656 return; 00657 default: 00658 // Unknown URI mode results in an invalid URI. 00659 break; 00660 } 00661 } 00662 00663 NodeErr: 00664 reset(); 00665 m_strProtocol = _url; 00666 m_iUriMode = Invalid; 00667 } 00668 00669 void KURL::parseRawURI( const QString& _url, int encoding_hint ) 00670 { 00671 uint len = _url.length(); 00672 const QChar* buf = _url.unicode(); 00673 00674 uint pos = 0; 00675 00676 // Accept any amount of (alpha|digit|'+'|'-') 00677 // '.' is not currently accepted, because current KURL may be confused. 00678 // Proceed with : 00679 while( pos < len && (isalpha((int)buf[pos]) || isdigit((int)buf[pos]) || 00680 buf[pos] == '+' || buf[pos] == '-')) pos++; 00681 00682 // Note that m_strProtocol is already set here, so we just skip over the protocol. 00683 if (pos < len && buf[pos] == ':' ) 00684 pos++; 00685 else { 00686 reset(); 00687 m_strProtocol = _url; 00688 m_iUriMode = Invalid; 00689 return; 00690 } 00691 00692 if ( pos == len ) 00693 m_strPath = QString::null; 00694 else 00695 m_strPath = decode( QString( buf + pos, len - pos ), encoding_hint ); 00696 00697 m_bIsMalformed = false; 00698 00699 return; 00700 } 00701 00702 void KURL::parseMailto( const QString& _url, int encoding_hint ) 00703 { 00704 parseURL( _url, encoding_hint); 00705 if ( m_bIsMalformed ) 00706 return; 00707 QRegExp mailre("(.+@)(.+)"); 00708 if ( mailre.exactMatch( m_strPath ) ) 00709 { 00710 #ifndef KDE_QT_ONLY 00711 QString host = KIDNA::toUnicode( mailre.cap( 2 ) ); 00712 if (host.isEmpty()) 00713 host = mailre.cap( 2 ).lower(); 00714 #else 00715 QString host = mailre.cap( 2 ).lower(); 00716 #endif 00717 m_strPath = mailre.cap( 1 ) + host; 00718 } 00719 } 00720 00721 void KURL::parseURL( const QString& _url, int encoding_hint ) 00722 { 00723 QString port; 00724 bool badHostName = false; 00725 int start = 0; 00726 uint len = _url.length(); 00727 const QChar* buf = _url.unicode(); 00728 00729 QChar delim; 00730 QString tmp; 00731 00732 uint pos = 0; 00733 00734 // Node 1: Accept alpha or slash 00735 QChar x = buf[pos++]; 00736 if ( x == '/' ) 00737 goto Node9; 00738 if ( !isalpha( (int)x ) ) 00739 goto NodeErr; 00740 00741 // Node 2: Accept any amount of (alpha|digit|'+'|'-') 00742 // '.' is not currently accepted, because current KURL may be confused. 00743 // Proceed with :// :/ or : 00744 while( pos < len && (isalpha((int)buf[pos]) || isdigit((int)buf[pos]) || 00745 buf[pos] == '+' || buf[pos] == '-')) pos++; 00746 00747 // Note that m_strProtocol is already set here, so we just skip over the protocol. 00748 if ( pos+2 < len && buf[pos] == ':' && buf[pos+1] == '/' && buf[pos+2] == '/' ) 00749 { 00750 pos += 3; 00751 } 00752 else if (pos+1 < len && buf[pos] == ':' ) // Need to always compare length()-1 otherwise KURL passes "http:" as legal!! 00753 { 00754 pos++; 00755 start = pos; 00756 goto Node9; 00757 } 00758 else 00759 goto NodeErr; 00760 00761 //Node 3: We need at least one character here 00762 if ( pos == len ) 00763 goto NodeErr; 00764 start = pos; 00765 00766 // Node 4: Accept any amount of characters. 00767 if (buf[pos] == '[') // An IPv6 host follows. 00768 goto Node8; 00769 // Terminate on / or @ or ? or # or " or ; or < 00770 x = buf[pos]; 00771 while( (x != ':') && (x != '@') && (x != '/') && (x != '?') && (x != '#') ) 00772 { 00773 if ((x == '\"') || (x == ';') || (x == '<')) 00774 badHostName = true; 00775 if (++pos == len) 00776 break; 00777 x = buf[pos]; 00778 } 00779 if ( pos == len ) 00780 { 00781 if (badHostName) 00782 goto NodeErr; 00783 00784 setHost(decode(QString( buf + start, pos - start ), encoding_hint)); 00785 goto NodeOk; 00786 } 00787 if ( x == '@' ) 00788 { 00789 m_strUser = decode(QString( buf + start, pos - start ), encoding_hint); 00790 pos++; 00791 goto Node7; 00792 } 00793 else if ( (x == '/') || (x == '?') || (x == '#')) 00794 { 00795 if (badHostName) 00796 goto NodeErr; 00797 00798 setHost(decode(QString( buf + start, pos - start ), encoding_hint)); 00799 start = pos; 00800 goto Node9; 00801 } 00802 else if ( x != ':' ) 00803 goto NodeErr; 00804 m_strUser = decode(QString( buf + start, pos - start ), encoding_hint); 00805 pos++; 00806 00807 // Node 5: We need at least one character 00808 if ( pos == len ) 00809 goto NodeErr; 00810 start = pos++; 00811 00812 // Node 6: Read everything until @, /, ? or # 00813 while( (pos < len) && 00814 (buf[pos] != '@') && 00815 (buf[pos] != '/') && 00816 (buf[pos] != '?') && 00817 (buf[pos] != '#')) pos++; 00818 // If we now have a '@' the ':' seperates user and password. 00819 // Otherwise it seperates host and port. 00820 if ( (pos == len) || (buf[pos] != '@') ) 00821 { 00822 // Ok the : was used to separate host and port 00823 if (badHostName) 00824 goto NodeErr; 00825 setHost(m_strUser); 00826 m_strUser = QString::null; 00827 QString tmp( buf + start, pos - start ); 00828 char *endptr; 00829 m_iPort = (unsigned short int)strtol(tmp.ascii(), &endptr, 10); 00830 if ((pos == len) && (strlen(endptr) == 0)) 00831 goto NodeOk; 00832 // there is more after the digits 00833 pos -= strlen(endptr); 00834 if ((buf[pos] != '@') && 00835 (buf[pos] != '/') && 00836 (buf[pos] != '?') && 00837 (buf[pos] != '#')) 00838 goto NodeErr; 00839 00840 start = pos; 00841 goto Node9; 00842 } 00843 m_strPass = decode(QString( buf + start, pos - start), encoding_hint); 00844 pos++; 00845 00846 // Node 7: We need at least one character 00847 Node7: 00848 if ( pos == len ) 00849 goto NodeErr; 00850 00851 Node8: 00852 if (buf[pos] == '[') 00853 { 00854 // IPv6 address 00855 start = ++pos; // Skip '[' 00856 00857 if (pos == len) 00858 { 00859 badHostName = true; 00860 goto NodeErr; 00861 } 00862 // Node 8a: Read everything until ] or terminate 00863 badHostName = false; 00864 x = buf[pos]; 00865 while( (x != ']') ) 00866 { 00867 if ((x == '\"') || (x == ';') || (x == '<')) 00868 badHostName = true; 00869 if (++pos == len) 00870 { 00871 badHostName = true; 00872 break; 00873 } 00874 x = buf[pos]; 00875 } 00876 if (badHostName) 00877 goto NodeErr; 00878 setHost(decode(QString( buf + start, pos - start ), encoding_hint)); 00879 if (pos < len) pos++; // Skip ']' 00880 if (pos == len) 00881 goto NodeOk; 00882 } 00883 else 00884 { 00885 // Non IPv6 address, with a user 00886 start = pos; 00887 00888 // Node 8b: Read everything until / : or terminate 00889 badHostName = false; 00890 x = buf[pos]; 00891 while( (x != ':') && (x != '@') && (x != '/') && (x != '?') && (x != '#') ) 00892 { 00893 if ((x == '\"') || (x == ';') || (x == '<')) 00894 badHostName = true; 00895 if (++pos == len) 00896 break; 00897 x = buf[pos]; 00898 } 00899 if (badHostName) 00900 goto NodeErr; 00901 if ( pos == len ) 00902 { 00903 setHost(decode(QString( buf + start, pos - start ), encoding_hint)); 00904 goto NodeOk; 00905 } 00906 setHost(decode(QString( buf + start, pos - start ), encoding_hint)); 00907 } 00908 x = buf[pos]; 00909 if ( x == '/' || x == '#' || x == '?' ) 00910 { 00911 start = pos; 00912 goto Node9; 00913 } 00914 else if ( x != ':' ) 00915 goto NodeErr; 00916 pos++; 00917 00918 // Node 8c: Accept at least one digit 00919 if ( pos == len ) 00920 goto NodeErr; 00921 start = pos; 00922 if ( !isdigit( buf[pos++] ) ) 00923 goto NodeErr; 00924 00925 // Node 8d: Accept any amount of digits 00926 while( pos < len && isdigit( buf[pos] ) ) pos++; 00927 port = QString( buf + start, pos - start ); 00928 m_iPort = port.toUShort(); 00929 if ( pos == len ) 00930 goto NodeOk; 00931 start = pos; 00932 00933 Node9: // parse path until query or reference reached 00934 00935 while( pos < len && buf[pos] != '#' && buf[pos]!='?' ) pos++; 00936 00937 tmp = QString( buf + start, pos - start ); 00938 //kdDebug(126)<<" setting encoded path to:"<<tmp<<endl; 00939 setEncodedPath( tmp, encoding_hint ); 00940 00941 if ( pos == len ) 00942 goto NodeOk; 00943 00944 //Node10: // parse query or reference depending on what comes first 00945 delim = (buf[pos++]=='#'?'?':'#'); 00946 00947 start = pos; 00948 00949 while(pos < len && buf[pos]!=delim ) pos++; 00950 00951 tmp = QString(buf + start, pos - start); 00952 if (delim=='#') 00953 _setQuery(tmp, encoding_hint); 00954 else 00955 m_strRef_encoded = tmp; 00956 00957 if (pos == len) 00958 goto NodeOk; 00959 00960 //Node11: // feed the rest into the remaining variable 00961 tmp = QString( buf + pos + 1, len - pos - 1); 00962 if (delim == '#') 00963 m_strRef_encoded = tmp; 00964 else 00965 _setQuery(tmp, encoding_hint); 00966 00967 NodeOk: 00968 //kdDebug(126)<<"parsing finished. m_strProtocol="<<m_strProtocol<<" m_strHost="<<m_strHost<<" m_strPath="<<m_strPath<<endl; 00969 m_bIsMalformed = false; // Valid URL 00970 00971 //kdDebug()<<"Prot="<<m_strProtocol<<"\nUser="<<m_strUser<<"\nPass="<<m_strPass<<"\nHost="<<m_strHost<<"\nPath="<<m_strPath<<"\nQuery="<<m_strQuery_encoded<<"\nRef="<<m_strRef_encoded<<"\nPort="<<m_iPort<<endl; 00972 if (m_strProtocol.isEmpty()) 00973 { 00974 m_iUriMode = URL; 00975 m_strProtocol = fileProt; 00976 } 00977 return; 00978 00979 NodeErr: 00980 // kdDebug(126) << "KURL couldn't parse URL \"" << _url << "\"" << endl; 00981 reset(); 00982 m_strProtocol = _url; 00983 m_iUriMode = Invalid; 00984 } 00985 00986 KURL& KURL::operator=( const QString& _url ) 00987 { 00988 reset(); 00989 parse( _url ); 00990 00991 return *this; 00992 } 00993 00994 KURL& KURL::operator=( const char * _url ) 00995 { 00996 reset(); 00997 parse( QString::fromLatin1(_url) ); 00998 00999 return *this; 01000 } 01001 01002 #ifndef QT_NO_NETWORKPROTOCOL 01003 KURL& KURL::operator=( const QUrl & u ) 01004 { 01005 m_strProtocol = u.protocol(); 01006 m_iUriMode = Auto; 01007 m_strUser = u.user(); 01008 m_strPass = u.password(); 01009 m_strHost = u.host(); 01010 m_strPath = u.path( false ); 01011 m_strPath_encoded = QString::null; 01012 m_strQuery_encoded = u.query(); 01013 m_strRef_encoded = u.ref(); 01014 m_bIsMalformed = !u.isValid(); 01015 m_iPort = u.port(); 01016 01017 return *this; 01018 } 01019 #endif 01020 01021 KURL& KURL::operator=( const KURL& _u ) 01022 { 01023 m_strProtocol = _u.m_strProtocol; 01024 m_strUser = _u.m_strUser; 01025 m_strPass = _u.m_strPass; 01026 m_strHost = _u.m_strHost; 01027 m_strPath = _u.m_strPath; 01028 m_strPath_encoded = _u.m_strPath_encoded; 01029 m_strQuery_encoded = _u.m_strQuery_encoded; 01030 m_strRef_encoded = _u.m_strRef_encoded; 01031 m_bIsMalformed = _u.m_bIsMalformed; 01032 m_iPort = _u.m_iPort; 01033 m_iUriMode = _u.m_iUriMode; 01034 01035 return *this; 01036 } 01037 01038 bool KURL::operator<( const KURL& _u) const 01039 { 01040 int i; 01041 if (!_u.isValid()) 01042 { 01043 if (!isValid()) 01044 { 01045 i = m_strProtocol.compare(_u.m_strProtocol); 01046 return (i < 0); 01047 } 01048 return false; 01049 } 01050 if (!isValid()) 01051 return true; 01052 01053 i = m_strProtocol.compare(_u.m_strProtocol); 01054 if (i) return (i < 0); 01055 01056 i = m_strHost.compare(_u.m_strHost); 01057 if (i) return (i < 0); 01058 01059 if (m_iPort != _u.m_iPort) return (m_iPort < _u.m_iPort); 01060 01061 i = m_strPath.compare(_u.m_strPath); 01062 if (i) return (i < 0); 01063 01064 i = m_strQuery_encoded.compare(_u.m_strQuery_encoded); 01065 if (i) return (i < 0); 01066 01067 i = m_strRef_encoded.compare(_u.m_strRef_encoded); 01068 if (i) return (i < 0); 01069 01070 i = m_strUser.compare(_u.m_strUser); 01071 if (i) return (i < 0); 01072 01073 i = m_strPass.compare(_u.m_strPass); 01074 if (i) return (i < 0); 01075 01076 return false; 01077 } 01078 01079 bool KURL::operator==( const KURL& _u ) const 01080 { 01081 if ( !isValid() || !_u.isValid() ) 01082 return false; 01083 01084 if ( m_strProtocol == _u.m_strProtocol && 01085 m_strUser == _u.m_strUser && 01086 m_strPass == _u.m_strPass && 01087 m_strHost == _u.m_strHost && 01088 m_strPath == _u.m_strPath && 01089 // The encoded path may be null, but the URLs are still equal (David) 01090 ( m_strPath_encoded.isNull() || _u.m_strPath_encoded.isNull() || 01091 m_strPath_encoded == _u.m_strPath_encoded ) && 01092 m_strQuery_encoded == _u.m_strQuery_encoded && 01093 m_strRef_encoded == _u.m_strRef_encoded && 01094 m_iPort == _u.m_iPort ) 01095 { 01096 return true; 01097 } 01098 01099 return false; 01100 } 01101 01102 bool KURL::operator==( const QString& _u ) const 01103 { 01104 KURL u( _u ); 01105 return ( *this == u ); 01106 } 01107 01108 bool KURL::cmp( const KURL &u, bool ignore_trailing ) const 01109 { 01110 return equals( u, ignore_trailing ); 01111 } 01112 01113 bool KURL::equals( const KURL &_u, bool ignore_trailing ) const 01114 { 01115 if ( !isValid() || !_u.isValid() ) 01116 return false; 01117 01118 if ( ignore_trailing ) 01119 { 01120 QString path1 = path(1); 01121 QString path2 = _u.path(1); 01122 if ( path1 != path2 ) 01123 return false; 01124 01125 if ( m_strProtocol == _u.m_strProtocol && 01126 m_strUser == _u.m_strUser && 01127 m_strPass == _u.m_strPass && 01128 m_strHost == _u.m_strHost && 01129 m_strQuery_encoded == _u.m_strQuery_encoded && 01130 m_strRef_encoded == _u.m_strRef_encoded && 01131 m_iPort == _u.m_iPort ) 01132 return true; 01133 01134 return false; 01135 } 01136 01137 return ( *this == _u ); 01138 } 01139 01140 bool KURL::isParentOf( const KURL& _u ) const 01141 { 01142 if ( !isValid() || !_u.isValid() ) 01143 return false; 01144 01145 if ( m_strProtocol == _u.m_strProtocol && 01146 m_strUser == _u.m_strUser && 01147 m_strPass == _u.m_strPass && 01148 m_strHost == _u.m_strHost && 01149 m_strQuery_encoded == _u.m_strQuery_encoded && 01150 m_strRef_encoded == _u.m_strRef_encoded && 01151 m_iPort == _u.m_iPort ) 01152 { 01153 if ( path().isEmpty() || _u.path().isEmpty() ) 01154 return false; // can't work with implicit paths 01155 01156 QString p1( cleanpath( path(), true, false ) ); 01157 if ( p1[p1.length()-1] != '/' ) 01158 p1 += '/'; 01159 QString p2( cleanpath( _u.path(), true, false ) ); 01160 if ( p2[p2.length()-1] != '/' ) 01161 p2 += '/'; 01162 01163 //kdDebug(126) << "p1=" << p1 << endl; 01164 //kdDebug(126) << "p2=" << p2 << endl; 01165 //kdDebug(126) << "p1.length()=" << p1.length() << endl; 01166 //kdDebug(126) << "p2.left(!$)=" << p2.left( p1.length() ) << endl; 01167 return p2.startsWith( p1 ); 01168 } 01169 return false; 01170 } 01171 01172 void KURL::setFileName( const QString& _txt ) 01173 { 01174 m_strRef_encoded = QString::null; 01175 int i = 0; 01176 while( _txt[i] == '/' ) ++i; 01177 QString tmp; 01178 if ( i ) 01179 tmp = _txt.mid( i ); 01180 else 01181 tmp = _txt; 01182 01183 QString path = m_strPath_encoded.isEmpty() ? m_strPath : m_strPath_encoded; 01184 if ( path.isEmpty() ) 01185 path = "/"; 01186 else 01187 { 01188 int lastSlash = path.findRev( '/' ); 01189 if ( lastSlash == -1) 01190 { 01191 // The first character is not a '/' ??? 01192 // This looks strange ... 01193 path = "/"; 01194 } 01195 else if ( path.right(1) != "/" ) 01196 path.truncate( lastSlash+1 ); // keep the "/" 01197 } 01198 if (m_strPath_encoded.isEmpty()) 01199 { 01200 path += tmp; 01201 setPath( path ); 01202 } 01203 else 01204 { 01205 path += encode_string(tmp); 01206 setEncodedPath( path ); 01207 } 01208 cleanPath(); 01209 } 01210 01211 void KURL::cleanPath( bool cleanDirSeparator ) // taken from the old KURL 01212 { 01213 if (m_iUriMode != URL) return; 01214 m_strPath = cleanpath(m_strPath, cleanDirSeparator, false); 01215 // WABA: Is this safe when "/../" is encoded with %? 01216 m_strPath_encoded = cleanpath(m_strPath_encoded, cleanDirSeparator, true); 01217 } 01218 01219 static QString trailingSlash( int _trailing, const QString &path ) 01220 { 01221 QString result = path; 01222 01223 if ( _trailing == 0 ) 01224 return result; 01225 else if ( _trailing == 1 ) 01226 { 01227 int len = result.length(); 01228 if ( (len == 0) || (result[ len - 1 ] != '/') ) 01229 result += "/"; 01230 return result; 01231 } 01232 else if ( _trailing == -1 ) 01233 { 01234 if ( result == "/" ) 01235 return result; 01236 int len = result.length(); 01237 if ( (len != 0) && (result[ len - 1 ] == '/') ) 01238 result.truncate( len - 1 ); 01239 return result; 01240 } 01241 else { 01242 assert( 0 ); 01243 return QString::null; 01244 } 01245 } 01246 01247 void KURL::adjustPath( int _trailing ) 01248 { 01249 if (!m_strPath_encoded.isEmpty()) 01250 { 01251 m_strPath_encoded = trailingSlash( _trailing, m_strPath_encoded ); 01252 } 01253 m_strPath = trailingSlash( _trailing, m_strPath ); 01254 } 01255 01256 01257 QString KURL::encodedPathAndQuery( int _trailing, bool _no_empty_path, int encoding_hint ) const 01258 { 01259 QString tmp; 01260 if (!m_strPath_encoded.isEmpty() && encoding_hint == 0) 01261 { 01262 tmp = trailingSlash( _trailing, m_strPath_encoded ); 01263 } 01264 else 01265 { 01266 tmp = path( _trailing ); 01267 if ( _no_empty_path && tmp.isEmpty() ) 01268 tmp = "/"; 01269 if (m_iUriMode == Mailto) 01270 { 01271 tmp = encode( tmp, 2, encoding_hint ); 01272 } 01273 else 01274 { 01275 tmp = encode( tmp, 1, encoding_hint ); 01276 } 01277 } 01278 01279 // TODO apply encoding_hint to the query 01280 if (!m_strQuery_encoded.isNull()) 01281 tmp += '?' + m_strQuery_encoded; 01282 return tmp; 01283 } 01284 01285 void KURL::setEncodedPath( const QString& _txt, int encoding_hint ) 01286 { 01287 m_strPath_encoded = _txt; 01288 01289 decode( m_strPath_encoded, m_strPath, m_strPath_encoded, encoding_hint ); 01290 // Throw away encoding for local files, makes file-operations faster. 01291 if (m_strProtocol == fileProt) 01292 m_strPath_encoded = QString::null; 01293 01294 if ( m_iUriMode == Auto ) 01295 m_iUriMode = URL; 01296 } 01297 01298 01299 void KURL::setEncodedPathAndQuery( const QString& _txt, int encoding_hint ) 01300 { 01301 int pos = _txt.find( '?' ); 01302 if ( pos == -1 ) 01303 { 01304 setEncodedPath(_txt, encoding_hint); 01305 m_strQuery_encoded = QString::null; 01306 } 01307 else 01308 { 01309 setEncodedPath(_txt.left( pos ), encoding_hint); 01310 _setQuery(_txt.right(_txt.length() - pos - 1), encoding_hint); 01311 } 01312 } 01313 01314 QString KURL::path( int _trailing ) const 01315 { 01316 return trailingSlash( _trailing, path() ); 01317 } 01318 01319 bool KURL::isLocalFile() const 01320 { 01321 if ( (m_strProtocol != fileProt ) || hasSubURL() ) 01322 return false; 01323 01324 if (m_strHost.isEmpty() || (m_strHost == "localhost")) 01325 return true; 01326 01327 char hostname[ 256 ]; 01328 hostname[ 0 ] = '\0'; 01329 if (!gethostname( hostname, 255 )) 01330 hostname[sizeof(hostname)-1] = '\0'; 01331 01332 for(char *p = hostname; *p; p++) 01333 *p = tolower(*p); 01334 01335 return (m_strHost == hostname); 01336 } 01337 01338 void KURL::setFileEncoding(const QString &encoding) 01339 { 01340 if (!isLocalFile()) 01341 return; 01342 01343 QString q = query(); 01344 01345 if (!q.isEmpty() && (q[0] == '?')) 01346 q = q.mid(1); 01347 01348 QStringList args = QStringList::split('&', q); 01349 for(QStringList::Iterator it = args.begin(); 01350 it != args.end();) 01351 { 01352 QString s = decode_string(*it); 01353 if (s.startsWith("charset=")) 01354 it = args.erase(it); 01355 else 01356 ++it; 01357 } 01358 if (!encoding.isEmpty()) 01359 args.append("charset="+encode_string(encoding)); 01360 01361 if (args.isEmpty()) 01362 _setQuery(QString::null); 01363 else 01364 _setQuery(args.join("&")); 01365 } 01366 01367 QString KURL::fileEncoding() const 01368 { 01369 if (!isLocalFile()) 01370 return QString::null; 01371 01372 QString q = query(); 01373 01374 if (q.isEmpty()) 01375 return QString::null; 01376 01377 if (q[0] == '?') 01378 q = q.mid(1); 01379 01380 QStringList args = QStringList::split('&', q); 01381 for(QStringList::ConstIterator it = args.begin(); 01382 it != args.end(); 01383 ++it) 01384 { 01385 QString s = decode_string(*it); 01386 if (s.startsWith("charset=")) 01387 return s.mid(8); 01388 } 01389 return QString::null; 01390 } 01391 01392 bool KURL::hasSubURL() const 01393 { 01394 if ( m_strProtocol.isEmpty() || m_bIsMalformed ) 01395 return false; 01396 if (m_strRef_encoded.isEmpty()) 01397 return false; 01398 if (m_strRef_encoded.startsWith("gzip:")) 01399 return true; 01400 if (m_strRef_encoded.startsWith("bzip:")) 01401 return true; 01402 if (m_strRef_encoded.startsWith("bzip2:")) 01403 return true; 01404 if (m_strRef_encoded.startsWith("tar:")) 01405 return true; 01406 if (m_strRef_encoded.startsWith("ar:")) 01407 return true; 01408 if (m_strRef_encoded.startsWith("zip:")) 01409 return true; 01410 if ( m_strProtocol == "error" ) // anything that starts with error: has suburls 01411 return true; 01412 return false; 01413 } 01414 01415 QString KURL::url( int _trailing, int encoding_hint ) const 01416 { 01417 if( m_bIsMalformed ) 01418 { 01419 // Return the whole url even when the url is 01420 // malformed. Under such conditions the url 01421 // is stored in m_strProtocol. 01422 return m_strProtocol; 01423 } 01424 01425 QString u = m_strProtocol; 01426 if (!u.isEmpty()) 01427 u += ":"; 01428 01429 if ( hasHost() ) 01430 { 01431 u += "//"; 01432 if ( hasUser() ) 01433 { 01434 u += encode(m_strUser, 0, encoding_hint); 01435 if ( hasPass() ) 01436 { 01437 u += ":"; 01438 u += encode(m_strPass, 0, encoding_hint); 01439 } 01440 u += "@"; 01441 } 01442 if ( m_iUriMode == URL ) 01443 { 01444 bool IPv6 = (m_strHost.find(':') != -1); 01445 if (IPv6) 01446 u += '[' + m_strHost + ']'; 01447 else 01448 u += encodeHost(m_strHost, true, encoding_hint); 01449 if ( m_iPort != 0 ) { 01450 QString buffer; 01451 buffer.sprintf( ":%u", m_iPort ); 01452 u += buffer; 01453 } 01454 } 01455 else 01456 { 01457 u += m_strHost; 01458 } 01459 } 01460 01461 if ( m_iUriMode == URL || m_iUriMode == Mailto ) 01462 u += encodedPathAndQuery( _trailing, false, encoding_hint ); 01463 else 01464 u += m_strPath; 01465 01466 if ( hasRef() ) 01467 { 01468 u += "#"; 01469 u += m_strRef_encoded; 01470 } 01471 01472 return u; 01473 } 01474 01475 QString KURL::prettyURL( int _trailing ) const 01476 { 01477 if( m_bIsMalformed ) 01478 { 01479 // Return the whole url even when the url is 01480 // malformed. Under such conditions the url 01481 // is stored in m_strProtocol. 01482 return m_strProtocol; 01483 } 01484 01485 QString u = m_strProtocol; 01486 if (!u.isEmpty()) 01487 u += ":"; 01488 01489 if ( hasHost() ) 01490 { 01491 u += "//"; 01492 if ( hasUser() ) 01493 { 01494 u += lazy_encode(m_strUser); 01495 // Don't show password! 01496 u += "@"; 01497 } 01498 if ( m_iUriMode == URL ) 01499 { 01500 bool IPv6 = (m_strHost.find(':') != -1); 01501 if (IPv6) 01502 { 01503 u += '[' + m_strHost + ']'; 01504 } 01505 else 01506 { 01507 u += lazy_encode(m_strHost); 01508 } 01509 } 01510 else 01511 { 01512 u += lazy_encode(m_strHost); 01513 } 01514 if ( m_iPort != 0 ) { 01515 QString buffer; 01516 buffer.sprintf( ":%u", m_iPort ); 01517 u += buffer; 01518 } 01519 } 01520 01521 if (m_iUriMode == Mailto) 01522 { 01523 u += lazy_encode( m_strPath, false ); 01524 } 01525 else 01526 { 01527 u += trailingSlash( _trailing, lazy_encode( m_strPath ) ); 01528 } 01529 01530 if (!m_strQuery_encoded.isNull()) 01531 u += '?' + m_strQuery_encoded; 01532 01533 if ( hasRef() ) 01534 { 01535 u += "#"; 01536 u += m_strRef_encoded; 01537 } 01538 01539 return u; 01540 } 01541 01542 QString KURL::prettyURL( int _trailing, AdjustementFlags _flags) const 01543 { 01544 QString u = prettyURL(_trailing); 01545 if (_flags & StripFileProtocol && u.startsWith("file:")) 01546 u.remove(0, 5); 01547 return u; 01548 } 01549 01550 QString KURL::htmlURL() const 01551 { 01552 return QStyleSheet::escape(prettyURL()); 01553 } 01554 01555 KURL::List KURL::split( const KURL& _url ) 01556 { 01557 QString ref; 01558 KURL::List lst; 01559 KURL url = _url; 01560 01561 while(true) 01562 { 01563 KURL u = url; 01564 u.m_strRef_encoded = QString::null; 01565 lst.append(u); 01566 if (url.hasSubURL()) 01567 { 01568 url = KURL(url.m_strRef_encoded); 01569 } 01570 else 01571 { 01572 ref = url.m_strRef_encoded; 01573 break; 01574 } 01575 } 01576 01577 // Set HTML ref in all URLs. 01578 KURL::List::Iterator it; 01579 for( it = lst.begin() ; it != lst.end(); ++it ) 01580 { 01581 (*it).m_strRef_encoded = ref; 01582 } 01583 01584 return lst; 01585 } 01586 01587 KURL::List KURL::split( const QString& _url ) 01588 { 01589 return split(KURL(_url)); 01590 } 01591 01592 KURL KURL::join( const KURL::List & lst ) 01593 { 01594 if (lst.isEmpty()) return KURL(); 01595 KURL tmp; 01596 01597 KURL::List::ConstIterator first = lst.fromLast(); 01598 for( KURL::List::ConstIterator it = first; it != lst.end(); --it ) 01599 { 01600 KURL u(*it); 01601 if (it != first) 01602 { 01603 if (!u.m_strRef_encoded) u.m_strRef_encoded = tmp.url(); 01604 else u.m_strRef_encoded += "#" + tmp.url(); // Support more than one suburl thingy 01605 } 01606 tmp = u; 01607 } 01608 01609 return tmp; 01610 } 01611 01612 QString KURL::fileName( bool _strip_trailing_slash ) const 01613 { 01614 QString fname; 01615 if (hasSubURL()) { // If we have a suburl, then return the filename from there 01616 KURL::List list = KURL::split(*this); 01617 KURL::List::Iterator it = list.fromLast(); 01618 return (*it).fileName(_strip_trailing_slash); 01619 } 01620 const QString &path = m_strPath; 01621 01622 int len = path.length(); 01623 if ( len == 0 ) 01624 return fname; 01625 01626 if ( _strip_trailing_slash ) 01627 { 01628 while ( len >= 1 && path[ len - 1 ] == '/' ) 01629 len--; 01630 } 01631 else if ( path[ len - 1 ] == '/' ) 01632 return fname; 01633 01634 // Does the path only consist of '/' characters ? 01635 if ( len == 1 && path[ 0 ] == '/' ) 01636 return fname; 01637 01638 // Skip last n slashes 01639 int n = 1; 01640 if (!m_strPath_encoded.isEmpty()) 01641 { 01642 // This is hairy, we need the last unencoded slash. 01643 // Count in the encoded string how many encoded slashes follow the last 01644 // unencoded one. 01645 int i = m_strPath_encoded.findRev( '/', len - 1 ); 01646 QString fileName_encoded = m_strPath_encoded.mid(i+1); 01647 n += fileName_encoded.contains("%2f", false); 01648 } 01649 int i = len; 01650 do { 01651 i = path.findRev( '/', i - 1 ); 01652 } 01653 while (--n && (i > 0)); 01654 01655 // If ( i == -1 ) => the first character is not a '/' 01656 // So it's some URL like file:blah.tgz, return the whole path 01657 if ( i == -1 ) { 01658 if ( len == (int)path.length() ) 01659 fname = path; 01660 else 01661 // Might get here if _strip_trailing_slash is true 01662 fname = path.left( len ); 01663 } 01664 else 01665 { 01666 fname = path.mid( i + 1, len - i - 1 ); // TO CHECK 01667 } 01668 return fname; 01669 } 01670 01671 void KURL::addPath( const QString& _txt ) 01672 { 01673 if (hasSubURL()) 01674 { 01675 KURL::List lst = split( *this ); 01676 KURL &u = lst.last(); 01677 u.addPath(_txt); 01678 *this = join( lst ); 01679 return; 01680 } 01681 01682 m_strPath_encoded = QString::null; 01683 01684 if ( _txt.isEmpty() ) 01685 return; 01686 01687 int i = 0; 01688 int len = m_strPath.length(); 01689 // Add the trailing '/' if it is missing 01690 if ( _txt[0] != '/' && ( len == 0 || m_strPath[ len - 1 ] != '/' ) ) 01691 m_strPath += "/"; 01692 01693 // No double '/' characters 01694 i = 0; 01695 if ( len != 0 && m_strPath[ len - 1 ] == '/' ) 01696 { 01697 while( _txt[i] == '/' ) 01698 ++i; 01699 } 01700 01701 m_strPath += _txt.mid( i ); 01702 } 01703 01704 QString KURL::directory( bool _strip_trailing_slash_from_result, 01705 bool _ignore_trailing_slash_in_path ) const 01706 { 01707 QString result = m_strPath_encoded.isEmpty() ? m_strPath : m_strPath_encoded; 01708 if ( _ignore_trailing_slash_in_path ) 01709 result = trailingSlash( -1, result ); 01710 01711 if ( result.isEmpty() || result == "/" ) 01712 return result; 01713 01714 int i = result.findRev( "/" ); 01715 // If ( i == -1 ) => the first character is not a '/' 01716 // So it's some URL like file:blah.tgz, with no path 01717 if ( i == -1 ) 01718 return QString::null; 01719 01720 if ( i == 0 ) 01721 { 01722 result = "/"; 01723 return result; 01724 } 01725 01726 if ( _strip_trailing_slash_from_result ) 01727 result = result.left( i ); 01728 else 01729 result = result.left( i + 1 ); 01730 01731 if (!m_strPath_encoded.isEmpty()) 01732 result = decode(result); 01733 01734 return result; 01735 } 01736 01737 01738 bool KURL::cd( const QString& _dir ) 01739 { 01740 if ( _dir.isEmpty() || m_bIsMalformed ) 01741 return false; 01742 01743 if (hasSubURL()) 01744 { 01745 KURL::List lst = split( *this ); 01746 KURL &u = lst.last(); 01747 u.cd(_dir); 01748 *this = join( lst ); 01749 return true; 01750 } 01751 01752 // absolute path ? 01753 if ( _dir[0] == '/' ) 01754 { 01755 m_strPath_encoded = QString::null; 01756 m_strPath = _dir; 01757 setHTMLRef( QString::null ); 01758 m_strQuery_encoded = QString::null; 01759 return true; 01760 } 01761 01762 // Users home directory on the local disk ? 01763 if ( ( _dir[0] == '~' ) && ( m_strProtocol == fileProt )) 01764 { 01765 m_strPath_encoded = QString::null; 01766 m_strPath = QDir::homeDirPath(); 01767 m_strPath += "/"; 01768 m_strPath += _dir.right(m_strPath.length() - 1); 01769 setHTMLRef( QString::null ); 01770 m_strQuery_encoded = QString::null; 01771 return true; 01772 } 01773 01774 // relative path 01775 // we always work on the past of the first url. 01776 // Sub URLs are not touched. 01777 01778 // append '/' if necessary 01779 QString p = path(1); 01780 p += _dir; 01781 p = cleanpath( p, true, false ); 01782 setPath( p ); 01783 01784 setHTMLRef( QString::null ); 01785 m_strQuery_encoded = QString::null; 01786 01787 return true; 01788 } 01789 01790 KURL KURL::upURL( ) const 01791 { 01792 if (!query().isEmpty()) 01793 { 01794 KURL u(*this); 01795 u._setQuery(QString::null); 01796 return u; 01797 }; 01798 01799 if (!hasSubURL()) 01800 { 01801 KURL u(*this); 01802 u.cd("../"); 01803 return u; 01804 } 01805 01806 // We have a subURL. 01807 KURL::List lst = split( *this ); 01808 if (lst.isEmpty()) 01809 return KURL(); // Huh? 01810 while (true) 01811 { 01812 KURL &u = lst.last(); 01813 QString old = u.path(); 01814 u.cd("../"); 01815 if (u.path() != old) 01816 break; // Finshed. 01817 if (lst.count() == 1) 01818 break; // Finished. 01819 lst.remove(lst.fromLast()); 01820 } 01821 return join( lst ); 01822 } 01823 01824 QString KURL::htmlRef() const 01825 { 01826 if ( !hasSubURL() ) 01827 { 01828 return decode( ref() ); 01829 } 01830 01831 List lst = split( *this ); 01832 return decode( (*lst.begin()).ref() ); 01833 } 01834 01835 QString KURL::encodedHtmlRef() const 01836 { 01837 if ( !hasSubURL() ) 01838 { 01839 return ref(); 01840 } 01841 01842 List lst = split( *this ); 01843 return (*lst.begin()).ref(); 01844 } 01845 01846 void KURL::setHTMLRef( const QString& _ref ) 01847 { 01848 if ( !hasSubURL() ) 01849 { 01850 m_strRef_encoded = encode( _ref, 0, 0 /*?*/); 01851 return; 01852 } 01853 01854 List lst = split( *this ); 01855 01856 (*lst.begin()).setRef( encode( _ref, 0, 0 /*?*/) ); 01857 01858 *this = join( lst ); 01859 } 01860 01861 bool KURL::hasHTMLRef() const 01862 { 01863 if ( !hasSubURL() ) 01864 { 01865 return hasRef(); 01866 } 01867 01868 List lst = split( *this ); 01869 return (*lst.begin()).hasRef(); 01870 } 01871 01872 void 01873 KURL::setProtocol( const QString& _txt ) 01874 { 01875 m_strProtocol = _txt; 01876 if ( m_iUriMode == Auto ) m_iUriMode = uriModeForProtocol( m_strProtocol ); 01877 m_bIsMalformed = false; 01878 } 01879 01880 void 01881 KURL::setUser( const QString& _txt ) 01882 { 01883 m_strUser = _txt; 01884 } 01885 01886 void 01887 KURL::setPass( const QString& _txt ) 01888 { 01889 m_strPass = _txt; 01890 } 01891 01892 void 01893 KURL::setHost( const QString& _txt ) 01894 { 01895 if ( m_iUriMode == Auto ) 01896 m_iUriMode = URL; 01897 switch ( m_iUriMode ) 01898 { 01899 case URL: 01900 #ifndef KDE_QT_ONLY 01901 m_strHost = KIDNA::toUnicode(_txt); 01902 if (m_strHost.isEmpty()) 01903 m_strHost = _txt.lower(); // Probably an invalid hostname, but... 01904 #else 01905 m_strHost = _txt.lower(); 01906 #endif 01907 break; 01908 default: 01909 m_strHost = _txt; 01910 break; 01911 } 01912 } 01913 01914 void 01915 KURL::setPort( unsigned short int _p ) 01916 { 01917 m_iPort = _p; 01918 } 01919 01920 void KURL::setPath( const QString & path ) 01921 { 01922 if (isEmpty()) 01923 m_bIsMalformed = false; 01924 if (m_strProtocol.isEmpty()) 01925 { 01926 m_strProtocol = fileProt; 01927 } 01928 m_strPath = path; 01929 m_strPath_encoded = QString::null; 01930 if ( m_iUriMode == Auto ) 01931 m_iUriMode = URL; 01932 } 01933 01934 void KURL::setDirectory( const QString &dir) 01935 { 01936 if ( dir.endsWith("/")) 01937 setPath(dir); 01938 else 01939 setPath(dir+"/"); 01940 } 01941 01942 void KURL::setQuery( const QString &_txt, int encoding_hint) 01943 { 01944 if (_txt[0] == '?') 01945 _setQuery( _txt.mid(1), encoding_hint ); 01946 else 01947 _setQuery( _txt, encoding_hint ); 01948 } 01949 01950 // This is a private function that expects a query without '?' 01951 void KURL::_setQuery( const QString &_txt, int encoding_hint) 01952 { 01953 m_strQuery_encoded = _txt; 01954 if (!_txt.length()) 01955 return; 01956 01957 int l = m_strQuery_encoded.length(); 01958 int i = 0; 01959 QString result; 01960 while (i < l) 01961 { 01962 int s = i; 01963 // Re-encode. Break encoded string up according to the reserved 01964 // characters '&:;=/?' and re-encode part by part. 01965 while(i < l) 01966 { 01967 char c = m_strQuery_encoded[i].latin1(); 01968 if ((c == '&') || (c == ':') || (c == ';') || 01969 (c == '=') || (c == '/') || (c == '?')) 01970 break; 01971 i++; 01972 } 01973 if (i > s) 01974 { 01975 QString tmp = m_strQuery_encoded.mid(s, i-s); 01976 QString newTmp; 01977 decode( tmp, newTmp, tmp, encoding_hint, false ); 01978 result += tmp; 01979 } 01980 if (i < l) 01981 { 01982 result += m_strQuery_encoded[i]; 01983 i++; 01984 } 01985 } 01986 m_strQuery_encoded = result; 01987 } 01988 01989 QString KURL::query() const 01990 { 01991 if (m_strQuery_encoded.isNull()) 01992 return QString::null; 01993 return '?'+m_strQuery_encoded; 01994 } 01995 01996 QString KURL::decode_string(const QString &str, int encoding_hint) 01997 { 01998 return decode(str, encoding_hint); 01999 } 02000 02001 QString KURL::encode_string(const QString &str, int encoding_hint) 02002 { 02003 return encode(str, 1, encoding_hint); 02004 } 02005 02006 QString KURL::encode_string_no_slash(const QString &str, int encoding_hint) 02007 { 02008 return encode(str, 0, encoding_hint); 02009 } 02010 02011 bool urlcmp( const QString& _url1, const QString& _url2 ) 02012 { 02013 // Both empty ? 02014 if ( _url1.isEmpty() && _url2.isEmpty() ) 02015 return true; 02016 // Only one empty ? 02017 if ( _url1.isEmpty() || _url2.isEmpty() ) 02018 return false; 02019 02020 KURL::List list1 = KURL::split( _url1 ); 02021 KURL::List list2 = KURL::split( _url2 ); 02022 02023 // Malformed ? 02024 if ( list1.isEmpty() || list2.isEmpty() ) 02025 return false; 02026 02027 return ( list1 == list2 ); 02028 } 02029 02030 bool urlcmp( const QString& _url1, const QString& _url2, bool _ignore_trailing, bool _ignore_ref ) 02031 { 02032 // Both empty ? 02033 if ( _url1.isEmpty() && _url2.isEmpty() ) 02034 return true; 02035 // Only one empty ? 02036 if ( _url1.isEmpty() || _url2.isEmpty() ) 02037 return false; 02038 02039 KURL::List list1 = KURL::split( _url1 ); 02040 KURL::List list2 = KURL::split( _url2 ); 02041 02042 // Malformed ? 02043 if ( list1.isEmpty() || list2.isEmpty() ) 02044 return false; 02045 02046 unsigned int size = list1.count(); 02047 if ( list2.count() != size ) 02048 return false; 02049 02050 if ( _ignore_ref ) 02051 { 02052 (*list1.begin()).setRef(QString::null); 02053 (*list2.begin()).setRef(QString::null); 02054 } 02055 02056 KURL::List::Iterator it1 = list1.begin(); 02057 KURL::List::Iterator it2 = list2.begin(); 02058 for( ; it1 != list1.end() ; ++it1, ++it2 ) 02059 if ( !(*it1).equals( *it2, _ignore_trailing ) ) 02060 return false; 02061 02062 return true; 02063 } 02064 02065 QMap< QString, QString > KURL::queryItems( int options ) const { 02066 return queryItems(options, 0); 02067 } 02068 02069 QMap< QString, QString > KURL::queryItems( int options, int encoding_hint ) const { 02070 if ( m_strQuery_encoded.isEmpty() ) 02071 return QMap<QString,QString>(); 02072 02073 QMap< QString, QString > result; 02074 QStringList items = QStringList::split( '&', m_strQuery_encoded ); 02075 for ( QStringList::const_iterator it = items.begin() ; it != items.end() ; ++it ) { 02076 int equal_pos = (*it).find( '=' ); 02077 if ( equal_pos > 0 ) { // = is not the first char... 02078 QString name = (*it).left( equal_pos ); 02079 if ( options & CaseInsensitiveKeys ) 02080 name = name.lower(); 02081 QString value = (*it).mid( equal_pos + 1 ); 02082 if ( value.isEmpty() ) 02083 result.insert( name, QString::fromLatin1("") ); 02084 else { 02085 // ### why is decoding name not necessary? 02086 value.replace( '+', ' ' ); // + in queries means space 02087 result.insert( name, decode_string( value, encoding_hint ) ); 02088 } 02089 } else if ( equal_pos < 0 ) { // no = 02090 QString name = (*it); 02091 if ( options & CaseInsensitiveKeys ) 02092 name = name.lower(); 02093 result.insert( name, QString::null ); 02094 } 02095 } 02096 02097 return result; 02098 } 02099 02100 QString KURL::queryItem( const QString& _item ) const 02101 { 02102 return queryItem( _item, 0 ); 02103 } 02104 02105 QString KURL::queryItem( const QString& _item, int encoding_hint ) const 02106 { 02107 QString item = _item + '='; 02108 if ( m_strQuery_encoded.length() <= 1 ) 02109 return QString::null; 02110 02111 QStringList items = QStringList::split( '&', m_strQuery_encoded ); 02112 unsigned int _len = item.length(); 02113 for ( QStringList::ConstIterator it = items.begin(); it != items.end(); ++it ) 02114 { 02115 if ( (*it).startsWith( item ) ) 02116 { 02117 if ( (*it).length() > _len ) 02118 { 02119 QString str = (*it).mid( _len ); 02120 str.replace( '+', ' ' ); // + in queries means space. 02121 return decode_string( str, encoding_hint ); 02122 } 02123 else // empty value 02124 return QString::fromLatin1(""); 02125 } 02126 } 02127 02128 return QString::null; 02129 } 02130 02131 void KURL::removeQueryItem( const QString& _item ) 02132 { 02133 QString item = _item + '='; 02134 if ( m_strQuery_encoded.length() <= 1 ) 02135 return; 02136 02137 QStringList items = QStringList::split( '&', m_strQuery_encoded ); 02138 for ( QStringList::Iterator it = items.begin(); it != items.end(); ) 02139 { 02140 if ( (*it).startsWith( item ) || (*it == _item) ) 02141 { 02142 QStringList::Iterator deleteIt = it; 02143 ++it; 02144 items.remove(deleteIt); 02145 } 02146 else 02147 { 02148 ++it; 02149 } 02150 } 02151 m_strQuery_encoded = items.join( "&" ); 02152 } 02153 02154 void KURL::addQueryItem( const QString& _item, const QString& _value, int encoding_hint ) 02155 { 02156 QString item = _item + '='; 02157 QString value = encode( _value, 0, encoding_hint ); 02158 02159 if (!m_strQuery_encoded.isEmpty()) 02160 m_strQuery_encoded += '&'; 02161 m_strQuery_encoded += item + value; 02162 } 02163 02164 // static 02165 KURL KURL::fromPathOrURL( const QString& text ) 02166 { 02167 if ( text.isEmpty() ) 02168 return KURL(); 02169 02170 KURL url; 02171 if ( text[0] == '/' ) 02172 url.setPath( text ); 02173 else 02174 url = text; 02175 02176 return url; 02177 } 02178 02179 static QString _relativePath(const QString &base_dir, const QString &path, bool &isParent) 02180 { 02181 QString _base_dir(QDir::cleanDirPath(base_dir)); 02182 QString _path(QDir::cleanDirPath(path.isEmpty() || (path[0] != '/') ? _base_dir+"/"+path : path)); 02183 02184 if (_base_dir.isEmpty()) 02185 return _path; 02186 02187 if (_base_dir[_base_dir.length()-1] != '/') 02188 _base_dir.append('/'); 02189 02190 QStringList list1 = QStringList::split('/', _base_dir); 02191 QStringList list2 = QStringList::split('/', _path); 02192 02193 // Find where they meet 02194 uint level = 0; 02195 uint maxLevel = QMIN(list1.count(), list2.count()); 02196 while((level < maxLevel) && (list1[level] == list2[level])) level++; 02197 02198 QString result; 02199 // Need to go down out of the first path to the common branch. 02200 for(uint i = level; i < list1.count(); i++) 02201 result.append("../"); 02202 02203 // Now up up from the common branch to the second path. 02204 for(uint i = level; i < list2.count(); i++) 02205 result.append(list2[i]).append("/"); 02206 02207 if ((level < list2.count()) && (path[path.length()-1] != '/')) 02208 result.truncate(result.length()-1); 02209 02210 isParent = (level == list1.count()); 02211 02212 return result; 02213 } 02214 02215 QString KURL::relativePath(const QString &base_dir, const QString &path, bool *isParent) 02216 { 02217 bool parent = false; 02218 QString result = _relativePath(base_dir, path, parent); 02219 if (parent) 02220 result.prepend("./"); 02221 02222 if (isParent) 02223 *isParent = parent; 02224 02225 return result; 02226 } 02227 02228 02229 QString KURL::relativeURL(const KURL &base_url, const KURL &url, int encoding_hint) 02230 { 02231 if ((url.protocol() != base_url.protocol()) || 02232 (url.host() != base_url.host()) || 02233 (url.port() && url.port() != base_url.port()) || 02234 (url.hasUser() && url.user() != base_url.user()) || 02235 (url.hasPass() && url.pass() != base_url.pass())) 02236 { 02237 return url.url(0, encoding_hint); 02238 } 02239 02240 QString relURL; 02241 02242 if ((base_url.path() != url.path()) || (base_url.query() != url.query())) 02243 { 02244 bool dummy; 02245 QString basePath = base_url.directory(false, false); 02246 relURL = encode( _relativePath(basePath, url.path(), dummy), 1, encoding_hint); 02247 relURL += url.query(); 02248 } 02249 02250 if ( url.hasRef() ) 02251 { 02252 relURL += "#"; 02253 relURL += url.ref(); 02254 } 02255 02256 if ( relURL.isEmpty() ) 02257 return "./"; 02258 02259 return relURL; 02260 } 02261 02262 int KURL::uriMode() const 02263 { 02264 return m_iUriMode; 02265 } 02266 02267 KURL::URIMode KURL::uriModeForProtocol(const QString& protocol) 02268 { 02269 #ifndef KDE_QT_ONLY 02270 KURL::URIMode mode = Auto; 02271 if (KGlobal::_instance) 02272 mode = KProtocolInfo::uriParseMode(protocol); 02273 if (mode == Auto ) { 02274 #else 02275 KURL::URIMode mode = Auto; 02276 #endif 02277 if ( protocol == "ed2k" || protocol == "sig2dat" || protocol == "slsk" || protocol == "data" ) mode = RawURI; 02278 else if ( protocol == "mailto" ) mode = Mailto; 02279 else mode = URL; 02280 #ifndef KDE_QT_ONLY 02281 } 02282 #endif 02283 return mode; 02284 }
KDE Logo
This file is part of the documentation for kdecore Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Aug 20 09:48:27 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003