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 if (str.isEmpty()) 00166 return true; 00167 00168 bool endldif = false, end = false; 00169 LDIF ldif; 00170 LDIF::ParseVal ret; 00171 const char *latinstr = str.latin1(); 00172 int latinstrlen = qstrlen( latinstr ); 00173 QByteArray data; 00174 Addressee a; 00175 Address homeAddr, workAddr; 00176 00177 data.setRawData( latinstr, latinstrlen ); 00178 ldif.setLDIF( data ); 00179 if (!dt.isValid()) 00180 dt = QDateTime::currentDateTime(); 00181 a.setRevision(dt); 00182 homeAddr = Address( Address::Home ); 00183 workAddr = Address( Address::Work ); 00184 00185 do { 00186 ret = ldif.nextItem(); 00187 switch ( ret ) { 00188 case LDIF::Item: { 00189 QString fieldname = ldif.attr().lower(); 00190 QString value = QString::fromUtf8( ldif.val(), ldif.val().size() ); 00191 evaluatePair( a, homeAddr, workAddr, fieldname, value ); 00192 break; 00193 } 00194 case LDIF::EndEntry: 00195 // if the new address is not empty, append it 00196 if ( !a.formattedName().isEmpty() || !a.name().isEmpty() || 00197 !a.familyName().isEmpty() ) { 00198 if ( !homeAddr.isEmpty() ) 00199 a.insertAddress( homeAddr ); 00200 if ( !workAddr.isEmpty() ) 00201 a.insertAddress( workAddr ); 00202 addrList.append( a ); 00203 } 00204 a = Addressee(); 00205 a.setRevision(dt); 00206 homeAddr = Address( Address::Home ); 00207 workAddr = Address( Address::Work ); 00208 break; 00209 case LDIF::MoreData: { 00210 if ( endldif ) 00211 end = true; 00212 else { 00213 ldif.endLDIF(); 00214 endldif = true; 00215 break; 00216 } 00217 } 00218 default: 00219 break; 00220 } 00221 } while ( !end ); 00222 00223 data.resetRawData( latinstr, latinstrlen ); 00224 00225 return true; 00226 } 00227 00228 bool LDIFConverter::evaluatePair( Addressee &a, Address &homeAddr, 00229 Address &workAddr, 00230 QString &fieldname, QString &value ) 00231 { 00232 if ( fieldname == QString::fromLatin1( "dn" ) ) // ignore & return false! 00233 return false; 00234 00235 if ( fieldname.startsWith("#") ) { 00236 return true; 00237 } 00238 00239 if ( fieldname.isEmpty() && !a.note().isEmpty() ) { 00240 // some LDIF export filters are borken and add additional 00241 // comments on stand-alone lines. Just add them to the notes for now. 00242 a.setNote( a.note() + "\n" + value ); 00243 return true; 00244 } 00245 00246 if ( fieldname == QString::fromLatin1( "givenname" ) ) { 00247 a.setGivenName( value ); 00248 return true; 00249 } 00250 00251 if ( fieldname == QString::fromLatin1( "xmozillanickname") || 00252 fieldname == QString::fromLatin1( "nickname") ) { 00253 a.setNickName( value ); 00254 return true; 00255 } 00256 00257 if ( fieldname == QString::fromLatin1( "sn" ) ) { 00258 a.setFamilyName( value ); 00259 return true; 00260 } 00261 00262 if ( fieldname == QString::fromLatin1( "uid" ) ) { 00263 a.setUid( value ); 00264 return true; 00265 } 00266 if ( fieldname == QString::fromLatin1( "mail" ) || 00267 fieldname == QString::fromLatin1( "mozillasecondemail" ) ) { // mozilla 00268 if ( a.emails().findIndex( value ) == -1 ) 00269 a.insertEmail( value ); 00270 return true; 00271 } 00272 00273 if ( fieldname == QString::fromLatin1( "title" ) ) { 00274 a.setTitle( value ); 00275 return true; 00276 } 00277 00278 if ( fieldname == QString::fromLatin1( "vocation" ) ) { 00279 a.setPrefix( value ); 00280 return true; 00281 } 00282 00283 if ( fieldname == QString::fromLatin1( "cn" ) ) { 00284 a.setFormattedName( value ); 00285 return true; 00286 } 00287 00288 if ( fieldname == QString::fromLatin1( "o" ) || 00289 fieldname == QString::fromLatin1( "organization" ) || // Exchange 00290 fieldname == QString::fromLatin1( "organizationname" ) ) { // Exchange 00291 a.setOrganization( value ); 00292 return true; 00293 } 00294 00295 if ( fieldname == QString::fromLatin1( "description" ) ) { 00296 addComment: 00297 if ( !a.note().isEmpty() ) 00298 a.setNote( a.note() + "\n" ); 00299 a.setNote( a.note() + value ); 00300 return true; 00301 } 00302 00303 if ( fieldname == QString::fromLatin1( "custom1" ) || 00304 fieldname == QString::fromLatin1( "custom2" ) || 00305 fieldname == QString::fromLatin1( "custom3" ) || 00306 fieldname == QString::fromLatin1( "custom4" ) ) { 00307 goto addComment; 00308 } 00309 00310 if ( fieldname == QString::fromLatin1( "homeurl" ) || 00311 fieldname == QString::fromLatin1( "workurl" ) ) { 00312 if (a.url().isEmpty()) { 00313 a.setUrl( KURL( value ) ); 00314 return true; 00315 } 00316 if ( a.url().prettyURL() == KURL(value).prettyURL() ) 00317 return true; 00318 // TODO: current version of kabc only supports one URL. 00319 // TODO: change this with KDE 4 00320 } 00321 00322 if ( fieldname == QString::fromLatin1( "homephone" ) ) { 00323 a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Home ) ); 00324 return true; 00325 } 00326 00327 if ( fieldname == QString::fromLatin1( "telephonenumber" ) ) { 00328 a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Work ) ); 00329 return true; 00330 } 00331 00332 if ( fieldname == QString::fromLatin1( "mobile" ) ) { // mozilla/Netscape 7 00333 a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Cell ) ); 00334 return true; 00335 } 00336 00337 if ( fieldname == QString::fromLatin1( "cellphone" ) ) { 00338 a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Cell ) ); 00339 return true; 00340 } 00341 00342 if ( fieldname == QString::fromLatin1( "pager" ) || // mozilla 00343 fieldname == QString::fromLatin1( "pagerphone" ) ) { // mozilla 00344 a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Pager ) ); 00345 return true; 00346 } 00347 00348 if ( fieldname == QString::fromLatin1( "facsimiletelephonenumber" ) ) { 00349 a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Fax ) ); 00350 return true; 00351 } 00352 00353 if ( fieldname == QString::fromLatin1( "xmozillaanyphone" ) ) { // mozilla 00354 a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Work ) ); 00355 return true; 00356 } 00357 00358 if ( fieldname == QString::fromLatin1( "street" ) || 00359 fieldname == QString::fromLatin1( "streethomeaddress" ) ) { 00360 homeAddr.setStreet( value ); 00361 return true; 00362 } 00363 00364 if ( fieldname == QString::fromLatin1( "postaladdress" ) ) { // mozilla 00365 workAddr.setStreet( value ); 00366 return true; 00367 } 00368 00369 if ( fieldname == QString::fromLatin1( "mozillapostaladdress2" ) ) { // mozilla 00370 workAddr.setStreet( workAddr.street() + QString::fromLatin1( "\n" ) + value ); 00371 return true; 00372 } 00373 00374 if ( fieldname == QString::fromLatin1( "postalcode" ) ) { 00375 workAddr.setPostalCode( value ); 00376 return true; 00377 } 00378 00379 if ( fieldname == QString::fromLatin1( "postofficebox" ) ) { 00380 workAddr.setPostOfficeBox( value ); 00381 return true; 00382 } 00383 00384 if ( fieldname == QString::fromLatin1( "homepostaladdress" ) ) { // Netscape 7 00385 homeAddr.setStreet( value ); 00386 return true; 00387 } 00388 00389 if ( fieldname == QString::fromLatin1( "mozillahomepostaladdress2" ) ) { // mozilla 00390 homeAddr.setStreet( homeAddr.street() + QString::fromLatin1( "\n" ) + value ); 00391 return true; 00392 } 00393 00394 if ( fieldname == QString::fromLatin1( "mozillahomelocalityname" ) ) { // mozilla 00395 homeAddr.setLocality( value ); 00396 return true; 00397 } 00398 00399 if ( fieldname == QString::fromLatin1( "mozillahomestate" ) ) { // mozilla 00400 homeAddr.setRegion( value ); 00401 return true; 00402 } 00403 00404 if ( fieldname == QString::fromLatin1( "mozillahomepostalcode" ) ) { // mozilla 00405 homeAddr.setPostalCode( value ); 00406 return true; 00407 } 00408 00409 if ( fieldname == QString::fromLatin1( "mozillahomecountryname" ) ) { // mozilla 00410 if ( value.length() <= 2 ) 00411 value = Address::ISOtoCountry(value); 00412 homeAddr.setCountry( value ); 00413 return true; 00414 } 00415 00416 if ( fieldname == QString::fromLatin1( "locality" ) ) { 00417 workAddr.setLocality( value ); 00418 return true; 00419 } 00420 00421 if ( fieldname == QString::fromLatin1( "streetaddress" ) ) { // Netscape 4.x 00422 workAddr.setStreet( value ); 00423 return true; 00424 } 00425 00426 if ( fieldname == QString::fromLatin1( "countryname" ) || 00427 fieldname == QString::fromLatin1( "c" ) ) { // mozilla 00428 if ( value.length() <= 2 ) 00429 value = Address::ISOtoCountry(value); 00430 workAddr.setCountry( value ); 00431 return true; 00432 } 00433 00434 if ( fieldname == QString::fromLatin1( "l" ) ) { // mozilla 00435 workAddr.setLocality( value ); 00436 return true; 00437 } 00438 00439 if ( fieldname == QString::fromLatin1( "st" ) ) { 00440 workAddr.setRegion( value ); 00441 return true; 00442 } 00443 00444 if ( fieldname == QString::fromLatin1( "ou" ) ) { 00445 a.setRole( value ); 00446 return true; 00447 } 00448 00449 if ( fieldname == QString::fromLatin1( "department" ) ) { 00450 a.insertCustom( "KADDRESSBOOK", "X-Department", value ); 00451 return true; 00452 } 00453 00454 if ( fieldname == QString::fromLatin1( "member" ) ) { 00455 // this is a mozilla list member (cn=xxx, mail=yyy) 00456 QStringList list( QStringList::split( ',', value ) ); 00457 QString name, email; 00458 00459 QStringList::Iterator it; 00460 for ( it = list.begin(); it != list.end(); ++it ) { 00461 if ( (*it).startsWith( "cn=" ) ) 00462 name = (*it).mid( 3 ).stripWhiteSpace(); 00463 if ( (*it).startsWith( "mail=" ) ) 00464 email = (*it).mid( 5 ).stripWhiteSpace(); 00465 } 00466 if ( !name.isEmpty() && !email.isEmpty() ) 00467 email = " <" + email + ">"; 00468 a.insertEmail( name + email ); 00469 a.insertCategory( i18n( "List of Emails" ) ); 00470 return true; 00471 } 00472 00473 if ( fieldname == QString::fromLatin1( "modifytimestamp" ) ) { 00474 if (value == QString::fromLatin1("0Z")) // ignore 00475 return true; 00476 QDateTime dt = VCardStringToDate( value ); 00477 if ( dt.isValid() ) { 00478 a.setRevision(dt); 00479 return true; 00480 } 00481 } 00482 00483 if ( fieldname == QString::fromLatin1( "objectclass" ) ) // ignore 00484 return true; 00485 00486 kdWarning() << QString("LDIFConverter: Unknown field for '%1': '%2=%3'\n") 00487 .arg(a.formattedName()).arg(fieldname).arg(value); 00488 00489 return true; 00490 } 00491 00492 /* The following functions are obsoleted. Similar functionality can be found 00493 * in the LDIF class */ 00494 00495 bool LDIFConverter::parseSingleLine( Addressee &a, Address &homeAddr, 00496 Address &workAddr, QString &line ) 00497 { 00498 if ( line.isEmpty() ) 00499 return true; 00500 00501 QString fieldname, value; 00502 QByteArray val; 00503 00504 LDIF::splitLine( line.latin1(), fieldname, val ); 00505 value = QString::fromUtf8( val.data(), val.size() ); 00506 return evaluatePair( a, homeAddr, workAddr, fieldname, value); 00507 } 00508 00509 00510 bool LDIFConverter::splitLine( QString &line, QString &fieldname, QString &value) 00511 { 00512 QByteArray val; 00513 bool ret = LDIF::splitLine( line.latin1(), fieldname, val ); 00514 value = QString::fromUtf8( val.data(), val.size() ); 00515 return ret; 00516 } 00517 00518 00519 QString LDIFConverter::makeLDIFfieldString( QString formatStr, QString value, bool allowEncode ) 00520 { 00521 if ( value.isEmpty() ) 00522 return QString(); 00523 00524 // append format if not given 00525 if (formatStr.find(':') == -1) 00526 formatStr.append(": %1\n"); 00527 00528 // check if base64-encoding is needed 00529 bool printable = true; 00530 unsigned int i, len; 00531 len = value.length(); 00532 for (i = 0; i<len; ++i ) { 00533 if (!value[i].isPrint()) { 00534 printable = false; 00535 break; 00536 } 00537 } 00538 00539 if (printable) // always encode if we find special chars... 00540 printable = (value.find('\n') == -1); 00541 00542 if (!printable && allowEncode) { 00543 // encode to base64 00544 value = KCodecs::base64Encode( value.utf8() ); 00545 int p = formatStr.find(':'); 00546 if (p>=0) 00547 formatStr.insert(p, ':'); 00548 } 00549 00550 // generate the new string and split it to 72 chars/line 00551 QCString txt = (formatStr.arg(value)).utf8(); 00552 00553 if (allowEncode) { 00554 len = txt.length(); 00555 if (len && txt[len-1] == '\n') 00556 --len; 00557 i = 72; 00558 while (i < len) { 00559 txt.insert(i, "\n "); 00560 i += 72+1; 00561 len += 2; 00562 } 00563 } 00564 00565 return QString::fromUtf8(txt); 00566 } 00567
KDE Logo
This file is part of the documentation for kabc Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Apr 12 23:27:21 2005 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003