00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
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 "ldifconverter.h"
00049 #include "vcardconverter.h"
00050 
00051 using namespace KABC;
00052 
00053 
00054 
00055 bool LDIFConverter::addresseeToLDIF( const AddresseeList &addrList, QString &str )
00056 {
00057   AddresseeList::ConstIterator it;
00058   for ( it = addrList.begin(); it != addrList.end(); ++it ) {
00059     addresseeToLDIF( *it, str );
00060   }
00061   return true;
00062 }
00063 
00064 QString LDIFConverter::makeLDIFfieldString( QString formatStr, QString value, bool allowEncode )
00065 {
00066   if ( value.isEmpty() )
00067     return QString();
00068 
00069   
00070   if (formatStr.find(':') == -1)
00071     formatStr.append(": %1\n");
00072 
00073   
00074   bool printable = true;
00075   unsigned int i, len;
00076   len = value.length();
00077   for (i = 0; i<len; ++i ) {
00078      if (!value[i].isPrint()) {
00079         printable = false;
00080         break;
00081      }
00082   }
00083 
00084   if (printable) 
00085     printable = (value.find('\n') == -1);
00086 
00087   if (!printable && allowEncode) { 
00088     
00089     value = KCodecs::base64Encode( value.utf8() );
00090     int p = formatStr.find(':');
00091     if (p>=0)
00092       formatStr.insert(p, ':');
00093   }
00094 
00095   
00096   QCString txt = (formatStr.arg(value)).utf8();
00097 
00098   if (allowEncode) {
00099     len = txt.length();
00100     if (len && txt[len-1] == '\n')
00101       --len;
00102     i = 72;
00103     while (i < len) {
00104       txt.insert(i, "\n ");
00105       i += 72+1;
00106       len += 2;
00107     }
00108   }
00109 
00110   return QString::fromUtf8(txt);
00111 }
00112 
00113 
00114 
00115 static void ldif_out( QTextStream &t, QString formatStr, QString value, bool allowEncode = true )
00116 {
00117   if ( value.isEmpty() )
00118     return;
00119 
00120   QString txt = LDIFConverter::makeLDIFfieldString( formatStr, value, allowEncode );
00121 
00122   
00123   t << txt;
00124 }
00125 
00126 
00127 bool LDIFConverter::addresseeToLDIF( const Addressee &addr, QString &str )
00128 {
00129   if ( addr.isEmpty() )
00130       return false;
00131 
00132   QTextStream t( str, IO_WriteOnly|IO_Append );
00133   t.setEncoding( QTextStream::UnicodeUTF8 );
00134 
00135   const Address homeAddr = addr.address( Address::Home );
00136   const Address workAddr = addr.address( Address::Work );
00137 
00138   ldif_out( t, "dn: %1", QString( "cn=%1,mail=%2\n" )
00139             .arg( addr.formattedName().simplifyWhiteSpace() )
00140             .arg( addr.preferredEmail() ), false  );
00141   ldif_out( t, "givenname: %1\n", addr.givenName() );
00142   ldif_out( t, "sn: %1\n", addr.familyName() );
00143   ldif_out( t, "cn: %1\n", addr.formattedName().simplifyWhiteSpace() );
00144   ldif_out( t, "uid: %1\n", addr.uid() );
00145   ldif_out( t, "nickname: %1\n", addr.nickName() );
00146   ldif_out( t, "xmozillanickname: %1\n", addr.nickName() );
00147 
00148   ldif_out( t, "mail: %1\n", addr.preferredEmail() );
00149   if ( addr.emails().count() > 1 )
00150     ldif_out( t, "mozillasecondemail: %1\n", addr.emails()[ 1 ] );
00151 
00152 
00153   ldif_out( t, "telephonenumber: %1\n", addr.phoneNumber( PhoneNumber::Work ).number() );
00154   ldif_out( t, "facsimiletelephonenumber: %1\n", addr.phoneNumber( PhoneNumber::Fax ).number() );
00155   ldif_out( t, "homephone: %1\n", addr.phoneNumber( PhoneNumber::Home ).number() );
00156   ldif_out( t, "mobile: %1\n", addr.phoneNumber( PhoneNumber::Cell ).number() ); 
00157   ldif_out( t, "cellphone: %1\n", addr.phoneNumber( PhoneNumber::Cell ).number() ); 
00158   ldif_out( t, "pager: %1\n", addr.phoneNumber( PhoneNumber::Pager ).number() );
00159   ldif_out( t, "pagerphone: %1\n", addr.phoneNumber( PhoneNumber::Pager ).number() );
00160 
00161   ldif_out( t, "streethomeaddress: %1\n", homeAddr.street() );
00162   ldif_out( t, "postalcode: %1\n", workAddr.postalCode() );
00163   ldif_out( t, "postofficebox: %1\n", workAddr.postOfficeBox() );
00164 
00165   QStringList streets = QStringList::split( '\n', homeAddr.street() );
00166   if ( streets.count() > 0 )
00167     ldif_out( t, "homepostaladdress: %1\n", streets[ 0 ] ); 
00168   if ( streets.count() > 1 )
00169     ldif_out( t, "mozillahomepostaladdress2: %1\n", streets[ 1 ] ); 
00170   ldif_out( t, "mozillahomelocalityname: %1\n", homeAddr.locality() ); 
00171   ldif_out( t, "mozillahomestate: %1\n", homeAddr.region() );
00172   ldif_out( t, "mozillahomepostalcode: %1\n", homeAddr.postalCode() );
00173   ldif_out( t, "mozillahomecountryname: %1\n", Address::ISOtoCountry(homeAddr.country()) );
00174   ldif_out( t, "locality: %1\n", workAddr.locality() );
00175   ldif_out( t, "streetaddress: %1\n", workAddr.street() ); 
00176 
00177   streets = QStringList::split( '\n', workAddr.street() );
00178   if ( streets.count() > 0 )
00179     ldif_out( t, "postaladdress: %1\n", streets[ 0 ] );
00180   if ( streets.count() > 1 )
00181     ldif_out( t, "mozillapostaladdress2: %1\n", streets[ 1 ] );
00182   ldif_out( t, "countryname: %1\n", Address::ISOtoCountry(workAddr.country()) );
00183   ldif_out( t, "l: %1\n", workAddr.locality() );
00184   ldif_out( t, "c: %1\n", Address::ISOtoCountry(workAddr.country()) );
00185   ldif_out( t, "st: %1\n", workAddr.region() );
00186 
00187   ldif_out( t, "title: %1\n", addr.title() );
00188   ldif_out( t, "vocation: %1\n", addr.prefix() );
00189   ldif_out( t, "ou: %1\n", addr.role() );
00190   ldif_out( t, "o: %1\n", addr.organization() );
00191   ldif_out( t, "organization: %1\n", addr.organization() );
00192   ldif_out( t, "organizationname: %1\n", addr.organization() );
00193   ldif_out( t, "department: %1\n", addr.custom("KADDRESSBOOK", "X-Department") );
00194   ldif_out( t, "workurl: %1\n", addr.url().prettyURL() );
00195   ldif_out( t, "homeurl: %1\n", addr.url().prettyURL() );
00196   ldif_out( t, "description: %1\n", addr.note() );
00197   if (addr.revision().isValid())
00198     ldif_out(t, "modifytimestamp: %1\n", dateToVCardString( addr.revision()) );
00199 
00200   t << "objectclass: top\n";
00201   t << "objectclass: person\n";
00202   t << "objectclass: organizationalPerson\n";
00203 
00204   t << "\n";
00205 
00206   return true;
00207 }
00208 
00209 
00210 
00211 
00212 bool LDIFConverter::LDIFToAddressee( const QString &str, AddresseeList &addrList, QDateTime dt )
00213 {
00214   QStringList lines;
00215 
00216   if (!dt.isValid())
00217     dt = QDateTime::currentDateTime();
00218 
00219   lines = QStringList::split( QRegExp("[\x0d\x0a]"), str, false );
00220 
00221   
00222   QStringList::Iterator last = lines.end();
00223   for ( QStringList::Iterator it = lines.begin(); it != lines.end(); ++it ) {
00224     if ( (*it).startsWith("#") ) { 
00225       it = lines.remove(it);
00226       it--;
00227       continue;
00228     }
00229     if ( last == lines.end() ) {
00230       last = it;
00231       continue;
00232     }
00233     if ((*last).find("::")!=-1 && (*it).find(":")==-1) { 
00234       *last += (*it);
00235       lines.remove(it);
00236       it = last;
00237       continue;
00238     }
00239     if ((*last).find(":")!=-1 && (*it).startsWith(" ")) { 
00240       *last += (*it).mid(1);
00241       lines.remove(it);
00242       it = last;
00243       continue;
00244     }
00245     last = it;
00246   }
00247 
00248   
00249   addrList = AddresseeList();
00250 
00251   Addressee a;
00252   Address homeAddr, workAddr;
00253   bool cont;
00254   QStringList dnList;
00255   QString dnEntry;
00256 
00257   
00258   for ( QStringList::Iterator it = lines.begin(); it != lines.end(); ++it ) {
00259 
00260     
00261     a = Addressee();
00262     a.setRevision(dt);
00263     homeAddr = Address( Address::Home );
00264     workAddr = Address( Address::Work );
00265 
00266     
00267     if (dnList.count()) {
00268       for ( QStringList::Iterator dne = dnList.begin(); dne != dnList.end(); ++dne ) {
00269          parseSingleLine( a, homeAddr, workAddr, *dne );
00270       }
00271     }
00272 
00273     
00274     do {
00275       cont = parseSingleLine( a, homeAddr, workAddr, *it );
00276       if (cont && it!=lines.end()) {
00277         ++it;
00278       }
00279     } while (cont && it!=lines.end());
00280 
00281     
00282     if ( !a.formattedName().isEmpty() || !a.name().isEmpty() || 
00283          !a.familyName().isEmpty() ) {
00284       if ( !homeAddr.isEmpty() )
00285         a.insertAddress( homeAddr );
00286       if ( !workAddr.isEmpty() )
00287         a.insertAddress( workAddr );
00288       addrList.append( a );
00289     }
00290 
00291     
00292     if ( it == lines.end() )
00293       break;
00294 
00295     
00296     
00297     dnEntry = (*it).replace( '=', ": " );
00298     dnList = QStringList::split( ',', dnEntry, false );
00299     dnList.pop_front();
00300 
00301   } 
00302 
00303   return true;
00304 }
00305 
00306 bool LDIFConverter::parseSingleLine( Addressee &a, Address &homeAddr,
00307                                      Address &workAddr, QString &line )
00308 {
00309   if ( line.isEmpty() )
00310     return true;
00311 
00312   QString fieldname, value;
00313   splitLine( line, fieldname, value);
00314   return evaluatePair( a, homeAddr, workAddr, fieldname, value);
00315 }
00316 
00317 
00318 bool LDIFConverter::splitLine( QString &line, QString &fieldname, QString &value)
00319 {
00320   int position;
00321 
00322   position = line.find( "::" );
00323   if ( position != -1 ) {
00324     
00325     fieldname = line.left( position ).lower();
00326     value = QString::fromUtf8( KCodecs::base64Decode(
00327               line.mid( position + 3, line.length() - position - 2 ).latin1() ) )
00328               .simplifyWhiteSpace();
00329     return true;
00330   }
00331 
00332   position = line.find( ":" );
00333   if ( position != -1 ) {
00334     fieldname = line.left( position ).lower();
00335     
00336     
00337     
00338     value = QString::fromUtf8( line.mid( position + 2, line.length() - position - 2 ).latin1() );
00339     return true;
00340   }
00341 
00342   
00343   fieldname = "";
00344   value = line;
00345   return true;
00346 }
00347 
00348 
00349 bool LDIFConverter::evaluatePair( Addressee &a, Address &homeAddr,
00350                                   Address &workAddr,
00351                                   QString &fieldname, QString &value )
00352 {
00353   if ( fieldname == QString::fromLatin1( "dn" ) ) 
00354     return false;
00355 
00356   if ( fieldname.startsWith("#") ) {
00357     return true;
00358   }
00359 
00360   if ( fieldname.isEmpty() && !a.note().isEmpty() ) {
00361     
00362     
00363     a.setNote( a.note() + "\n" + value );
00364     return true;
00365   }
00366 
00367   if ( fieldname == QString::fromLatin1( "givenname" ) ) {
00368     a.setGivenName( value );
00369     return true;
00370   }
00371 
00372   if ( fieldname == QString::fromLatin1( "xmozillanickname") || 
00373        fieldname == QString::fromLatin1( "nickname") ) {
00374     a.setNickName( value );
00375     return true;
00376   }
00377 
00378   if ( fieldname == QString::fromLatin1( "sn" ) ) {
00379     a.setFamilyName( value );
00380     return true;
00381   }
00382 
00383   if ( fieldname == QString::fromLatin1( "uid" ) ) {
00384     a.setUid( value );
00385     return true;
00386   }
00387   if ( fieldname == QString::fromLatin1( "mail" ) ||
00388        fieldname == QString::fromLatin1( "mozillasecondemail" ) ) { 
00389     if ( a.emails().findIndex( value ) == -1 )
00390       a.insertEmail( value );
00391     return true;
00392   }
00393 
00394   if ( fieldname == QString::fromLatin1( "title" ) ) {
00395     a.setTitle( value );
00396     return true;
00397   }
00398 
00399   if ( fieldname == QString::fromLatin1( "vocation" ) ) {
00400     a.setPrefix( value );
00401     return true;
00402   }
00403 
00404   if ( fieldname == QString::fromLatin1( "cn" ) ) {
00405     a.setFormattedName( value );
00406     return true;
00407   }
00408 
00409   if ( fieldname == QString::fromLatin1( "o" ) || 
00410        fieldname == QString::fromLatin1( "organization" ) ||      
00411        fieldname == QString::fromLatin1( "organizationname" ) ) { 
00412     a.setOrganization( value );
00413     return true;
00414   }
00415 
00416   if ( fieldname == QString::fromLatin1( "description" ) ) {
00417 addComment:
00418     if ( !a.note().isEmpty() )
00419       a.setNote( a.note() + "\n" );
00420     a.setNote( a.note() + value );
00421     return true;
00422   }
00423 
00424   if ( fieldname == QString::fromLatin1( "custom1" ) ||
00425        fieldname == QString::fromLatin1( "custom2" ) ||
00426        fieldname == QString::fromLatin1( "custom3" ) ||
00427        fieldname == QString::fromLatin1( "custom4" ) ) {
00428     goto addComment;
00429   }
00430 
00431   if ( fieldname == QString::fromLatin1( "homeurl" ) ||
00432        fieldname == QString::fromLatin1( "workurl" ) ) {
00433     if (a.url().isEmpty()) {
00434       a.setUrl( value );
00435       return true;
00436     }
00437     if ( a.url().prettyURL() == KURL(value).prettyURL() )
00438       return true;
00439     
00440     
00441   }
00442 
00443   if ( fieldname == QString::fromLatin1( "homephone" ) ) { 
00444     a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Home ) );
00445     return true;
00446   }
00447 
00448   if ( fieldname == QString::fromLatin1( "telephonenumber" ) ) {
00449     a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Work ) );
00450     return true;
00451   }
00452 
00453   if ( fieldname == QString::fromLatin1( "mobile" ) ) {     
00454     a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Cell ) );
00455     return true;
00456   }
00457 
00458   if ( fieldname == QString::fromLatin1( "cellphone" ) ) {
00459     a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Cell ) );
00460     return true;
00461   }
00462 
00463   if ( fieldname == QString::fromLatin1( "pager" )  ||       
00464        fieldname == QString::fromLatin1( "pagerphone" ) ) {  
00465     a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Pager ) );
00466     return true;
00467   }
00468 
00469   if ( fieldname == QString::fromLatin1( "facsimiletelephonenumber" ) ) {
00470     a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Fax ) );
00471     return true;
00472   }
00473 
00474   if ( fieldname == QString::fromLatin1( "xmozillaanyphone" ) ) { 
00475     a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Work ) );
00476     return true;
00477   }
00478 
00479   if ( fieldname == QString::fromLatin1( "street" ) ||
00480        fieldname == QString::fromLatin1( "streethomeaddress" ) ) {
00481     homeAddr.setStreet( value );
00482     return true;
00483   }
00484 
00485   if ( fieldname == QString::fromLatin1( "postaladdress" ) ) {  
00486     workAddr.setStreet( value );
00487     return true;
00488   }
00489 
00490   if ( fieldname == QString::fromLatin1( "mozillapostaladdress2" ) ) {  
00491     workAddr.setStreet( workAddr.street() + QString::fromLatin1( "\n" ) + value );
00492     return true;
00493   }
00494 
00495   if ( fieldname == QString::fromLatin1( "postalcode" ) ) {
00496     workAddr.setPostalCode( value );
00497     return true;
00498   }
00499 
00500   if ( fieldname == QString::fromLatin1( "postofficebox" ) ) {
00501     workAddr.setPostOfficeBox( value );
00502     return true;
00503   }
00504 
00505   if ( fieldname == QString::fromLatin1( "homepostaladdress" ) ) {  
00506     homeAddr.setStreet( value );
00507     return true;
00508   }
00509 
00510   if ( fieldname == QString::fromLatin1( "mozillahomepostaladdress2" ) ) {  
00511     homeAddr.setStreet( homeAddr.street() + QString::fromLatin1( "\n" ) + value );
00512     return true;
00513   }
00514 
00515   if ( fieldname == QString::fromLatin1( "mozillahomelocalityname" ) ) {  
00516     homeAddr.setLocality( value );
00517     return true;
00518   }
00519 
00520   if ( fieldname == QString::fromLatin1( "mozillahomestate" )   ) { 
00521     homeAddr.setRegion( value );
00522     return true;
00523   }
00524 
00525   if ( fieldname == QString::fromLatin1( "mozillahomepostalcode" ) ) {  
00526     homeAddr.setPostalCode( value );
00527     return true;
00528   }
00529 
00530   if ( fieldname == QString::fromLatin1( "mozillahomecountryname" ) ) { 
00531     if ( value.length() <= 2 )
00532       value = Address::ISOtoCountry(value);
00533     homeAddr.setCountry( value );
00534     return true;
00535   }
00536 
00537   if ( fieldname == QString::fromLatin1( "locality" ) ) {
00538     workAddr.setLocality( value );
00539     return true;
00540   }
00541 
00542   if ( fieldname == QString::fromLatin1( "streetaddress" ) ) { 
00543     workAddr.setStreet( value );
00544     return true;
00545   }
00546 
00547   if ( fieldname == QString::fromLatin1( "countryname" ) ||
00548        fieldname == QString::fromLatin1( "c" ) ) {  
00549     if ( value.length() <= 2 )
00550       value = Address::ISOtoCountry(value);
00551     workAddr.setCountry( value );
00552     return true;
00553   }
00554 
00555   if ( fieldname == QString::fromLatin1( "l" ) ) {  
00556     workAddr.setLocality( value );
00557     return true;
00558   }
00559 
00560   if ( fieldname == QString::fromLatin1( "st" ) ) {
00561     workAddr.setRegion( value );
00562     return true;
00563   }
00564 
00565   if ( fieldname == QString::fromLatin1( "ou" ) ) {
00566     a.setRole( value );
00567     return true;
00568   }
00569 
00570   if ( fieldname == QString::fromLatin1( "department" ) ) {
00571     a.insertCustom( "KADDRESSBOOK", "X-Department", value );
00572     return true;
00573   }
00574 
00575   if ( fieldname == QString::fromLatin1( "member" ) ) {
00576     
00577     QStringList list( QStringList::split( ',', value ) );
00578     QString name, email;
00579 
00580     QStringList::Iterator it;
00581     for ( it = list.begin(); it != list.end(); ++it ) {
00582       if ( (*it).startsWith( "cn=" ) )
00583         name = (*it).mid( 3 ).stripWhiteSpace();
00584       if ( (*it).startsWith( "mail=" ) )
00585         email = (*it).mid( 5 ).stripWhiteSpace();
00586     }
00587     if ( !name.isEmpty() && !email.isEmpty() )
00588       email = " <" + email + ">";
00589     a.insertEmail( name + email );
00590     a.insertCategory( i18n( "List of Emails" ) );
00591     return true;
00592   }
00593 
00594   if ( fieldname == QString::fromLatin1( "modifytimestamp" ) ) {
00595     if (value == QString::fromLatin1("0Z")) 
00596       return true;
00597     QDateTime dt = VCardStringToDate( value );
00598     if ( dt.isValid() ) {
00599       a.setRevision(dt);
00600       return true;
00601     }
00602   }
00603 
00604   if ( fieldname == QString::fromLatin1( "objectclass" ) ) 
00605     return true;
00606 
00607   kdWarning() << QString("LDIFConverter: Unknown field for '%1': '%2=%3'\n")
00608                              .arg(a.formattedName()).arg(fieldname).arg(value);
00609 
00610   return true;
00611 }
00612