summaryrefslogtreecommitdiffstats
path: root/kabc/ldifconverter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kabc/ldifconverter.cpp')
-rw-r--r--kabc/ldifconverter.cpp573
1 files changed, 573 insertions, 0 deletions
diff --git a/kabc/ldifconverter.cpp b/kabc/ldifconverter.cpp
new file mode 100644
index 000000000..684f07bbd
--- /dev/null
+++ b/kabc/ldifconverter.cpp
@@ -0,0 +1,573 @@
+/*
+ This file is part of libkabc.
+ Copyright (c) 2003 Helge Deller <deller@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+/*
+ Useful links:
+ - http://tldp.org/HOWTO/LDAP-Implementation-HOWTO/schemas.html
+ - http://www.faqs.org/rfcs/rfc2849.html
+
+ Not yet handled items:
+ - objectclass microsoftaddressbook
+ - info,
+ - initials,
+ - otherfacsimiletelephonenumber,
+ - otherpager,
+ - physicaldeliveryofficename,
+*/
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qregexp.h>
+#include <qtextstream.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kmdcodec.h>
+
+#include "addressee.h"
+#include "address.h"
+
+#include "ldif.h"
+#include "ldifconverter.h"
+#include "vcardconverter.h"
+
+using namespace KABC;
+
+/* generate LDIF stream */
+
+bool LDIFConverter::addresseeToLDIF( const AddresseeList &addrList, QString &str )
+{
+ AddresseeList::ConstIterator it;
+ for ( it = addrList.begin(); it != addrList.end(); ++it ) {
+ addresseeToLDIF( *it, str );
+ }
+ return true;
+}
+
+
+
+static void ldif_out( QTextStream &t, QString formatStr, QString value )
+{
+ if ( value.isEmpty() )
+ return;
+
+ QCString txt = LDIF::assembleLine( formatStr, value, 72 );
+
+ // write the string
+ t << QString::fromUtf8(txt) << "\n";
+}
+
+bool LDIFConverter::addresseeToLDIF( const Addressee &addr, QString &str )
+{
+ if ( addr.isEmpty() )
+ return false;
+
+ QTextStream t( str, IO_WriteOnly|IO_Append );
+ t.setEncoding( QTextStream::UnicodeUTF8 );
+
+ const Address homeAddr = addr.address( Address::Home );
+ const Address workAddr = addr.address( Address::Work );
+
+ ldif_out( t, "dn", QString( "cn=%1,mail=%2" )
+ .arg( addr.formattedName().simplifyWhiteSpace() )
+ .arg( addr.preferredEmail() ) );
+ ldif_out( t, "givenname", addr.givenName() );
+ ldif_out( t, "sn", addr.familyName() );
+ ldif_out( t, "cn", addr.formattedName().simplifyWhiteSpace() );
+ ldif_out( t, "uid", addr.uid() );
+ ldif_out( t, "nickname", addr.nickName() );
+ ldif_out( t, "xmozillanickname", addr.nickName() );
+
+ ldif_out( t, "mail", addr.preferredEmail() );
+ if ( addr.emails().count() > 1 )
+ ldif_out( t, "mozillasecondemail", addr.emails()[ 1 ] );
+//ldif_out( t, "mozilla_AIMScreenName: %1\n", "screen_name" );
+
+ ldif_out( t, "telephonenumber", addr.phoneNumber( PhoneNumber::Work ).number() );
+ ldif_out( t, "facsimiletelephonenumber", addr.phoneNumber( PhoneNumber::Fax ).number() );
+ ldif_out( t, "homephone", addr.phoneNumber( PhoneNumber::Home ).number() );
+ ldif_out( t, "mobile", addr.phoneNumber( PhoneNumber::Cell ).number() ); // Netscape 7
+ ldif_out( t, "cellphone", addr.phoneNumber( PhoneNumber::Cell ).number() ); // Netscape 4.x
+ ldif_out( t, "pager", addr.phoneNumber( PhoneNumber::Pager ).number() );
+ ldif_out( t, "pagerphone", addr.phoneNumber( PhoneNumber::Pager ).number() );
+
+ ldif_out( t, "streethomeaddress", homeAddr.street() );
+ ldif_out( t, "postalcode", workAddr.postalCode() );
+ ldif_out( t, "postofficebox", workAddr.postOfficeBox() );
+
+ QStringList streets = QStringList::split( '\n', homeAddr.street() );
+ if ( streets.count() > 0 )
+ ldif_out( t, "homepostaladdress", streets[ 0 ] ); // Netscape 7
+ if ( streets.count() > 1 )
+ ldif_out( t, "mozillahomepostaladdress2", streets[ 1 ] ); // Netscape 7
+ ldif_out( t, "mozillahomelocalityname", homeAddr.locality() ); // Netscape 7
+ ldif_out( t, "mozillahomestate", homeAddr.region() );
+ ldif_out( t, "mozillahomepostalcode", homeAddr.postalCode() );
+ ldif_out( t, "mozillahomecountryname", Address::ISOtoCountry(homeAddr.country()) );
+ ldif_out( t, "locality", workAddr.locality() );
+ ldif_out( t, "streetaddress", workAddr.street() ); // Netscape 4.x
+
+ streets = QStringList::split( '\n', workAddr.street() );
+ if ( streets.count() > 0 )
+ ldif_out( t, "postaladdress", streets[ 0 ] );
+ if ( streets.count() > 1 )
+ ldif_out( t, "mozillapostaladdress2", streets[ 1 ] );
+ ldif_out( t, "countryname", Address::ISOtoCountry(workAddr.country()) );
+ ldif_out( t, "l", workAddr.locality() );
+ ldif_out( t, "c", Address::ISOtoCountry(workAddr.country()) );
+ ldif_out( t, "st", workAddr.region() );
+
+ ldif_out( t, "title", addr.title() );
+ ldif_out( t, "vocation", addr.prefix() );
+ ldif_out( t, "ou", addr.role() );
+ ldif_out( t, "o", addr.organization() );
+ ldif_out( t, "organization", addr.organization() );
+ ldif_out( t, "organizationname", addr.organization() );
+
+ // Compatibility with older kabc versions.
+ if ( !addr.department().isEmpty() )
+ ldif_out( t, "department", addr.department() );
+ else
+ ldif_out( t, "department", addr.custom("KADDRESSBOOK", "X-Department") );
+
+ ldif_out( t, "workurl", addr.url().prettyURL() );
+ ldif_out( t, "homeurl", addr.url().prettyURL() );
+ ldif_out( t, "description", addr.note() );
+ if (addr.revision().isValid())
+ ldif_out(t, "modifytimestamp", dateToVCardString( addr.revision()) );
+
+ t << "objectclass: top\n";
+ t << "objectclass: person\n";
+ t << "objectclass: organizationalPerson\n";
+
+ t << "\n";
+
+ return true;
+}
+
+
+/* convert from LDIF stream */
+
+bool LDIFConverter::LDIFToAddressee( const QString &str, AddresseeList &addrList, QDateTime dt )
+{
+ if (str.isEmpty())
+ return true;
+
+ bool endldif = false, end = false;
+ LDIF ldif;
+ LDIF::ParseVal ret;
+ const char *latinstr = str.latin1();
+ int latinstrlen = qstrlen( latinstr );
+ QByteArray data;
+ Addressee a;
+ Address homeAddr, workAddr;
+
+ data.setRawData( latinstr, latinstrlen );
+ ldif.setLDIF( data );
+ if (!dt.isValid())
+ dt = QDateTime::currentDateTime();
+ a.setRevision(dt);
+ homeAddr = Address( Address::Home );
+ workAddr = Address( Address::Work );
+
+ do {
+ ret = ldif.nextItem();
+ switch ( ret ) {
+ case LDIF::Item: {
+ QString fieldname = ldif.attr().lower();
+ QString value = QString::fromUtf8( ldif.val(), ldif.val().size() );
+ evaluatePair( a, homeAddr, workAddr, fieldname, value );
+ break;
+ }
+ case LDIF::EndEntry:
+ // if the new address is not empty, append it
+ if ( !a.formattedName().isEmpty() || !a.name().isEmpty() ||
+ !a.familyName().isEmpty() ) {
+ if ( !homeAddr.isEmpty() )
+ a.insertAddress( homeAddr );
+ if ( !workAddr.isEmpty() )
+ a.insertAddress( workAddr );
+ addrList.append( a );
+ }
+ a = Addressee();
+ a.setRevision(dt);
+ homeAddr = Address( Address::Home );
+ workAddr = Address( Address::Work );
+ break;
+ case LDIF::MoreData: {
+ if ( endldif )
+ end = true;
+ else {
+ ldif.endLDIF();
+ endldif = true;
+ break;
+ }
+ }
+ default:
+ break;
+ }
+ } while ( !end );
+
+ data.resetRawData( latinstr, latinstrlen );
+
+ return true;
+}
+
+bool LDIFConverter::evaluatePair( Addressee &a, Address &homeAddr,
+ Address &workAddr,
+ QString &fieldname, QString &value )
+{
+ if ( fieldname == QString::fromLatin1( "dn" ) ) // ignore & return false!
+ return false;
+
+ if ( fieldname.startsWith("#") ) {
+ return true;
+ }
+
+ if ( fieldname.isEmpty() && !a.note().isEmpty() ) {
+ // some LDIF export filters are borken and add additional
+ // comments on stand-alone lines. Just add them to the notes for now.
+ a.setNote( a.note() + "\n" + value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "givenname" ) ) {
+ a.setGivenName( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "xmozillanickname") ||
+ fieldname == QString::fromLatin1( "nickname") ) {
+ a.setNickName( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "sn" ) ) {
+ a.setFamilyName( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "uid" ) ) {
+ a.setUid( value );
+ return true;
+ }
+ if ( fieldname == QString::fromLatin1( "mail" ) ||
+ fieldname == QString::fromLatin1( "mozillasecondemail" ) ) { // mozilla
+ if ( a.emails().findIndex( value ) == -1 )
+ a.insertEmail( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "title" ) ) {
+ a.setTitle( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "vocation" ) ) {
+ a.setPrefix( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "cn" ) ) {
+ a.setFormattedName( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "o" ) ||
+ fieldname == QString::fromLatin1( "organization" ) || // Exchange
+ fieldname == QString::fromLatin1( "organizationname" ) ) { // Exchange
+ a.setOrganization( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "description" ) ) {
+addComment:
+ if ( !a.note().isEmpty() )
+ a.setNote( a.note() + "\n" );
+ a.setNote( a.note() + value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "custom1" ) ||
+ fieldname == QString::fromLatin1( "custom2" ) ||
+ fieldname == QString::fromLatin1( "custom3" ) ||
+ fieldname == QString::fromLatin1( "custom4" ) ) {
+ goto addComment;
+ }
+
+ if ( fieldname == QString::fromLatin1( "homeurl" ) ||
+ fieldname == QString::fromLatin1( "workurl" ) ) {
+ if (a.url().isEmpty()) {
+ a.setUrl( KURL( value ) );
+ return true;
+ }
+ if ( a.url().prettyURL() == KURL(value).prettyURL() )
+ return true;
+ // TODO: current version of kabc only supports one URL.
+ // TODO: change this with KDE 4
+ }
+
+ if ( fieldname == QString::fromLatin1( "homephone" ) ) {
+ a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Home ) );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "telephonenumber" ) ) {
+ a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Work ) );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "mobile" ) ) { // mozilla/Netscape 7
+ a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Cell ) );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "cellphone" ) ) {
+ a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Cell ) );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "pager" ) || // mozilla
+ fieldname == QString::fromLatin1( "pagerphone" ) ) { // mozilla
+ a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Pager ) );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "facsimiletelephonenumber" ) ) {
+ a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Fax ) );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "xmozillaanyphone" ) ) { // mozilla
+ a.insertPhoneNumber( PhoneNumber( value, PhoneNumber::Work ) );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "street" ) ||
+ fieldname == QString::fromLatin1( "streethomeaddress" ) ) {
+ homeAddr.setStreet( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "postaladdress" ) ) { // mozilla
+ workAddr.setStreet( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "mozillapostaladdress2" ) ) { // mozilla
+ workAddr.setStreet( workAddr.street() + QString::fromLatin1( "\n" ) + value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "postalcode" ) ) {
+ workAddr.setPostalCode( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "postofficebox" ) ) {
+ workAddr.setPostOfficeBox( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "homepostaladdress" ) ) { // Netscape 7
+ homeAddr.setStreet( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "mozillahomepostaladdress2" ) ) { // mozilla
+ homeAddr.setStreet( homeAddr.street() + QString::fromLatin1( "\n" ) + value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "mozillahomelocalityname" ) ) { // mozilla
+ homeAddr.setLocality( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "mozillahomestate" ) ) { // mozilla
+ homeAddr.setRegion( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "mozillahomepostalcode" ) ) { // mozilla
+ homeAddr.setPostalCode( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "mozillahomecountryname" ) ) { // mozilla
+ if ( value.length() <= 2 )
+ value = Address::ISOtoCountry(value);
+ homeAddr.setCountry( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "locality" ) ) {
+ workAddr.setLocality( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "streetaddress" ) ) { // Netscape 4.x
+ workAddr.setStreet( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "countryname" ) ||
+ fieldname == QString::fromLatin1( "c" ) ) { // mozilla
+ if ( value.length() <= 2 )
+ value = Address::ISOtoCountry(value);
+ workAddr.setCountry( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "l" ) ) { // mozilla
+ workAddr.setLocality( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "st" ) ) {
+ workAddr.setRegion( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "ou" ) ) {
+ a.setRole( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "department" ) ) {
+ a.setDepartment( value );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "member" ) ) {
+ // this is a mozilla list member (cn=xxx, mail=yyy)
+ QStringList list( QStringList::split( ',', value ) );
+ QString name, email;
+
+ QStringList::Iterator it;
+ for ( it = list.begin(); it != list.end(); ++it ) {
+ if ( (*it).startsWith( "cn=" ) )
+ name = (*it).mid( 3 ).stripWhiteSpace();
+ if ( (*it).startsWith( "mail=" ) )
+ email = (*it).mid( 5 ).stripWhiteSpace();
+ }
+ if ( !name.isEmpty() && !email.isEmpty() )
+ email = " <" + email + ">";
+ a.insertEmail( name + email );
+ a.insertCategory( i18n( "List of Emails" ) );
+ return true;
+ }
+
+ if ( fieldname == QString::fromLatin1( "modifytimestamp" ) ) {
+ if (value == QString::fromLatin1("0Z")) // ignore
+ return true;
+ QDateTime dt = VCardStringToDate( value );
+ if ( dt.isValid() ) {
+ a.setRevision(dt);
+ return true;
+ }
+ }
+
+ if ( fieldname == QString::fromLatin1( "objectclass" ) ) // ignore
+ return true;
+
+ kdWarning() << QString("LDIFConverter: Unknown field for '%1': '%2=%3'\n")
+ .arg(a.formattedName()).arg(fieldname).arg(value);
+
+ return true;
+}
+
+/* The following functions are obsoleted. Similar functionality can be found
+ * in the LDIF class */
+
+bool LDIFConverter::parseSingleLine( Addressee &a, Address &homeAddr,
+ Address &workAddr, QString &line )
+{
+ if ( line.isEmpty() )
+ return true;
+
+ QString fieldname, value;
+ QByteArray val;
+
+ LDIF::splitLine( line.latin1(), fieldname, val );
+ value = QString::fromUtf8( val.data(), val.size() );
+ return evaluatePair( a, homeAddr, workAddr, fieldname, value);
+}
+
+
+bool LDIFConverter::splitLine( QString &line, QString &fieldname, QString &value)
+{
+ QByteArray val;
+ bool ret = LDIF::splitLine( line.latin1(), fieldname, val );
+ value = QString::fromUtf8( val.data(), val.size() );
+ return ret;
+}
+
+
+QString LDIFConverter::makeLDIFfieldString( QString formatStr, QString value, bool allowEncode )
+{
+ if ( value.isEmpty() )
+ return QString();
+
+ // append format if not given
+ if (formatStr.find(':') == -1)
+ formatStr.append(": %1\n");
+
+ // check if base64-encoding is needed
+ bool printable = true;
+ unsigned int i, len;
+ len = value.length();
+ for (i = 0; i<len; ++i ) {
+ if (!value[i].isPrint()) {
+ printable = false;
+ break;
+ }
+ }
+
+ if (printable) // always encode if we find special chars...
+ printable = (value.find('\n') == -1);
+
+ if (!printable && allowEncode) {
+ // encode to base64
+ value = KCodecs::base64Encode( value.utf8() );
+ int p = formatStr.find(':');
+ if (p>=0)
+ formatStr.insert(p, ':');
+ }
+
+ // generate the new string and split it to 72 chars/line
+ QCString txt = (formatStr.arg(value)).utf8();
+
+ if (allowEncode) {
+ len = txt.length();
+ if (len && txt[len-1] == '\n')
+ --len;
+ i = 72;
+ while (i < len) {
+ txt.insert(i, "\n ");
+ i += 72+1;
+ len += 2;
+ }
+ }
+
+ return QString::fromUtf8(txt);
+}
+