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.90.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 30 10:21:07 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003