kabc Library API Documentation

ldifconverter.cpp

00001 /* 00002 This file is part of libkabc. 00003 Copyright (c) 2003 Helge Deller <deller@kde.org> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00018 Boston, MA 02111-1307, USA. 00019 */ 00020 00021 00022 /* 00023 Useful links: 00024 - http://tldp.org/HOWTO/LDAP-Implementation-HOWTO/schemas.html 00025 - http://www.faqs.org/rfcs/rfc2849.html 00026 00027 Not yet handled items: 00028 - objectclass microsoftaddressbook 00029 - info, 00030 - initials, 00031 - otherfacsimiletelephonenumber, 00032 - otherpager, 00033 - physicaldeliveryofficename, 00034 */ 00035 00036 #include <qstring.h> 00037 #include <qstringlist.h> 00038 #include <qregexp.h> 00039 #include <qtextstream.h> 00040 00041 #include <klocale.h> 00042 #include <kdebug.h> 00043 #include <kmdcodec.h> 00044 00045 #include "addressee.h" 00046 #include "address.h" 00047 00048 #include "ldif.h" 00049 #include "ldifconverter.h" 00050 #include "vcardconverter.h" 00051 00052 using namespace KABC; 00053 00054 /* generate LDIF stream */ 00055 00056 bool LDIFConverter::addresseeToLDIF( const AddresseeList &addrList, QString &str ) 00057 { 00058 AddresseeList::ConstIterator it; 00059 for ( it = addrList.begin(); it != addrList.end(); ++it ) { 00060 addresseeToLDIF( *it, str ); 00061 } 00062 return true; 00063 } 00064 00065 00066 00067 static void ldif_out( QTextStream &t, QString formatStr, QString value ) 00068 { 00069 if ( value.isEmpty() ) 00070 return; 00071 00072 QCString txt = LDIF::assembleLine( formatStr, value, 72 ); 00073 00074 // write the string 00075 t << QString::fromUtf8(txt) << "\n"; 00076 } 00077 00078 bool LDIFConverter::addresseeToLDIF( const Addressee &addr, QString &str ) 00079 { 00080 if ( addr.isEmpty() ) 00081 return false; 00082 00083 QTextStream t( str, IO_WriteOnly|IO_Append ); 00084 t.setEncoding( QTextStream::UnicodeUTF8 ); 00085 00086 const Address homeAddr = addr.address( Address::Home ); 00087 const Address workAddr = addr.address( Address::Work ); 00088 00089 ldif_out( t, "dn", QString( "cn=%1,mail=%2" ) 00090 .arg( addr.formattedName().simplifyWhiteSpace() ) 00091 .arg( addr.preferredEmail() ) ); 00092 ldif_out( t, "givenname", addr.givenName() ); 00093 ldif_out( t, "sn", addr.familyName() ); 00094 ldif_out( t, "cn", addr.formattedName().simplifyWhiteSpace() ); 00095 ldif_out( t, "uid", addr.uid() ); 00096 ldif_out( t, "nickname", addr.nickName() ); 00097 ldif_out( t, "xmozillanickname", addr.nickName() ); 00098 00099 ldif_out( t, "mail", addr.preferredEmail() ); 00100 if ( addr.emails().count() > 1 ) 00101 ldif_out( t, "mozillasecondemail", addr.emails()[ 1 ] ); 00102 //ldif_out( t, "mozilla_AIMScreenName: %1\n", "screen_name" ); 00103 00104 ldif_out( t, "telephonenumber", addr.phoneNumber( PhoneNumber::Work ).number() ); 00105 ldif_out( t, "facsimiletelephonenumber", addr.phoneNumber( PhoneNumber::Fax ).number() ); 00106 ldif_out( t, "homephone", addr.phoneNumber( PhoneNumber::Home ).number() ); 00107 ldif_out( t, "mobile", addr.phoneNumber( PhoneNumber::Cell ).number() ); // Netscape 7 00108 ldif_out( t, "cellphone", addr.phoneNumber( PhoneNumber::Cell ).number() ); // Netscape 4.x 00109 ldif_out( t, "pager", addr.phoneNumber( PhoneNumber::Pager ).number() ); 00110 ldif_out( t, "pagerphone", addr.phoneNumber( PhoneNumber::Pager ).number() ); 00111 00112 ldif_out( t, "streethomeaddress", homeAddr.street() ); 00113 ldif_out( t, "postalcode", workAddr.postalCode() ); 00114 ldif_out( t, "postofficebox", workAddr.postOfficeBox() ); 00115 00116 QStringList streets = QStringList::split( '\n', homeAddr.street() ); 00117 if ( streets.count() > 0 ) 00118 ldif_out( t, "homepostaladdress", streets[ 0 ] ); // Netscape 7 00119 if ( streets.count() > 1 ) 00120 ldif_out( t, "mozillahomepostaladdress2", streets[ 1 ] ); // Netscape 7 00121 ldif_out( t, "mozillahomelocalityname", homeAddr.locality() ); // Netscape 7 00122 ldif_out( t, "mozillahomestate", homeAddr.region() ); 00123 ldif_out( t, "mozillahomepostalcode", homeAddr.postalCode() ); 00124 ldif_out( t, "mozillahomecountryname", Address::ISOtoCountry(homeAddr.country()) ); 00125 ldif_out( t, "locality", workAddr.locality() ); 00126 ldif_out( t, "streetaddress", workAddr.street() ); // Netscape 4.x 00127 00128 streets = QStringList::split( '\n', workAddr.street() ); 00129 if ( streets.count() > 0 ) 00130 ldif_out( t, "postaladdress", streets[ 0 ] ); 00131 if ( streets.count() > 1 ) 00132 ldif_out( t, "mozillapostaladdress2", streets[ 1 ] ); 00133 ldif_out( t, "countryname", Address::ISOtoCountry(workAddr.country()) ); 00134 ldif_out( t, "l", workAddr.locality() ); 00135 ldif_out( t, "c", Address::ISOtoCountry(workAddr.country()) ); 00136 ldif_out( t, "st", workAddr.region() ); 00137 00138 ldif_out( t, "title", addr.title() ); 00139 ldif_out( t, "vocation", addr.prefix() ); 00140 ldif_out( t, "ou", addr.role() ); 00141 ldif_out( t, "o", addr.organization() ); 00142 ldif_out( t, "organization", addr.organization() ); 00143 ldif_out( t, "organizationname", addr.organization() ); 00144 ldif_out( t, "department", addr.custom("KADDRESSBOOK", "X-Department") ); 00145 ldif_out( t, "workurl", addr.url().prettyURL() ); 00146 ldif_out( t, "homeurl", addr.url().prettyURL() ); 00147 ldif_out( t, "description", addr.note() ); 00148 if (addr.revision().isValid()) 00149 ldif_out(t, "modifytimestamp", dateToVCardString( addr.revision()) ); 00150 00151 t << "objectclass: top\n"; 00152 t << "objectclass: person\n"; 00153 t << "objectclass: organizationalPerson\n"; 00154 00155 t << "\n"; 00156 00157 return true; 00158 } 00159 00160 00161 /* convert from LDIF stream */ 00162 00163 bool LDIFConverter::LDIFToAddressee( const QString &str, AddresseeList &addrList, QDateTime dt ) 00164 { 00165 bool endldif = false, end = false; 00166 LDIF ldif; 00167 LDIF::ParseVal ret; 00168 const char *latinstr = str.latin1(); 00169 QByteArray data; 00170 Addressee a; 00171 Address homeAddr, workAddr; 00172 00173 data.setRawData( latinstr, qstrlen( latinstr ) ); 00174 ldif.setLDIF( data ); 00175 if (!dt.isValid()) 00176 dt = QDateTime::currentDateTime(); 00177 a.setRevision(dt); 00178 homeAddr = Address( Address::Home ); 00179 workAddr = Address( Address::Work ); 00180 00181 do { 00182 ret = ldif.nextItem(); 00183 switch ( ret ) { 00184 case LDIF::Item: { 00185 QString fieldname = ldif.attr().lower(); 00186 QString value = QString::fromUtf8( ldif.val(), ldif.val().size() ); 00187 evaluatePair( a, homeAddr, workAddr, fieldname, value ); 00188 break; 00189 } 00190 case LDIF::EndEntry: 00191 // if the new address is not empty, append it 00192 if ( !a.formattedName().isEmpty() || !a.name().isEmpty() || 00193 !a.familyName().isEmpty() ) { 00194 if ( !homeAddr.isEmpty() ) 00195 a.insertAddress( homeAddr ); 00196 if ( !workAddr.isEmpty() ) 00197 a.insertAddress( workAddr ); 00198 addrList.append( a ); 00199 } 00200 a = Addressee(); 00201 a.setRevision(dt); 00202 homeAddr = Address( Address::Home ); 00203 workAddr = Address( Address::Work ); 00204 break; 00205 case LDIF::MoreData: { 00206 if ( endldif ) 00207 end = true; 00208 else { 00209 ldif.endLDIF(); 00210 endldif = true; 00211 break; 00212 } 00213 } 00214 default: 00215 break; 00216 } 00217 } while ( !end ); 00218 00219 data.resetRawData( latinstr, qstrlen( latinstr ) ); 00220 00221 return true; 00222 } 00223 00224 bool LDIFConverter::evaluatePair( Addressee &a, Address &homeAddr, 00225 Address &workAddr, 00226 QString &fieldname, QString &value ) 00227 { 00228 if ( fieldname == QString::fromLatin1( "dn" ) ) // ignore & return false! 00229 return false; 00230 00231 if ( fieldname.startsWith("#") ) { 00232 return true; 00233 } 00234 00235 if ( fieldname.isEmpty() && !a.note().isEmpty() ) { 00236 // some LDIF export filters are borken and add additional 00237 // comments on stand-alone lines. Just add them to the notes for now. 00238 a.setNote( a.note() + "\n" + value ); 00239 return true; 00240 } 00241 00242 if ( fieldname == QString::fromLatin1( "givenname" ) ) { 00243 a.setGivenName( value ); 00244 return true; 00245 } 00246 00247 if ( fieldname == QString::fromLatin1( "xmozillanickname") || 00248 fieldname == QString::fromLatin1( "nickname") ) { 00249 a.setNickName( value ); 00250 return true; 00251 } 00252 00253 if ( fieldname == QString::fromLatin1( "sn" ) ) { 00254 a.setFamilyName( value ); 00255 return true; 00256 } 00257 00258 if ( fieldname == QString::fromLatin1( "uid" ) ) { 00259 a.setUid( value ); 00260 return true; 00261 } 00262 if ( fieldname == QString::fromLatin1( "mail" ) || 00263 fieldname == QString::fromLatin1( "mozillasecondemail" ) ) { // mozilla 00264 if ( a.emails().findIndex( value ) == -1 ) 00265 a.insertEmail( value ); 00266 return true; 00267 } 00268 00269 if ( fieldname == QString::fromLatin1( "title" ) ) { 00270 a.setTitle( value ); 00271 return true; 00272 } 00273 00274 if ( fieldname == QString::fromLatin1( "vocation" ) ) { 00275 a.setPrefix( value ); 00276 return true; 00277 } 00278 00279 if ( fieldname == QString::fromLatin1( "cn" ) ) { 00280 a.setFormattedName( value ); 00281 return true; 00282 } 00283 00284 if ( fieldname == QString::fromLatin1( "o" ) || 00285 fieldname == QString::fromLatin1( "organization" ) || // Exchange 00286 fieldname == QString::fromLatin1( "organizationname" ) ) { // Exchange 00287 a.setOrganization( value ); 00288 return true; 00289 } 00290 00291 if ( fieldname == QString::fromLatin1( "description" ) ) { 00292 addComment: 00293 if ( !a.note().isEmpty() ) 00294 a.setNote( a.note() + "\n" ); 00295 a.setNote( a.note() + value ); 00296 return true; 00297 } 00298 00299 if ( fieldname == QString::fromLatin1( "custom1" ) || 00300 fieldname == QString::fromLatin1( "custom2" ) || 00301 fieldname == QString::fromLatin1( "custom3" ) || 00302 fieldname == QString::fromLatin1( "custom4" ) ) { 00303 goto addComment; 00304 } 00305 00306 if ( fieldname == QString::fromLatin1( "homeurl" ) || 00307 fieldname == QString::fromLatin1( "workurl" ) ) { 00308 if (a.url().isEmpty()) { 00309 a.setUrl( KURL( value ) ); 00310 return true; 00311 } 00312 if ( a.url().prettyURL() == KURL(value).prettyURL() ) 00313 return true; 00314 // TODO: current version of kabc only supports one URL. 00315 // TODO: change this with KDE 4 00316 } 00317 00318 if ( fieldname == QString::fromLatin1( "homephone" ) ) { 00319 a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Home ) ); 00320 return true; 00321 } 00322 00323 if ( fieldname == QString::fromLatin1( "telephonenumber" ) ) { 00324 a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Work ) ); 00325 return true; 00326 } 00327 00328 if ( fieldname == QString::fromLatin1( "mobile" ) ) { // mozilla/Netscape 7 00329 a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Cell ) ); 00330 return true; 00331 } 00332 00333 if ( fieldname == QString::fromLatin1( "cellphone" ) ) { 00334 a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Cell ) ); 00335 return true; 00336 } 00337 00338 if ( fieldname == QString::fromLatin1( "pager" ) || // mozilla 00339 fieldname == QString::fromLatin1( "pagerphone" ) ) { // mozilla 00340 a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Pager ) ); 00341 return true; 00342 } 00343 00344 if ( fieldname == QString::fromLatin1( "facsimiletelephonenumber" ) ) { 00345 a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Fax ) ); 00346 return true; 00347 } 00348 00349 if ( fieldname == QString::fromLatin1( "xmozillaanyphone" ) ) { // mozilla 00350 a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Work ) ); 00351 return true; 00352 } 00353 00354 if ( fieldname == QString::fromLatin1( "street" ) || 00355 fieldname == QString::fromLatin1( "streethomeaddress" ) ) { 00356 homeAddr.setStreet( value ); 00357 return true; 00358 } 00359 00360 if ( fieldname == QString::fromLatin1( "postaladdress" ) ) { // mozilla 00361 workAddr.setStreet( value ); 00362 return true; 00363 } 00364 00365 if ( fieldname == QString::fromLatin1( "mozillapostaladdress2" ) ) { // mozilla 00366 workAddr.setStreet( workAddr.street() + QString::fromLatin1( "\n" ) + value ); 00367 return true; 00368 } 00369 00370 if ( fieldname == QString::fromLatin1( "postalcode" ) ) { 00371 workAddr.setPostalCode( value ); 00372 return true; 00373 } 00374 00375 if ( fieldname == QString::fromLatin1( "postofficebox" ) ) { 00376 workAddr.setPostOfficeBox( value ); 00377 return true; 00378 } 00379 00380 if ( fieldname == QString::fromLatin1( "homepostaladdress" ) ) { // Netscape 7 00381 homeAddr.setStreet( value ); 00382 return true; 00383 } 00384 00385 if ( fieldname == QString::fromLatin1( "mozillahomepostaladdress2" ) ) { // mozilla 00386 homeAddr.setStreet( homeAddr.street() + QString::fromLatin1( "\n" ) + value ); 00387 return true; 00388 } 00389 00390 if ( fieldname == QString::fromLatin1( "mozillahomelocalityname" ) ) { // mozilla 00391 homeAddr.setLocality( value ); 00392 return true; 00393 } 00394 00395 if ( fieldname == QString::fromLatin1( "mozillahomestate" ) ) { // mozilla 00396 homeAddr.setRegion( value ); 00397 return true; 00398 } 00399 00400 if ( fieldname == QString::fromLatin1( "mozillahomepostalcode" ) ) { // mozilla 00401 homeAddr.setPostalCode( value ); 00402 return true; 00403 } 00404 00405 if ( fieldname == QString::fromLatin1( "mozillahomecountryname" ) ) { // mozilla 00406 if ( value.length() <= 2 ) 00407 value = Address::ISOtoCountry(value); 00408 homeAddr.setCountry( value ); 00409 return true; 00410 } 00411 00412 if ( fieldname == QString::fromLatin1( "locality" ) ) { 00413 workAddr.setLocality( value ); 00414 return true; 00415 } 00416 00417 if ( fieldname == QString::fromLatin1( "streetaddress" ) ) { // Netscape 4.x 00418 workAddr.setStreet( value ); 00419 return true; 00420 } 00421 00422 if ( fieldname == QString::fromLatin1( "countryname" ) || 00423 fieldname == QString::fromLatin1( "c" ) ) { // mozilla 00424 if ( value.length() <= 2 ) 00425 value = Address::ISOtoCountry(value); 00426 workAddr.setCountry( value ); 00427 return true; 00428 } 00429 00430 if ( fieldname == QString::fromLatin1( "l" ) ) { // mozilla 00431 workAddr.setLocality( value ); 00432 return true; 00433 } 00434 00435 if ( fieldname == QString::fromLatin1( "st" ) ) { 00436 workAddr.setRegion( value ); 00437 return true; 00438 } 00439 00440 if ( fieldname == QString::fromLatin1( "ou" ) ) { 00441 a.setRole( value ); 00442 return true; 00443 } 00444 00445 if ( fieldname == QString::fromLatin1( "department" ) ) { 00446 a.insertCustom( "KADDRESSBOOK", "X-Department", value ); 00447 return true; 00448 } 00449 00450 if ( fieldname == QString::fromLatin1( "member" ) ) { 00451 // this is a mozilla list member (cn=xxx, mail=yyy) 00452 QStringList list( QStringList::split( ',', value ) ); 00453 QString name, email; 00454 00455 QStringList::Iterator it; 00456 for ( it = list.begin(); it != list.end(); ++it ) { 00457 if ( (*it).startsWith( "cn=" ) ) 00458 name = (*it).mid( 3 ).stripWhiteSpace(); 00459 if ( (*it).startsWith( "mail=" ) ) 00460 email = (*it).mid( 5 ).stripWhiteSpace(); 00461 } 00462 if ( !name.isEmpty() && !email.isEmpty() ) 00463 email = " <" + email + ">"; 00464 a.insertEmail( name + email ); 00465 a.insertCategory( i18n( "List of Emails" ) ); 00466 return true; 00467 } 00468 00469 if ( fieldname == QString::fromLatin1( "modifytimestamp" ) ) { 00470 if (value == QString::fromLatin1("0Z")) // ignore 00471 return true; 00472 QDateTime dt = VCardStringToDate( value ); 00473 if ( dt.isValid() ) { 00474 a.setRevision(dt); 00475 return true; 00476 } 00477 } 00478 00479 if ( fieldname == QString::fromLatin1( "objectclass" ) ) // ignore 00480 return true; 00481 00482 kdWarning() << QString("LDIFConverter: Unknown field for '%1': '%2=%3'\n") 00483 .arg(a.formattedName()).arg(fieldname).arg(value); 00484 00485 return true; 00486 } 00487 00488 /* The following functions are obsoleted. Similar functionality can be found 00489 * in the LDIF class */ 00490 00491 bool LDIFConverter::parseSingleLine( Addressee &a, Address &homeAddr, 00492 Address &workAddr, QString &line ) 00493 { 00494 if ( line.isEmpty() ) 00495 return true; 00496 00497 QString fieldname, value; 00498 QByteArray val; 00499 00500 LDIF::splitLine( line.latin1(), fieldname, val ); 00501 value = QString::fromUtf8( val.data(), val.size() ); 00502 return evaluatePair( a, homeAddr, workAddr, fieldname, value); 00503 } 00504 00505 00506 bool LDIFConverter::splitLine( QString &line, QString &fieldname, QString &value) 00507 { 00508 QByteArray val; 00509 bool ret = LDIF::splitLine( line.latin1(), fieldname, val ); 00510 value = QString::fromUtf8( val.data(), val.size() ); 00511 return ret; 00512 } 00513 00514 00515 QString LDIFConverter::makeLDIFfieldString( QString formatStr, QString value, bool allowEncode ) 00516 { 00517 if ( value.isEmpty() ) 00518 return QString(); 00519 00520 // append format if not given 00521 if (formatStr.find(':') == -1) 00522 formatStr.append(": %1\n"); 00523 00524 // check if base64-encoding is needed 00525 bool printable = true; 00526 unsigned int i, len; 00527 len = value.length(); 00528 for (i = 0; i<len; ++i ) { 00529 if (!value[i].isPrint()) { 00530 printable = false; 00531 break; 00532 } 00533 } 00534 00535 if (printable) // always encode if we find special chars... 00536 printable = (value.find('\n') == -1); 00537 00538 if (!printable && allowEncode) { 00539 // encode to base64 00540 value = KCodecs::base64Encode( value.utf8() ); 00541 int p = formatStr.find(':'); 00542 if (p>=0) 00543 formatStr.insert(p, ':'); 00544 } 00545 00546 // generate the new string and split it to 72 chars/line 00547 QCString txt = (formatStr.arg(value)).utf8(); 00548 00549 if (allowEncode) { 00550 len = txt.length(); 00551 if (len && txt[len-1] == '\n') 00552 --len; 00553 i = 72; 00554 while (i < len) { 00555 txt.insert(i, "\n "); 00556 i += 72+1; 00557 len += 2; 00558 } 00559 } 00560 00561 return QString::fromUtf8(txt); 00562 } 00563
KDE Logo
This file is part of the documentation for kabc Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Sep 29 09:44:37 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003