kitchensync

addressbook.cpp

00001 /*
00002     This file is part of KitchenSync.
00003 
00004     Copyright (c) 2002,2003 Holger Freyther <freyther@kde.org>
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Library General Public
00008     License as published by the Free Software Foundation; either
00009     version 2 of the License, or (at your option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     Library General Public License for more details.
00015 
00016     You should have received a copy of the GNU Library General Public License
00017     along with this library; see the file COPYING.LIB.  If not, write to
00018     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019     Boston, MA 02110-1301, USA.
00020 */
00021 
00022 #include <qdom.h>
00023 #include <qfile.h>
00024 
00025 #include <klocale.h>
00026 
00027 
00028 #include "device.h"
00029 #include "addressbook.h"
00030 
00031 
00032 using namespace OpieHelper;
00033 
00034 AddressBook::AddressBook( CategoryEdit *edit,
00035                           KSync::KonnectorUIDHelper* helper,
00036                           const QString &tz,
00037                           Device *dev )
00038     : Base( edit,  helper,  tz, dev )
00039 {
00040 }
00041 AddressBook::~AddressBook(){
00042 }
00043 
00044 KSync::AddressBookSyncee* AddressBook::toKDE( const QString &fileName, ExtraMap& map )
00045 {
00046   KSync::AddressBookSyncee *syncee = new KSync::AddressBookSyncee();
00047   syncee->setTitle( i18n("Opie") );
00048   syncee->setIdentifier( "Opie-Addresses" );
00049 
00050   //return entry;
00051   QFile file( fileName );
00052   if ( !file.open(IO_ReadOnly ) ) {
00053     //delete syncee; there is not addressbook so to get one synced we need to add an empty Syncee
00054     return syncee;
00055   }
00056 
00057   QDomDocument doc("mydocument" );
00058   if ( !doc.setContent( &file ) ) {
00059     file.close();
00060     delete syncee;
00061     return 0;
00062   }
00063 
00064 
00065   QDomElement docElem = doc.documentElement( );
00066   QDomNode n =  docElem.firstChild();
00067   QStringList attr = supportedAttributes();
00068   while ( !n.isNull() ) {
00069     QDomElement e = n.toElement();
00070     if ( !e.isNull() ) {
00071       if ( e.tagName() == QString::fromLatin1( "Contacts" ) ) { // we're looking for them
00072         QDomNode no = e.firstChild();
00073         while ( !no.isNull() ) {
00074           QDomElement el = no.toElement();
00075           if ( !el.isNull() ) {
00076             KABC::Addressee adr;
00077             adr.setUid( kdeId( "AddressBookSyncEntry",  el.attribute("Uid" ) ) );
00078             adr.setFamilyName( el.attribute( "LastName" ) );
00079             adr.setGivenName( el.attribute( "FirstName" ) );
00080             adr.setAdditionalName( el.attribute( "MiddleName" )  );
00081             adr.setSuffix( el.attribute( "Suffix" ) );
00082             adr.setNickName( el.attribute( "Nickname" ) );
00083 
00084             QDate date = dateFromString( el.attribute( "Birthday" ) );
00085             if ( date.isValid() )
00086               adr.setBirthday( date );
00087 
00088             adr.setRole( el.attribute( "JobTitle" ) );
00089             if ( !el.attribute( "FileAs" ).isEmpty() )
00090               adr.setFormattedName( el.attribute( "FileAs" ) );
00091 
00092             adr.setOrganization( el.attribute( "Company" ) );
00093 
00094             KABC::PhoneNumber businessPhoneNum( el.attribute( "BusinessPhone" ),
00095                                                 KABC::PhoneNumber::Work );
00096             KABC::PhoneNumber businessFaxNum( el.attribute( "BusinessFax" ),
00097                                               KABC::PhoneNumber::Work | KABC::PhoneNumber::Fax );
00098             KABC::PhoneNumber businessMobile( el.attribute( "BusinessMobile" ),
00099                                               KABC::PhoneNumber::Work | KABC::PhoneNumber::Cell );
00100             KABC::PhoneNumber businessPager( el.attribute( "BusinessPager" ),
00101                                              KABC::PhoneNumber::Work | KABC::PhoneNumber::Pager );
00102             if ( !businessPhoneNum.number().isEmpty() )
00103               adr.insertPhoneNumber( businessPhoneNum );
00104             if ( !businessFaxNum.number().isEmpty() )
00105               adr.insertPhoneNumber( businessFaxNum );
00106             if ( !businessMobile.number().isEmpty() )
00107               adr.insertPhoneNumber( businessMobile );
00108             if ( !businessPager.number().isEmpty() )
00109               adr.insertPhoneNumber( businessPager  );
00110 
00111             // Handle multiple mail addresses
00112             QString DefaultEmail = el.attribute( "DefaultEmail" );
00113             if ( !DefaultEmail.isEmpty() )
00114               adr.insertEmail( DefaultEmail, true ); // preferred
00115 
00116             QString Emails = el.attribute("Emails");
00117             int emailCount = 1;
00118             QString Email = Emails.section( ' ', 1, 1, QString::SectionSkipEmpty );
00119             while ( !Email.isEmpty() ) {
00120               // Handle all the secondary emails ...
00121               if ( Email != DefaultEmail )
00122                 adr.insertEmail( Email, false );
00123               emailCount++;
00124               Email = Emails.section( ' ', emailCount, emailCount, QString::SectionSkipEmpty );
00125             }
00126 
00127 
00128             KABC::PhoneNumber homePhoneNum( el.attribute( "HomePhone" ),
00129                                             KABC::PhoneNumber::Home );
00130             KABC::PhoneNumber homeFax( el.attribute( "HomeFax" ),
00131                                        KABC::PhoneNumber::Home | KABC::PhoneNumber::Fax );
00132 
00133             KABC::PhoneNumber homeMobile( el.attribute( "HomeMobile" ),
00134                                           KABC::PhoneNumber::Cell );
00135 
00136             if ( !homePhoneNum.number().isEmpty() )
00137               adr.insertPhoneNumber( homePhoneNum );
00138             if ( !homeFax.number().isEmpty() )
00139               adr.insertPhoneNumber( homeFax );
00140             if ( !homeMobile.number().isEmpty() )
00141               adr.insertPhoneNumber( homeMobile );
00142 
00143             KABC::Address business( KABC::Address::Work );
00144             business.setStreet( el.attribute( "BusinessStreet" ) );
00145             business.setLocality( el.attribute( "BusinessCity"  ) );
00146             business.setRegion( el.attribute( "BusinessState" ) );
00147             business.setPostalCode( el.attribute( "BusinessZip" )  );
00148             business.setCountry( el.attribute( "BusinessCountry" ) );
00149 
00150             if ( !business.isEmpty() )
00151               adr.insertAddress( business );
00152 
00153             KABC::Address home( KABC::Address::Home );
00154             home.setStreet( el.attribute( "HomeStreet" ) );
00155             home.setLocality( el.attribute( "HomeCity" ) );
00156             home.setRegion( el.attribute( "HomeState" ) );
00157             home.setPostalCode( el.attribute( "HomeZip" ) );
00158             home.setCountry( el.attribute( "HomeCountry" ) );
00159 
00160             if ( !home.isEmpty() )
00161               adr.insertAddress( home );
00162 
00163             adr.setNickName( el.attribute( "Nickname" ) );
00164             adr.setNote( el.attribute( "Notes" ) );
00165 
00166             {
00167               QStringList categories = QStringList::split(";", el.attribute("Categories" ) );
00168               QString cat;
00169               QStringList added;
00170               for ( uint i = 0; i < categories.count(); i++ ) {
00171                 cat = m_edit->categoryById( categories[ i ], "Contacts" );
00172 
00173                 // if name is not empty and we did not add the
00174                 // cat try to repair broken files
00175                 if ( !cat.isEmpty() && !added.contains( cat ) ) {
00176                   adr.insertCategory( cat );
00177                   added << cat;
00178                 }
00179               }
00180             }
00181 
00182             if ( !el.attribute( "Department" ).isEmpty() )
00183               adr.insertCustom( "KADDRESSBOOK", "X-Department",  el.attribute( "Department" ) );
00184             if ( !el.attribute( "HomeWebPage" ).isEmpty() )
00185               adr.insertCustom( "opie", "HomeWebPage", el.attribute( "HomeWebPage" ) );
00186             if ( !el.attribute( "Spouse" ).isEmpty() )
00187               adr.insertCustom( "KADDRESSBOOK", "X-SpousesName", el.attribute( "Spouse" ) );
00188             if ( !el.attribute( "Gender" ).isEmpty() )
00189               adr.insertCustom( "opie", "Gender", el.attribute( "Gender" ) );
00190 
00191             QDate ann = dateFromString( el.attribute( "Anniversary" ) );
00192             if ( ann.isValid() ) {
00193               adr.insertCustom( "KADDRESSBOOK", "X-Anniversary", ann.toString( Qt::ISODate ) );
00194             }
00195 
00196             if ( !el.attribute( "Children" ).isEmpty() )
00197               adr.insertCustom("opie", "Children", el.attribute("Children") );
00198             if ( !el.attribute( "Office" ).isEmpty() )
00199               adr.insertCustom("KADDRESSBOOK", "X-Office", el.attribute("Office") );
00200             if ( !el.attribute( "Profession" ).isEmpty() )
00201               adr.insertCustom("KADDRESSBOOK", "X-Profession", el.attribute("Profession") );
00202             if ( !el.attribute( "Assistant" ).isEmpty() )
00203               adr.insertCustom("KADDRESSBOOK", "X-AssistantsName", el.attribute("Assistant") );
00204             if ( !el.attribute( "Manager" ).isEmpty() )
00205               adr.insertCustom("KADDRESSBOOK", "X-ManagersName", el.attribute("Manager") );
00206 
00207             KSync::AddressBookSyncEntry* entry = new KSync::AddressBookSyncEntry( adr, syncee );
00208             syncee->addEntry ( entry );
00209 
00210             // now on to the extra stuff
00211             map.add( "addressbook", el.attribute( "Uid" ), el.attributes(), attr );
00212           }
00213 
00214           no = no.nextSibling();
00215         }
00216       }
00217     }
00218 
00219     n = n.nextSibling();
00220   }
00221 
00222   return syncee;
00223 }
00224 KTempFile* AddressBook::fromKDE( KSync::AddressBookSyncee *syncee, ExtraMap& map )
00225 {
00226     //  ok lets write back the changes from the Konnector
00227     m_kde2opie.clear(); // clear the reference first
00228     Kontainer::ValueList newIds = syncee->ids( "AddressBookSyncEntry");
00229     for ( Kontainer::ValueList::ConstIterator idIt = newIds.begin(); idIt != newIds.end(); ++idIt ) {
00230         m_helper->addId("AddressBookSyncEntry",  (*idIt).first,  (*idIt).second ); // FIXME update this name later
00231     }
00232     KTempFile* tempFile = file();
00233     if ( tempFile->textStream() ) {
00234         QTextStream *stream = tempFile->textStream();
00235         stream->setEncoding( QTextStream::UnicodeUTF8 );
00236         *stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>" << endl;
00237         *stream << " <Groups>" << endl;
00238         *stream << " </Groups>" << endl;
00239         *stream << " <Contacts> " << endl;
00240 // for all entries
00241         KABC::Addressee ab;
00242         KSync::AddressBookSyncEntry *entry;
00243         for ( entry = syncee->firstEntry(); entry != 0l;  entry = syncee->nextEntry() ) {
00244             /* do not safe deleted records */
00245             if (entry->wasRemoved() )
00246                 continue;
00247 
00248             ab = entry->addressee();
00249             *stream << "<Contact ";
00250             *stream << appendText( "FirstName=\"" + escape(ab.givenName()) + "\" ",
00251                                    "FirstName=\"\" " );
00252             *stream << appendText( "MiddleName=\"" + escape(ab.additionalName()) + "\" ",
00253                                    "MiddleName=\"\" " );
00254             *stream << appendText( "LastName=\"" + escape(ab.familyName()) + "\" ",
00255                                    "LastName=\"\" " );
00256             *stream << appendText( "Suffix=\"" + escape(ab.suffix()) + "\" ",
00257                                    "Suffix=\"\" " );
00258 
00259             QString sortStr;
00260             sortStr = ab.formattedName();
00261             /* is formattedName is empty we use the assembled name as fallback */
00262             if (sortStr.isEmpty() )
00263                 sortStr = ab.assembledName();
00264             *stream << "FileAs=\"" + escape(sortStr) + "\" ";
00265 
00266             *stream << appendText( "JobTitle=\"" + escape(ab.role()) + "\" ",
00267                                    "JobTitle=\"\" " );
00268             *stream << appendText( "Department=\"" + escape(ab.custom( "KADDRESSBOOK", "X-Department" )) + "\" ",
00269                                    "Department=\"\" ");
00270             *stream << appendText( "Company=\"" + escape(ab.organization()) + "\" ",
00271                                    "Company=\"\" " );
00272 
00273             KABC::PhoneNumber businessPhoneNum = ab.phoneNumber(KABC::PhoneNumber::Work );
00274             *stream << appendText( "BusinessPhone=\"" + escape( businessPhoneNum.number() ) + "\" ",
00275                                    "BusinessPhone=\"\" " );
00276 
00277             KABC::PhoneNumber businessFaxNum = ab.phoneNumber(KABC::PhoneNumber::Work | KABC::PhoneNumber::Fax );
00278             *stream << appendText( "BusinessFax=\"" + escape( businessFaxNum.number() ) + "\" ",
00279                                    "BusinessFax=\"\" " );
00280 
00281             KABC::PhoneNumber businessMobile = ab.phoneNumber(KABC::PhoneNumber::Work | KABC::PhoneNumber::Cell );
00282             *stream << appendText( "BusinessMobile=\"" + escape( businessMobile.number() ) + "\" ",
00283                                    "BusinessMobile=\"\" " );
00284 
00285             *stream << appendText( "DefaultEmail=\"" + escape( ab.preferredEmail() ) + "\" ",
00286                                    "DefaultEmail=\"\" " );
00287             QStringList list = ab.emails();
00288             if ( list.count() > 0 ) {
00289         QStringList::Iterator it = list.begin();
00290                 *stream << "Emails=\"" << escape( *it );
00291         while (++it != list.end())
00292           *stream << ' ' << escape( *it );
00293                 *stream << "\" ";
00294         }
00295 
00296             KABC::PhoneNumber homePhoneNum = ab.phoneNumber(KABC::PhoneNumber::Home );
00297             *stream << appendText( "HomePhone=\"" + escape( homePhoneNum.number() ) + "\" ",
00298                                    "HomePhone=\"\" " );
00299 
00300             KABC::PhoneNumber homeFax = ab.phoneNumber( KABC::PhoneNumber::Home | KABC::PhoneNumber::Fax );
00301             *stream << appendText( "HomeFax=\"" + escape( homeFax.number() ) + "\" ",
00302                                    "HomeFax=\"\" " );
00303 
00304             KABC::PhoneNumber homeMobile = ab.phoneNumber( KABC::PhoneNumber::Cell );
00305             *stream << appendText( "HomeMobile=\"" + escape( homeMobile.number() ) + "\" ",
00306                                    "HomeMobile=\"\" " );
00307             KABC::Address business = ab.address(KABC::Address::Work  );
00308             *stream << appendText( "BusinessStreet=\"" + escape( business.street() ) + "\" ",
00309                                    "BusinessStreet=\"\" " );
00310             *stream << appendText( "BusinessCity=\"" + escape( business.locality() ) + "\" ",
00311                                    "BusinessCity=\"\" " );
00312             *stream << appendText( "BusinessZip=\"" + escape( business.postalCode() ) + "\" ",
00313                                    "BusinessZip=\"\" " );
00314             *stream << appendText( "BusinessCountry=\"" + escape( business.country() ) + "\" ",
00315                                    "BusinessCountry=\"\" " );
00316             *stream << appendText( "BusinessState=\"" + escape( business.region() ) + "\" ",
00317                                    "BusinessState=\"\" " );
00318             //stream << "BusinessPager=\"" << << "\" ";
00319 
00320 
00321             *stream << appendText( "Office=\"" + escape( ab.custom( "KADDRESSBOOK",  "X-Office" ) ) + "\" ",
00322                                    "Office=\"\" " );
00323             *stream << appendText( "Profession=\"" + escape( ab.custom( "KADDRESSBOOK",  "X-Profession" ) ) + "\" ",
00324                                    "Profession=\"\" " );
00325             *stream << appendText( "Assistant=\"" + escape( ab.custom( "KADDRESSBOOK",  "X-AssistantsName") ) + "\" ",
00326                                    "Assistant=\"\" " );
00327             *stream << appendText( "Manager=\"" + escape( ab.custom( "KADDRESSBOOK",  "X-ManagersName" ) ) + "\" ",
00328                                    "Manager=\"\" " );
00329 
00330             KABC::Address home = ab.address( KABC::Address::Home );
00331             *stream << appendText( "HomeStreet=\"" + escape( home.street() ) + "\" ",
00332                                    "HomeStreet=\"\" " );
00333             *stream << appendText( "HomeCity=\"" +  escape( home.locality() ) + "\" ",
00334                                    "HomeCity=\"\" " );
00335             *stream << appendText( "HomeState=\"" +  escape( home.region() ) + "\" ",
00336                                    "HomeState=\"\" " );
00337             *stream << appendText( "HomeZip=\"" +  escape( home.postalCode() ) + "\" ",
00338                                    "HomeZip=\"\" " );
00339             *stream << appendText( "HomeCountry=\"" + escape( home.country() ) + "\" ",
00340                                    "HomeCountry=\"\" ");
00341 
00342             *stream << appendText( "HomeWebPage=\"" + escape( ab.custom( "opie", "HomeWebPage" ) ) + "\" ",
00343                                    "HomeWebPage=\"\" " );
00344             *stream << appendText( "Spouse=\"" + escape( ab.custom( "KADDRESSBOOK",  "X-SpousesName") ) + "\" ",
00345                                    "Spouse=\"\" " );
00346             *stream << appendText( "Gender=\"" + escape( ab.custom( "opie",  "Gender") ) + "\" ",
00347                                    "Gender=\"\" " );
00348 
00349             if ( ab.birthday().date().isValid() )
00350                 *stream << appendText( "Birthday=\"" + escape( dateToString(ab.birthday().date() ) ) + "\" ",
00351                                        "Birthday=\"\" " );
00352 
00353             /*
00354              * Anniversary block again
00355              * Go from ISO -> QDate -> toString and then escape
00356              */
00357             {
00358                 QDate ann = QDate::fromString( ab.custom("KADDRESSBOOK", "X-Anniversary"), Qt::ISODate );
00359                 if (ann.isValid() ) {
00360                     *stream << appendText( "Anniversary=\"" + escape( dateToString( ann )  ) + "\" ",
00361                                            "Anniversary=\"\" " );
00362                 }
00363             }
00364             *stream << appendText( "Nickname=\"" + escape( ab.nickName() ) + "\" ",
00365                                    "Nickname=\"\" " );
00366             *stream << appendText( "Children=\"" + escape( ab.custom("opie", "Children" ) ) + "\" ",
00367                                    "Children=\"\" ");
00368             *stream << appendText( "Notes=\"" + escape( ab.note() ) + "\" ",
00369                                    "Notes=\"\" " );
00370             *stream << appendText("Categories=\"" +
00371                                   categoriesToNumber( ab.categories(), "Contacts") + "\" ",
00372                                   "Categories=\"\" " );
00373 
00374             QString uid = konnectorId( "AddressBookSyncEntry", ab.uid() );
00375             *stream << "Uid=\"" <<  uid << "\" ";
00376             *stream << map.toString( "addressbook", uid );
00377             *stream << " />" << endl;
00378         } // off for
00379         *stream << "</Contacts>" << endl;
00380         *stream << "</AddressBook>" << endl;
00381     }
00382     // now replace the UIDs for us
00383     m_helper->replaceIds( "AddressBookSyncEntry",  m_kde2opie ); // to keep the use small
00384 
00385     tempFile->close();
00386 
00387     return tempFile;
00388 }
00389 
00390 QStringList AddressBook::supportedAttributes() {
00391     QStringList lst;
00392     lst << "FirstName";
00393     lst << "MiddleName";
00394     lst << "LastName";
00395     lst << "Suffix";
00396     lst << "FileAs";
00397     lst << "JobTitle";
00398     lst << "Department";
00399     lst << "Company";
00400     lst << "BusinessPhone";
00401     lst << "BusinessFax";
00402     lst << "BusinessMobile";
00403     lst << "DefaultEmail";
00404     lst << "Emails";
00405     lst << "HomePhone";
00406     lst << "HomeFax";
00407     lst << "HomeMobile";
00408     lst << "BusinessStreet";
00409     lst << "BusinessCity";
00410     lst << "BusinessZip";
00411     lst << "BusinessCountry";
00412     lst << "BusinessState";
00413     lst << "Office";
00414     lst << "Profession";
00415     lst << "Assistant";
00416     lst << "Manager";
00417     lst << "HomeStreet";
00418     lst << "HomeCity";
00419     lst << "HomeState";
00420     lst << "HomeZip";
00421     lst << "HomeCountry";
00422     lst << "HomeWebPage";
00423     lst << "Spouse";
00424     lst << "Gender";
00425     lst << "Anniversary";
00426     lst << "Nickname";
00427     lst << "Children";
00428     lst << "Notes";
00429     lst << "Categories";
00430     lst << "Uid";
00431     lst << "Birthday";
00432 
00433     return lst;
00434 }
00435 
00436 // FROM TT timeconversion.cpp GPLed
00437 QDate AddressBook::fromString( const QString &datestr )
00438 {
00439     if (datestr.isEmpty() )
00440         return QDate();
00441 
00442     int monthPos = datestr.find('.');
00443     int yearPos = datestr.find('.', monthPos+1 );
00444     if ( monthPos == -1 || yearPos == -1 ) {
00445     return QDate();
00446     }
00447     int d = datestr.left( monthPos ).toInt();
00448     int m = datestr.mid( monthPos+1, yearPos - monthPos - 1 ).toInt();
00449     int y = datestr.mid( yearPos+1 ).toInt();
00450     QDate date ( y,m,d );
00451 
00452 
00453     return date;
00454 }
00455 
00456 
00457 QString AddressBook::dateToString( const QDate &d )
00458 {
00459     if ( d.isNull() || !d.isValid() )
00460         return QString::null;
00461 
00462     // ISO format in year, month, day (YYYYMMDD); e.g. 20021231
00463     QString year = QString::number( d.year() );
00464     QString month = QString::number( d.month() );
00465     month = month.rightJustify( 2, '0' );
00466     QString day = QString::number( d.day() );
00467     day = day.rightJustify( 2, '0' );
00468 
00469     QString str = year + month + day;
00470 
00471     return str;
00472 }
00473 
00474 QDate AddressBook::dateFromString( const QString& s )
00475 {
00476     QDate date;
00477 
00478     if ( s.isEmpty() )
00479         return date;
00480 
00481     // Be backward compatible to old Opie format:
00482     // Try to load old format. If it fails, try new ISO-Format!
00483     date = fromString ( s );
00484     if ( date.isValid() )
00485         return date;
00486 
00487     // Read ISO-Format (YYYYMMDD)
00488     int year = s.mid(0, 4).toInt();
00489     int month = s.mid(4,2).toInt();
00490     int day = s.mid(6,2).toInt();
00491 
00492     // do some quick sanity checking
00493     if ( year < 1900 || year > 3000 )
00494         return date;
00495 
00496     if ( month < 0 || month > 12 )
00497         return date;
00498 
00499     if ( day < 0 || day > 31 )
00500         return date;
00501 
00502 
00503     date.setYMD( year, month, day );
00504 
00505     if ( !date.isValid() )
00506         return QDate();
00507 
00508 
00509     return date;
00510 }
KDE Home | KDE Accessibility Home | Description of Access Keys